3 * Set tabs to 4 for best viewing.
5 * Latest version is available at http://php.weblogs.com/adodb
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 V4.22 15 Apr 2004 (c) 2000-2004 John Lim (jlim\@natsoft.com.my). All rights reserved.
19 Released under both BSD license and Lesser GPL library license. You can choose which license
22 PHP's database access functions are not standardised. This creates a need for a database
23 class library to hide the differences between the different database API's (encapsulate
24 the differences) so we can easily switch databases.
26 We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, DB2,
27 Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access,
28 ADO, SAP DB, SQLite and ODBC. We have had successful reports of connecting to Progress and
29 other databases via ODBC.
31 Latest Download at http://php.weblogs.com/adodb<br>
32 Manual is at http://php.weblogs.com/adodb_manual
36 if (!defined('_ADODB_LAYER')) {
37 define('_ADODB_LAYER', 1);
39 //==========================================================================
40 // CONSTANT DEFINITIONS
41 //==========================================================================
44 * Set ADODB_DIR to the directory where this file resides...
45 * This constant was formerly called $ADODB_RootPath
47 if (!defined('ADODB_DIR')) define('ADODB_DIR', dirname(__FILE__));
49 //==========================================================================
51 //==========================================================================
54 $ADODB_vers, // database version
55 $ADODB_COUNTRECS, // count number of records returned - slows down query
56 $ADODB_CACHE_DIR, // directory to cache recordsets
57 $ADODB_EXTENSION, // ADODB extension installed
58 $ADODB_COMPAT_PATCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF
59 $ADODB_FETCH_MODE; // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...
61 //==========================================================================
63 //==========================================================================
65 $ADODB_EXTENSION = defined('ADODB_EXTENSION');
66 if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) {
68 define('ADODB_BAD_RS', '<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');
70 // allow [ ] @ ` " and . in table names
71 define('ADODB_TABLE_REGEX', '([]0-9a-z_\"\`\.\@\[-]*)');
73 // prefetching used by oracle
74 if (!defined('ADODB_PREFETCH_ROWS')) define('ADODB_PREFETCH_ROWS', 10);
78 Controls ADODB_FETCH_ASSOC field-name case. Default is 2, use native case-names.
79 This currently works only with mssql, odbc, oci8po and ibase derived drivers.
81 0 = assoc lowercase field names. $rs->fields['orderid']
82 1 = assoc uppercase field names. $rs->fields['ORDERID']
83 2 = use native-case field names. $rs->fields['OrderID']
86 define('ADODB_FETCH_DEFAULT', 0);
87 define('ADODB_FETCH_NUM', 1);
88 define('ADODB_FETCH_ASSOC', 2);
89 define('ADODB_FETCH_BOTH', 3);
91 if (!defined('TIMESTAMP_FIRST_YEAR')) define('TIMESTAMP_FIRST_YEAR', 100);
93 if (strnatcmp(PHP_VERSION, '4.3.0') >= 0) {
94 define('ADODB_PHPVER', 0x4300);
95 } elseif (strnatcmp(PHP_VERSION, '4.2.0') >= 0) {
96 define('ADODB_PHPVER', 0x4200);
97 } elseif (strnatcmp(PHP_VERSION, '4.0.5') >= 0) {
98 define('ADODB_PHPVER', 0x4050);
100 define('ADODB_PHPVER', 0x4000);
104 //if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
108 Accepts $src and $dest arrays, replacing string $data
110 function ADODB_str_replace($src, $dest, $data)
112 if (ADODB_PHPVER >= 0x4050) return str_replace($src, $dest, $data);
116 while ($s !== false) {
117 $data = str_replace($s, $d, $data);
124 function ADODB_Setup()
127 $ADODB_vers, // database version
128 $ADODB_COUNTRECS, // count number of records returned - slows down query
129 $ADODB_CACHE_DIR, // directory to cache recordsets
132 $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
134 if (!isset($ADODB_CACHE_DIR)) {
135 $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp';
137 // do not accept url based paths, eg. http:/ or ftp:/
138 if (strpos($ADODB_CACHE_DIR, '://') !== false)
139 die("Illegal path http:// or ftp://");
143 // Initialize random number generator for randomizing cache flushes
144 srand(((double)microtime()) * 1000000);
147 * ADODB version as a string.
149 $ADODB_vers = 'V4.22 15 Apr 2004 (c) 2000-2004 John Lim (jlim#natsoft.com.my). All rights reserved. Released BSD & LGPL.';
152 * Determines whether recordset->RecordCount() is used.
153 * Set to false for highest performance -- RecordCount() will always return -1 then
154 * for databases that provide "virtual" recordcounts...
156 if (!isset($ADODB_COUNTRECS)) $ADODB_COUNTRECS = true;
160 //==========================================================================
161 // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB
162 //==========================================================================
166 //==========================================================================
167 // CLASS ADOFieldObject
168 //==========================================================================
170 * Helper class for FetchFields -- holds info on a column
178 // additional fields by dannym... (danny_milo@yahoo.com)
179 var $not_null = false;
180 // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^
181 // so we can as well make not_null standard (leaving it at "false" does not harm anyways)
183 var $has_default = false; // this one I have done only in mysql and postgres for now ...
184 // others to come (dannym)
185 var $default_value; // default, if any, and supported. Check has_default first.
189 function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection)
191 //print "Errorno ($fn errno=$errno m=$errmsg) ";
192 $thisConnection->_transOK = false;
193 if ($thisConnection->_oldRaiseFn) {
194 $fn = $thisConnection->_oldRaiseFn;
195 $fn($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection);
199 //==========================================================================
200 // CLASS ADOConnection
201 //==========================================================================
204 * Connection object. For connecting to databases, and executing queries.
211 var $dataProvider = 'native';
212 var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql
213 var $database = ''; /// Name of database to be used.
214 var $host = ''; /// The hostname of the database server
215 var $user = ''; /// The username which is used to connect to the database server.
216 var $password = ''; /// Password for the username. For security, we no longer store it.
217 var $debug = false; /// if set to true will output sql statements
218 var $maxblobsize = 256000; /// maximum size of blobs or large text fields -- some databases die otherwise like foxpro
219 var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase
220 var $substr = 'substr'; /// substring operator
221 var $length = 'length'; /// string length operator
222 var $random = 'rand()'; /// random function
223 var $upperCase = false; /// uppercase function
224 var $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the database
225 var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt.
226 var $true = '1'; /// string that represents TRUE for a database
227 var $false = '0'; /// string that represents FALSE for a database
228 var $replaceQuote = "\\'"; /// string to use to replace quotes
229 var $nameQuote = '"'; /// string to use to quote identifiers and names
230 var $charSet = false; /// character set to use - only for interbase
231 var $metaDatabasesSQL = '';
232 var $metaTablesSQL = '';
233 var $uniqueOrderBy = false; /// All order by columns have to be unique
234 var $emptyDate = ' ';
235 var $emptyTimeStamp = ' ';
236 var $lastInsID = false;
238 var $hasInsertID = false; /// supports autoincrement ID?
239 var $hasAffectedRows = false; /// supports affected rows for update/delete?
240 var $hasTop = false; /// support mssql/access SELECT TOP 10 * FROM TABLE
241 var $hasLimit = false; /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10
242 var $readOnly = false; /// this is a readonly database - used by phpLens
243 var $hasMoveFirst = false; /// has ability to run MoveFirst(), scrolling backwards
244 var $hasGenID = false; /// can generate sequences using GenID();
245 var $hasTransactions = true; /// has transactions
247 var $genID = 0; /// sequence id used by GenID();
248 var $raiseErrorFn = false; /// error function to call
249 var $isoDates = false; /// accepts dates in ISO format
250 var $cacheSecs = 3600; /// cache for 1 hour
251 var $sysDate = false; /// name of function that returns the current date
252 var $sysTimeStamp = false; /// name of function that returns the current timestamp
253 var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets
255 var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' '
256 var $numCacheHits = 0;
257 var $numCacheMisses = 0;
258 var $pageExecuteCountRows = true;
259 var $uniqueSort = false; /// indicates that all fields in order by must be unique
260 var $leftOuter = false; /// operator to use for left outer join in WHERE clause
261 var $rightOuter = false; /// operator to use for right outer join in WHERE clause
262 var $ansiOuter = false; /// whether ansi outer join syntax supported
263 var $autoRollback = false; // autoRollback on PConnect().
264 var $poorAffectedRows = false; // affectedRows not working or unreliable
266 var $fnExecute = false;
267 var $fnCacheExecute = false;
268 var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char
269 var $rsPrefix = "ADORecordSet_";
271 var $autoCommit = true; /// do not modify this yourself - actually private
272 var $transOff = 0; /// temporarily disable transactions
273 var $transCnt = 0; /// count of nested transactions
275 var $fetchMode = false;
279 var $_oldRaiseFn = false;
280 var $_transOK = null;
281 var $_connectionID = false; /// The returned link identifier whenever a successful database connection is made.
282 var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will
283 /// then returned by the errorMsg() function
284 var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8
285 var $_queryID = false; /// This variable keeps the last created result link identifier
287 var $_isPersistentConnection = false; /// A boolean variable to state whether its a persistent connection or normal connection. */
288 var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.
289 var $_evalAll = false;
290 var $_affected = false;
291 var $_logsql = false;
297 function ADOConnection()
299 die('Virtual Class -- cannot instantiate');
303 Get server version info...
305 @returns An array with 2 elements: $arr['string'] is the description string,
306 and $arr[version] is the version (also a string).
308 function ServerInfo()
310 return array('description' => '', 'version' => '');
313 function _findvers($str)
315 if (preg_match('/([0-9]+\.([0-9\.])+)/', $str, $arr)) return $arr[1];
320 * All error messages go through this bottleneck function.
321 * You can define your own handler by defining the function name in ADODB_OUTP.
323 function outp($msg, $newline = true)
325 global $HTTP_SERVER_VARS, $ADODB_FLUSH, $ADODB_OUTP;
327 if (defined('ADODB_OUTP')) {
331 } elseif (isset($ADODB_OUTP)) {
337 if ($newline) $msg .= "<br>\n";
339 if (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT'])) echo $msg;
340 else echo strip_tags($msg);
341 if (!empty($ADODB_FLUSH) && ob_get_length() !== false) flush(); // dp not flush if output buffering enabled - useless - thx to Jesse Mullan
347 $rs =& $this->Execute("select $this->sysTimeStamp");
348 if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields));
354 * Connect to database
356 * @param [argHostname] Host to connect to
357 * @param [argUsername] Userid to login
358 * @param [argPassword] Associated password
359 * @param [argDatabaseName] database
360 * @param [forceNew] force new connection
362 * @return true or false
364 function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false)
366 if ($argHostname != "") $this->host = $argHostname;
367 if ($argUsername != "") $this->user = $argUsername;
368 if ($argPassword != "") $this->password = $argPassword; // not stored for security reasons
369 if ($argDatabaseName != "") $this->database = $argDatabaseName;
371 $this->_isPersistentConnection = false;
372 if ($fn = $this->raiseErrorFn) {
374 if ($this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
376 if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
378 $err = $this->ErrorMsg();
379 if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
380 $fn($this->databaseType, 'CONNECT', $this->ErrorNo(), $err, $this->host, $this->database, $this);
383 if ($this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
385 if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
388 if ($this->debug) ADOConnection::outp($this->host . ': ' . $this->ErrorMsg());
392 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
394 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
399 * Always force a new connection to database - currently only works with oracle
401 * @param [argHostname] Host to connect to
402 * @param [argUsername] Userid to login
403 * @param [argPassword] Associated password
404 * @param [argDatabaseName] database
406 * @return true or false
408 function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
410 return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
414 * Establish persistent connect to database
416 * @param [argHostname] Host to connect to
417 * @param [argUsername] Userid to login
418 * @param [argPassword] Associated password
419 * @param [argDatabaseName] database
421 * @return return true or false
423 function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
425 if (defined('ADODB_NEVER_PERSIST'))
426 return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
428 if ($argHostname != "") $this->host = $argHostname;
429 if ($argUsername != "") $this->user = $argUsername;
430 if ($argPassword != "") $this->password = $argPassword;
431 if ($argDatabaseName != "") $this->database = $argDatabaseName;
433 $this->_isPersistentConnection = true;
435 if ($fn = $this->raiseErrorFn) {
436 if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
437 $err = $this->ErrorMsg();
438 if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
439 $fn($this->databaseType, 'PCONNECT', $this->ErrorNo(), $err, $this->host, $this->database, $this);
441 if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
443 if ($this->debug) ADOConnection::outp($this->host . ': ' . $this->ErrorMsg());
447 // Format date column in sql string given an input format that understands Y M D
448 function SQLDate($fmt, $col = false)
450 if (!$col) $col = $this->sysDate;
451 return $col; // child class implement
455 * Should prepare the sql statement and return the stmt resource.
456 * For databases that do not support this, we return the $sql. To ensure
457 * compatibility with databases that do not support prepare:
459 * $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
460 * $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
461 * $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
463 * @param sql SQL to send to database
465 * @return return FALSE, or the prepared statement, or the original sql if
466 * if the database does not support prepare.
469 function Prepare($sql)
475 * Some databases, eg. mssql require a different function for preparing
476 * stored procedures. So we cannot use Prepare().
478 * Should prepare the stored procedure and return the stmt resource.
479 * For databases that do not support this, we return the $sql. To ensure
480 * compatibility with databases that do not support prepare:
482 * @param sql SQL to send to database
484 * @return return FALSE, or the prepared statement, or the original sql if
485 * if the database does not support prepare.
488 function PrepareSP($sql, $param = true)
490 return $this->Prepare($sql, $param);
498 return $this->qstr($s, false);
502 Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de>
506 return $this->qstr($s, get_magic_quotes_gpc());
511 $s = $this->qstr($s, false);
515 * PEAR DB Compat - do not use internally.
517 function ErrorNative()
519 return $this->ErrorNo();
524 * PEAR DB Compat - do not use internally.
526 function nextId($seq_name)
528 return $this->GenID($seq_name);
532 * Lock a row, will escalate and lock the table if row locking not supported
533 * will normally free the lock at the end of the transaction
535 * @param $table name of table to lock
536 * @param $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
538 function RowLock($table, $where)
543 function CommitLock($table)
545 return $this->CommitTrans();
548 function RollbackLock($table)
550 return $this->RollbackTrans();
554 * PEAR DB Compat - do not use internally.
556 * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
557 * for easy porting :-)
559 * @param mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
560 * @returns The previous fetch mode
562 function SetFetchMode($mode)
564 $old = $this->fetchMode;
565 $this->fetchMode = $mode;
567 if ($old === false) {
568 global $ADODB_FETCH_MODE;
569 return $ADODB_FETCH_MODE;
576 * PEAR DB Compat - do not use internally.
578 function &Query($sql, $inputarr = false)
580 $rs = &$this->Execute($sql, $inputarr);
581 if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
587 * PEAR DB Compat - do not use internally
589 function &LimitQuery($sql, $offset, $count, $params = false)
591 $rs = &$this->SelectLimit($sql, $count, $offset, $params);
592 if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
598 * PEAR DB Compat - do not use internally
600 function Disconnect()
602 return $this->Close();
606 Returns placeholder for parameter, eg.
609 will return ':a' for Oracle, and '?' for most other databases...
611 For databases that require positioned params, eg $1, $2, $3 for postgresql,
612 pass in Param(false) before setting the first parameter.
614 function Param($name)
620 InParameter and OutParameter are self-documenting versions of Parameter().
622 function InParameter(&$stmt, &$var, $name, $maxLen = 4000, $type = false)
624 return $this->Parameter($stmt, $var, $name, false, $maxLen, $type);
629 function OutParameter(&$stmt, &$var, $name, $maxLen = 4000, $type = false)
631 return $this->Parameter($stmt, $var, $name, true, $maxLen, $type);
637 $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
638 $db->Parameter($stmt,$id,'myid');
639 $db->Parameter($stmt,$group,'group',64);
642 @param $stmt Statement returned by Prepare() or PrepareSP().
643 @param $var PHP variable to bind to
644 @param $name Name of stored procedure variable name to bind to.
645 @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
646 @param [$maxLen] Holds an maximum length of the variable.
647 @param [$type] The data type of $var. Legal values depend on driver.
650 function Parameter(&$stmt, &$var, $name, $isOutput = false, $maxLen = 4000, $type = false)
656 Improved method of initiating a transaction. Used together with CompleteTrans().
659 a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.
660 Only the outermost block is treated as a transaction.<br>
661 b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>
662 c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block
663 are disabled, making it backward compatible.
665 function StartTrans($errfn = 'ADODB_TransMonitor')
667 if ($this->transOff > 0) {
668 $this->transOff += 1;
672 $this->_oldRaiseFn = $this->raiseErrorFn;
673 $this->raiseErrorFn = $errfn;
674 $this->_transOK = true;
676 if ($this->debug && $this->transCnt > 0) ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
682 Used together with StartTrans() to end a transaction. Monitors connection
683 for sql errors, and will commit or rollback as appropriate.
685 @autoComplete if true, monitor sql errors and commit and rollback as appropriate,
686 and if set to false force rollback even if no SQL error detected.
687 @returns true on commit, false on rollback.
689 function CompleteTrans($autoComplete = true)
691 if ($this->transOff > 1) {
692 $this->transOff -= 1;
695 $this->raiseErrorFn = $this->_oldRaiseFn;
698 if ($this->_transOK && $autoComplete) {
699 if (!$this->CommitTrans()) {
700 $this->_transOK = false;
701 if ($this->debug) ADOConnection::outp("Smart Commit failed");
703 if ($this->debug) ADOConnection::outp("Smart Commit occurred");
705 $this->RollbackTrans();
706 if ($this->debug) ADOCOnnection::outp("Smart Rollback occurred");
709 return $this->_transOK;
713 At the end of a StartTrans/CompleteTrans block, perform a rollback.
718 if ($this->transOff == 0) {
719 ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
721 ADOConnection::outp("FailTrans was called");
724 $this->_transOK = false;
728 Check if transaction has failed, only for Smart Transactions.
730 function HasFailedTrans()
732 if ($this->transOff > 0) return $this->_transOK == false;
739 * @param sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
740 * @param [inputarr] holds the input data to bind to. Null elements will be set to null.
741 * @return RecordSet or false
743 function &Execute($sql, $inputarr = false)
745 if ($this->fnExecute) {
746 $fn = $this->fnExecute;
747 $ret =& $fn($this, $sql, $inputarr);
748 if (isset($ret)) return $ret;
750 if ($inputarr && is_array($inputarr)) {
751 $element0 = reset($inputarr);
752 # is_object check is because oci8 descriptors can be passed in
753 $array_2d = is_array($element0) && !is_object(reset($element0));
755 if (!is_array($sql) && !$this->_bindInputArray) {
756 $sqlarr = explode('?', $sql);
758 if (!$array_2d) $inputarr = array($inputarr);
759 foreach ($inputarr as $arr) {
762 foreach ($arr as $v) {
764 // from Ron Baldwin <ron.baldwin@sourceprose.com>
765 // Only quote string types
766 if (gettype($v) == 'string')
767 $sql .= $this->qstr($v);
768 else if ($v === null)
776 if ($i + 1 != sizeof($sqlarr))
777 ADOConnection::outp("Input Array does not match ?: " . htmlspecialchars($sql));
779 $ret =& $this->_Execute($sql, false);
780 if (!$ret) return $ret;
784 $stmt = $this->Prepare($sql);
785 foreach ($inputarr as $arr) {
786 $ret =& $this->_Execute($stmt, $arr);
787 if (!$ret) return $ret;
790 $ret =& $this->_Execute($sql, $inputarr);
793 $ret =& $this->_Execute($sql, false);
799 function& _Execute($sql, $inputarr = false)
803 global $HTTP_SERVER_VARS;
807 foreach ($inputarr as $kk => $vv) {
808 if (is_string($vv) && strlen($vv) > 64) $vv = substr($vv, 0, 64) . '...';
809 $ss .= "($kk=>'$vv') ";
813 $sqlTxt = str_replace(',', ', ', is_array($sql) ? $sql[0] : $sql);
815 // check if running from browser or command-line
816 $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
819 if ($this->debug === -1)
820 ADOConnection::outp("<br>\n($this->databaseType): " . htmlspecialchars($sqlTxt) . " <code>$ss</code>\n<br>\n", false);
822 ADOConnection::outp("<hr>\n($this->databaseType): " . htmlspecialchars($sqlTxt) . " <code>$ss</code>\n<hr>\n", false);
824 ADOConnection::outp("-----\n($this->databaseType): " . ($sqlTxt) . " \n-----\n", false);
826 $this->_queryID = $this->_query($sql, $inputarr);
828 Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
829 because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion
831 if ($this->databaseType == 'mssql') {
832 // ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6
833 if ($emsg = $this->ErrorMsg()) {
834 if ($err = $this->ErrorNo()) ADOConnection::outp($err . ': ' . $emsg);
836 } elseif (!$this->_queryID) {
837 ADOConnection::outp($this->ErrorNo() . ': ' . $this->ErrorMsg());
840 //****************************
841 // non-debug version of query
842 //****************************
844 $this->_queryID = @$this->_query($sql, $inputarr);
847 /************************
848 // OK, query executed
849 *************************/
851 if ($this->_queryID === false) {
852 // error handling if query fails
853 if ($this->debug == 99) adodb_backtrace(true, 5);
854 $fn = $this->raiseErrorFn;
856 $fn($this->databaseType, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $sql, $inputarr, $this);
863 if ($this->_queryID === true) {
864 // return simplified empty recordset for inserts/updates/deletes with lower overhead
865 $rs =& new ADORecordSet_empty();
869 // return real recordset from select statement
870 $rsclass = $this->rsPrefix . $this->databaseType;
871 $rs =& new $rsclass($this->_queryID, $this->fetchMode);
872 $rs->connection = &$this; // Pablo suggestion
874 if (is_array($sql)) $rs->sql = $sql[0];
875 else $rs->sql = $sql;
876 if ($rs->_numOfRows <= 0) {
877 global $ADODB_COUNTRECS;
879 if ($ADODB_COUNTRECS) {
881 $rs = &$this->_rs2rs($rs, -1, -1, !is_array($sql));
882 $rs->_queryID = $this->_queryID;
890 function CreateSequence($seqname = 'adodbseq', $startID = 1)
892 if (empty($this->_genSeqSQL)) return false;
893 return $this->Execute(sprintf($this->_genSeqSQL, $seqname, $startID));
896 function DropSequence($seqname)
898 if (empty($this->_dropSeqSQL)) return false;
899 return $this->Execute(sprintf($this->_dropSeqSQL, $seqname));
903 * Generates a sequence id and stores it in $this->genID;
904 * GenID is only available if $this->hasGenID = true;
906 * @param seqname name of sequence to use
907 * @param startID if sequence does not exist, start at this ID
908 * @return 0 if not supported, otherwise a sequence id
910 function GenID($seqname = 'adodbseq', $startID = 1)
912 if (!$this->hasGenID) {
913 return 0; // formerly returns false pre 1.60
916 $getnext = sprintf($this->_genIDSQL, $seqname);
918 $holdtransOK = $this->_transOK;
919 $rs = @$this->Execute($getnext);
921 $this->_transOK = $holdtransOK; //if the status was ok before reset
922 $createseq = $this->Execute(sprintf($this->_genSeqSQL, $seqname, $startID));
923 $rs = $this->Execute($getnext);
925 if ($rs && !$rs->EOF) $this->genID = reset($rs->fields);
926 else $this->genID = 0; // false
928 if ($rs) $rs->Close();
934 * @return the last inserted ID. Not all databases support this.
938 if ($this->_logsql && $this->lastInsID) return $this->lastInsID;
939 if ($this->hasInsertID) return $this->_insertid();
941 ADOConnection::outp('<p>Insert_ID error</p>');
949 * Portable Insert ID. Pablo Roca <pabloroca@mvps.org>
951 * @return the last inserted ID. All databases support this. But aware possible
952 * problems in multiuser environments. Heavy test this before deploying.
954 function PO_Insert_ID($table = "", $id = "")
956 if ($this->hasInsertID) {
957 return $this->Insert_ID();
959 return $this->GetOne("SELECT MAX($id) FROM $table");
964 * @return # rows affected by UPDATE/DELETE
966 function Affected_Rows()
968 if ($this->hasAffectedRows) {
969 if ($this->fnExecute === 'adodb_log_sql') {
970 if ($this->_logsql && $this->_affected !== false) return $this->_affected;
972 $val = $this->_affectedrows();
973 return ($val < 0) ? false : $val;
976 if ($this->debug) ADOConnection::outp('<p>Affected_Rows error</p>', false);
982 * @return the last error message
986 return '!! ' . strtoupper($this->dataProvider . ' ' . $this->databaseType) . ': ' . $this->_errorMsg;
991 * @return the last error number. Normally 0 means no error.
995 return ($this->_errorMsg) ? -1 : 0;
998 function MetaError($err = false)
1000 include_once(ADODB_DIR . "/adodb-error.inc.php");
1001 if ($err === false) $err = $this->ErrorNo();
1002 return adodb_error($this->dataProvider, $this->databaseType, $err);
1005 function MetaErrorMsg($errno)
1007 include_once(ADODB_DIR . "/adodb-error.inc.php");
1008 return adodb_errormsg($errno);
1012 * @returns an array with the primary key columns in it.
1014 function MetaPrimaryKeys($table, $owner = false)
1016 // owner not used in base class - see oci8
1018 $objs =& $this->MetaColumns($table);
1020 foreach ($objs as $v) {
1021 if (!empty($v->primary_key))
1025 if (sizeof($p)) return $p;
1026 if (function_exists('ADODB_VIEW_PRIMARYKEYS'))
1027 return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);
1032 * @returns assoc array where keys are tables, and values are foreign keys
1034 function MetaForeignKeys($table, $owner = false, $upper = false)
1040 * Choose a database to connect to. Many databases do not support this.
1042 * @param dbName is the name of the database to select
1043 * @return true or false
1045 function SelectDB($dbName)
1052 * Will select, getting rows from $offset (1-based), for $nrows.
1053 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1054 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1055 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1057 * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
1058 * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
1060 * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
1061 * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
1064 * @param [offset] is the row to start calculations from (1-based)
1065 * @param [nrows] is the number of rows to get
1066 * @param [inputarr] array of bind variables
1067 * @param [secs2cache] is a private parameter only used by jlim
1068 * @return the recordset ($rs->databaseType == 'array')
1070 function &SelectLimit($sql, $nrows = -1, $offset = -1, $inputarr = false, $secs2cache = 0)
1072 if ($this->hasTop && $nrows > 0) {
1073 // suggested by Reinhard Balling. Access requires top after distinct
1074 // Informix requires first before distinct - F Riosa
1075 $ismssql = (strpos($this->databaseType, 'mssql') !== false);
1076 if ($ismssql) $isaccess = false;
1077 else $isaccess = (strpos($this->databaseType, 'access') !== false);
1081 // access includes ties in result
1083 $sql = preg_replace(
1084 '/(^\s*select\s+(distinctrow|distinct)?)/i', '\\1 ' . $this->hasTop . ' ' . $nrows . ' ', $sql);
1086 if ($secs2cache > 0) {
1087 $ret =& $this->CacheExecute($secs2cache, $sql, $inputarr);
1089 $ret =& $this->Execute($sql, $inputarr);
1091 return $ret; // PHP5 fix
1092 } elseif ($ismssql) {
1093 $sql = preg_replace(
1094 '/(^\s*select\s+(distinctrow|distinct)?)/i', '\\1 ' . $this->hasTop . ' ' . $nrows . ' ', $sql);
1096 $sql = preg_replace(
1097 '/(^\s*select\s)/i', '\\1 ' . $this->hasTop . ' ' . $nrows . ' ', $sql);
1100 $nn = $nrows + $offset;
1101 if ($isaccess || $ismssql) {
1102 $sql = preg_replace(
1103 '/(^\s*select\s+(distinctrow|distinct)?)/i', '\\1 ' . $this->hasTop . ' ' . $nn . ' ', $sql);
1105 $sql = preg_replace(
1106 '/(^\s*select\s)/i', '\\1 ' . $this->hasTop . ' ' . $nn . ' ', $sql);
1111 // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows
1112 // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.
1113 global $ADODB_COUNTRECS;
1115 $savec = $ADODB_COUNTRECS;
1116 $ADODB_COUNTRECS = false;
1119 if ($secs2cache > 0) $rs = &$this->CacheExecute($secs2cache, $sql, $inputarr);
1120 else $rs = &$this->Execute($sql, $inputarr);
1122 if ($secs2cache > 0) $rs = &$this->CacheExecute($secs2cache, $sql, $inputarr);
1123 else $rs = &$this->Execute($sql, $inputarr);
1125 $ADODB_COUNTRECS = $savec;
1126 if ($rs && !$rs->EOF) {
1127 $rs =& $this->_rs2rs($rs, $nrows, $offset);
1134 * Create serializable recordset. Breaks rs link to connection.
1136 * @param rs the recordset to serialize
1138 function &SerializableRS(&$rs)
1140 $rs2 =& $this->_rs2rs($rs);
1142 $rs2->connection =& $ignore;
1148 * Convert database recordset to an array recordset
1149 * input recordset's cursor should be at beginning, and
1150 * old $rs will be closed.
1152 * @param rs the recordset to copy
1153 * @param [nrows] number of rows to retrieve (optional)
1154 * @param [offset] offset by number of rows (optional)
1155 * @return the new recordset
1157 function &_rs2rs(&$rs, $nrows = -1, $offset = -1, $close = true)
1159 if (!$rs) return false;
1161 $dbtype = $rs->databaseType;
1163 $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?
1166 if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {
1168 $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?
1172 for ($i = 0, $max = $rs->FieldCount(); $i < $max; $i++) {
1173 $flds[] = $rs->FetchField($i);
1175 $arr =& $rs->GetArrayLimit($nrows, $offset);
1177 if ($close) $rs->Close();
1179 $arrayClass = $this->arrayClass;
1181 $rs2 =& new $arrayClass();
1182 $rs2->connection = &$this;
1183 $rs2->sql = $rs->sql;
1184 $rs2->dataProvider = $this->dataProvider;
1185 $rs2->InitArrayFields($arr, $flds);
1190 * Return all rows. Compat with PEAR DB
1192 function &GetAll($sql, $inputarr = false)
1194 $arr =& $this->GetArray($sql, $inputarr);
1198 function &GetAssoc($sql, $inputarr = false, $force_array = false, $first2cols = false)
1200 $rs =& $this->Execute($sql, $inputarr);
1201 if (!$rs) return false;
1203 $arr =& $rs->GetAssoc($force_array, $first2cols);
1207 function &CacheGetAssoc($secs2cache, $sql = false, $inputarr = false, $force_array = false, $first2cols = false)
1209 if (!is_numeric($secs2cache)) {
1210 $first2cols = $force_array;
1211 $force_array = $inputarr;
1213 $rs =& $this->CacheExecute($secs2cache, $sql, $inputarr);
1214 if (!$rs) return false;
1216 $arr =& $rs->GetAssoc($force_array, $first2cols);
1221 * Return first element of first row of sql statement. Recordset is disposed
1224 * @param sql SQL statement
1225 * @param [inputarr] input bind array
1227 function GetOne($sql, $inputarr = false)
1229 global $ADODB_COUNTRECS;
1230 $crecs = $ADODB_COUNTRECS;
1231 $ADODB_COUNTRECS = false;
1234 $rs = &$this->Execute($sql, $inputarr);
1236 if (!$rs->EOF) $ret = reset($rs->fields);
1239 $ADODB_COUNTRECS = $crecs;
1243 function CacheGetOne($secs2cache, $sql = false, $inputarr = false)
1246 $rs = &$this->CacheExecute($secs2cache, $sql, $inputarr);
1248 if (!$rs->EOF) $ret = reset($rs->fields);
1255 function GetCol($sql, $inputarr = false, $trim = false)
1258 $rs = &$this->Execute($sql, $inputarr);
1263 $rv[] = trim(reset($rs->fields));
1268 $rv[] = reset($rs->fields);
1277 function CacheGetCol($secs, $sql = false, $inputarr = false, $trim = false)
1280 $rs = &$this->CacheExecute($secs, $sql, $inputarr);
1284 $rv[] = trim(reset($rs->fields));
1289 $rv[] = reset($rs->fields);
1299 Calculate the offset of a date for a particular database and generate
1300 appropriate SQL. Useful for calculating future/past dates and storing
1303 If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
1305 function OffsetDate($dayFraction, $date = false)
1307 if (!$date) $date = $this->sysDate;
1308 return '(' . $date . '+' . $dayFraction . ')';
1314 * @param sql SQL statement
1315 * @param [inputarr] input bind array
1317 function &GetArray($sql, $inputarr = false)
1319 global $ADODB_COUNTRECS;
1321 $savec = $ADODB_COUNTRECS;
1322 $ADODB_COUNTRECS = false;
1323 $rs =& $this->Execute($sql, $inputarr);
1324 $ADODB_COUNTRECS = $savec;
1326 if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
1328 $arr =& $rs->GetArray();
1333 function &CacheGetAll($secs2cache, $sql = false, $inputarr = false)
1335 global $ADODB_COUNTRECS;
1337 $savec = $ADODB_COUNTRECS;
1338 $ADODB_COUNTRECS = false;
1339 $rs =& $this->CacheExecute($secs2cache, $sql, $inputarr);
1340 $ADODB_COUNTRECS = $savec;
1343 if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
1346 $arr =& $rs->GetArray();
1353 * Return one row of sql statement. Recordset is disposed for you.
1355 * @param sql SQL statement
1356 * @param [inputarr] input bind array
1358 function &GetRow($sql, $inputarr = false)
1360 global $ADODB_COUNTRECS;
1361 $crecs = $ADODB_COUNTRECS;
1362 $ADODB_COUNTRECS = false;
1364 $rs =& $this->Execute($sql, $inputarr);
1366 $ADODB_COUNTRECS = $crecs;
1368 if (!$rs->EOF) $arr = $rs->fields;
1369 else $arr = array();
1377 function &CacheGetRow($secs2cache, $sql = false, $inputarr = false)
1379 $rs =& $this->CacheExecute($secs2cache, $sql, $inputarr);
1382 if (!$rs->EOF) $arr = $rs->fields;
1390 * Insert or replace a single record. Note: this is not the same as MySQL's replace.
1391 * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
1392 * Also note that no table locking is done currently, so it is possible that the
1393 * record be inserted twice by two programs...
1395 * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
1398 * $fieldArray associative array of data (you must quote strings yourself).
1399 * $keyCol the primary key field name or if compound key, array of field names
1400 * autoQuote set to true to use a hueristic to quote strings. Works with nulls and numbers
1401 * but does not work with dates nor SQL functions.
1402 * has_autoinc the primary key is an auto-inc field, so skip in insert.
1404 * Currently blob replace not supported
1406 * returns 0 = fail, 1 = update, 2 = insert
1409 function Replace($table, $fieldArray, $keyCol, $autoQuote = false, $has_autoinc = false)
1411 global $ADODB_INCLUDED_LIB;
1412 if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR . '/adodb-lib.inc.php');
1414 return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);
1419 * Will select, getting rows from $offset (1-based), for $nrows.
1420 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1421 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1422 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1424 * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
1425 * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
1427 * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
1429 * @param [secs2cache] seconds to cache data, set to 0 to force query. This is optional
1431 * @param [offset] is the row to start calculations from (1-based)
1432 * @param [nrows] is the number of rows to get
1433 * @param [inputarr] array of bind variables
1434 * @return the recordset ($rs->databaseType == 'array')
1436 function &CacheSelectLimit($secs2cache, $sql, $nrows = -1, $offset = -1, $inputarr = false)
1438 if (!is_numeric($secs2cache)) {
1439 if ($sql === false) $sql = -1;
1440 if ($offset == -1) $offset = false;
1441 // sql, nrows, offset,inputarr
1442 $rs =& $this->SelectLimit($secs2cache, $sql, $nrows, $offset, $this->cacheSecs);
1444 if ($sql === false) ADOConnection::outp("Warning: \$sql missing from CacheSelectLimit()");
1445 $rs =& $this->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
1451 * Flush cached recordsets that match a particular $sql statement.
1452 * If $sql == false, then we purge all files in the cache.
1454 function CacheFlush($sql = false, $inputarr = false)
1456 global $ADODB_CACHE_DIR;
1458 if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
1459 if (strncmp(PHP_OS, 'WIN', 3) === 0) {
1460 $cmd = 'del /s ' . str_replace('/', '\\', $ADODB_CACHE_DIR) . '\adodb_*.cache';
1462 $cmd = 'rm -rf ' . $ADODB_CACHE_DIR . '/??/adodb_*.cache';
1463 // old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`';
1466 ADOConnection::outp("CacheFlush: $cmd<br><pre>\n", system($cmd), "</pre>");
1472 $f = $this->_gencachename($sql . serialize($inputarr), false);
1473 adodb_write_file($f, ''); // is adodb_write_file needed?
1475 if ($this->debug) ADOConnection::outp("CacheFlush: failed for $f");
1480 * Private function to generate filename for caching.
1481 * Filename is generated based on:
1484 * - database type (oci8, ibase, ifx, etc)
1488 * We create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
1489 * Assuming that we can have 50,000 files per directory with good performance,
1490 * then we can scale to 12.8 million unique cached recordsets. Wow!
1492 function _gencachename($sql, $createdir)
1494 global $ADODB_CACHE_DIR;
1496 $m = md5($sql . $this->databaseType . $this->database . $this->user);
1497 $dir = $ADODB_CACHE_DIR . '/' . substr($m, 0, 2);
1498 if ($createdir && !file_exists($dir)) {
1500 if (!mkdir($dir, 0771))
1501 if ($this->debug) ADOConnection::outp("Unable to mkdir $dir for $sql");
1504 return $dir . '/adodb_' . $m . '.cache';
1509 * Execute SQL, caching recordsets.
1511 * @param [secs2cache] seconds to cache data, set to 0 to force query.
1512 * This is an optional parameter.
1513 * @param sql SQL statement to execute
1514 * @param [inputarr] holds the input data to bind to
1515 * @return RecordSet or false
1517 function &CacheExecute($secs2cache, $sql = false, $inputarr = false)
1519 if (!is_numeric($secs2cache)) {
1522 $secs2cache = $this->cacheSecs;
1524 global $ADODB_INCLUDED_CSV;
1525 if (empty($ADODB_INCLUDED_CSV)) include_once(ADODB_DIR . '/adodb-csvlib.inc.php');
1527 if (is_array($sql)) $sql = $sql[0];
1529 $md5file = $this->_gencachename($sql . serialize($inputarr), true);
1532 if ($secs2cache > 0) {
1533 $rs = &csv2rs($md5file, $err, $secs2cache);
1534 $this->numCacheHits += 1;
1538 $this->numCacheMisses += 1;
1541 // no cached rs found
1543 if (get_magic_quotes_runtime()) {
1544 ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
1546 if ($this->debug !== -1) ADOConnection::outp(" $md5file cache failure: $err (see sql below)");
1548 $rs = &$this->Execute($sql, $inputarr);
1551 $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately
1552 $txt = _rs2serialize($rs, false, $sql); // serialize
1554 if (!adodb_write_file($md5file, $txt, $this->debug)) {
1555 if ($fn = $this->raiseErrorFn) {
1556 $fn($this->databaseType, 'CacheExecute', -32000, "Cache write error", $md5file, $sql, $this);
1558 if ($this->debug) ADOConnection::outp(" Cache write error");
1560 if ($rs->EOF && !$eof) {
1562 //$rs = &csv2rs($md5file,$err);
1563 $rs->connection = &$this; // Pablo suggestion
1569 $this->_errorMsg = '';
1570 $this->_errorCode = 0;
1572 if ($this->fnCacheExecute) {
1573 $fn = $this->fnCacheExecute;
1574 $fn($this, $secs2cache, $sql, $inputarr);
1576 // ok, set cached object found
1577 $rs->connection = &$this; // Pablo suggestion
1579 global $HTTP_SERVER_VARS;
1581 $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
1582 $ttl = $rs->timeCreated + $secs2cache - time();
1583 $s = is_array($sql) ? $sql[0] : $sql;
1584 if ($inBrowser) $s = '<i>' . htmlspecialchars($s) . '</i>';
1586 ADOConnection::outp(" $md5file reloaded, ttl=$ttl [ $s ]");
1594 * Generates an Update Query based on an existing recordset.
1595 * $arrFields is an associative array of fields with the value
1596 * that should be assigned.
1598 * Note: This function should only be used on a recordset
1599 * that is run against a single table and sql should only
1600 * be a simple select stmt with no groupby/orderby/limit
1602 * "Jonathan Younger" <jyounger@unilab.com>
1604 function GetUpdateSQL(&$rs, $arrFields, $forceUpdate = false, $magicq = false)
1606 global $ADODB_INCLUDED_LIB;
1607 if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR . '/adodb-lib.inc.php');
1608 return _adodb_getupdatesql($this, $rs, $arrFields, $forceUpdate, $magicq);
1613 * Generates an Insert Query based on an existing recordset.
1614 * $arrFields is an associative array of fields with the value
1615 * that should be assigned.
1617 * Note: This function should only be used on a recordset
1618 * that is run against a single table.
1620 function GetInsertSQL(&$rs, $arrFields, $magicq = false)
1622 global $ADODB_INCLUDED_LIB;
1623 if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR . '/adodb-lib.inc.php');
1624 return _adodb_getinsertsql($this, $rs, $arrFields, $magicq);
1629 * Update a blob column, given a where clause. There are more sophisticated
1630 * blob handling functions that we could have implemented, but all require
1631 * a very complex API. Instead we have chosen something that is extremely
1632 * simple to understand and use.
1634 * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
1636 * Usage to update a $blobvalue which has a primary key blob_id=1 into a
1637 * field blobtable.blobcolumn:
1639 * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
1643 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
1644 * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
1647 function UpdateBlob($table, $column, $val, $where, $blobtype = 'BLOB')
1649 return $this->Execute("UPDATE $table SET $column=? WHERE $where", array($val)) != false;
1654 * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
1656 * $blobtype supports 'BLOB' and 'CLOB'
1658 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
1659 * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
1661 function UpdateBlobFile($table, $column, $path, $where, $blobtype = 'BLOB')
1663 $fd = fopen($path, 'rb');
1664 if ($fd === false) return false;
1665 $val = fread($fd, filesize($path));
1667 return $this->UpdateBlob($table, $column, $val, $where, $blobtype);
1670 function BlobDecode($blob)
1675 function BlobEncode($blob)
1680 function SetCharSet($charset)
1685 function IfNull($field, $ifNull)
1687 return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
1690 function LogSQL($enable = true)
1692 include_once(ADODB_DIR . '/adodb-perf.inc.php');
1694 if ($enable) $this->fnExecute = 'adodb_log_sql';
1695 else $this->fnExecute = false;
1697 $old = $this->_logsql;
1698 $this->_logsql = $enable;
1699 if ($enable && !$old) $this->_affected = false;
1703 function GetCharSet()
1710 * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
1712 * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
1713 * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
1715 function UpdateClob($table, $column, $val, $where)
1717 return $this->UpdateBlob($table, $column, $val, $where, 'CLOB');
1722 * Change the SQL connection locale to a specified locale.
1723 * This is used to get the date formats written depending on the client locale.
1725 function SetDateLocale($locale = 'En')
1727 $this->locale = $locale;
1731 $this->fmtDate = "Y-m-d";
1732 $this->fmtTimeStamp = "Y-m-d H:i:s";
1738 $this->fmtDate = "d-m-Y";
1739 $this->fmtTimeStamp = "d-m-Y H:i:s";
1743 $this->fmtDate = "d.m.Y";
1744 $this->fmtTimeStamp = "d.m.Y H:i:s";
1751 * $meta contains the desired type, which could be...
1752 * C for character. You will have to define the precision yourself.
1753 * X for teXt. For unlimited character lengths.
1755 * F for floating point, with no need to define scale and precision
1756 * N for decimal numbers, you will have to define the (scale, precision) yourself
1759 * L for logical/Boolean
1761 * R for autoincrement counter/integer
1762 * and if you want to use double-byte, add a 2 to the end, like C2 or X2.
1765 * @return the actual type of the data or false if no such type available
1767 function ActualType($meta)
1793 return $this->_close();
1795 // "Simon Lee" <simon@mediaroad.com> reports that persistent connections need
1796 // to be closed too!
1797 //if ($this->_isPersistentConnection != true) return $this->_close();
1802 * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
1804 * @return true if succeeded or false if database does not support transactions
1806 function BeginTrans()
1813 * If database does not support transactions, always return true as data always commited
1815 * @param $ok set to false to rollback transaction, true to commit
1817 * @return true/false.
1819 function CommitTrans($ok = true)
1826 * If database does not support transactions, rollbacks always fail, so return false
1828 * @return true/false.
1830 function RollbackTrans()
1837 * return the databases that the driver can connect to.
1838 * Some databases will return an empty array.
1840 * @return an array of database names.
1842 function MetaDatabases()
1844 global $ADODB_FETCH_MODE;
1846 if ($this->metaDatabasesSQL) {
1847 $save = $ADODB_FETCH_MODE;
1848 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
1850 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
1852 $arr = $this->GetCol($this->metaDatabasesSQL);
1853 if (isset($savem)) $this->SetFetchMode($savem);
1854 $ADODB_FETCH_MODE = $save;
1863 * @param ttype can either be 'VIEW' or 'TABLE' or false.
1864 * If false, both views and tables are returned.
1865 * "VIEW" returns only views
1866 * "TABLE" returns only tables
1867 * @param showSchema returns the schema/user with the table name, eg. USER.TABLE
1868 * @param mask is the input mask - only supported by oci8 and postgresql
1870 * @return array of tables for current database.
1872 function &MetaTables($ttype = false, $showSchema = false, $mask = false)
1874 global $ADODB_FETCH_MODE;
1876 if ($mask) return false;
1878 if ($this->metaTablesSQL) {
1879 // complicated state saving by the need for backward compat
1880 $save = $ADODB_FETCH_MODE;
1881 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
1883 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
1885 $rs = $this->Execute($this->metaTablesSQL);
1886 if (isset($savem)) $this->SetFetchMode($savem);
1887 $ADODB_FETCH_MODE = $save;
1889 if ($rs === false) return false;
1890 $arr =& $rs->GetArray();
1893 if ($hast = ($ttype && isset($arr[0][1]))) {
1894 $showt = strncmp($ttype, 'T', 1);
1897 for ($i = 0; $i < sizeof($arr); $i++) {
1900 if (strncmp($arr[$i][1], 'T', 1) == 0) $arr2[] = trim($arr[$i][0]);
1902 if (strncmp($arr[$i][1], 'V', 1) == 0) $arr2[] = trim($arr[$i][0]);
1905 $arr2[] = trim($arr[$i][0]);
1914 function _findschema(&$table, &$schema)
1916 if (!$schema && ($at = strpos($table, '.')) !== false) {
1917 $schema = substr($table, 0, $at);
1918 $table = substr($table, $at + 1);
1923 * List columns in a database as an array of ADOFieldObjects.
1924 * See top of file for definition of object.
1926 * @param table table name to query
1927 * @param upper uppercase table name (required by some databases)
1928 * @schema is optional database schema to use - not supported by all databases.
1930 * @return array of ADOFieldObjects for current table.
1932 function &MetaColumns($table, $upper = true)
1934 global $ADODB_FETCH_MODE;
1936 if (!empty($this->metaColumnsSQL)) {
1939 $this->_findschema($table, $schema);
1941 $save = $ADODB_FETCH_MODE;
1942 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
1943 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
1944 $rs = $this->Execute(sprintf($this->metaColumnsSQL, ($upper) ? strtoupper($table) : $table));
1945 if (isset($savem)) $this->SetFetchMode($savem);
1946 $ADODB_FETCH_MODE = $save;
1947 if ($rs === false) return false;
1950 while (!$rs->EOF) { //print_r($rs->fields);
1951 $fld =& new ADOFieldObject();
1952 $fld->name = $upper ? strtoupper($rs->fields[0]) : $rs->fields[0];
1953 $fld->type = $rs->fields[1];
1954 if (isset($rs->fields[3]) && $rs->fields[3]) {
1955 if ($rs->fields[3] > 0) $fld->max_length = $rs->fields[3];
1956 $fld->scale = $rs->fields[4];
1957 if ($fld->scale > 0) $fld->max_length += 1;
1959 $fld->max_length = $rs->fields[2];
1961 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
1962 else $retarr[$fld->name] = $fld;
1972 * List indexes on a table as an array.
1973 * @param table table name to query
1974 * @param primary include primary keys.
1976 * @return array of indexes on current table.
1978 function &MetaIndexes($table, $primary = false, $owner = false)
1984 * List columns names in a table as an array.
1985 * @param table table name to query
1987 * @return array of column names for current table.
1989 function &MetaColumnNames($table)
1991 $objarr =& $this->MetaColumns($table);
1992 if (!is_array($objarr)) return false;
1995 foreach ($objarr as $v) {
1996 $arr[strtoupper($v->name)] = $v->name;
2002 * Different SQL databases used different methods to combine strings together.
2003 * This function provides a wrapper.
2005 * param s variable number of string parameters
2007 * Usage: $db->Concat($str1,$str2);
2009 * @return concatenated string
2013 $arr = func_get_args();
2014 return implode($this->concat_operator, $arr);
2019 * Converts a date "d" to a string that the database can understand.
2021 * @param d a date in Unix date time format.
2023 * @return date string in database date format
2027 if (empty($d) && $d !== 0) return 'null';
2029 if (is_string($d) && !is_numeric($d)) {
2030 if ($d === 'null' || strncmp($d, "'", 1) === 0) return $d;
2031 if ($this->isoDates) return "'$d'";
2032 $d = ADOConnection::UnixDate($d);
2035 return adodb_date($this->fmtDate, $d);
2040 * Converts a timestamp "ts" to a string that the database can understand.
2042 * @param ts a timestamp in Unix date time format.
2044 * @return timestamp string in database timestamp format
2046 function DBTimeStamp($ts)
2048 if (empty($ts) && $ts !== 0) return 'null';
2050 # strlen(14) allows YYYYMMDDHHMMSS format
2051 if (!is_string($ts) || (is_numeric($ts) && strlen($ts) < 14))
2052 return adodb_date($this->fmtTimeStamp, $ts);
2054 if ($ts === 'null') return $ts;
2055 if ($this->isoDates && strlen($ts) !== 14) return "'$ts'";
2057 $ts = ADOConnection::UnixTimeStamp($ts);
2058 return adodb_date($this->fmtTimeStamp, $ts);
2062 * Also in ADORecordSet.
2063 * @param $v is a date string in YYYY-MM-DD format
2065 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2067 function UnixDate($v)
2069 if (!preg_match("|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|",
2073 if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;
2075 return @adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]);
2080 * Also in ADORecordSet.
2081 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
2083 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2085 function UnixTimeStamp($v)
2088 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
2092 if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2] <= 1) return 0;
2095 if (!isset($rr[5])) return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]);
2096 return @adodb_mktime($rr[5], $rr[6], $rr[7], $rr[2], $rr[3], $rr[1]);
2100 * Also in ADORecordSet.
2102 * Format database date based on user defined format.
2104 * @param v is the character date in YYYY-MM-DD format, returned by database
2105 * @param fmt is the format to apply to it, using date()
2107 * @return a date formated as user desires
2110 function UserDate($v, $fmt = 'Y-m-d')
2112 $tt = $this->UnixDate($v);
2113 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2114 if (($tt === false || $tt == -1) && $v != false) return $v;
2115 else if ($tt == 0) return $this->emptyDate;
2116 else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
2119 return adodb_date($fmt, $tt);
2125 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
2126 * @param fmt is the format to apply to it, using date()
2128 * @return a timestamp formated as user desires
2130 function UserTimeStamp($v, $fmt = 'Y-m-d H:i:s')
2132 # strlen(14) allows YYYYMMDDHHMMSS format
2133 if (is_numeric($v) && strlen($v) < 14) return adodb_date($fmt, $v);
2134 $tt = $this->UnixTimeStamp($v);
2135 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2136 if (($tt === false || $tt == -1) && $v != false) return $v;
2137 if ($tt == 0) return $this->emptyTimeStamp;
2138 return adodb_date($fmt, $tt);
2142 * Quotes a string, without prefixing nor appending quotes.
2144 function addq($s, $magicq = false)
2148 if ($this->replaceQuote[0] == '\\') {
2149 // only since php 4.0.5
2150 $s = adodb_str_replace(array('\\', "\0"), array('\\\\', "\\\0"), $s);
2151 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2153 return str_replace("'", $this->replaceQuote, $s);
2156 // undo magic quotes for "
2157 $s = str_replace('\\"', '"', $s);
2159 if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything
2161 else { // change \' to '' for sybase/mssql
2162 $s = str_replace('\\\\', '\\', $s);
2163 return str_replace("\\'", $this->replaceQuote, $s);
2168 * Correctly quotes a string so that all strings are escaped. We prefix and append
2169 * to the string single-quotes.
2170 * An example is $db->qstr("Don't bother",magic_quotes_runtime());
2172 * @param s the string to quote
2173 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
2174 * This undoes the stupidity of magic quotes for GPC.
2176 * @return quoted string to be sent back to database
2178 function qstr($s, $magic_quotes = false)
2180 if (!$magic_quotes) {
2182 if ($this->replaceQuote[0] == '\\') {
2183 // only since php 4.0.5
2184 $s = adodb_str_replace(array('\\', "\0"), array('\\\\', "\\\0"), $s);
2185 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2187 return "'" . str_replace("'", $this->replaceQuote, $s) . "'";
2190 // undo magic quotes for "
2191 $s = str_replace('\\"', '"', $s);
2193 if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything
2195 else { // change \' to '' for sybase/mssql
2196 $s = str_replace('\\\\', '\\', $s);
2197 return "'" . str_replace("\\'", $this->replaceQuote, $s) . "'";
2203 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2204 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2205 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2207 * See readme.htm#ex8 for an example of usage.
2210 * @param nrows is the number of rows per page to get
2211 * @param page is the page number to get (1-based)
2212 * @param [inputarr] array of bind variables
2213 * @param [secs2cache] is a private parameter only used by jlim
2214 * @return the recordset ($rs->databaseType == 'array')
2216 * NOTE: phpLens uses a different algorithm and does not use PageExecute().
2219 function &PageExecute($sql, $nrows, $page, $inputarr = false, $secs2cache = 0)
2221 global $ADODB_INCLUDED_LIB;
2222 if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR . '/adodb-lib.inc.php');
2223 if ($this->pageExecuteCountRows) return _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2224 return _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2230 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2231 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2232 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2234 * @param secs2cache seconds to cache data, set to 0 to force query
2236 * @param nrows is the number of rows per page to get
2237 * @param page is the page number to get (1-based)
2238 * @param [inputarr] array of bind variables
2239 * @return the recordset ($rs->databaseType == 'array')
2241 function &CachePageExecute($secs2cache, $sql, $nrows, $page, $inputarr = false)
2243 /*switch($this->dataProvider) {
2247 default: $secs2cache = 0; break;
2249 $rs =& $this->PageExecute($sql, $nrows, $page, $inputarr, $secs2cache);
2253 } // end class ADOConnection
2256 //==============================================================================================
2257 // CLASS ADOFetchObj
2258 //==============================================================================================
2261 * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
2269 //==============================================================================================
2270 // CLASS ADORecordSet_empty
2271 //==============================================================================================
2274 * Lightweight recordset when there are no records to be returned
2276 class ADORecordSet_empty
2278 var $dataProvider = 'empty';
2279 var $databaseType = false;
2281 var $_numOfRows = 0;
2282 var $fields = false;
2283 var $connection = false;
2290 function RecordCount()
2295 function PO_RecordCount()
2310 function FieldCount()
2316 //==============================================================================================
2317 // DATE AND TIME FUNCTIONS
2318 //==============================================================================================
2319 include_once(ADODB_DIR . '/adodb-time.inc.php');
2321 //==============================================================================================
2322 // CLASS ADORecordSet
2323 //==============================================================================================
2325 if (PHP_VERSION < 5) include_once(ADODB_DIR . '/adodb-php4.inc.php');
2326 else include_once(ADODB_DIR . '/adodb-iterator.inc.php');
2328 * RecordSet class that represents the dataset returned by the database.
2329 * To keep memory overhead low, this class holds only the current row in memory.
2330 * No prefetching of data is done, so the RecordCount() can return -1 ( which
2331 * means recordcount not known).
2333 class ADORecordSet extends ADODB_BASE_RS
2338 var $dataProvider = "native";
2339 var $fields = false; /// holds the current row data
2340 var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob
2341 /// in other words, we use a text area for editing.
2342 var $canSeek = false; /// indicates that seek is supported
2343 var $sql; /// sql text
2344 var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object.
2346 var $emptyTimeStamp = ' '; /// what to display when $time==0
2347 var $emptyDate = ' '; /// what to display when $time==0
2349 var $timeCreated = 0; /// datetime in Unix format rs created -- for cached recordsets
2351 var $bind = false; /// used by Fields() to hold array - should be private?
2352 var $fetchMode; /// default fetch mode
2353 var $connection = false; /// the parent connection
2357 var $_numOfRows = -1;
2358 /** number of rows, or -1 */
2359 var $_numOfFields = -1;
2360 /** number of fields in recordset */
2362 /** This variable keeps the result link identifier. */
2363 var $_currentRow = -1;
2364 /** This variable keeps the current row in the Recordset. */
2365 var $_closed = false;
2366 /** has recordset been closed */
2367 var $_inited = false;
2368 /** Init() should only be called once */
2370 /** Used by FetchObj */
2372 /** Used by FetchObj */
2374 var $_currentPage = -1;
2375 /** Added by Iván Oliva to implement recordset pagination */
2376 var $_atFirstPage = false;
2377 /** Added by Iván Oliva to implement recordset pagination */
2378 var $_atLastPage = false;
2379 /** Added by Iván Oliva to implement recordset pagination */
2380 var $_lastPageNo = -1;
2381 var $_maxRecordCount = 0;
2382 var $datetime = false;
2387 * @param queryID this is the queryID returned by ADOConnection->_query()
2390 function ADORecordSet($queryID)
2392 $this->_queryID = $queryID;
2398 if ($this->_inited) return;
2399 $this->_inited = true;
2400 if ($this->_queryID) @$this->_initrs();
2402 $this->_numOfRows = 0;
2403 $this->_numOfFields = 0;
2405 if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
2407 $this->_currentRow = 0;
2408 if ($this->EOF = ($this->_fetch() === false)) {
2409 $this->_numOfRows = 0; // _numOfRows could be -1
2418 * Generate a SELECT tag string from a recordset, and return the string.
2419 * If the recordset has 2 cols, we treat the 1st col as the containing
2420 * the text to display to the user, and 2nd col as the return value. Default
2421 * strings are compared with the FIRST column.
2423 * @param name name of SELECT tag
2424 * @param [defstr] the value to hilite. Use an array for multiple hilites for listbox.
2425 * @param [blank1stItem] true to leave the 1st item in list empty
2426 * @param [multiple] true for listbox, false for popup
2427 * @param [size] #rows to show for listbox. not used by popup
2428 * @param [selectAttr] additional attributes to defined for SELECT tag.
2429 * useful for holding javascript onChange='...' handlers.
2430 & @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with
2431 * column 0 (1st col) if this is true. This is not documented.
2435 * changes by glen.davies@cce.ac.nz to support multiple hilited items
2437 function GetMenu($name, $defstr = '', $blank1stItem = true, $multiple = false,
2438 $size = 0, $selectAttr = '', $compareFields0 = true)
2440 global $ADODB_INCLUDED_LIB;
2441 if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR . '/adodb-lib.inc.php');
2442 return _adodb_getmenu($this, $name, $defstr, $blank1stItem, $multiple,
2443 $size, $selectAttr, $compareFields0);
2447 * Generate a SELECT tag string from a recordset, and return the string.
2448 * If the recordset has 2 cols, we treat the 1st col as the containing
2449 * the text to display to the user, and 2nd col as the return value. Default
2450 * strings are compared with the SECOND column.
2453 function GetMenu2($name, $defstr = '', $blank1stItem = true, $multiple = false, $size = 0, $selectAttr = '')
2455 global $ADODB_INCLUDED_LIB;
2456 if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR . '/adodb-lib.inc.php');
2457 return _adodb_getmenu($this, $name, $defstr, $blank1stItem, $multiple,
2458 $size, $selectAttr, false);
2463 * return recordset as a 2-dimensional array.
2465 * @param [nRows] is the number of rows to return. -1 means every row.
2467 * @return an array indexed by the rows (0-based) from the recordset
2469 function &GetArray($nRows = -1)
2471 global $ADODB_EXTENSION;
2472 if ($ADODB_EXTENSION) return adodb_getall($this, $nRows);
2476 while (!$this->EOF && $nRows != $cnt) {
2477 $results[] = $this->fields;
2484 function &GetAll($nRows = -1)
2486 $arr =& $this->GetArray($nRows);
2491 * Some databases allow multiple recordsets to be returned. This function
2492 * will return true if there is a next recordset, or false if no more.
2494 function NextRecordSet()
2500 * return recordset as a 2-dimensional array.
2501 * Helper function for ADOConnection->SelectLimit()
2503 * @param offset is the row to start calculations from (1-based)
2504 * @param [nrows] is the number of rows to return
2506 * @return an array indexed by the rows (0-based) from the recordset
2508 function &GetArrayLimit($nrows, $offset = -1)
2511 $arr =& $this->GetArray($nrows);
2515 $this->Move($offset);
2519 while (!$this->EOF && $nrows != $cnt) {
2520 $results[$cnt++] = $this->fields;
2529 * Synonym for GetArray() for compatibility with ADO.
2531 * @param [nRows] is the number of rows to return. -1 means every row.
2533 * @return an array indexed by the rows (0-based) from the recordset
2535 function &GetRows($nRows = -1)
2537 $arr =& $this->GetArray($nRows);
2542 * return whole recordset as a 2-dimensional associative array if there are more than 2 columns.
2543 * The first column is treated as the key and is not included in the array.
2544 * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless
2545 * $force_array == true.
2547 * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional
2548 * array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,
2551 * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and
2552 * instead of returning array[col0] => array(remaining cols), return array[col0] => col1
2554 * @return an associative array indexed by the first column of the array,
2555 * or false if the data has less than 2 cols.
2557 function &GetAssoc($force_array = false, $first2cols = false)
2559 $cols = $this->_numOfFields;
2563 $numIndex = isset($this->fields[0]);
2566 if (!$first2cols && ($cols > 2 || $force_array)) {
2568 while (!$this->EOF) {
2569 $results[trim($this->fields[0])] = array_slice($this->fields, 1);
2573 while (!$this->EOF) {
2574 $results[trim(reset($this->fields))] = array_slice($this->fields, 1);
2579 // return scalar values
2581 while (!$this->EOF) {
2582 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
2583 $results[trim(($this->fields[0]))] = $this->fields[1];
2587 while (!$this->EOF) {
2588 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
2589 $v1 = trim(reset($this->fields));
2590 $v2 = '' . next($this->fields);
2591 $results[$v1] = $v2;
2602 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
2603 * @param fmt is the format to apply to it, using date()
2605 * @return a timestamp formated as user desires
2607 function UserTimeStamp($v, $fmt = 'Y-m-d H:i:s')
2609 if (is_numeric($v) && strlen($v) < 14) return adodb_date($fmt, $v);
2610 $tt = $this->UnixTimeStamp($v);
2611 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2612 if (($tt === false || $tt == -1) && $v != false) return $v;
2613 if ($tt === 0) return $this->emptyTimeStamp;
2614 return adodb_date($fmt, $tt);
2619 * @param v is the character date in YYYY-MM-DD format, returned by database
2620 * @param fmt is the format to apply to it, using date()
2622 * @return a date formated as user desires
2624 function UserDate($v, $fmt = 'Y-m-d')
2626 $tt = $this->UnixDate($v);
2627 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2628 if (($tt === false || $tt == -1) && $v != false) return $v;
2629 else if ($tt == 0) return $this->emptyDate;
2630 else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
2632 return adodb_date($fmt, $tt);
2638 * @param $v is a date string in YYYY-MM-DD format
2640 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2642 function UnixDate($v)
2645 if (!preg_match("|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|",
2649 if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;
2651 return @adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]);
2656 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
2658 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2660 function UnixTimeStamp($v)
2664 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
2667 if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2] <= 1) return 0;
2670 if (!isset($rr[5])) return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]);
2671 return @adodb_mktime($rr[5], $rr[6], $rr[7], $rr[2], $rr[3], $rr[1]);
2676 * PEAR DB Compat - do not use internally
2680 return $this->Close();
2685 * PEAR DB compat, number of rows
2689 return $this->_numOfRows;
2694 * PEAR DB compat, number of cols
2698 return $this->_numOfFields;
2702 * Fetch a row, returning false if no more rows.
2703 * This is PEAR DB compat mode.
2705 * @return false or array containing the current record
2707 function &FetchRow()
2709 if ($this->EOF) return false;
2710 $arr = $this->fields;
2711 $this->_currentRow++;
2712 if (!$this->_fetch()) $this->EOF = true;
2718 * Fetch a row, returning PEAR_Error if no more rows.
2719 * This is PEAR DB compat mode.
2721 * @return DB_OK or error object
2723 function FetchInto(&$arr)
2725 if ($this->EOF) return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF', -1) : false;
2726 $arr = $this->fields;
2733 * Move to the first row in the recordset. Many databases do NOT support this.
2735 * @return true or false
2737 function MoveFirst()
2739 if ($this->_currentRow == 0) return true;
2740 return $this->Move(0);
2745 * Move to the last row in the recordset.
2747 * @return true or false
2751 if ($this->_numOfRows >= 0) return $this->Move($this->_numOfRows - 1);
2752 if ($this->EOF) return false;
2753 while (!$this->EOF) {
2764 * Move to next record in the recordset.
2766 * @return true if there still rows available, or false if there are no more rows (EOF).
2771 $this->_currentRow++;
2772 if ($this->_fetch()) return true;
2775 /* -- tested error handling when scrolling cursor -- seems useless.
2776 $conn = $this->connection;
2777 if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
2778 $fn = $conn->raiseErrorFn;
2779 $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
2786 * Random access to a specific row in the recordset. Some databases do not support
2787 * access to previous rows in the databases (no scrolling backwards).
2789 * @param rowNumber is the row to move to (0-based)
2791 * @return true if there still rows available, or false if there are no more rows (EOF).
2793 function Move($rowNumber = 0)
2796 if ($rowNumber == $this->_currentRow) return true;
2797 if ($rowNumber >= $this->_numOfRows)
2798 if ($this->_numOfRows != -1) $rowNumber = $this->_numOfRows - 2;
2800 if ($this->canSeek) {
2802 if ($this->_seek($rowNumber)) {
2803 $this->_currentRow = $rowNumber;
2804 if ($this->_fetch()) {
2812 if ($rowNumber < $this->_currentRow) return false;
2813 global $ADODB_EXTENSION;
2814 if ($ADODB_EXTENSION) {
2815 while (!$this->EOF && $this->_currentRow < $rowNumber) {
2816 adodb_movenext($this);
2820 while (!$this->EOF && $this->_currentRow < $rowNumber) {
2821 $this->_currentRow++;
2823 if (!$this->_fetch()) $this->EOF = true;
2826 return !($this->EOF);
2829 $this->fields = false;
2836 * Get the value of a field in the current row by column name.
2837 * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
2839 * @param colname is the field to access
2841 * @return the value of $colname column
2843 function Fields($colname)
2845 return $this->fields[$colname];
2848 function GetAssocKeys($upper = true)
2850 $this->bind = array();
2851 for ($i = 0; $i < $this->_numOfFields; $i++) {
2852 $o =& $this->FetchField($i);
2853 if ($upper === 2) $this->bind[$o->name] = $i;
2854 else $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $i;
2859 * Use associative array to get fields array for databases that do not support
2860 * associative arrays. Submitted by Paolo S. Asioli paolo.asioli@libero.it
2862 * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC
2863 * before you execute your SQL statement, and access $rs->fields['col'] directly.
2865 * $upper 0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField
2867 function &GetRowAssoc($upper = 1)
2870 // if (!$this->fields) return $record;
2873 $this->GetAssocKeys($upper);
2876 foreach ($this->bind as $k => $v) {
2877 $record[$k] = $this->fields[$v];
2885 * Clean up recordset
2887 * @return true or false
2891 // free connection object - this seems to globally free the object
2892 // and not merely the reference, so don't do this...
2893 // $this->connection = false;
2894 if (!$this->_closed) {
2895 $this->_closed = true;
2896 return $this->_close();
2902 * synonyms RecordCount and RowCount
2904 * @return the number of rows or -1 if this is not supported
2906 function RecordCount()
2908 return $this->_numOfRows;
2913 * If we are using PageExecute(), this will return the maximum possible rows
2914 * that can be returned when paging a recordset.
2916 function MaxRecordCount()
2918 return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();
2922 * synonyms RecordCount and RowCount
2924 * @return the number of rows or -1 if this is not supported
2928 return $this->_numOfRows;
2933 * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
2935 * @return the number of records from a previous SELECT. All databases support this.
2937 * But aware possible problems in multiuser environments. For better speed the table
2938 * must be indexed by the condition. Heavy test this before deploying.
2940 function PO_RecordCount($table = "", $condition = "")
2943 $lnumrows = $this->_numOfRows;
2944 // the database doesn't support native recordcount, so we do a workaround
2945 if ($lnumrows == -1 && $this->connection) {
2947 if ($condition) $condition = " WHERE " . $condition;
2948 $resultrows = &$this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
2949 if ($resultrows) $lnumrows = reset($resultrows->fields);
2956 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
2958 function CurrentRow()
2960 return $this->_currentRow;
2964 * synonym for CurrentRow -- for ADO compat
2966 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
2968 function AbsolutePosition()
2970 return $this->_currentRow;
2974 * @return the number of columns in the recordset. Some databases will set this to 0
2975 * if no records are returned, others will return the number of columns in the query.
2977 function FieldCount()
2979 return $this->_numOfFields;
2984 * Get the ADOFieldObject of a specific column.
2986 * @param fieldoffset is the column position to access(0-based).
2988 * @return the ADOFieldObject for that column, or false.
2990 function &FetchField($fieldoffset)
2992 // must be defined by child class
2996 * Get the ADOFieldObjects of all columns in an array.
2999 function FieldTypesArray()
3002 for ($i = 0, $max = $this->_numOfFields; $i < $max; $i++)
3003 $arr[] = $this->FetchField($i);
3008 * Return the fields array of the current row as an object for convenience.
3009 * The default case is lowercase field names.
3011 * @return the object with the properties set to the fields of the current row
3013 function &FetchObj()
3015 $o =& $this->FetchObject(false);
3020 * Return the fields array of the current row as an object for convenience.
3021 * The default case is uppercase.
3023 * @param $isupper to set the object property names to uppercase
3025 * @return the object with the properties set to the fields of the current row
3027 function &FetchObject($isupper = true)
3029 if (empty($this->_obj)) {
3030 $this->_obj =& new ADOFetchObj();
3031 $this->_names = array();
3032 for ($i = 0; $i < $this->_numOfFields; $i++) {
3033 $f = $this->FetchField($i);
3034 $this->_names[] = $f->name;
3039 for ($i = 0; $i < $this->_numOfFields; $i++) {
3040 $name = $this->_names[$i];
3041 if ($isupper) $n = strtoupper($name);
3044 $o->$n = $this->Fields($name);
3050 * Return the fields array of the current row as an object for convenience.
3051 * The default is lower-case field names.
3053 * @return the object with the properties set to the fields of the current row,
3056 * Fixed bug reported by tim@orotech.net
3058 function &FetchNextObj()
3060 return $this->FetchNextObject(false);
3065 * Return the fields array of the current row as an object for convenience.
3066 * The default is upper case field names.
3068 * @param $isupper to set the object property names to uppercase
3070 * @return the object with the properties set to the fields of the current row,
3073 * Fixed bug reported by tim@orotech.net
3075 function &FetchNextObject($isupper = true)
3078 if ($this->_numOfRows != 0 && !$this->EOF) {
3079 $o = $this->FetchObject($isupper);
3080 $this->_currentRow++;
3081 if ($this->_fetch()) return $o;
3088 * Get the metatype of the column. This is used for formatting. This is because
3089 * many databases use different names for the same type, so we transform the original
3090 * type to our standardised version which uses 1 character codes:
3092 * @param t is the type passed in. Normally is ADOFieldObject->type.
3093 * @param len is the maximum length of that field. This is because we treat character
3094 * fields bigger than a certain size as a 'B' (blob).
3095 * @param fieldobj is the field object returned by the database driver. Can hold
3096 * additional info (eg. primary_key for mysql).
3098 * @return the general type of the data:
3099 * C for character < 200 chars
3100 * X for teXt (>= 200 chars)
3102 * N for numeric floating point
3105 * L for logical/Boolean
3107 * R for autoincrement counter/integer
3111 function MetaType($t, $len = -1, $fieldobj = false)
3113 if (is_object($t)) {
3115 $t = $fieldobj->type;
3116 $len = $fieldobj->max_length;
3118 // changed in 2.32 to hashing instead of switch stmt for speed...
3119 static $typeMap = array(
3130 'INTERVAL' => 'C', # Postgres
3145 'LONGBINARY' => 'B',
3148 'YEAR' => 'D', // mysql
3155 'TIMESTAMPTZ' => 'T',
3165 'SERIAL' => 'R', // ifx
3166 'INT IDENTITY' => 'R',
3170 'INTEGER UNSIGNED' => 'I',
3176 'LONG' => 'N', // interbase is numeric, oci8 is blob
3177 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
3182 'DOUBLE PRECISION' => 'N',
3183 'SMALLFLOAT' => 'N',
3194 'SQLSMFLOAT' => 'N',
3197 'SQLDECIMAL' => 'N',
3202 'SQLINTERVAL' => 'N',
3208 $t = strtoupper($t);
3209 $tmap = @$typeMap[$t];
3213 // is the char field is too long, return as text field...
3214 if ($this->blobSize >= 0) {
3215 if ($len > $this->blobSize) return 'X';
3216 } elseif ($len > 250) {
3222 if (!empty($fieldobj->primary_key)) return 'R';
3229 if (isset($fieldobj->binary))
3230 return ($fieldobj->binary) ? 'B' : 'X';
3234 if (!empty($this->datetime)) return 'T';
3238 if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B';
3248 * set/returns the current recordset page when paginating
3250 function AbsolutePage($page = -1)
3252 if ($page != -1) $this->_currentPage = $page;
3253 return $this->_currentPage;
3257 * set/returns the status of the atFirstPage flag when paginating
3259 function AtFirstPage($status = false)
3261 if ($status != false) $this->_atFirstPage = $status;
3262 return $this->_atFirstPage;
3265 function LastPageNo($page = false)
3267 if ($page != false) $this->_lastPageNo = $page;
3268 return $this->_lastPageNo;
3272 * set/returns the status of the atLastPage flag when paginating
3274 function AtLastPage($status = false)
3276 if ($status != false) $this->_atLastPage = $status;
3277 return $this->_atLastPage;
3280 } // end class ADORecordSet
3282 //==============================================================================================
3283 // CLASS ADORecordSet_array
3284 //==============================================================================================
3287 * This class encapsulates the concept of a recordset created in memory
3288 * as an array. This is useful for the creation of cached recordsets.
3290 * Note that the constructor is different from the standard ADORecordSet
3293 class ADORecordSet_array extends ADORecordSet
3295 var $databaseType = 'array';
3297 var $_array; // holds the 2-dimensional data array
3298 var $_types; // the array of types of each column (C B I L M)
3299 var $_colnames; // names of each column in array
3300 var $_skiprow1; // skip 1st row because it holds column names
3301 var $_fieldarr; // holds array of field objects
3302 var $canSeek = true;
3303 var $affectedrows = false;
3304 var $insertid = false;
3306 var $compat = false;
3312 function ADORecordSet_array($fakeid = 1)
3314 global $ADODB_FETCH_MODE, $ADODB_COMPAT_FETCH;
3316 // fetch() on EOF does not delete $this->fields
3317 $this->compat = !empty($ADODB_COMPAT_FETCH);
3318 $this->ADORecordSet($fakeid); // fake queryID
3319 $this->fetchMode = $ADODB_FETCH_MODE;
3326 * @param array is a 2-dimensional array holding the data.
3327 * The first row should hold the column names
3328 * unless paramter $colnames is used.
3329 * @param typearr holds an array of types. These are the same types
3330 * used in MetaTypes (C,B,L,I,N).
3331 * @param [colnames] array of column names. If set, then the first row of
3332 * $array should not hold the column names.
3334 function InitArray($array, $typearr, $colnames = false)
3336 $this->_array = $array;
3337 $this->_types = $typearr;
3339 $this->_skiprow1 = false;
3340 $this->_colnames = $colnames;
3342 $this->_skiprow1 = true;
3343 $this->_colnames = $array[0];
3349 * Setup the Array and datatype file objects
3351 * @param array is a 2-dimensional array holding the data.
3352 * The first row should hold the column names
3353 * unless paramter $colnames is used.
3354 * @param fieldarr holds an array of ADOFieldObject's.
3356 function InitArrayFields(&$array, &$fieldarr)
3358 $this->_array =& $array;
3359 $this->_skiprow1 = false;
3361 $this->_fieldobjects =& $fieldarr;
3366 function &GetArray($nRows = -1)
3368 if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) {
3369 return $this->_array;
3371 $arr =& ADORecordSet::GetArray($nRows);
3378 $this->_numOfRows = sizeof($this->_array);
3379 if ($this->_skiprow1) $this->_numOfRows -= 1;
3381 $this->_numOfFields = (isset($this->_fieldobjects)) ?
3382 sizeof($this->_fieldobjects) : sizeof($this->_types);
3385 /* Use associative array to get fields array */
3386 function Fields($colname)
3388 if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
3391 $this->bind = array();
3392 for ($i = 0; $i < $this->_numOfFields; $i++) {
3393 $o = $this->FetchField($i);
3394 $this->bind[strtoupper($o->name)] = $i;
3397 return $this->fields[$this->bind[strtoupper($colname)]];
3400 function &FetchField($fieldOffset = -1)
3402 if (isset($this->_fieldobjects)) {
3403 return $this->_fieldobjects[$fieldOffset];
3405 $o = new ADOFieldObject();
3406 $o->name = $this->_colnames[$fieldOffset];
3407 $o->type = $this->_types[$fieldOffset];
3408 $o->max_length = -1; // length not known
3413 function _seek($row)
3415 if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) {
3416 $this->_currentRow = $row;
3417 if ($this->_skiprow1) $row += 1;
3418 $this->fields = $this->_array[$row];
3427 $this->_currentRow++;
3429 $pos = $this->_currentRow;
3431 if ($this->_numOfRows <= $pos) {
3432 if (!$this->compat) $this->fields = false;
3434 if ($this->_skiprow1) $pos += 1;
3435 $this->fields = $this->_array[$pos];
3446 $pos = $this->_currentRow;
3448 if ($this->_numOfRows <= $pos) {
3449 if (!$this->compat) $this->fields = false;
3452 if ($this->_skiprow1) $pos += 1;
3453 $this->fields = $this->_array[$pos];
3462 } // ADORecordSet_array
3464 //==============================================================================================
3466 //==============================================================================================
3469 * Synonym for ADOLoadCode. Private function. Do not use.
3473 function ADOLoadDB($dbType)
3475 return ADOLoadCode($dbType);
3479 * Load the code for a specific database driver. Private function. Do not use.
3481 function ADOLoadCode($dbType)
3483 global $ADODB_LASTDB;
3485 if (!$dbType) return false;
3486 $db = strtolower($dbType);
3496 @include_once(ADODB_DIR . "/drivers/adodb-" . $db . ".inc.php");
3497 $ADODB_LASTDB = $db;
3499 $ok = class_exists("ADODB_" . $db);
3500 if ($ok) return $db;
3502 $file = ADODB_DIR . "/drivers/adodb-" . $db . ".inc.php";
3503 if (!file_exists($file)) ADOConnection::outp("Missing file: $file");
3504 else ADOConnection::outp("Syntax error in file: $file");
3509 * synonym for ADONewConnection for people like me who cannot remember the correct name
3511 function &NewADOConnection($db = '')
3513 $tmp =& ADONewConnection($db);
3518 * Instantiate a new Connection class for a specific database driver.
3520 * @param [db] is the database Connection object to create. If undefined,
3521 * use the last database driver that was loaded by ADOLoadCode().
3523 * @return the freshly created instance of the Connection class.
3525 function &ADONewConnection($db = '')
3527 GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB;
3529 if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE', 2);
3530 $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false;
3532 if (!empty($ADODB_NEWCONNECTION)) {
3533 $obj = $ADODB_NEWCONNECTION($db);
3535 if ($errorfn) $obj->raiseErrorFn = $errorfn;
3540 if (!isset($ADODB_LASTDB)) $ADODB_LASTDB = '';
3541 if (empty($db)) $db = $ADODB_LASTDB;
3543 if ($db != $ADODB_LASTDB) $db = ADOLoadCode($db);
3549 $errorfn('ADONewConnection', 'ADONewConnection', -998,
3550 "could not load the database driver for '$db",
3551 $db, false, $ignore);
3553 ADOConnection::outp("<p>ADONewConnection: Unable to load database driver '$db'</p>", false);
3558 $cls = 'ADODB_' . $db;
3559 if (!class_exists($cls)) {
3565 if ($errorfn) $obj->raiseErrorFn = $errorfn;
3570 // $perf == true means called by NewPerfMonitor()
3571 function _adodb_getdriver($provider, $drivername, $perf = false)
3573 if ($provider !== 'native' && $provider != 'odbc' && $provider != 'ado')
3574 $drivername = $provider;
3576 if (substr($drivername, 0, 5) == 'odbc_') $drivername = substr($drivername, 5);
3577 else if (substr($drivername, 0, 4) == 'ado_') $drivername = substr($drivername, 4);
3579 switch ($drivername) {
3581 $drivername = 'oci8';
3583 //case 'sybase': $drivername = 'mssql';break;
3585 if ($perf) $drivername = '';
3590 $drivername = 'generic';
3598 function &NewPerfMonitor(&$conn)
3600 $drivername = _adodb_getdriver($conn->dataProvider, $conn->databaseType, true);
3601 if (!$drivername || $drivername == 'generic') return false;
3602 include_once(ADODB_DIR . '/adodb-perf.inc.php');
3603 @include_once(ADODB_DIR . "/perf/perf-$drivername.inc.php");
3604 $class = "Perf_$drivername";
3605 if (!class_exists($class)) return false;
3606 $perf =& new $class($conn);
3611 function &NewDataDictionary(&$conn)
3613 $drivername = _adodb_getdriver($conn->dataProvider, $conn->databaseType);
3615 include_once(ADODB_DIR . '/adodb-lib.inc.php');
3616 include_once(ADODB_DIR . '/adodb-datadict.inc.php');
3617 $path = ADODB_DIR . "/datadict/datadict-$drivername.inc.php";
3619 if (!file_exists($path)) {
3620 ADOConnection::outp("Database driver '$path' not available");
3623 include_once($path);
3624 $class = "ADODB2_$drivername";
3625 $dict =& new $class();
3626 $dict->dataProvider = $conn->dataProvider;
3627 $dict->connection = &$conn;
3628 $dict->upperName = strtoupper($drivername);
3629 $dict->quote = $conn->nameQuote;
3630 if (is_resource($conn->_connectionID))
3631 $dict->serverInfo = $conn->ServerInfo();
3638 * Save a file $filename and its $contents (normally for caching) with file locking
3640 function adodb_write_file($filename, $contents, $debug = false)
3642 # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
3643 # So to simulate locking, we assume that rename is an atomic operation.
3644 # First we delete $filename, then we create a $tempfile write to it and
3645 # rename to the desired $filename. If the rename works, then we successfully
3646 # modified the file exclusively.
3647 # What a stupid need - having to simulate locking.
3649 # 1. $tempfile name is not unique -- very very low
3650 # 2. unlink($filename) fails -- ok, rename will fail
3651 # 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs
3652 # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and cache updated
3653 if (strncmp(PHP_OS, 'WIN', 3) === 0) {
3654 // skip the decimal place
3655 $mtime = substr(str_replace(' ', '_', microtime()), 2);
3656 // getmypid() actually returns 0 on Win98 - never mind!
3657 $tmpname = $filename . uniqid($mtime) . getmypid();
3658 if (!($fd = fopen($tmpname, 'a'))) return false;
3659 $ok = ftruncate($fd, 0);
3660 if (!fwrite($fd, $contents)) $ok = false;
3662 chmod($tmpname, 0644);
3663 // the tricky moment
3665 if (!@rename($tmpname, $filename)) {
3670 if ($debug) ADOConnection::outp(" Rename $tmpname " . ($ok ? 'ok' : 'failed'));
3674 if (!($fd = fopen($filename, 'a'))) return false;
3675 if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
3676 $ok = fwrite($fd, $contents);
3678 chmod($filename, 0644);
3681 if ($debug) ADOConnection::outp(" Failed acquiring lock for $filename<br>\n");
3689 Perform a print_r, with pre tags for better formatting.
3691 function adodb_pr($var)
3693 if (isset($_SERVER['HTTP_USER_AGENT'])) {
3702 Perform a stack-crawl and pretty print it.
3704 @param printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then).
3705 @param levels Number of levels to display
3707 function adodb_backtrace($printOrArr = true, $levels = 9999)
3710 if (PHPVERSION() < 4.3) return;
3712 $html = (isset($_SERVER['HTTP_USER_AGENT']));
3713 $fmt = ($html) ? "</font><font color=#808080 size=-1> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s";
3717 $s = ($html) ? '<pre align=left>' : '';
3719 if (is_array($printOrArr)) $traceArr = $printOrArr;
3720 else $traceArr = debug_backtrace();
3721 array_shift($traceArr);
3722 $tabs = sizeof($traceArr) - 1;
3724 foreach ($traceArr as $arr) {
3726 if ($levels < 0) break;
3729 for ($i = 0; $i < $tabs; $i++) $s .= ($html) ? ' ' : "\t";
3731 if ($html) $s .= '<font face="Courier New,Courier">';
3732 if (isset($arr['class'])) $s .= $arr['class'] . '.';
3733 if (isset($arr['args']))
3734 foreach ($arr['args'] as $v) {
3735 if (is_null($v)) $args[] = 'null';
3736 else if (is_array($v)) $args[] = 'Array[' . sizeof($v) . ']';
3737 else if (is_object($v)) $args[] = 'Object:' . get_class($v);
3738 else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
3741 $str = htmlspecialchars(substr($v, 0, $MAXSTRLEN));
3742 if (strlen($v) > $MAXSTRLEN) $str .= '...';
3746 $s .= $arr['function'] . '(' . implode(', ', $args) . ')';
3749 $s .= @sprintf($fmt, $arr['line'], $arr['file'], basename($arr['file']));
3753 if ($html) $s .= '</pre>';
3754 if ($printOrArr) print $s;
3764 // c-basic-offset: 4
3765 // c-hanging-comment-ender-p: nil
3766 // indent-tabs-mode: nil