3 * Set tabs to 4 for best viewing.
5 * Latest version is available at http://adodb.sourceforge.net
7 * This is the main include file for ADOdb.
8 * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php
10 * The ADOdb files are formatted so that doxygen can be used to generate documentation.
11 * Doxygen is a documentation generation tool and can be downloaded from http://doxygen.org/
17 @version v5.20.1 06-Dec-2015
18 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
19 @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community
21 Released under both BSD license and Lesser GPL library license. You can choose which license
24 PHP's database access functions are not standardised. This creates a need for a database
25 class library to hide the differences between the different database API's (encapsulate
26 the differences) so we can easily switch databases.
28 We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, DB2,
29 Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access,
30 ADO, SAP DB, SQLite and ODBC. We have had successful reports of connecting to Progress and
31 other databases via ODBC.
33 Latest Download at http://adodb.sourceforge.net/
37 if (!defined('_ADODB_LAYER')) {
38 define('_ADODB_LAYER',1);
40 //==============================================================================================
41 // CONSTANT DEFINITIONS
42 //==============================================================================================
46 * Set ADODB_DIR to the directory where this file resides...
47 * This constant was formerly called $ADODB_RootPath
49 if (!defined('ADODB_DIR')) {
50 define('ADODB_DIR',dirname(__FILE__));
53 //==============================================================================================
55 //==============================================================================================
58 $ADODB_vers, // database version
59 $ADODB_COUNTRECS, // count number of records returned - slows down query
60 $ADODB_CACHE_DIR, // directory to cache recordsets
63 $ADODB_EXTENSION, // ADODB extension installed
64 $ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF
65 $ADODB_FETCH_MODE, // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...
67 $ADODB_QUOTE_FIELDNAMES; // Allows you to force quotes (backticks) around field names in queries generated by getinsertsql and getupdatesql.
69 //==============================================================================================
71 //==============================================================================================
73 $ADODB_EXTENSION = defined('ADODB_EXTENSION');
75 // ********************************************************
76 // Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).
77 // Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi
79 // 0 = ignore empty fields. All empty fields in array are ignored.
80 // 1 = force null. All empty, php null and string 'null' fields are changed to sql NULL values.
81 // 2 = force empty. All empty, php null and string 'null' fields are changed to sql empty '' or 0 values.
82 // 3 = force value. Value is left as it is. Php null and string 'null' are set to sql NULL values and empty fields '' are set to empty '' sql values.
84 define('ADODB_FORCE_IGNORE',0);
85 define('ADODB_FORCE_NULL',1);
86 define('ADODB_FORCE_EMPTY',2);
87 define('ADODB_FORCE_VALUE',3);
88 // ********************************************************
91 if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) {
93 define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');
95 // allow [ ] @ ` " and . in table names
96 define('ADODB_TABLE_REGEX','([]0-9a-z_\:\"\`\.\@\[-]*)');
98 // prefetching used by oracle
99 if (!defined('ADODB_PREFETCH_ROWS')) {
100 define('ADODB_PREFETCH_ROWS',10);
107 * Set global variable $ADODB_FETCH_MODE to one of these constants or use
108 * the SetFetchMode() method to control how recordset fields are returned
109 * when fetching data.
112 * - ASSOC: array('id' => 456, 'name' => 'john')
113 * - BOTH: array(0 => 456, 'id' => 456, 1 => 'john', 'name' => 'john')
114 * - DEFAULT: driver-dependent
116 define('ADODB_FETCH_DEFAULT', 0);
117 define('ADODB_FETCH_NUM', 1);
118 define('ADODB_FETCH_ASSOC', 2);
119 define('ADODB_FETCH_BOTH', 3);
122 * Associative array case constants
124 * By defining the ADODB_ASSOC_CASE constant to one of these values, it is
125 * possible to control the case of field names (associative array's keys)
126 * when operating in ADODB_FETCH_ASSOC fetch mode.
127 * - LOWER: $rs->fields['orderid']
128 * - UPPER: $rs->fields['ORDERID']
129 * - NATIVE: $rs->fields['OrderID'] (or whatever the RDBMS will return)
131 * The default is to use native case-names.
133 * NOTE: This functionality is not implemented everywhere, it currently
134 * works only with: mssql, odbc, oci8 and ibase derived drivers
136 define('ADODB_ASSOC_CASE_LOWER', 0);
137 define('ADODB_ASSOC_CASE_UPPER', 1);
138 define('ADODB_ASSOC_CASE_NATIVE', 2);
141 if (!defined('TIMESTAMP_FIRST_YEAR')) {
142 define('TIMESTAMP_FIRST_YEAR',100);
146 * AutoExecute constants
147 * (moved from adodb-pear.inc.php since they are only used in here)
149 define('DB_AUTOQUERY_INSERT', 1);
150 define('DB_AUTOQUERY_UPDATE', 2);
153 // PHP's version scheme makes converting to numbers difficult - workaround
154 $_adodb_ver = (float) PHP_VERSION;
155 if ($_adodb_ver >= 5.2) {
156 define('ADODB_PHPVER',0x5200);
157 } else if ($_adodb_ver >= 5.0) {
158 define('ADODB_PHPVER',0x5000);
160 die("PHP5 or later required. You are running ".PHP_VERSION);
167 Accepts $src and $dest arrays, replacing string $data
169 function ADODB_str_replace($src, $dest, $data) {
170 if (ADODB_PHPVER >= 0x4050) {
171 return str_replace($src,$dest,$data);
176 while ($s !== false) {
177 $data = str_replace($s,$d,$data);
184 function ADODB_Setup() {
186 $ADODB_vers, // database version
187 $ADODB_COUNTRECS, // count number of records returned - slows down query
188 $ADODB_CACHE_DIR, // directory to cache recordsets
194 $ADODB_QUOTE_FIELDNAMES;
196 if (empty($ADODB_CACHE_CLASS)) {
197 $ADODB_CACHE_CLASS = 'ADODB_Cache_File' ;
199 $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
200 $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE;
201 $ADODB_GETONE_EOF = null;
203 if (!isset($ADODB_CACHE_DIR)) {
204 $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp';
206 // do not accept url based paths, eg. http:/ or ftp:/
207 if (strpos($ADODB_CACHE_DIR,'://') !== false) {
208 die("Illegal path http:// or ftp://");
213 // Initialize random number generator for randomizing cache flushes
214 // -- note Since PHP 4.2.0, the seed becomes optional and defaults to a random value if omitted.
215 // MDL-41198 Removed random seed initialization.
216 // srand(((double)microtime())*1000000);
219 * ADODB version as a string.
221 $ADODB_vers = 'v5.20.1 06-Dec-2015';
224 * Determines whether recordset->RecordCount() is used.
225 * Set to false for highest performance -- RecordCount() will always return -1 then
226 * for databases that provide "virtual" recordcounts...
228 if (!isset($ADODB_COUNTRECS)) {
229 $ADODB_COUNTRECS = true;
234 //==============================================================================================
235 // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB
236 //==============================================================================================
240 //==============================================================================================
241 // CLASS ADOFieldObject
242 //==============================================================================================
244 * Helper class for FetchFields -- holds info on a column
246 class ADOFieldObject {
251 // additional fields by dannym... (danny_milo@yahoo.com)
252 var $not_null = false;
253 // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^
254 // so we can as well make not_null standard (leaving it at "false" does not harm anyways)
256 var $has_default = false; // this one I have done only in mysql and postgres for now ...
257 // others to come (dannym)
258 var $default_value; // default, if any, and supported. Check has_default first.
263 function _adodb_safedate($s) {
264 return str_replace(array("'", '\\'), '', $s);
267 // parse date string to prevent injection attack
268 // date string will have one quote at beginning e.g. '3434343'
269 function _adodb_safedateq($s) {
276 for($i=1; $i<$len; $i++) {
281 } elseif ($ch === "'") {
289 return strlen($s2) == 0 ? 'null' : $s2;
293 // for transaction handling
295 function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection) {
296 //print "Errorno ($fn errno=$errno m=$errmsg) ";
297 $thisConnection->_transOK = false;
298 if ($thisConnection->_oldRaiseFn) {
299 $fn = $thisConnection->_oldRaiseFn;
300 $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
306 class ADODB_Cache_File {
308 var $createdir = true; // requires creation of temp dirs
310 function __construct() {
311 global $ADODB_INCLUDED_CSV;
312 if (empty($ADODB_INCLUDED_CSV)) {
313 include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
317 // write serialised recordset to cache item/file
318 function writecache($filename, $contents, $debug, $secs2cache) {
319 return adodb_write_file($filename, $contents,$debug);
322 // load serialised recordset and unserialise it
323 function &readcache($filename, &$err, $secs2cache, $rsClass) {
324 $rs = csv2rs($filename,$err,$secs2cache,$rsClass);
328 // flush all items in cache
329 function flushall($debug=false) {
330 global $ADODB_CACHE_DIR;
334 if (strlen($ADODB_CACHE_DIR) > 1) {
335 $rez = $this->_dirFlush($ADODB_CACHE_DIR);
337 ADOConnection::outp( "flushall: $ADODB_CACHE_DIR<br><pre>\n". $rez."</pre>");
343 // flush one file in cache
344 function flushcache($f, $debug=false) {
347 ADOConnection::outp( "flushcache: failed for $f");
352 function getdirname($hash) {
353 global $ADODB_CACHE_DIR;
354 if (!isset($this->notSafeMode)) {
355 $this->notSafeMode = !ini_get('safe_mode');
357 return ($this->notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($hash,0,2) : $ADODB_CACHE_DIR;
360 // create temp directories
361 function createdir($hash, $debug) {
362 global $ADODB_CACHE_PERMS;
364 $dir = $this->getdirname($hash);
365 if ($this->notSafeMode && !file_exists($dir)) {
367 if (!@mkdir($dir, empty($ADODB_CACHE_PERMS) ? 0771 : $ADODB_CACHE_PERMS)) {
368 if(!is_dir($dir) && $debug) {
369 ADOConnection::outp("Cannot create $dir");
379 * Private function to erase all of the files and subdirectories in a directory.
381 * Just specify the directory, and tell it if you want to delete the directory or just clear it out.
382 * Note: $kill_top_level is used internally in the function to flush subdirectories.
384 function _dirFlush($dir, $kill_top_level = false) {
385 if(!$dh = @opendir($dir)) return;
387 while (($obj = readdir($dh))) {
388 if($obj=='.' || $obj=='..') continue;
391 if (strpos($obj,'.cache')) {
395 $this->_dirFlush($f, true);
398 if ($kill_top_level === true) {
405 //==============================================================================================
406 // CLASS ADOConnection
407 //==============================================================================================
410 * Connection object. For connecting to databases, and executing queries.
412 abstract class ADOConnection {
416 var $dataProvider = 'native';
417 var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql
418 var $database = ''; /// Name of database to be used.
419 var $host = ''; /// The hostname of the database server
420 var $user = ''; /// The username which is used to connect to the database server.
421 var $password = ''; /// Password for the username. For security, we no longer store it.
422 var $debug = false; /// if set to true will output sql statements
423 var $maxblobsize = 262144; /// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxpro
424 var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase
425 var $substr = 'substr'; /// substring operator
426 var $length = 'length'; /// string length ofperator
427 var $random = 'rand()'; /// random function
428 var $upperCase = 'upper'; /// uppercase function
429 var $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the database
430 var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt.
431 var $true = '1'; /// string that represents TRUE for a database
432 var $false = '0'; /// string that represents FALSE for a database
433 var $replaceQuote = "\\'"; /// string to use to replace quotes
434 var $nameQuote = '"'; /// string to use to quote identifiers and names
435 var $charSet=false; /// character set to use - only for interbase, postgres and oci8
436 var $metaDatabasesSQL = '';
437 var $metaTablesSQL = '';
438 var $uniqueOrderBy = false; /// All order by columns have to be unique
439 var $emptyDate = ' ';
440 var $emptyTimeStamp = ' ';
441 var $lastInsID = false;
443 var $hasInsertID = false; /// supports autoincrement ID?
444 var $hasAffectedRows = false; /// supports affected rows for update/delete?
445 var $hasTop = false; /// support mssql/access SELECT TOP 10 * FROM TABLE
446 var $hasLimit = false; /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10
447 var $readOnly = false; /// this is a readonly database - used by phpLens
448 var $hasMoveFirst = false; /// has ability to run MoveFirst(), scrolling backwards
449 var $hasGenID = false; /// can generate sequences using GenID();
450 var $hasTransactions = true; /// has transactions
452 var $genID = 0; /// sequence id used by GenID();
453 var $raiseErrorFn = false; /// error function to call
454 var $isoDates = false; /// accepts dates in ISO format
455 var $cacheSecs = 3600; /// cache for 1 hour
458 var $memCache = false; /// should we use memCache instead of caching in files
459 var $memCacheHost; /// memCache host
460 var $memCachePort = 11211; /// memCache port
461 var $memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib)
463 var $sysDate = false; /// name of function that returns the current date
464 var $sysTimeStamp = false; /// name of function that returns the current timestamp
465 var $sysUTimeStamp = false; // name of function that returns the current timestamp accurate to the microsecond or nearest fraction
466 var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets
468 var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' '
469 var $numCacheHits = 0;
470 var $numCacheMisses = 0;
471 var $pageExecuteCountRows = true;
472 var $uniqueSort = false; /// indicates that all fields in order by must be unique
473 var $leftOuter = false; /// operator to use for left outer join in WHERE clause
474 var $rightOuter = false; /// operator to use for right outer join in WHERE clause
475 var $ansiOuter = false; /// whether ansi outer join syntax supported
476 var $autoRollback = false; // autoRollback on PConnect().
477 var $poorAffectedRows = false; // affectedRows not working or unreliable
479 var $fnExecute = false;
480 var $fnCacheExecute = false;
481 var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char
482 var $rsPrefix = "ADORecordSet_";
484 var $autoCommit = true; /// do not modify this yourself - actually private
485 var $transOff = 0; /// temporarily disable transactions
486 var $transCnt = 0; /// count of nested transactions
488 var $fetchMode=false;
490 var $null2null = 'null'; // in autoexecute/getinsertsql/getupdatesql, this value will be converted to a null
491 var $bulkBind = false; // enable 2D Execute array
495 var $_oldRaiseFn = false;
496 var $_transOK = null;
497 var $_connectionID = false; /// The returned link identifier whenever a successful database connection is made.
498 var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will
499 /// then returned by the errorMsg() function
500 var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8
501 var $_queryID = false; /// This variable keeps the last created result link identifier
503 var $_isPersistentConnection = false; /// A boolean variable to state whether its a persistent connection or normal connection. */
504 var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.
505 var $_evalAll = false;
506 var $_affected = false;
507 var $_logsql = false;
508 var $_transmode = ''; // transaction mode
511 * Additional parameters that may be passed to drivers in the connect string
512 * Driver must be coded to accept the parameters
514 protected $connectionParameters = array();
517 * Adds a parameter to the connection string.
519 * These parameters are added to the connection string when connecting,
520 * if the driver is coded to use it.
522 * @param string $parameter The name of the parameter to set
523 * @param string $value The value of the parameter
527 * @example, for mssqlnative driver ('CharacterSet','UTF-8')
529 final public function setConnectionParameter($parameter,$value)
532 $this->connectionParameters[$parameter] = $value;
536 static function Version() {
539 // Semantic Version number matching regex
540 $regex = '^[vV]?(\d+\.\d+\.\d+' // Version number (X.Y.Z) with optional 'V'
541 . '(?:-(?:' // Optional preprod version: a '-'
542 . 'dev|' // followed by 'dev'
543 . '(?:(?:alpha|beta|rc)(?:\.\d+))' // or a preprod suffix and version number
544 . '))?)(?:\s|$)'; // Whitespace or end of string
546 if (!preg_match("/$regex/", $ADODB_vers, $matches)) {
547 // This should normally not happen... Return whatever is between the start
548 // of the string and the first whitespace (or the end of the string).
549 self::outp("Invalid version number: '$ADODB_vers'", 'Version');
550 $regex = '^[vV]?(.*?)(?:\s|$)';
551 preg_match("/$regex/", $ADODB_vers, $matches);
557 Get server version info...
559 @returns An array with 2 elements: $arr['string'] is the description string,
560 and $arr[version] is the version (also a string).
562 function ServerInfo() {
563 return array('description' => '', 'version' => '');
566 function IsConnected() {
567 return !empty($this->_connectionID);
570 function _findvers($str) {
571 if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) {
579 * All error messages go through this bottleneck function.
580 * You can define your own handler by defining the function name in ADODB_OUTP.
582 static function outp($msg,$newline=true) {
583 global $ADODB_FLUSH,$ADODB_OUTP;
585 if (defined('ADODB_OUTP')) {
589 } else if (isset($ADODB_OUTP)) {
599 if (isset($_SERVER['HTTP_USER_AGENT']) || !$newline) {
602 echo strip_tags($msg);
606 if (!empty($ADODB_FLUSH) && ob_get_length() !== false) {
607 flush(); // do not flush if output buffering enabled - useless - thx to Jesse Mullan
613 $rs = $this->_Execute("select $this->sysTimeStamp");
614 if ($rs && !$rs->EOF) {
615 return $this->UnixTimeStamp(reset($rs->fields));
622 * Connect to database
624 * @param [argHostname] Host to connect to
625 * @param [argUsername] Userid to login
626 * @param [argPassword] Associated password
627 * @param [argDatabaseName] database
628 * @param [forceNew] force new connection
630 * @return true or false
632 function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) {
633 if ($argHostname != "") {
634 $this->host = $argHostname;
636 if ( strpos($this->host, ':') > 0 && isset($this->port) ) {
637 list($this->host, $this->port) = explode(":", $this->host, 2);
639 if ($argUsername != "") {
640 $this->user = $argUsername;
642 if ($argPassword != "") {
643 $this->password = 'not stored'; // not stored for security reasons
645 if ($argDatabaseName != "") {
646 $this->database = $argDatabaseName;
649 $this->_isPersistentConnection = false;
652 if ($rez=$this->_nconnect($this->host, $this->user, $argPassword, $this->database)) {
656 if ($rez=$this->_connect($this->host, $this->user, $argPassword, $this->database)) {
661 $err = $this->ErrorMsg();
663 $err = "Connection error to server '$argHostname' with user '$argUsername'";
667 $err = "Missing extension for ".$this->dataProvider;
670 if ($fn = $this->raiseErrorFn) {
671 $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
674 $this->_connectionID = false;
676 ADOConnection::outp( $this->host.': '.$err);
681 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) {
682 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
687 * Always force a new connection to database - currently only works with oracle
689 * @param [argHostname] Host to connect to
690 * @param [argUsername] Userid to login
691 * @param [argPassword] Associated password
692 * @param [argDatabaseName] database
694 * @return true or false
696 function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {
697 return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
701 * Establish persistent connect to database
703 * @param [argHostname] Host to connect to
704 * @param [argUsername] Userid to login
705 * @param [argPassword] Associated password
706 * @param [argDatabaseName] database
708 * @return return true or false
710 function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {
712 if (defined('ADODB_NEVER_PERSIST')) {
713 return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
716 if ($argHostname != "") {
717 $this->host = $argHostname;
719 if ( strpos($this->host, ':') > 0 && isset($this->port) ) {
720 list($this->host, $this->port) = explode(":", $this->host, 2);
722 if ($argUsername != "") {
723 $this->user = $argUsername;
725 if ($argPassword != "") {
726 $this->password = 'not stored';
728 if ($argDatabaseName != "") {
729 $this->database = $argDatabaseName;
732 $this->_isPersistentConnection = true;
734 if ($rez = $this->_pconnect($this->host, $this->user, $argPassword, $this->database)) {
738 $err = $this->ErrorMsg();
740 $err = "Connection error to server '$argHostname' with user '$argUsername'";
744 $err = "Missing extension for ".$this->dataProvider;
747 if ($fn = $this->raiseErrorFn) {
748 $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
751 $this->_connectionID = false;
753 ADOConnection::outp( $this->host.': '.$err);
758 function outp_throw($msg,$src='WARN',$sql='') {
759 if (defined('ADODB_ERROR_HANDLER') && ADODB_ERROR_HANDLER == 'adodb_throw') {
760 adodb_throw($this->databaseType,$src,-9999,$msg,$sql,false,$this);
763 ADOConnection::outp($msg);
766 // create cache class. Code is backward compat with old memcache implementation
767 function _CreateCache() {
768 global $ADODB_CACHE, $ADODB_CACHE_CLASS;
770 if ($this->memCache) {
771 global $ADODB_INCLUDED_MEMCACHE;
773 if (empty($ADODB_INCLUDED_MEMCACHE)) {
774 include_once(ADODB_DIR.'/adodb-memcache.lib.inc.php');
776 $ADODB_CACHE = new ADODB_Cache_MemCache($this);
778 $ADODB_CACHE = new $ADODB_CACHE_CLASS($this);
782 // Format date column in sql string given an input format that understands Y M D
783 function SQLDate($fmt, $col=false) {
785 $col = $this->sysDate;
787 return $col; // child class implement
791 * Should prepare the sql statement and return the stmt resource.
792 * For databases that do not support this, we return the $sql. To ensure
793 * compatibility with databases that do not support prepare:
795 * $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
796 * $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
797 * $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
799 * @param sql SQL to send to database
801 * @return return FALSE, or the prepared statement, or the original sql if
802 * if the database does not support prepare.
805 function Prepare($sql) {
810 * Some databases, eg. mssql require a different function for preparing
811 * stored procedures. So we cannot use Prepare().
813 * Should prepare the stored procedure and return the stmt resource.
814 * For databases that do not support this, we return the $sql. To ensure
815 * compatibility with databases that do not support prepare:
817 * @param sql SQL to send to database
819 * @return return FALSE, or the prepared statement, or the original sql if
820 * if the database does not support prepare.
823 function PrepareSP($sql,$param=true) {
824 return $this->Prepare($sql,$param);
831 return $this->qstr($s,false);
835 * Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de>
837 function QMagic($s) {
838 return $this->qstr($s,get_magic_quotes_gpc());
842 //if (!empty($this->qNull && $s == 'null') {
845 $s = $this->qstr($s,false);
849 * PEAR DB Compat - do not use internally.
851 function ErrorNative() {
852 return $this->ErrorNo();
857 * PEAR DB Compat - do not use internally.
859 function nextId($seq_name) {
860 return $this->GenID($seq_name);
864 * Lock a row, will escalate and lock the table if row locking not supported
865 * will normally free the lock at the end of the transaction
867 * @param $table name of table to lock
868 * @param $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
870 function RowLock($table,$where,$col='1 as adodbignore') {
874 function CommitLock($table) {
875 return $this->CommitTrans();
878 function RollbackLock($table) {
879 return $this->RollbackTrans();
883 * PEAR DB Compat - do not use internally.
885 * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
886 * for easy porting :-)
888 * @param mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
889 * @returns The previous fetch mode
891 function SetFetchMode($mode) {
892 $old = $this->fetchMode;
893 $this->fetchMode = $mode;
895 if ($old === false) {
896 global $ADODB_FETCH_MODE;
897 return $ADODB_FETCH_MODE;
904 * PEAR DB Compat - do not use internally.
906 function Query($sql, $inputarr=false) {
907 $rs = $this->Execute($sql, $inputarr);
908 if (!$rs && defined('ADODB_PEAR')) {
909 return ADODB_PEAR_Error();
916 * PEAR DB Compat - do not use internally
918 function LimitQuery($sql, $offset, $count, $params=false) {
919 $rs = $this->SelectLimit($sql, $count, $offset, $params);
920 if (!$rs && defined('ADODB_PEAR')) {
921 return ADODB_PEAR_Error();
928 * PEAR DB Compat - do not use internally
930 function Disconnect() {
931 return $this->Close();
935 * Returns a placeholder for query parameters
936 * e.g. $DB->Param('a') will return
937 * - '?' for most databases
939 * - '$1', '$2', etc. for PostgreSQL
940 * @param string $name parameter's name, false to force a reset of the
941 * number to 1 (for databases that require positioned
942 * params such as PostgreSQL; note that ADOdb will
943 * automatically reset this when executing a query )
944 * @param string $type (unused)
945 * @return string query parameter placeholder
947 function Param($name,$type='C') {
952 InParameter and OutParameter are self-documenting versions of Parameter().
954 function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {
955 return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
960 function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {
961 return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);
968 $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
969 $db->Parameter($stmt,$id,'myid');
970 $db->Parameter($stmt,$group,'group',64);
973 @param $stmt Statement returned by Prepare() or PrepareSP().
974 @param $var PHP variable to bind to
975 @param $name Name of stored procedure variable name to bind to.
976 @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
977 @param [$maxLen] Holds an maximum length of the variable.
978 @param [$type] The data type of $var. Legal values depend on driver.
981 function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) {
986 function IgnoreErrors($saveErrs=false) {
988 $saveErrs = array($this->raiseErrorFn,$this->_transOK);
989 $this->raiseErrorFn = false;
992 $this->raiseErrorFn = $saveErrs[0];
993 $this->_transOK = $saveErrs[1];
998 * Improved method of initiating a transaction. Used together with CompleteTrans().
999 * Advantages include:
1001 * a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.
1002 * Only the outermost block is treated as a transaction.<br>
1003 * b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>
1004 * c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block
1005 * are disabled, making it backward compatible.
1007 function StartTrans($errfn = 'ADODB_TransMonitor') {
1008 if ($this->transOff > 0) {
1009 $this->transOff += 1;
1013 $this->_oldRaiseFn = $this->raiseErrorFn;
1014 $this->raiseErrorFn = $errfn;
1015 $this->_transOK = true;
1017 if ($this->debug && $this->transCnt > 0) {
1018 ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
1020 $ok = $this->BeginTrans();
1021 $this->transOff = 1;
1027 Used together with StartTrans() to end a transaction. Monitors connection
1028 for sql errors, and will commit or rollback as appropriate.
1030 @autoComplete if true, monitor sql errors and commit and rollback as appropriate,
1031 and if set to false force rollback even if no SQL error detected.
1032 @returns true on commit, false on rollback.
1034 function CompleteTrans($autoComplete = true) {
1035 if ($this->transOff > 1) {
1036 $this->transOff -= 1;
1039 $this->raiseErrorFn = $this->_oldRaiseFn;
1041 $this->transOff = 0;
1042 if ($this->_transOK && $autoComplete) {
1043 if (!$this->CommitTrans()) {
1044 $this->_transOK = false;
1046 ADOConnection::outp("Smart Commit failed");
1050 ADOConnection::outp("Smart Commit occurred");
1054 $this->_transOK = false;
1055 $this->RollbackTrans();
1057 ADOCOnnection::outp("Smart Rollback occurred");
1061 return $this->_transOK;
1065 At the end of a StartTrans/CompleteTrans block, perform a rollback.
1067 function FailTrans() {
1069 if ($this->transOff == 0) {
1070 ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
1072 ADOConnection::outp("FailTrans was called");
1075 $this->_transOK = false;
1079 Check if transaction has failed, only for Smart Transactions.
1081 function HasFailedTrans() {
1082 if ($this->transOff > 0) {
1083 return $this->_transOK == false;
1091 * @param sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
1092 * @param [inputarr] holds the input data to bind to. Null elements will be set to null.
1093 * @return RecordSet or false
1095 function Execute($sql,$inputarr=false) {
1096 if ($this->fnExecute) {
1097 $fn = $this->fnExecute;
1098 $ret = $fn($this,$sql,$inputarr);
1103 if ($inputarr !== false) {
1104 if (!is_array($inputarr)) {
1105 $inputarr = array($inputarr);
1108 $element0 = reset($inputarr);
1109 # is_object check because oci8 descriptors can be passed in
1110 $array_2d = $this->bulkBind && is_array($element0) && !is_object(reset($element0));
1112 //remove extra memory copy of input -mikefedyk
1115 if (!is_array($sql) && !$this->_bindInputArray) {
1116 // @TODO this would consider a '?' within a string as a parameter...
1117 $sqlarr = explode('?',$sql);
1118 $nparams = sizeof($sqlarr)-1;
1120 // Make sure the number of parameters provided in the input
1121 // array matches what the query expects
1122 if ($nparams != count($inputarr)) {
1124 "Input array has " . count($inputarr) .
1125 " params, does not match query: '" . htmlspecialchars($sql) . "'",
1132 $inputarr = array($inputarr);
1135 foreach($inputarr as $arr) {
1137 //Use each() instead of foreach to reduce memory usage -mikefedyk
1138 while(list(, $v) = each($arr)) {
1139 $sql .= $sqlarr[$i];
1140 // from Ron Baldwin <ron.baldwin#sourceprose.com>
1141 // Only quote string types
1143 if ($typ == 'string') {
1144 //New memory copy of input created here -mikefedyk
1145 $sql .= $this->qstr($v);
1146 } else if ($typ == 'double') {
1147 $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1
1148 } else if ($typ == 'boolean') {
1149 $sql .= $v ? $this->true : $this->false;
1150 } else if ($typ == 'object') {
1151 if (method_exists($v, '__toString')) {
1152 $sql .= $this->qstr($v->__toString());
1154 $sql .= $this->qstr((string) $v);
1156 } else if ($v === null) {
1163 if ($i == $nparams) {
1167 if (isset($sqlarr[$i])) {
1168 $sql .= $sqlarr[$i];
1169 if ($i+1 != sizeof($sqlarr)) {
1170 $this->outp_throw( "Input Array does not match ?: ".htmlspecialchars($sql),'Execute');
1172 } else if ($i != sizeof($sqlarr)) {
1173 $this->outp_throw( "Input array does not match ?: ".htmlspecialchars($sql),'Execute');
1176 $ret = $this->_Execute($sql);
1183 if (is_string($sql)) {
1184 $stmt = $this->Prepare($sql);
1189 foreach($inputarr as $arr) {
1190 $ret = $this->_Execute($stmt,$arr);
1196 $ret = $this->_Execute($sql,$inputarr);
1200 $ret = $this->_Execute($sql,false);
1206 function _Execute($sql,$inputarr=false) {
1207 // ExecuteCursor() may send non-string queries (such as arrays),
1208 // so we need to ignore those.
1209 if( is_string($sql) ) {
1210 // Strips keyword used to help generate SELECT COUNT(*) queries
1211 // from SQL if it exists.
1212 $sql = ADODB_str_replace( '_ADODB_COUNT', '', $sql );
1216 global $ADODB_INCLUDED_LIB;
1217 if (empty($ADODB_INCLUDED_LIB)) {
1218 include(ADODB_DIR.'/adodb-lib.inc.php');
1220 $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr);
1222 $this->_queryID = @$this->_query($sql,$inputarr);
1225 // ************************
1226 // OK, query executed
1227 // ************************
1229 // error handling if query fails
1230 if ($this->_queryID === false) {
1231 if ($this->debug == 99) {
1232 adodb_backtrace(true,5);
1234 $fn = $this->raiseErrorFn;
1236 $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
1241 // return simplified recordset for inserts/updates/deletes with lower overhead
1242 if ($this->_queryID === true) {
1243 $rsclass = $this->rsPrefix.'empty';
1244 $rs = (class_exists($rsclass)) ? new $rsclass(): new ADORecordSet_empty();
1249 // return real recordset from select statement
1250 $rsclass = $this->rsPrefix.$this->databaseType;
1251 $rs = new $rsclass($this->_queryID,$this->fetchMode);
1252 $rs->connection = $this; // Pablo suggestion
1254 if (is_array($sql)) {
1259 if ($rs->_numOfRows <= 0) {
1260 global $ADODB_COUNTRECS;
1261 if ($ADODB_COUNTRECS) {
1263 $rs = $this->_rs2rs($rs,-1,-1,!is_array($sql));
1264 $rs->_queryID = $this->_queryID;
1266 $rs->_numOfRows = 0;
1272 function CreateSequence($seqname='adodbseq',$startID=1) {
1273 if (empty($this->_genSeqSQL)) {
1276 return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
1279 function DropSequence($seqname='adodbseq') {
1280 if (empty($this->_dropSeqSQL)) {
1283 return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
1287 * Generates a sequence id and stores it in $this->genID;
1288 * GenID is only available if $this->hasGenID = true;
1290 * @param seqname name of sequence to use
1291 * @param startID if sequence does not exist, start at this ID
1292 * @return 0 if not supported, otherwise a sequence id
1294 function GenID($seqname='adodbseq',$startID=1) {
1295 if (!$this->hasGenID) {
1296 return 0; // formerly returns false pre 1.60
1299 $getnext = sprintf($this->_genIDSQL,$seqname);
1301 $holdtransOK = $this->_transOK;
1303 $save_handler = $this->raiseErrorFn;
1304 $this->raiseErrorFn = '';
1305 @($rs = $this->Execute($getnext));
1306 $this->raiseErrorFn = $save_handler;
1309 $this->_transOK = $holdtransOK; //if the status was ok before reset
1310 $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
1311 $rs = $this->Execute($getnext);
1313 if ($rs && !$rs->EOF) {
1314 $this->genID = reset($rs->fields);
1316 $this->genID = 0; // false
1323 return $this->genID;
1327 * @param $table string name of the table, not needed by all databases (eg. mysql), default ''
1328 * @param $column string name of the column, not needed by all databases (eg. mysql), default ''
1329 * @return the last inserted ID. Not all databases support this.
1331 function Insert_ID($table='',$column='') {
1332 if ($this->_logsql && $this->lastInsID) {
1333 return $this->lastInsID;
1335 if ($this->hasInsertID) {
1336 return $this->_insertid($table,$column);
1339 ADOConnection::outp( '<p>Insert_ID error</p>');
1347 * Portable Insert ID. Pablo Roca <pabloroca#mvps.org>
1349 * @return the last inserted ID. All databases support this. But aware possible
1350 * problems in multiuser environments. Heavy test this before deploying.
1352 function PO_Insert_ID($table="", $id="") {
1353 if ($this->hasInsertID){
1354 return $this->Insert_ID($table,$id);
1356 return $this->GetOne("SELECT MAX($id) FROM $table");
1361 * @return # rows affected by UPDATE/DELETE
1363 function Affected_Rows() {
1364 if ($this->hasAffectedRows) {
1365 if ($this->fnExecute === 'adodb_log_sql') {
1366 if ($this->_logsql && $this->_affected !== false) {
1367 return $this->_affected;
1370 $val = $this->_affectedrows();
1371 return ($val < 0) ? false : $val;
1375 ADOConnection::outp( '<p>Affected_Rows error</p>',false);
1382 * @return the last error message
1384 function ErrorMsg() {
1385 if ($this->_errorMsg) {
1386 return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
1394 * @return the last error number. Normally 0 means no error.
1396 function ErrorNo() {
1397 return ($this->_errorMsg) ? -1 : 0;
1400 function MetaError($err=false) {
1401 include_once(ADODB_DIR."/adodb-error.inc.php");
1402 if ($err === false) {
1403 $err = $this->ErrorNo();
1405 return adodb_error($this->dataProvider,$this->databaseType,$err);
1408 function MetaErrorMsg($errno) {
1409 include_once(ADODB_DIR."/adodb-error.inc.php");
1410 return adodb_errormsg($errno);
1414 * @returns an array with the primary key columns in it.
1416 function MetaPrimaryKeys($table, $owner=false) {
1417 // owner not used in base class - see oci8
1419 $objs = $this->MetaColumns($table);
1421 foreach($objs as $v) {
1422 if (!empty($v->primary_key)) {
1430 if (function_exists('ADODB_VIEW_PRIMARYKEYS')) {
1431 return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);
1437 * @returns assoc array where keys are tables, and values are foreign keys
1439 function MetaForeignKeys($table, $owner=false, $upper=false) {
1443 * Choose a database to connect to. Many databases do not support this.
1445 * @param dbName is the name of the database to select
1446 * @return true or false
1448 function SelectDB($dbName) {return false;}
1452 * Will select, getting rows from $offset (1-based), for $nrows.
1453 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1454 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1455 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1457 * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
1458 * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
1460 * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
1461 * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
1464 * @param [offset] is the row to start calculations from (1-based)
1465 * @param [nrows] is the number of rows to get
1466 * @param [inputarr] array of bind variables
1467 * @param [secs2cache] is a private parameter only used by jlim
1468 * @return the recordset ($rs->databaseType == 'array')
1470 function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) {
1471 if ($this->hasTop && $nrows > 0) {
1472 // suggested by Reinhard Balling. Access requires top after distinct
1473 // Informix requires first before distinct - F Riosa
1474 $ismssql = (strpos($this->databaseType,'mssql') !== false);
1478 $isaccess = (strpos($this->databaseType,'access') !== false);
1482 // access includes ties in result
1484 $sql = preg_replace(
1485 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1487 if ($secs2cache != 0) {
1488 $ret = $this->CacheExecute($secs2cache, $sql,$inputarr);
1490 $ret = $this->Execute($sql,$inputarr);
1492 return $ret; // PHP5 fix
1493 } else if ($ismssql){
1494 $sql = preg_replace(
1495 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1497 $sql = preg_replace(
1498 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1501 $nn = $nrows + $offset;
1502 if ($isaccess || $ismssql) {
1503 $sql = preg_replace(
1504 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1506 $sql = preg_replace(
1507 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1512 // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows
1513 // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.
1514 global $ADODB_COUNTRECS;
1516 $savec = $ADODB_COUNTRECS;
1517 $ADODB_COUNTRECS = false;
1520 if ($secs2cache != 0) {
1521 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1523 $rs = $this->Execute($sql,$inputarr);
1526 $ADODB_COUNTRECS = $savec;
1527 if ($rs && !$rs->EOF) {
1528 $rs = $this->_rs2rs($rs,$nrows,$offset);
1535 * Create serializable recordset. Breaks rs link to connection.
1537 * @param rs the recordset to serialize
1539 function SerializableRS(&$rs) {
1540 $rs2 = $this->_rs2rs($rs);
1542 $rs2->connection = $ignore;
1548 * Convert database recordset to an array recordset
1549 * input recordset's cursor should be at beginning, and
1550 * old $rs will be closed.
1552 * @param rs the recordset to copy
1553 * @param [nrows] number of rows to retrieve (optional)
1554 * @param [offset] offset by number of rows (optional)
1555 * @return the new recordset
1557 function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true) {
1561 $dbtype = $rs->databaseType;
1563 $rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?
1566 if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {
1568 $rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?
1572 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
1573 $flds[] = $rs->FetchField($i);
1576 $arr = $rs->GetArrayLimit($nrows,$offset);
1582 $arrayClass = $this->arrayClass;
1584 $rs2 = new $arrayClass();
1585 $rs2->connection = $this;
1586 $rs2->sql = $rs->sql;
1587 $rs2->dataProvider = $this->dataProvider;
1588 $rs2->InitArrayFields($arr,$flds);
1589 $rs2->fetchMode = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
1594 * Return all rows. Compat with PEAR DB
1596 function GetAll($sql, $inputarr=false) {
1597 $arr = $this->GetArray($sql,$inputarr);
1601 function GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false) {
1602 $rs = $this->Execute($sql, $inputarr);
1606 $arr = $rs->GetAssoc($force_array,$first2cols);
1610 function CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false) {
1611 if (!is_numeric($secs2cache)) {
1612 $first2cols = $force_array;
1613 $force_array = $inputarr;
1615 $rs = $this->CacheExecute($secs2cache, $sql, $inputarr);
1619 $arr = $rs->GetAssoc($force_array,$first2cols);
1624 * Return first element of first row of sql statement. Recordset is disposed
1627 * @param sql SQL statement
1628 * @param [inputarr] input bind array
1630 function GetOne($sql,$inputarr=false) {
1631 global $ADODB_COUNTRECS,$ADODB_GETONE_EOF;
1633 $crecs = $ADODB_COUNTRECS;
1634 $ADODB_COUNTRECS = false;
1637 $rs = $this->Execute($sql,$inputarr);
1640 $ret = $ADODB_GETONE_EOF;
1642 $ret = reset($rs->fields);
1647 $ADODB_COUNTRECS = $crecs;
1651 // $where should include 'WHERE fld=value'
1652 function GetMedian($table, $field,$where = '') {
1653 $total = $this->GetOne("select count(*) from $table $where");
1658 $midrow = (integer) ($total/2);
1659 $rs = $this->SelectLimit("select $field from $table $where order by 1",1,$midrow);
1660 if ($rs && !$rs->EOF) {
1661 return reset($rs->fields);
1667 function CacheGetOne($secs2cache,$sql=false,$inputarr=false) {
1668 global $ADODB_GETONE_EOF;
1671 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1674 $ret = $ADODB_GETONE_EOF;
1676 $ret = reset($rs->fields);
1684 function GetCol($sql, $inputarr = false, $trim = false) {
1686 $rs = $this->Execute($sql, $inputarr);
1691 $rv[] = trim(reset($rs->fields));
1696 $rv[] = reset($rs->fields);
1707 function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false) {
1708 $rs = $this->CacheExecute($secs, $sql, $inputarr);
1713 $rv[] = trim(reset($rs->fields));
1718 $rv[] = reset($rs->fields);
1729 function Transpose(&$rs,$addfieldnames=true) {
1730 $rs2 = $this->_rs2rs($rs);
1735 $rs2->_transpose($addfieldnames);
1740 Calculate the offset of a date for a particular database and generate
1741 appropriate SQL. Useful for calculating future/past dates and storing
1744 If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
1746 function OffsetDate($dayFraction,$date=false) {
1748 $date = $this->sysDate;
1750 return '('.$date.'+'.$dayFraction.')';
1756 * @param sql SQL statement
1757 * @param [inputarr] input bind array
1759 function GetArray($sql,$inputarr=false) {
1760 global $ADODB_COUNTRECS;
1762 $savec = $ADODB_COUNTRECS;
1763 $ADODB_COUNTRECS = false;
1764 $rs = $this->Execute($sql,$inputarr);
1765 $ADODB_COUNTRECS = $savec;
1767 if (defined('ADODB_PEAR')) {
1768 $cls = ADODB_PEAR_Error();
1773 $arr = $rs->GetArray();
1778 function CacheGetAll($secs2cache,$sql=false,$inputarr=false) {
1779 $arr = $this->CacheGetArray($secs2cache,$sql,$inputarr);
1783 function CacheGetArray($secs2cache,$sql=false,$inputarr=false) {
1784 global $ADODB_COUNTRECS;
1786 $savec = $ADODB_COUNTRECS;
1787 $ADODB_COUNTRECS = false;
1788 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1789 $ADODB_COUNTRECS = $savec;
1792 if (defined('ADODB_PEAR')) {
1793 $cls = ADODB_PEAR_Error();
1798 $arr = $rs->GetArray();
1803 function GetRandRow($sql, $arr= false) {
1804 $rezarr = $this->GetAll($sql, $arr);
1805 $sz = sizeof($rezarr);
1806 return $rezarr[abs(rand()) % $sz];
1810 * Return one row of sql statement. Recordset is disposed for you.
1811 * Note that SelectLimit should not be called.
1813 * @param sql SQL statement
1814 * @param [inputarr] input bind array
1816 function GetRow($sql,$inputarr=false) {
1817 global $ADODB_COUNTRECS;
1819 $crecs = $ADODB_COUNTRECS;
1820 $ADODB_COUNTRECS = false;
1822 $rs = $this->Execute($sql,$inputarr);
1824 $ADODB_COUNTRECS = $crecs;
1838 function CacheGetRow($secs2cache,$sql=false,$inputarr=false) {
1839 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1854 * Insert or replace a single record. Note: this is not the same as MySQL's replace.
1855 * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
1856 * Also note that no table locking is done currently, so it is possible that the
1857 * record be inserted twice by two programs...
1859 * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
1862 * $fieldArray associative array of data (you must quote strings yourself).
1863 * $keyCol the primary key field name or if compound key, array of field names
1864 * autoQuote set to true to use a hueristic to quote strings. Works with nulls and numbers
1865 * but does not work with dates nor SQL functions.
1866 * has_autoinc the primary key is an auto-inc field, so skip in insert.
1868 * Currently blob replace not supported
1870 * returns 0 = fail, 1 = update, 2 = insert
1873 function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false) {
1874 global $ADODB_INCLUDED_LIB;
1875 if (empty($ADODB_INCLUDED_LIB)) {
1876 include(ADODB_DIR.'/adodb-lib.inc.php');
1879 return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);
1884 * Will select, getting rows from $offset (1-based), for $nrows.
1885 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1886 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1887 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1889 * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
1890 * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
1892 * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
1894 * @param [secs2cache] seconds to cache data, set to 0 to force query. This is optional
1896 * @param [offset] is the row to start calculations from (1-based)
1897 * @param [nrows] is the number of rows to get
1898 * @param [inputarr] array of bind variables
1899 * @return the recordset ($rs->databaseType == 'array')
1901 function CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false) {
1902 if (!is_numeric($secs2cache)) {
1903 if ($sql === false) {
1906 if ($offset == -1) {
1909 // sql, nrows, offset,inputarr
1910 $rs = $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs);
1912 if ($sql === false) {
1913 $this->outp_throw("Warning: \$sql missing from CacheSelectLimit()",'CacheSelectLimit');
1915 $rs = $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
1921 * Flush cached recordsets that match a particular $sql statement.
1922 * If $sql == false, then we purge all files in the cache.
1924 function CacheFlush($sql=false,$inputarr=false) {
1925 global $ADODB_CACHE_DIR, $ADODB_CACHE;
1927 # Create cache if it does not exist
1928 if (empty($ADODB_CACHE)) {
1929 $this->_CreateCache();
1933 $ADODB_CACHE->flushall($this->debug);
1937 $f = $this->_gencachename($sql.serialize($inputarr),false);
1938 return $ADODB_CACHE->flushcache($f, $this->debug);
1943 * Private function to generate filename for caching.
1944 * Filename is generated based on:
1947 * - database type (oci8, ibase, ifx, etc)
1950 * - setFetchMode (adodb 4.23)
1952 * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
1953 * Assuming that we can have 50,000 files per directory with good performance,
1954 * then we can scale to 12.8 million unique cached recordsets. Wow!
1956 function _gencachename($sql,$createdir) {
1957 global $ADODB_CACHE, $ADODB_CACHE_DIR;
1959 if ($this->fetchMode === false) {
1960 global $ADODB_FETCH_MODE;
1961 $mode = $ADODB_FETCH_MODE;
1963 $mode = $this->fetchMode;
1965 $m = md5($sql.$this->databaseType.$this->database.$this->user.$mode);
1966 if (!$ADODB_CACHE->createdir) {
1970 $dir = $ADODB_CACHE->getdirname($m);
1972 $dir = $ADODB_CACHE->createdir($m, $this->debug);
1975 return $dir.'/adodb_'.$m.'.cache';
1980 * Execute SQL, caching recordsets.
1982 * @param [secs2cache] seconds to cache data, set to 0 to force query.
1983 * This is an optional parameter.
1984 * @param sql SQL statement to execute
1985 * @param [inputarr] holds the input data to bind to
1986 * @return RecordSet or false
1988 function CacheExecute($secs2cache,$sql=false,$inputarr=false) {
1989 global $ADODB_CACHE;
1991 if (empty($ADODB_CACHE)) {
1992 $this->_CreateCache();
1995 if (!is_numeric($secs2cache)) {
1998 $secs2cache = $this->cacheSecs;
2001 if (is_array($sql)) {
2008 $md5file = $this->_gencachename($sql.serialize($inputarr),true);
2011 if ($secs2cache > 0){
2012 $rs = $ADODB_CACHE->readcache($md5file,$err,$secs2cache,$this->arrayClass);
2013 $this->numCacheHits += 1;
2017 $this->numCacheMisses += 1;
2021 // no cached rs found
2023 if (get_magic_quotes_runtime() && !$this->memCache) {
2024 ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
2026 if ($this->debug !== -1) {
2027 ADOConnection::outp( " $md5file cache failure: $err (this is a notice and not an error)");
2031 $rs = $this->Execute($sqlparam,$inputarr);
2035 $rs = $this->_rs2rs($rs); // read entire recordset into memory immediately
2036 $rs->timeCreated = time(); // used by caching
2037 $txt = _rs2serialize($rs,false,$sql); // serialize
2039 $ok = $ADODB_CACHE->writecache($md5file,$txt,$this->debug, $secs2cache);
2041 if ($ok === false) {
2042 $em = 'Cache write error';
2045 if ($fn = $this->raiseErrorFn) {
2046 $fn($this->databaseType,'CacheExecute', $en, $em, $md5file,$sql,$this);
2049 $em = 'Cache file locked warning';
2051 // do not call error handling for just a warning
2055 ADOConnection::outp( " ".$em);
2058 if ($rs->EOF && !$eof) {
2060 //$rs = csv2rs($md5file,$err);
2061 $rs->connection = $this; // Pablo suggestion
2064 } else if (!$this->memCache) {
2065 $ADODB_CACHE->flushcache($md5file);
2068 $this->_errorMsg = '';
2069 $this->_errorCode = 0;
2071 if ($this->fnCacheExecute) {
2072 $fn = $this->fnCacheExecute;
2073 $fn($this, $secs2cache, $sql, $inputarr);
2075 // ok, set cached object found
2076 $rs->connection = $this; // Pablo suggestion
2078 if ($this->debug == 99) {
2081 $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
2082 $ttl = $rs->timeCreated + $secs2cache - time();
2083 $s = is_array($sql) ? $sql[0] : $sql;
2085 $s = '<i>'.htmlspecialchars($s).'</i>';
2088 ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
2096 Similar to PEAR DB's autoExecute(), except that
2097 $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
2098 If $mode == 'UPDATE', then $where is compulsory as a safety measure.
2100 $forceUpdate means that even if the data has not changed, perform update.
2102 function AutoExecute($table, $fields_values, $mode = 'INSERT', $where = false, $forceUpdate = true, $magicq = false) {
2103 if ($where === false && ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) ) {
2104 $this->outp_throw('AutoExecute: Illegal mode=UPDATE with empty WHERE clause', 'AutoExecute');
2108 $sql = "SELECT * FROM $table";
2109 $rs = $this->SelectLimit($sql, 1);
2111 return false; // table does not exist
2114 $rs->tableName = $table;
2115 if ($where !== false) {
2116 $sql .= " WHERE $where";
2122 case DB_AUTOQUERY_UPDATE:
2123 $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq);
2126 case DB_AUTOQUERY_INSERT:
2127 $sql = $this->GetInsertSQL($rs, $fields_values, $magicq);
2130 $this->outp_throw("AutoExecute: Unknown mode=$mode", 'AutoExecute');
2133 return $sql && $this->Execute($sql);
2138 * Generates an Update Query based on an existing recordset.
2139 * $arrFields is an associative array of fields with the value
2140 * that should be assigned.
2142 * Note: This function should only be used on a recordset
2143 * that is run against a single table and sql should only
2144 * be a simple select stmt with no groupby/orderby/limit
2146 * "Jonathan Younger" <jyounger@unilab.com>
2148 function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null) {
2149 global $ADODB_INCLUDED_LIB;
2151 // ********************************************************
2152 // This is here to maintain compatibility
2153 // with older adodb versions. Sets force type to force nulls if $forcenulls is set.
2154 if (!isset($force)) {
2155 global $ADODB_FORCE_TYPE;
2156 $force = $ADODB_FORCE_TYPE;
2158 // ********************************************************
2160 if (empty($ADODB_INCLUDED_LIB)) {
2161 include(ADODB_DIR.'/adodb-lib.inc.php');
2163 return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
2167 * Generates an Insert Query based on an existing recordset.
2168 * $arrFields is an associative array of fields with the value
2169 * that should be assigned.
2171 * Note: This function should only be used on a recordset
2172 * that is run against a single table.
2174 function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null) {
2175 global $ADODB_INCLUDED_LIB;
2176 if (!isset($force)) {
2177 global $ADODB_FORCE_TYPE;
2178 $force = $ADODB_FORCE_TYPE;
2180 if (empty($ADODB_INCLUDED_LIB)) {
2181 include(ADODB_DIR.'/adodb-lib.inc.php');
2183 return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
2188 * Update a blob column, given a where clause. There are more sophisticated
2189 * blob handling functions that we could have implemented, but all require
2190 * a very complex API. Instead we have chosen something that is extremely
2191 * simple to understand and use.
2193 * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
2195 * Usage to update a $blobvalue which has a primary key blob_id=1 into a
2196 * field blobtable.blobcolumn:
2198 * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
2202 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
2203 * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
2205 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') {
2206 return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
2211 * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
2213 * $blobtype supports 'BLOB' and 'CLOB'
2215 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
2216 * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
2218 function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') {
2219 $fd = fopen($path,'rb');
2220 if ($fd === false) {
2223 $val = fread($fd,filesize($path));
2225 return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
2228 function BlobDecode($blob) {
2232 function BlobEncode($blob) {
2236 function GetCharSet() {
2237 return $this->charSet;
2240 function SetCharSet($charset) {
2241 $this->charSet = $charset;
2245 function IfNull( $field, $ifNull ) {
2246 return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
2249 function LogSQL($enable=true) {
2250 include_once(ADODB_DIR.'/adodb-perf.inc.php');
2253 $this->fnExecute = 'adodb_log_sql';
2255 $this->fnExecute = false;
2258 $old = $this->_logsql;
2259 $this->_logsql = $enable;
2260 if ($enable && !$old) {
2261 $this->_affected = false;
2268 * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
2270 * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
2271 * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
2273 function UpdateClob($table,$column,$val,$where) {
2274 return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
2277 // not the fastest implementation - quick and dirty - jlim
2278 // for best performance, use the actual $rs->MetaType().
2279 function MetaType($t,$len=-1,$fieldobj=false) {
2281 if (empty($this->_metars)) {
2282 $rsclass = $this->rsPrefix.$this->databaseType;
2283 $this->_metars = new $rsclass(false,$this->fetchMode);
2284 $this->_metars->connection = $this;
2286 return $this->_metars->MetaType($t,$len,$fieldobj);
2291 * Change the SQL connection locale to a specified locale.
2292 * This is used to get the date formats written depending on the client locale.
2294 function SetDateLocale($locale = 'En') {
2295 $this->locale = $locale;
2296 switch (strtoupper($locale))
2299 $this->fmtDate="'Y-m-d'";
2300 $this->fmtTimeStamp = "'Y-m-d H:i:s'";
2304 $this->fmtDate = "'m-d-Y'";
2305 $this->fmtTimeStamp = "'m-d-Y H:i:s'";
2313 $this->fmtDate="'d-m-Y'";
2314 $this->fmtTimeStamp = "'d-m-Y H:i:s'";
2318 $this->fmtDate="'d.m.Y'";
2319 $this->fmtTimeStamp = "'d.m.Y H:i:s'";
2323 $this->fmtDate="'Y-m-d'";
2324 $this->fmtTimeStamp = "'Y-m-d H:i:s'";
2330 * GetActiveRecordsClass Performs an 'ALL' query
2332 * @param mixed $class This string represents the class of the current active record
2333 * @param mixed $table Table used by the active record object
2334 * @param mixed $whereOrderBy Where, order, by clauses
2335 * @param mixed $bindarr
2336 * @param mixed $primkeyArr
2337 * @param array $extra Query extras: limit, offset...
2338 * @param mixed $relations Associative array: table's foreign name, "hasMany", "belongsTo"
2342 function GetActiveRecordsClass(
2343 $class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false,
2347 global $_ADODB_ACTIVE_DBS;
2348 ## reduce overhead of adodb.inc.php -- moved to adodb-active-record.inc.php
2349 ## if adodb-active-recordx is loaded -- should be no issue as they will probably use Find()
2350 if (!isset($_ADODB_ACTIVE_DBS)) {
2351 include_once(ADODB_DIR.'/adodb-active-record.inc.php');
2353 return adodb_GetActiveRecordsClass($this, $class, $table, $whereOrderBy, $bindarr, $primkeyArr, $extra, $relations);
2356 function GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false) {
2357 $arr = $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr);
2365 $rez = $this->_close();
2366 $this->_connectionID = false;
2371 * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
2373 * @return true if succeeded or false if database does not support transactions
2375 function BeginTrans() {
2377 ADOConnection::outp("BeginTrans: Transactions not supported for this driver");
2382 /* set transaction mode */
2383 function SetTransactionMode( $transaction_mode ) {
2384 $transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider);
2385 $this->_transmode = $transaction_mode;
2388 http://msdn2.microsoft.com/en-US/ms173763.aspx
2389 http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html
2390 http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html
2391 http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm
2393 function MetaTransaction($mode,$db) {
2394 $mode = strtoupper($mode);
2395 $mode = str_replace('ISOLATION LEVEL ','',$mode);
2399 case 'READ UNCOMMITTED':
2403 return 'ISOLATION LEVEL READ COMMITTED';
2405 return 'ISOLATION LEVEL READ UNCOMMITTED';
2409 case 'READ COMMITTED':
2410 return 'ISOLATION LEVEL READ COMMITTED';
2413 case 'REPEATABLE READ':
2417 return 'ISOLATION LEVEL SERIALIZABLE';
2419 return 'ISOLATION LEVEL REPEATABLE READ';
2423 case 'SERIALIZABLE':
2424 return 'ISOLATION LEVEL SERIALIZABLE';
2433 * If database does not support transactions, always return true as data always commited
2435 * @param $ok set to false to rollback transaction, true to commit
2437 * @return true/false.
2439 function CommitTrans($ok=true) {
2445 * If database does not support transactions, rollbacks always fail, so return false
2447 * @return true/false.
2449 function RollbackTrans() {
2455 * return the databases that the driver can connect to.
2456 * Some databases will return an empty array.
2458 * @return an array of database names.
2460 function MetaDatabases() {
2461 global $ADODB_FETCH_MODE;
2463 if ($this->metaDatabasesSQL) {
2464 $save = $ADODB_FETCH_MODE;
2465 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2467 if ($this->fetchMode !== false) {
2468 $savem = $this->SetFetchMode(false);
2471 $arr = $this->GetCol($this->metaDatabasesSQL);
2472 if (isset($savem)) {
2473 $this->SetFetchMode($savem);
2475 $ADODB_FETCH_MODE = $save;
2484 * List procedures or functions in an array.
2485 * @param procedureNamePattern a procedure name pattern; must match the procedure name as it is stored in the database
2486 * @param catalog a catalog name; must match the catalog name as it is stored in the database;
2487 * @param schemaPattern a schema name pattern;
2489 * @return array of procedures on current database.
2492 * [name_of_procedure] => Array(
2493 * [type] => PROCEDURE or FUNCTION
2494 * [catalog] => Catalog_name
2495 * [schema] => Schema_name
2496 * [remarks] => explanatory comment on the procedure
2500 function MetaProcedures($procedureNamePattern = null, $catalog = null, $schemaPattern = null) {
2506 * @param ttype can either be 'VIEW' or 'TABLE' or false.
2507 * If false, both views and tables are returned.
2508 * "VIEW" returns only views
2509 * "TABLE" returns only tables
2510 * @param showSchema returns the schema/user with the table name, eg. USER.TABLE
2511 * @param mask is the input mask - only supported by oci8 and postgresql
2513 * @return array of tables for current database.
2515 function MetaTables($ttype=false,$showSchema=false,$mask=false) {
2516 global $ADODB_FETCH_MODE;
2521 if ($this->metaTablesSQL) {
2522 $save = $ADODB_FETCH_MODE;
2523 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2525 if ($this->fetchMode !== false) {
2526 $savem = $this->SetFetchMode(false);
2529 $rs = $this->Execute($this->metaTablesSQL);
2530 if (isset($savem)) {
2531 $this->SetFetchMode($savem);
2533 $ADODB_FETCH_MODE = $save;
2535 if ($rs === false) {
2538 $arr = $rs->GetArray();
2541 if ($hast = ($ttype && isset($arr[0][1]))) {
2542 $showt = strncmp($ttype,'T',1);
2545 for ($i=0; $i < sizeof($arr); $i++) {
2548 if (strncmp($arr[$i][1],'T',1) == 0) {
2549 $arr2[] = trim($arr[$i][0]);
2552 if (strncmp($arr[$i][1],'V',1) == 0) {
2553 $arr2[] = trim($arr[$i][0]);
2557 $arr2[] = trim($arr[$i][0]);
2566 function _findschema(&$table,&$schema) {
2567 if (!$schema && ($at = strpos($table,'.')) !== false) {
2568 $schema = substr($table,0,$at);
2569 $table = substr($table,$at+1);
2574 * List columns in a database as an array of ADOFieldObjects.
2575 * See top of file for definition of object.
2577 * @param $table table name to query
2578 * @param $normalize makes table name case-insensitive (required by some databases)
2579 * @schema is optional database schema to use - not supported by all databases.
2581 * @return array of ADOFieldObjects for current table.
2583 function MetaColumns($table,$normalize=true) {
2584 global $ADODB_FETCH_MODE;
2586 if (!empty($this->metaColumnsSQL)) {
2588 $this->_findschema($table,$schema);
2590 $save = $ADODB_FETCH_MODE;
2591 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2592 if ($this->fetchMode !== false) {
2593 $savem = $this->SetFetchMode(false);
2595 $rs = $this->Execute(sprintf($this->metaColumnsSQL,($normalize)?strtoupper($table):$table));
2596 if (isset($savem)) {
2597 $this->SetFetchMode($savem);
2599 $ADODB_FETCH_MODE = $save;
2600 if ($rs === false || $rs->EOF) {
2605 while (!$rs->EOF) { //print_r($rs->fields);
2606 $fld = new ADOFieldObject();
2607 $fld->name = $rs->fields[0];
2608 $fld->type = $rs->fields[1];
2609 if (isset($rs->fields[3]) && $rs->fields[3]) {
2610 if ($rs->fields[3]>0) {
2611 $fld->max_length = $rs->fields[3];
2613 $fld->scale = $rs->fields[4];
2614 if ($fld->scale>0) {
2615 $fld->max_length += 1;
2618 $fld->max_length = $rs->fields[2];
2621 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) {
2624 $retarr[strtoupper($fld->name)] = $fld;
2635 * List indexes on a table as an array.
2636 * @param table table name to query
2637 * @param primary true to only show primary keys. Not actually used for most databases
2639 * @return array of indexes on current table. Each element represents an index, and is itself an associative array.
2642 * [name_of_index] => Array(
2643 * [unique] => true or false
2644 * [columns] => Array(
2651 function MetaIndexes($table, $primary = false, $owner = false) {
2656 * List columns names in a table as an array.
2657 * @param table table name to query
2659 * @return array of column names for current table.
2661 function MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */) {
2662 $objarr = $this->MetaColumns($table);
2663 if (!is_array($objarr)) {
2670 foreach($objarr as $v)
2671 $arr[$v->attnum] = $v->name;
2674 foreach($objarr as $v) $arr[$i++] = $v->name;
2676 foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name;
2682 * Different SQL databases used different methods to combine strings together.
2683 * This function provides a wrapper.
2685 * param s variable number of string parameters
2687 * Usage: $db->Concat($str1,$str2);
2689 * @return concatenated string
2692 $arr = func_get_args();
2693 return implode($this->concat_operator, $arr);
2698 * Converts a date "d" to a string that the database can understand.
2700 * @param d a date in Unix date time format.
2702 * @return date string in database date format
2704 function DBDate($d, $isfld=false) {
2705 if (empty($d) && $d !== 0) {
2711 if (is_object($d)) {
2712 return $d->format($this->fmtDate);
2715 if (is_string($d) && !is_numeric($d)) {
2716 if ($d === 'null') {
2719 if (strncmp($d,"'",1) === 0) {
2720 $d = _adodb_safedateq($d);
2723 if ($this->isoDates) {
2726 $d = ADOConnection::UnixDate($d);
2729 return adodb_date($this->fmtDate,$d);
2732 function BindDate($d) {
2733 $d = $this->DBDate($d);
2734 if (strncmp($d,"'",1)) {
2738 return substr($d,1,strlen($d)-2);
2741 function BindTimeStamp($d) {
2742 $d = $this->DBTimeStamp($d);
2743 if (strncmp($d,"'",1)) {
2747 return substr($d,1,strlen($d)-2);
2752 * Converts a timestamp "ts" to a string that the database can understand.
2754 * @param ts a timestamp in Unix date time format.
2756 * @return timestamp string in database timestamp format
2758 function DBTimeStamp($ts,$isfld=false) {
2759 if (empty($ts) && $ts !== 0) {
2765 if (is_object($ts)) {
2766 return $ts->format($this->fmtTimeStamp);
2769 # strlen(14) allows YYYYMMDDHHMMSS format
2770 if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) {
2771 return adodb_date($this->fmtTimeStamp,$ts);
2774 if ($ts === 'null') {
2777 if ($this->isoDates && strlen($ts) !== 14) {
2778 $ts = _adodb_safedate($ts);
2781 $ts = ADOConnection::UnixTimeStamp($ts);
2782 return adodb_date($this->fmtTimeStamp,$ts);
2786 * Also in ADORecordSet.
2787 * @param $v is a date string in YYYY-MM-DD format
2789 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2791 static function UnixDate($v) {
2792 if (is_object($v)) {
2794 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2795 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2798 if (is_numeric($v) && strlen($v) !== 8) {
2801 if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", $v, $rr)) {
2805 if ($rr[1] <= TIMESTAMP_FIRST_YEAR) {
2810 return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2815 * Also in ADORecordSet.
2816 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
2818 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2820 static function UnixTimeStamp($v) {
2821 if (is_object($v)) {
2823 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2824 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2828 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
2829 ($v), $rr)) return false;
2831 if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) {
2836 if (!isset($rr[5])) {
2837 return adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2839 return @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
2843 * Also in ADORecordSet.
2845 * Format database date based on user defined format.
2847 * @param v is the character date in YYYY-MM-DD format, returned by database
2848 * @param fmt is the format to apply to it, using date()
2850 * @return a date formated as user desires
2852 function UserDate($v,$fmt='Y-m-d',$gmt=false) {
2853 $tt = $this->UnixDate($v);
2855 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2856 if (($tt === false || $tt == -1) && $v != false) {
2858 } else if ($tt == 0) {
2859 return $this->emptyDate;
2860 } else if ($tt == -1) {
2861 // pre-TIMESTAMP_FIRST_YEAR
2864 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2870 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
2871 * @param fmt is the format to apply to it, using date()
2873 * @return a timestamp formated as user desires
2875 function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false) {
2877 return $this->emptyTimeStamp;
2879 # strlen(14) allows YYYYMMDDHHMMSS format
2880 if (is_numeric($v) && strlen($v)<14) {
2881 return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v);
2883 $tt = $this->UnixTimeStamp($v);
2884 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2885 if (($tt === false || $tt == -1) && $v != false) {
2889 return $this->emptyTimeStamp;
2891 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2894 function escape($s,$magic_quotes=false) {
2895 return $this->addq($s,$magic_quotes);
2899 * Quotes a string, without prefixing nor appending quotes.
2901 function addq($s,$magic_quotes=false) {
2902 if (!$magic_quotes) {
2903 if ($this->replaceQuote[0] == '\\') {
2904 // only since php 4.0.5
2905 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2906 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2908 return str_replace("'",$this->replaceQuote,$s);
2911 // undo magic quotes for "
2912 $s = str_replace('\\"','"',$s);
2914 if ($this->replaceQuote == "\\'" || ini_get('magic_quotes_sybase')) {
2915 // ' already quoted, no need to change anything
2918 // change \' to '' for sybase/mssql
2919 $s = str_replace('\\\\','\\',$s);
2920 return str_replace("\\'",$this->replaceQuote,$s);
2925 * Correctly quotes a string so that all strings are escaped. We prefix and append
2926 * to the string single-quotes.
2927 * An example is $db->qstr("Don't bother",magic_quotes_runtime());
2929 * @param s the string to quote
2930 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
2931 * This undoes the stupidity of magic quotes for GPC.
2933 * @return quoted string to be sent back to database
2935 function qstr($s,$magic_quotes=false) {
2936 if (!$magic_quotes) {
2937 if ($this->replaceQuote[0] == '\\'){
2938 // only since php 4.0.5
2939 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2940 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2942 return "'".str_replace("'",$this->replaceQuote,$s)."'";
2945 // undo magic quotes for "
2946 $s = str_replace('\\"','"',$s);
2948 if ($this->replaceQuote == "\\'" || ini_get('magic_quotes_sybase')) {
2949 // ' already quoted, no need to change anything
2952 // change \' to '' for sybase/mssql
2953 $s = str_replace('\\\\','\\',$s);
2954 return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
2960 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2961 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2962 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2964 * See docs-adodb.htm#ex8 for an example of usage.
2967 * @param nrows is the number of rows per page to get
2968 * @param page is the page number to get (1-based)
2969 * @param [inputarr] array of bind variables
2970 * @param [secs2cache] is a private parameter only used by jlim
2971 * @return the recordset ($rs->databaseType == 'array')
2973 * NOTE: phpLens uses a different algorithm and does not use PageExecute().
2976 function PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0) {
2977 global $ADODB_INCLUDED_LIB;
2978 if (empty($ADODB_INCLUDED_LIB)) {
2979 include(ADODB_DIR.'/adodb-lib.inc.php');
2981 if ($this->pageExecuteCountRows) {
2982 $rs = _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2984 $rs = _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2991 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2992 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2993 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2995 * @param secs2cache seconds to cache data, set to 0 to force query
2997 * @param nrows is the number of rows per page to get
2998 * @param page is the page number to get (1-based)
2999 * @param [inputarr] array of bind variables
3000 * @return the recordset ($rs->databaseType == 'array')
3002 function CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false) {
3003 /*switch($this->dataProvider) {
3007 default: $secs2cache = 0; break;
3009 $rs = $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
3013 } // end class ADOConnection
3017 //==============================================================================================
3018 // CLASS ADOFetchObj
3019 //==============================================================================================
3022 * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
3027 //==============================================================================================
3028 // CLASS ADORecordSet_empty
3029 //==============================================================================================
3031 class ADODB_Iterator_empty implements Iterator {
3035 function __construct($rs) {
3039 function rewind() {}
3042 return !$this->rs->EOF;
3049 function current() {
3055 function __call($func, $params) {
3056 return call_user_func_array(array($this->rs, $func), $params);
3059 function hasMore() {
3067 * Lightweight recordset when there are no records to be returned
3069 class ADORecordSet_empty implements IteratorAggregate
3071 var $dataProvider = 'empty';
3072 var $databaseType = false;
3074 var $_numOfRows = 0;
3075 var $fields = false;
3076 var $connection = false;
3078 function RowCount() {
3082 function RecordCount() {
3086 function PO_RecordCount() {
3094 function FetchRow() {
3098 function FieldCount() {
3104 function getIterator() {
3105 return new ADODB_Iterator_empty($this);
3108 function GetAssoc() {
3112 function GetArray() {
3120 function GetArrayLimit() {
3124 function GetRows() {
3128 function GetRowAssoc() {
3132 function MaxRecordCount() {
3136 function NumRows() {
3140 function NumCols() {
3145 //==============================================================================================
3146 // DATE AND TIME FUNCTIONS
3147 //==============================================================================================
3148 if (!defined('ADODB_DATE_VERSION')) {
3149 include(ADODB_DIR.'/adodb-time.inc.php');
3152 //==============================================================================================
3153 // CLASS ADORecordSet
3154 //==============================================================================================
3156 class ADODB_Iterator implements Iterator {
3160 function __construct($rs) {
3165 $this->rs->MoveFirst();
3169 return !$this->rs->EOF;
3173 return $this->rs->_currentRow;
3176 function current() {
3177 return $this->rs->fields;
3181 $this->rs->MoveNext();
3184 function __call($func, $params) {
3185 return call_user_func_array(array($this->rs, $func), $params);
3188 function hasMore() {
3189 return !$this->rs->EOF;
3196 * RecordSet class that represents the dataset returned by the database.
3197 * To keep memory overhead low, this class holds only the current row in memory.
3198 * No prefetching of data is done, so the RecordCount() can return -1 ( which
3199 * means recordcount not known).
3201 class ADORecordSet implements IteratorAggregate {
3206 var $dataProvider = "native";
3207 var $fields = false; /// holds the current row data
3208 var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob
3209 /// in other words, we use a text area for editing.
3210 var $canSeek = false; /// indicates that seek is supported
3211 var $sql; /// sql text
3212 var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object.
3214 var $emptyTimeStamp = ' '; /// what to display when $time==0
3215 var $emptyDate = ' '; /// what to display when $time==0
3217 var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsets
3219 var $bind = false; /// used by Fields() to hold array - should be private?
3220 var $fetchMode; /// default fetch mode
3221 var $connection = false; /// the parent connection
3226 var $_numOfRows = -1; /** number of rows, or -1 */
3227 var $_numOfFields = -1; /** number of fields in recordset */
3228 var $_queryID = -1; /** This variable keeps the result link identifier. */
3229 var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */
3230 var $_closed = false; /** has recordset been closed */
3231 var $_inited = false; /** Init() should only be called once */
3232 var $_obj; /** Used by FetchObj */
3233 var $_names; /** Used by FetchObj */
3235 var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */
3236 var $_atFirstPage = false; /** Added by Iván Oliva to implement recordset pagination */
3237 var $_atLastPage = false; /** Added by Iván Oliva to implement recordset pagination */
3238 var $_lastPageNo = -1;
3239 var $_maxRecordCount = 0;
3240 var $datetime = false;
3245 * @param queryID this is the queryID returned by ADOConnection->_query()
3248 function __construct($queryID) {
3249 $this->_queryID = $queryID;
3252 function __destruct() {
3256 function getIterator() {
3257 return new ADODB_Iterator($this);
3260 /* this is experimental - i don't really know what to return... */
3261 function __toString() {
3262 include_once(ADODB_DIR.'/toexport.inc.php');
3263 return _adodb_export($this,',',',',false,true);
3267 if ($this->_inited) {
3270 $this->_inited = true;
3271 if ($this->_queryID) {
3274 $this->_numOfRows = 0;
3275 $this->_numOfFields = 0;
3277 if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
3278 $this->_currentRow = 0;
3279 if ($this->EOF = ($this->_fetch() === false)) {
3280 $this->_numOfRows = 0; // _numOfRows could be -1
3289 * Generate a SELECT tag string from a recordset, and return the string.
3290 * If the recordset has 2 cols, we treat the 1st col as the containing
3291 * the text to display to the user, and 2nd col as the return value. Default
3292 * strings are compared with the FIRST column.
3294 * @param name name of SELECT tag
3295 * @param [defstr] the value to hilite. Use an array for multiple hilites for listbox.
3296 * @param [blank1stItem] true to leave the 1st item in list empty
3297 * @param [multiple] true for listbox, false for popup
3298 * @param [size] #rows to show for listbox. not used by popup
3299 * @param [selectAttr] additional attributes to defined for SELECT tag.
3300 * useful for holding javascript onChange='...' handlers.
3301 & @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with
3302 * column 0 (1st col) if this is true. This is not documented.
3306 * changes by glen.davies@cce.ac.nz to support multiple hilited items
3308 function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
3309 $size=0, $selectAttr='',$compareFields0=true)
3311 global $ADODB_INCLUDED_LIB;
3312 if (empty($ADODB_INCLUDED_LIB)) {
3313 include(ADODB_DIR.'/adodb-lib.inc.php');
3315 return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
3316 $size, $selectAttr,$compareFields0);
3322 * Generate a SELECT tag string from a recordset, and return the string.
3323 * If the recordset has 2 cols, we treat the 1st col as the containing
3324 * the text to display to the user, and 2nd col as the return value. Default
3325 * strings are compared with the SECOND column.
3328 function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='') {
3329 return $this->GetMenu($name,$defstr,$blank1stItem,$multiple,
3330 $size, $selectAttr,false);
3336 function GetMenu3($name,$defstr='',$blank1stItem=true,$multiple=false,
3337 $size=0, $selectAttr='')
3339 global $ADODB_INCLUDED_LIB;
3340 if (empty($ADODB_INCLUDED_LIB)) {
3341 include(ADODB_DIR.'/adodb-lib.inc.php');
3343 return _adodb_getmenu_gp($this, $name,$defstr,$blank1stItem,$multiple,
3344 $size, $selectAttr,false);
3348 * return recordset as a 2-dimensional array.
3350 * @param [nRows] is the number of rows to return. -1 means every row.
3352 * @return an array indexed by the rows (0-based) from the recordset
3354 function GetArray($nRows = -1) {
3355 global $ADODB_EXTENSION; if ($ADODB_EXTENSION) {
3356 $results = adodb_getall($this,$nRows);
3361 while (!$this->EOF && $nRows != $cnt) {
3362 $results[] = $this->fields;
3369 function GetAll($nRows = -1) {
3370 $arr = $this->GetArray($nRows);
3375 * Some databases allow multiple recordsets to be returned. This function
3376 * will return true if there is a next recordset, or false if no more.
3378 function NextRecordSet() {
3383 * return recordset as a 2-dimensional array.
3384 * Helper function for ADOConnection->SelectLimit()
3386 * @param offset is the row to start calculations from (1-based)
3387 * @param [nrows] is the number of rows to return
3389 * @return an array indexed by the rows (0-based) from the recordset
3391 function GetArrayLimit($nrows,$offset=-1) {
3393 $arr = $this->GetArray($nrows);
3397 $this->Move($offset);
3401 while (!$this->EOF && $nrows != $cnt) {
3402 $results[$cnt++] = $this->fields;
3411 * Synonym for GetArray() for compatibility with ADO.
3413 * @param [nRows] is the number of rows to return. -1 means every row.
3415 * @return an array indexed by the rows (0-based) from the recordset
3417 function GetRows($nRows = -1) {
3418 $arr = $this->GetArray($nRows);
3423 * return whole recordset as a 2-dimensional associative array if there are more than 2 columns.
3424 * The first column is treated as the key and is not included in the array.
3425 * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless
3426 * $force_array == true.
3428 * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional
3429 * array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,
3432 * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and
3433 * instead of returning array[col0] => array(remaining cols), return array[col0] => col1
3435 * @return an associative array indexed by the first column of the array,
3436 * or false if the data has less than 2 cols.
3438 function GetAssoc($force_array = false, $first2cols = false) {
3439 global $ADODB_EXTENSION;
3441 $cols = $this->_numOfFields;
3447 if (!$this->fields) {
3451 // Determine whether the array is associative or 0-based numeric
3452 $numIndex = array_keys($this->fields) == range(0, count($this->fields) - 1);
3456 if (!$first2cols && ($cols > 2 || $force_array)) {
3457 if ($ADODB_EXTENSION) {
3459 while (!$this->EOF) {
3460 $results[trim($this->fields[0])] = array_slice($this->fields, 1);
3461 adodb_movenext($this);
3464 while (!$this->EOF) {
3465 // Fix for array_slice re-numbering numeric associative keys
3466 $keys = array_slice(array_keys($this->fields), 1);
3467 $sliced_array = array();
3469 foreach($keys as $key) {
3470 $sliced_array[$key] = $this->fields[$key];
3473 $results[trim(reset($this->fields))] = $sliced_array;
3474 adodb_movenext($this);
3479 while (!$this->EOF) {
3480 $results[trim($this->fields[0])] = array_slice($this->fields, 1);
3484 while (!$this->EOF) {
3485 // Fix for array_slice re-numbering numeric associative keys
3486 $keys = array_slice(array_keys($this->fields), 1);
3487 $sliced_array = array();
3489 foreach($keys as $key) {
3490 $sliced_array[$key] = $this->fields[$key];