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 } else if (strnatcmp(PHP_VERSION,'4.2.0')>=0) {
96 define('ADODB_PHPVER',0x4200);
97 } else if (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
172 class ADOFieldObject {
177 // additional fields by dannym... (danny_milo@yahoo.com)
178 var $not_null = false;
179 // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^
180 // so we can as well make not_null standard (leaving it at "false" does not harm anyways)
182 var $has_default = false; // this one I have done only in mysql and postgres for now ...
183 // others to come (dannym)
184 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.
206 class ADOConnection {
210 var $dataProvider = 'native';
211 var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql
212 var $database = ''; /// Name of database to be used.
213 var $host = ''; /// The hostname of the database server
214 var $user = ''; /// The username which is used to connect to the database server.
215 var $password = ''; /// Password for the username. For security, we no longer store it.
216 var $debug = false; /// if set to true will output sql statements
217 var $maxblobsize = 256000; /// maximum size of blobs or large text fields -- some databases die otherwise like foxpro
218 var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase
219 var $substr = 'substr'; /// substring operator
220 var $length = 'length'; /// string length operator
221 var $random = 'rand()'; /// random function
222 var $upperCase = false; /// uppercase function
223 var $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the database
224 var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt.
225 var $true = '1'; /// string that represents TRUE for a database
226 var $false = '0'; /// string that represents FALSE for a database
227 var $replaceQuote = "\\'"; /// string to use to replace quotes
228 var $nameQuote = '"'; /// string to use to quote identifiers and names
229 var $charSet=false; /// character set to use - only for interbase
230 var $metaDatabasesSQL = '';
231 var $metaTablesSQL = '';
232 var $uniqueOrderBy = false; /// All order by columns have to be unique
233 var $emptyDate = ' ';
234 var $emptyTimeStamp = ' ';
235 var $lastInsID = false;
237 var $hasInsertID = false; /// supports autoincrement ID?
238 var $hasAffectedRows = false; /// supports affected rows for update/delete?
239 var $hasTop = false; /// support mssql/access SELECT TOP 10 * FROM TABLE
240 var $hasLimit = false; /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10
241 var $readOnly = false; /// this is a readonly database - used by phpLens
242 var $hasMoveFirst = false; /// has ability to run MoveFirst(), scrolling backwards
243 var $hasGenID = false; /// can generate sequences using GenID();
244 var $hasTransactions = true; /// has transactions
246 var $genID = 0; /// sequence id used by GenID();
247 var $raiseErrorFn = false; /// error function to call
248 var $isoDates = false; /// accepts dates in ISO format
249 var $cacheSecs = 3600; /// cache for 1 hour
250 var $sysDate = false; /// name of function that returns the current date
251 var $sysTimeStamp = false; /// name of function that returns the current timestamp
252 var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets
254 var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' '
255 var $numCacheHits = 0;
256 var $numCacheMisses = 0;
257 var $pageExecuteCountRows = true;
258 var $uniqueSort = false; /// indicates that all fields in order by must be unique
259 var $leftOuter = false; /// operator to use for left outer join in WHERE clause
260 var $rightOuter = false; /// operator to use for right outer join in WHERE clause
261 var $ansiOuter = false; /// whether ansi outer join syntax supported
262 var $autoRollback = false; // autoRollback on PConnect().
263 var $poorAffectedRows = false; // affectedRows not working or unreliable
265 var $fnExecute = false;
266 var $fnCacheExecute = false;
267 var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char
268 var $rsPrefix = "ADORecordSet_";
270 var $autoCommit = true; /// do not modify this yourself - actually private
271 var $transOff = 0; /// temporarily disable transactions
272 var $transCnt = 0; /// count of nested transactions
274 var $fetchMode=false;
278 var $_oldRaiseFn = false;
279 var $_transOK = null;
280 var $_connectionID = false; /// The returned link identifier whenever a successful database connection is made.
281 var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will
282 /// then returned by the errorMsg() function
283 var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8
284 var $_queryID = false; /// This variable keeps the last created result link identifier
286 var $_isPersistentConnection = false; /// A boolean variable to state whether its a persistent connection or normal connection. */
287 var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.
288 var $_evalAll = false;
289 var $_affected = false;
290 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 } else if (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) {
761 foreach($arr as $v) {
763 // from Ron Baldwin <ron.baldwin@sourceprose.com>
764 // Only quote string types
765 if (gettype($v) == 'string')
766 $sql .= $this->qstr($v);
767 else if ($v === null)
775 if ($i+1 != sizeof($sqlarr))
776 ADOConnection::outp( "Input Array does not match ?: ".htmlspecialchars($sql));
778 $ret =& $this->_Execute($sql,false);
779 if (!$ret) return $ret;
783 $stmt = $this->Prepare($sql);
784 foreach($inputarr as $arr) {
785 $ret =& $this->_Execute($stmt,$arr);
786 if (!$ret) return $ret;
789 $ret =& $this->_Execute($sql,$inputarr);
792 $ret =& $this->_Execute($sql,false);
798 function& _Execute($sql,$inputarr=false)
802 global $HTTP_SERVER_VARS;
806 foreach($inputarr as $kk=>$vv) {
807 if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
808 $ss .= "($kk=>'$vv') ";
812 $sqlTxt = str_replace(',',', ',is_array($sql) ?$sql[0] : $sql);
814 // check if running from browser or command-line
815 $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
818 if ($this->debug === -1)
819 ADOConnection::outp( "<br>\n($this->databaseType): ".htmlspecialchars($sqlTxt)." <code>$ss</code>\n<br>\n",false);
821 ADOConnection::outp( "<hr>\n($this->databaseType): ".htmlspecialchars($sqlTxt)." <code>$ss</code>\n<hr>\n",false);
823 ADOConnection::outp("-----\n($this->databaseType): ".($sqlTxt)." \n-----\n",false);
825 $this->_queryID = $this->_query($sql,$inputarr);
827 Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
828 because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion
830 if ($this->databaseType == 'mssql') {
831 // ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6
832 if($emsg = $this->ErrorMsg()) {
833 if ($err = $this->ErrorNo()) ADOConnection::outp($err.': '.$emsg);
835 } else if (!$this->_queryID) {
836 ADOConnection::outp($this->ErrorNo() .': '. $this->ErrorMsg());
839 //****************************
840 // non-debug version of query
841 //****************************
843 $this->_queryID =@$this->_query($sql,$inputarr);
846 /************************
847 // OK, query executed
848 *************************/
850 if ($this->_queryID === false) {
851 // error handling if query fails
852 if ($this->debug == 99) adodb_backtrace(true,5);
853 $fn = $this->raiseErrorFn;
855 $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
862 if ($this->_queryID === true) {
863 // return simplified empty recordset for inserts/updates/deletes with lower overhead
864 $rs =& new ADORecordSet_empty();
868 // return real recordset from select statement
869 $rsclass = $this->rsPrefix.$this->databaseType;
870 $rs =& new $rsclass($this->_queryID,$this->fetchMode);
871 $rs->connection = &$this; // Pablo suggestion
873 if (is_array($sql)) $rs->sql = $sql[0];
874 else $rs->sql = $sql;
875 if ($rs->_numOfRows <= 0) {
876 global $ADODB_COUNTRECS;
878 if ($ADODB_COUNTRECS) {
880 $rs = &$this->_rs2rs($rs,-1,-1,!is_array($sql));
881 $rs->_queryID = $this->_queryID;
889 function CreateSequence($seqname='adodbseq',$startID=1)
891 if (empty($this->_genSeqSQL)) return false;
892 return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
895 function DropSequence($seqname)
897 if (empty($this->_dropSeqSQL)) return false;
898 return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
902 * Generates a sequence id and stores it in $this->genID;
903 * GenID is only available if $this->hasGenID = true;
905 * @param seqname name of sequence to use
906 * @param startID if sequence does not exist, start at this ID
907 * @return 0 if not supported, otherwise a sequence id
909 function GenID($seqname='adodbseq',$startID=1)
911 if (!$this->hasGenID) {
912 return 0; // formerly returns false pre 1.60
915 $getnext = sprintf($this->_genIDSQL,$seqname);
917 $holdtransOK = $this->_transOK;
918 $rs = @$this->Execute($getnext);
920 $this->_transOK = $holdtransOK; //if the status was ok before reset
921 $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
922 $rs = $this->Execute($getnext);
924 if ($rs && !$rs->EOF) $this->genID = reset($rs->fields);
925 else $this->genID = 0; // false
927 if ($rs) $rs->Close();
933 * @return the last inserted ID. Not all databases support this.
937 if ($this->_logsql && $this->lastInsID) return $this->lastInsID;
938 if ($this->hasInsertID) return $this->_insertid();
940 ADOConnection::outp( '<p>Insert_ID error</p>');
948 * Portable Insert ID. Pablo Roca <pabloroca@mvps.org>
950 * @return the last inserted ID. All databases support this. But aware possible
951 * problems in multiuser environments. Heavy test this before deploying.
953 function PO_Insert_ID($table="", $id="")
955 if ($this->hasInsertID){
956 return $this->Insert_ID();
958 return $this->GetOne("SELECT MAX($id) FROM $table");
963 * @return # rows affected by UPDATE/DELETE
965 function Affected_Rows()
967 if ($this->hasAffectedRows) {
968 if ($this->fnExecute === 'adodb_log_sql') {
969 if ($this->_logsql && $this->_affected !== false) return $this->_affected;
971 $val = $this->_affectedrows();
972 return ($val < 0) ? false : $val;
975 if ($this->debug) ADOConnection::outp( '<p>Affected_Rows error</p>',false);
981 * @return the last error message
985 return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
990 * @return the last error number. Normally 0 means no error.
994 return ($this->_errorMsg) ? -1 : 0;
997 function MetaError($err=false)
999 include_once(ADODB_DIR."/adodb-error.inc.php");
1000 if ($err === false) $err = $this->ErrorNo();
1001 return adodb_error($this->dataProvider,$this->databaseType,$err);
1004 function MetaErrorMsg($errno)
1006 include_once(ADODB_DIR."/adodb-error.inc.php");
1007 return adodb_errormsg($errno);
1011 * @returns an array with the primary key columns in it.
1013 function MetaPrimaryKeys($table, $owner=false)
1015 // owner not used in base class - see oci8
1017 $objs =& $this->MetaColumns($table);
1019 foreach($objs as $v) {
1020 if (!empty($v->primary_key))
1024 if (sizeof($p)) return $p;
1025 if (function_exists('ADODB_VIEW_PRIMARYKEYS'))
1026 return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);
1031 * @returns assoc array where keys are tables, and values are foreign keys
1033 function MetaForeignKeys($table, $owner=false, $upper=false)
1038 * Choose a database to connect to. Many databases do not support this.
1040 * @param dbName is the name of the database to select
1041 * @return true or false
1043 function SelectDB($dbName)
1048 * Will select, getting rows from $offset (1-based), for $nrows.
1049 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1050 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1051 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1053 * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
1054 * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
1056 * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
1057 * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
1060 * @param [offset] is the row to start calculations from (1-based)
1061 * @param [nrows] is the number of rows to get
1062 * @param [inputarr] array of bind variables
1063 * @param [secs2cache] is a private parameter only used by jlim
1064 * @return the recordset ($rs->databaseType == 'array')
1066 function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
1068 if ($this->hasTop && $nrows > 0) {
1069 // suggested by Reinhard Balling. Access requires top after distinct
1070 // Informix requires first before distinct - F Riosa
1071 $ismssql = (strpos($this->databaseType,'mssql') !== false);
1072 if ($ismssql) $isaccess = false;
1073 else $isaccess = (strpos($this->databaseType,'access') !== false);
1077 // access includes ties in result
1079 $sql = preg_replace(
1080 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
1082 if ($secs2cache>0) {
1083 $ret =& $this->CacheExecute($secs2cache, $sql,$inputarr);
1085 $ret =& $this->Execute($sql,$inputarr);
1087 return $ret; // PHP5 fix
1088 } else if ($ismssql){
1089 $sql = preg_replace(
1090 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
1092 $sql = preg_replace(
1093 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
1096 $nn = $nrows + $offset;
1097 if ($isaccess || $ismssql) {
1098 $sql = preg_replace(
1099 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1101 $sql = preg_replace(
1102 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1107 // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows
1108 // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.
1109 global $ADODB_COUNTRECS;
1111 $savec = $ADODB_COUNTRECS;
1112 $ADODB_COUNTRECS = false;
1115 if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1116 else $rs = &$this->Execute($sql,$inputarr);
1118 if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1119 else $rs = &$this->Execute($sql,$inputarr);
1121 $ADODB_COUNTRECS = $savec;
1122 if ($rs && !$rs->EOF) {
1123 $rs =& $this->_rs2rs($rs,$nrows,$offset);
1130 * Create serializable recordset. Breaks rs link to connection.
1132 * @param rs the recordset to serialize
1134 function &SerializableRS(&$rs)
1136 $rs2 =& $this->_rs2rs($rs);
1138 $rs2->connection =& $ignore;
1144 * Convert database recordset to an array recordset
1145 * input recordset's cursor should be at beginning, and
1146 * old $rs will be closed.
1148 * @param rs the recordset to copy
1149 * @param [nrows] number of rows to retrieve (optional)
1150 * @param [offset] offset by number of rows (optional)
1151 * @return the new recordset
1153 function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true)
1155 if (! $rs) return false;
1157 $dbtype = $rs->databaseType;
1159 $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?
1162 if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {
1164 $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?
1168 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
1169 $flds[] = $rs->FetchField($i);
1171 $arr =& $rs->GetArrayLimit($nrows,$offset);
1173 if ($close) $rs->Close();
1175 $arrayClass = $this->arrayClass;
1177 $rs2 =& new $arrayClass();
1178 $rs2->connection = &$this;
1179 $rs2->sql = $rs->sql;
1180 $rs2->dataProvider = $this->dataProvider;
1181 $rs2->InitArrayFields($arr,$flds);
1186 * Return all rows. Compat with PEAR DB
1188 function &GetAll($sql, $inputarr=false)
1190 $arr =& $this->GetArray($sql,$inputarr);
1194 function &GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false)
1196 $rs =& $this->Execute($sql, $inputarr);
1197 if (!$rs) return false;
1199 $arr =& $rs->GetAssoc($force_array,$first2cols);
1203 function &CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false)
1205 if (!is_numeric($secs2cache)) {
1206 $first2cols = $force_array;
1207 $force_array = $inputarr;
1209 $rs =& $this->CacheExecute($secs2cache, $sql, $inputarr);
1210 if (!$rs) return false;
1212 $arr =& $rs->GetAssoc($force_array,$first2cols);
1217 * Return first element of first row of sql statement. Recordset is disposed
1220 * @param sql SQL statement
1221 * @param [inputarr] input bind array
1223 function GetOne($sql,$inputarr=false)
1225 global $ADODB_COUNTRECS;
1226 $crecs = $ADODB_COUNTRECS;
1227 $ADODB_COUNTRECS = false;
1230 $rs = &$this->Execute($sql,$inputarr);
1232 if (!$rs->EOF) $ret = reset($rs->fields);
1235 $ADODB_COUNTRECS = $crecs;
1239 function CacheGetOne($secs2cache,$sql=false,$inputarr=false)
1242 $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1244 if (!$rs->EOF) $ret = reset($rs->fields);
1251 function GetCol($sql, $inputarr = false, $trim = false)
1254 $rs = &$this->Execute($sql, $inputarr);
1259 $rv[] = trim(reset($rs->fields));
1264 $rv[] = reset($rs->fields);
1273 function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false)
1276 $rs = &$this->CacheExecute($secs, $sql, $inputarr);
1280 $rv[] = trim(reset($rs->fields));
1285 $rv[] = reset($rs->fields);
1295 Calculate the offset of a date for a particular database and generate
1296 appropriate SQL. Useful for calculating future/past dates and storing
1299 If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
1301 function OffsetDate($dayFraction,$date=false)
1303 if (!$date) $date = $this->sysDate;
1304 return '('.$date.'+'.$dayFraction.')';
1310 * @param sql SQL statement
1311 * @param [inputarr] input bind array
1313 function &GetArray($sql,$inputarr=false)
1315 global $ADODB_COUNTRECS;
1317 $savec = $ADODB_COUNTRECS;
1318 $ADODB_COUNTRECS = false;
1319 $rs =& $this->Execute($sql,$inputarr);
1320 $ADODB_COUNTRECS = $savec;
1322 if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
1324 $arr =& $rs->GetArray();
1329 function &CacheGetAll($secs2cache,$sql=false,$inputarr=false)
1331 global $ADODB_COUNTRECS;
1333 $savec = $ADODB_COUNTRECS;
1334 $ADODB_COUNTRECS = false;
1335 $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1336 $ADODB_COUNTRECS = $savec;
1339 if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
1342 $arr =& $rs->GetArray();
1350 * Return one row of sql statement. Recordset is disposed for you.
1352 * @param sql SQL statement
1353 * @param [inputarr] input bind array
1355 function &GetRow($sql,$inputarr=false)
1357 global $ADODB_COUNTRECS;
1358 $crecs = $ADODB_COUNTRECS;
1359 $ADODB_COUNTRECS = false;
1361 $rs =& $this->Execute($sql,$inputarr);
1363 $ADODB_COUNTRECS = $crecs;
1365 if (!$rs->EOF) $arr = $rs->fields;
1366 else $arr = array();
1374 function &CacheGetRow($secs2cache,$sql=false,$inputarr=false)
1376 $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1379 if (!$rs->EOF) $arr = $rs->fields;
1387 * Insert or replace a single record. Note: this is not the same as MySQL's replace.
1388 * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
1389 * Also note that no table locking is done currently, so it is possible that the
1390 * record be inserted twice by two programs...
1392 * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
1395 * $fieldArray associative array of data (you must quote strings yourself).
1396 * $keyCol the primary key field name or if compound key, array of field names
1397 * autoQuote set to true to use a hueristic to quote strings. Works with nulls and numbers
1398 * but does not work with dates nor SQL functions.
1399 * has_autoinc the primary key is an auto-inc field, so skip in insert.
1401 * Currently blob replace not supported
1403 * returns 0 = fail, 1 = update, 2 = insert
1406 function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false)
1408 global $ADODB_INCLUDED_LIB;
1409 if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
1411 return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);
1416 * Will select, getting rows from $offset (1-based), for $nrows.
1417 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1418 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1419 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1421 * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
1422 * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
1424 * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
1426 * @param [secs2cache] seconds to cache data, set to 0 to force query. This is optional
1428 * @param [offset] is the row to start calculations from (1-based)
1429 * @param [nrows] is the number of rows to get
1430 * @param [inputarr] array of bind variables
1431 * @return the recordset ($rs->databaseType == 'array')
1433 function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false)
1435 if (!is_numeric($secs2cache)) {
1436 if ($sql === false) $sql = -1;
1437 if ($offset == -1) $offset = false;
1438 // sql, nrows, offset,inputarr
1439 $rs =& $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs);
1441 if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()");
1442 $rs =& $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
1448 * Flush cached recordsets that match a particular $sql statement.
1449 * If $sql == false, then we purge all files in the cache.
1451 function CacheFlush($sql=false,$inputarr=false)
1453 global $ADODB_CACHE_DIR;
1455 if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
1456 if (strncmp(PHP_OS,'WIN',3) === 0) {
1457 $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
1459 $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/??/adodb_*.cache';
1460 // old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`';
1463 ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>");
1469 $f = $this->_gencachename($sql.serialize($inputarr),false);
1470 adodb_write_file($f,''); // is adodb_write_file needed?
1472 if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f");
1477 * Private function to generate filename for caching.
1478 * Filename is generated based on:
1481 * - database type (oci8, ibase, ifx, etc)
1485 * We create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
1486 * Assuming that we can have 50,000 files per directory with good performance,
1487 * then we can scale to 12.8 million unique cached recordsets. Wow!
1489 function _gencachename($sql,$createdir)
1491 global $ADODB_CACHE_DIR;
1493 $m = md5($sql.$this->databaseType.$this->database.$this->user);
1494 $dir = $ADODB_CACHE_DIR.'/'.substr($m,0,2);
1495 if ($createdir && !file_exists($dir)) {
1497 if (!mkdir($dir,0771))
1498 if ($this->debug) ADOConnection::outp( "Unable to mkdir $dir for $sql");
1501 return $dir.'/adodb_'.$m.'.cache';
1506 * Execute SQL, caching recordsets.
1508 * @param [secs2cache] seconds to cache data, set to 0 to force query.
1509 * This is an optional parameter.
1510 * @param sql SQL statement to execute
1511 * @param [inputarr] holds the input data to bind to
1512 * @return RecordSet or false
1514 function &CacheExecute($secs2cache,$sql=false,$inputarr=false)
1516 if (!is_numeric($secs2cache)) {
1519 $secs2cache = $this->cacheSecs;
1521 global $ADODB_INCLUDED_CSV;
1522 if (empty($ADODB_INCLUDED_CSV)) include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
1524 if (is_array($sql)) $sql = $sql[0];
1526 $md5file = $this->_gencachename($sql.serialize($inputarr),true);
1529 if ($secs2cache > 0){
1530 $rs = &csv2rs($md5file,$err,$secs2cache);
1531 $this->numCacheHits += 1;
1535 $this->numCacheMisses += 1;
1538 // no cached rs found
1540 if (get_magic_quotes_runtime()) {
1541 ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
1543 if ($this->debug !== -1) ADOConnection::outp( " $md5file cache failure: $err (see sql below)");
1545 $rs = &$this->Execute($sql,$inputarr);
1548 $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately
1549 $txt = _rs2serialize($rs,false,$sql); // serialize
1551 if (!adodb_write_file($md5file,$txt,$this->debug)) {
1552 if ($fn = $this->raiseErrorFn) {
1553 $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);
1555 if ($this->debug) ADOConnection::outp( " Cache write error");
1557 if ($rs->EOF && !$eof) {
1559 //$rs = &csv2rs($md5file,$err);
1560 $rs->connection = &$this; // Pablo suggestion
1566 $this->_errorMsg = '';
1567 $this->_errorCode = 0;
1569 if ($this->fnCacheExecute) {
1570 $fn = $this->fnCacheExecute;
1571 $fn($this, $secs2cache, $sql, $inputarr);
1573 // ok, set cached object found
1574 $rs->connection = &$this; // Pablo suggestion
1576 global $HTTP_SERVER_VARS;
1578 $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
1579 $ttl = $rs->timeCreated + $secs2cache - time();
1580 $s = is_array($sql) ? $sql[0] : $sql;
1581 if ($inBrowser) $s = '<i>'.htmlspecialchars($s).'</i>';
1583 ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
1591 * Generates an Update Query based on an existing recordset.
1592 * $arrFields is an associative array of fields with the value
1593 * that should be assigned.
1595 * Note: This function should only be used on a recordset
1596 * that is run against a single table and sql should only
1597 * be a simple select stmt with no groupby/orderby/limit
1599 * "Jonathan Younger" <jyounger@unilab.com>
1601 function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false)
1603 global $ADODB_INCLUDED_LIB;
1604 if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
1605 return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq);
1610 * Generates an Insert Query based on an existing recordset.
1611 * $arrFields is an associative array of fields with the value
1612 * that should be assigned.
1614 * Note: This function should only be used on a recordset
1615 * that is run against a single table.
1617 function GetInsertSQL(&$rs, $arrFields,$magicq=false)
1619 global $ADODB_INCLUDED_LIB;
1620 if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
1621 return _adodb_getinsertsql($this,$rs,$arrFields,$magicq);
1626 * Update a blob column, given a where clause. There are more sophisticated
1627 * blob handling functions that we could have implemented, but all require
1628 * a very complex API. Instead we have chosen something that is extremely
1629 * simple to understand and use.
1631 * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
1633 * Usage to update a $blobvalue which has a primary key blob_id=1 into a
1634 * field blobtable.blobcolumn:
1636 * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
1640 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
1641 * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
1644 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
1646 return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
1651 * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
1653 * $blobtype supports 'BLOB' and 'CLOB'
1655 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
1656 * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
1658 function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
1660 $fd = fopen($path,'rb');
1661 if ($fd === false) return false;
1662 $val = fread($fd,filesize($path));
1664 return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
1667 function BlobDecode($blob)
1672 function BlobEncode($blob)
1677 function SetCharSet($charset)
1682 function IfNull( $field, $ifNull )
1684 return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
1687 function LogSQL($enable=true)
1689 include_once(ADODB_DIR.'/adodb-perf.inc.php');
1691 if ($enable) $this->fnExecute = 'adodb_log_sql';
1692 else $this->fnExecute = false;
1694 $old = $this->_logsql;
1695 $this->_logsql = $enable;
1696 if ($enable && !$old) $this->_affected = false;
1700 function GetCharSet()
1707 * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
1709 * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
1710 * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
1712 function UpdateClob($table,$column,$val,$where)
1714 return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
1719 * Change the SQL connection locale to a specified locale.
1720 * This is used to get the date formats written depending on the client locale.
1722 function SetDateLocale($locale = 'En')
1724 $this->locale = $locale;
1729 $this->fmtDate="Y-m-d";
1730 $this->fmtTimeStamp = "Y-m-d H:i:s";
1736 $this->fmtDate="d-m-Y";
1737 $this->fmtTimeStamp = "d-m-Y H:i:s";
1741 $this->fmtDate="d.m.Y";
1742 $this->fmtTimeStamp = "d.m.Y H:i:s";
1749 * $meta contains the desired type, which could be...
1750 * C for character. You will have to define the precision yourself.
1751 * X for teXt. For unlimited character lengths.
1753 * F for floating point, with no need to define scale and precision
1754 * N for decimal numbers, you will have to define the (scale, precision) yourself
1757 * L for logical/Boolean
1759 * R for autoincrement counter/integer
1760 * and if you want to use double-byte, add a 2 to the end, like C2 or X2.
1763 * @return the actual type of the data or false if no such type available
1765 function ActualType($meta)
1791 return $this->_close();
1793 // "Simon Lee" <simon@mediaroad.com> reports that persistent connections need
1794 // to be closed too!
1795 //if ($this->_isPersistentConnection != true) return $this->_close();
1800 * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
1802 * @return true if succeeded or false if database does not support transactions
1804 function BeginTrans() {return false;}
1808 * If database does not support transactions, always return true as data always commited
1810 * @param $ok set to false to rollback transaction, true to commit
1812 * @return true/false.
1814 function CommitTrans($ok=true)
1819 * If database does not support transactions, rollbacks always fail, so return false
1821 * @return true/false.
1823 function RollbackTrans()
1828 * return the databases that the driver can connect to.
1829 * Some databases will return an empty array.
1831 * @return an array of database names.
1833 function MetaDatabases()
1835 global $ADODB_FETCH_MODE;
1837 if ($this->metaDatabasesSQL) {
1838 $save = $ADODB_FETCH_MODE;
1839 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
1841 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
1843 $arr = $this->GetCol($this->metaDatabasesSQL);
1844 if (isset($savem)) $this->SetFetchMode($savem);
1845 $ADODB_FETCH_MODE = $save;
1854 * @param ttype can either be 'VIEW' or 'TABLE' or false.
1855 * If false, both views and tables are returned.
1856 * "VIEW" returns only views
1857 * "TABLE" returns only tables
1858 * @param showSchema returns the schema/user with the table name, eg. USER.TABLE
1859 * @param mask is the input mask - only supported by oci8 and postgresql
1861 * @return array of tables for current database.
1863 function &MetaTables($ttype=false,$showSchema=false,$mask=false)
1865 global $ADODB_FETCH_MODE;
1867 if ($mask) return false;
1869 if ($this->metaTablesSQL) {
1870 // complicated state saving by the need for backward compat
1871 $save = $ADODB_FETCH_MODE;
1872 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
1874 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
1876 $rs = $this->Execute($this->metaTablesSQL);
1877 if (isset($savem)) $this->SetFetchMode($savem);
1878 $ADODB_FETCH_MODE = $save;
1880 if ($rs === false) return false;
1881 $arr =& $rs->GetArray();
1884 if ($hast = ($ttype && isset($arr[0][1]))) {
1885 $showt = strncmp($ttype,'T',1);
1888 for ($i=0; $i < sizeof($arr); $i++) {
1891 if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]);
1893 if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]);
1896 $arr2[] = trim($arr[$i][0]);
1905 function _findschema(&$table,&$schema)
1907 if (!$schema && ($at = strpos($table,'.')) !== false) {
1908 $schema = substr($table,0,$at);
1909 $table = substr($table,$at+1);
1914 * List columns in a database as an array of ADOFieldObjects.
1915 * See top of file for definition of object.
1917 * @param table table name to query
1918 * @param upper uppercase table name (required by some databases)
1919 * @schema is optional database schema to use - not supported by all databases.
1921 * @return array of ADOFieldObjects for current table.
1923 function &MetaColumns($table,$upper=true)
1925 global $ADODB_FETCH_MODE;
1927 if (!empty($this->metaColumnsSQL)) {
1930 $this->_findschema($table,$schema);
1932 $save = $ADODB_FETCH_MODE;
1933 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
1934 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
1935 $rs = $this->Execute(sprintf($this->metaColumnsSQL,($upper)?strtoupper($table):$table));
1936 if (isset($savem)) $this->SetFetchMode($savem);
1937 $ADODB_FETCH_MODE = $save;
1938 if ($rs === false) return false;
1941 while (!$rs->EOF) { //print_r($rs->fields);
1942 $fld =& new ADOFieldObject();
1943 $fld->name = $upper ? strtoupper($rs->fields[0]) : $rs->fields[0];
1944 $fld->type = $rs->fields[1];
1945 if (isset($rs->fields[3]) && $rs->fields[3]) {
1946 if ($rs->fields[3]>0) $fld->max_length = $rs->fields[3];
1947 $fld->scale = $rs->fields[4];
1948 if ($fld->scale>0) $fld->max_length += 1;
1950 $fld->max_length = $rs->fields[2];
1952 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
1953 else $retarr[$fld->name] = $fld;
1963 * List indexes on a table as an array.
1964 * @param table table name to query
1965 * @param primary include primary keys.
1967 * @return array of indexes on current table.
1969 function &MetaIndexes($table, $primary = false, $owner = false)
1975 * List columns names in a table as an array.
1976 * @param table table name to query
1978 * @return array of column names for current table.
1980 function &MetaColumnNames($table)
1982 $objarr =& $this->MetaColumns($table);
1983 if (!is_array($objarr)) return false;
1986 foreach($objarr as $v) {
1987 $arr[strtoupper($v->name)] = $v->name;
1993 * Different SQL databases used different methods to combine strings together.
1994 * This function provides a wrapper.
1996 * param s variable number of string parameters
1998 * Usage: $db->Concat($str1,$str2);
2000 * @return concatenated string
2004 $arr = func_get_args();
2005 return implode($this->concat_operator, $arr);
2010 * Converts a date "d" to a string that the database can understand.
2012 * @param d a date in Unix date time format.
2014 * @return date string in database date format
2018 if (empty($d) && $d !== 0) return 'null';
2020 if (is_string($d) && !is_numeric($d)) {
2021 if ($d === 'null' || strncmp($d,"'",1) === 0) return $d;
2022 if ($this->isoDates) return "'$d'";
2023 $d = ADOConnection::UnixDate($d);
2026 return adodb_date($this->fmtDate,$d);
2031 * Converts a timestamp "ts" to a string that the database can understand.
2033 * @param ts a timestamp in Unix date time format.
2035 * @return timestamp string in database timestamp format
2037 function DBTimeStamp($ts)
2039 if (empty($ts) && $ts !== 0) return 'null';
2041 # strlen(14) allows YYYYMMDDHHMMSS format
2042 if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14))
2043 return adodb_date($this->fmtTimeStamp,$ts);
2045 if ($ts === 'null') return $ts;
2046 if ($this->isoDates && strlen($ts) !== 14) return "'$ts'";
2048 $ts = ADOConnection::UnixTimeStamp($ts);
2049 return adodb_date($this->fmtTimeStamp,$ts);
2053 * Also in ADORecordSet.
2054 * @param $v is a date string in YYYY-MM-DD format
2056 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2058 function UnixDate($v)
2060 if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|",
2061 ($v), $rr)) return false;
2063 if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;
2065 return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2070 * Also in ADORecordSet.
2071 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
2073 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2075 function UnixTimeStamp($v)
2078 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
2079 ($v), $rr)) return false;
2081 if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) return 0;
2084 if (!isset($rr[5])) return adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2085 return @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
2089 * Also in ADORecordSet.
2091 * Format database date based on user defined format.
2093 * @param v is the character date in YYYY-MM-DD format, returned by database
2094 * @param fmt is the format to apply to it, using date()
2096 * @return a date formated as user desires
2099 function UserDate($v,$fmt='Y-m-d')
2101 $tt = $this->UnixDate($v);
2102 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2103 if (($tt === false || $tt == -1) && $v != false) return $v;
2104 else if ($tt == 0) return $this->emptyDate;
2105 else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
2108 return adodb_date($fmt,$tt);
2114 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
2115 * @param fmt is the format to apply to it, using date()
2117 * @return a timestamp formated as user desires
2119 function UserTimeStamp($v,$fmt='Y-m-d H:i:s')
2121 # strlen(14) allows YYYYMMDDHHMMSS format
2122 if (is_numeric($v) && strlen($v)<14) return adodb_date($fmt,$v);
2123 $tt = $this->UnixTimeStamp($v);
2124 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2125 if (($tt === false || $tt == -1) && $v != false) return $v;
2126 if ($tt == 0) return $this->emptyTimeStamp;
2127 return adodb_date($fmt,$tt);
2131 * Quotes a string, without prefixing nor appending quotes.
2133 function addq($s, $magicq=false)
2137 if ($this->replaceQuote[0] == '\\'){
2138 // only since php 4.0.5
2139 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2140 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2142 return str_replace("'",$this->replaceQuote,$s);
2145 // undo magic quotes for "
2146 $s = str_replace('\\"','"',$s);
2148 if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything
2150 else {// change \' to '' for sybase/mssql
2151 $s = str_replace('\\\\','\\',$s);
2152 return str_replace("\\'",$this->replaceQuote,$s);
2157 * Correctly quotes a string so that all strings are escaped. We prefix and append
2158 * to the string single-quotes.
2159 * An example is $db->qstr("Don't bother",magic_quotes_runtime());
2161 * @param s the string to quote
2162 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
2163 * This undoes the stupidity of magic quotes for GPC.
2165 * @return quoted string to be sent back to database
2167 function qstr($s,$magic_quotes=false)
2169 if (!$magic_quotes) {
2171 if ($this->replaceQuote[0] == '\\'){
2172 // only since php 4.0.5
2173 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2174 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2176 return "'".str_replace("'",$this->replaceQuote,$s)."'";
2179 // undo magic quotes for "
2180 $s = str_replace('\\"','"',$s);
2182 if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything
2184 else {// change \' to '' for sybase/mssql
2185 $s = str_replace('\\\\','\\',$s);
2186 return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
2192 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2193 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2194 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2196 * See readme.htm#ex8 for an example of usage.
2199 * @param nrows is the number of rows per page to get
2200 * @param page is the page number to get (1-based)
2201 * @param [inputarr] array of bind variables
2202 * @param [secs2cache] is a private parameter only used by jlim
2203 * @return the recordset ($rs->databaseType == 'array')
2205 * NOTE: phpLens uses a different algorithm and does not use PageExecute().
2208 function &PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0)
2210 global $ADODB_INCLUDED_LIB;
2211 if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
2212 if ($this->pageExecuteCountRows) return _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2213 return _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2219 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2220 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2221 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2223 * @param secs2cache seconds to cache data, set to 0 to force query
2225 * @param nrows is the number of rows per page to get
2226 * @param page is the page number to get (1-based)
2227 * @param [inputarr] array of bind variables
2228 * @return the recordset ($rs->databaseType == 'array')
2230 function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false)
2232 /*switch($this->dataProvider) {
2236 default: $secs2cache = 0; break;
2238 $rs =& $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
2242 } // end class ADOConnection
2246 //==============================================================================================
2247 // CLASS ADOFetchObj
2248 //==============================================================================================
2251 * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
2256 //==============================================================================================
2257 // CLASS ADORecordSet_empty
2258 //==============================================================================================
2261 * Lightweight recordset when there are no records to be returned
2263 class ADORecordSet_empty
2265 var $dataProvider = 'empty';
2266 var $databaseType = false;
2268 var $_numOfRows = 0;
2269 var $fields = false;
2270 var $connection = false;
2271 function RowCount() {return 0;}
2272 function RecordCount() {return 0;}
2273 function PO_RecordCount(){return 0;}
2274 function Close(){return true;}
2275 function FetchRow() {return false;}
2276 function FieldCount(){ return 0;}
2279 //==============================================================================================
2280 // DATE AND TIME FUNCTIONS
2281 //==============================================================================================
2282 include_once(ADODB_DIR.'/adodb-time.inc.php');
2284 //==============================================================================================
2285 // CLASS ADORecordSet
2286 //==============================================================================================
2288 if (PHP_VERSION < 5) include_once(ADODB_DIR.'/adodb-php4.inc.php');
2289 else include_once(ADODB_DIR.'/adodb-iterator.inc.php');
2291 * RecordSet class that represents the dataset returned by the database.
2292 * To keep memory overhead low, this class holds only the current row in memory.
2293 * No prefetching of data is done, so the RecordCount() can return -1 ( which
2294 * means recordcount not known).
2296 class ADORecordSet extends ADODB_BASE_RS {
2300 var $dataProvider = "native";
2301 var $fields = false; /// holds the current row data
2302 var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob
2303 /// in other words, we use a text area for editing.
2304 var $canSeek = false; /// indicates that seek is supported
2305 var $sql; /// sql text
2306 var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object.
2308 var $emptyTimeStamp = ' '; /// what to display when $time==0
2309 var $emptyDate = ' '; /// what to display when $time==0
2311 var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsets
2313 var $bind = false; /// used by Fields() to hold array - should be private?
2314 var $fetchMode; /// default fetch mode
2315 var $connection = false; /// the parent connection
2319 var $_numOfRows = -1; /** number of rows, or -1 */
2320 var $_numOfFields = -1; /** number of fields in recordset */
2321 var $_queryID = -1; /** This variable keeps the result link identifier. */
2322 var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */
2323 var $_closed = false; /** has recordset been closed */
2324 var $_inited = false; /** Init() should only be called once */
2325 var $_obj; /** Used by FetchObj */
2326 var $_names; /** Used by FetchObj */
2328 var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */
2329 var $_atFirstPage = false; /** Added by Iván Oliva to implement recordset pagination */
2330 var $_atLastPage = false; /** Added by Iván Oliva to implement recordset pagination */
2331 var $_lastPageNo = -1;
2332 var $_maxRecordCount = 0;
2333 var $datetime = false;
2338 * @param queryID this is the queryID returned by ADOConnection->_query()
2341 function ADORecordSet($queryID)
2343 $this->_queryID = $queryID;
2350 if ($this->_inited) return;
2351 $this->_inited = true;
2352 if ($this->_queryID) @$this->_initrs();
2354 $this->_numOfRows = 0;
2355 $this->_numOfFields = 0;
2357 if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
2359 $this->_currentRow = 0;
2360 if ($this->EOF = ($this->_fetch() === false)) {
2361 $this->_numOfRows = 0; // _numOfRows could be -1
2370 * Generate a SELECT tag string from a recordset, and return the string.
2371 * If the recordset has 2 cols, we treat the 1st col as the containing
2372 * the text to display to the user, and 2nd col as the return value. Default
2373 * strings are compared with the FIRST column.
2375 * @param name name of SELECT tag
2376 * @param [defstr] the value to hilite. Use an array for multiple hilites for listbox.
2377 * @param [blank1stItem] true to leave the 1st item in list empty
2378 * @param [multiple] true for listbox, false for popup
2379 * @param [size] #rows to show for listbox. not used by popup
2380 * @param [selectAttr] additional attributes to defined for SELECT tag.
2381 * useful for holding javascript onChange='...' handlers.
2382 & @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with
2383 * column 0 (1st col) if this is true. This is not documented.
2387 * changes by glen.davies@cce.ac.nz to support multiple hilited items
2389 function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
2390 $size=0, $selectAttr='',$compareFields0=true)
2392 global $ADODB_INCLUDED_LIB;
2393 if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
2394 return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
2395 $size, $selectAttr,$compareFields0);
2399 * Generate a SELECT tag string from a recordset, and return the string.
2400 * If the recordset has 2 cols, we treat the 1st col as the containing
2401 * the text to display to the user, and 2nd col as the return value. Default
2402 * strings are compared with the SECOND column.
2405 function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='')
2407 global $ADODB_INCLUDED_LIB;
2408 if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
2409 return _adodb_getmenu($this,$name,$defstr,$blank1stItem,$multiple,
2410 $size, $selectAttr,false);
2415 * return recordset as a 2-dimensional array.
2417 * @param [nRows] is the number of rows to return. -1 means every row.
2419 * @return an array indexed by the rows (0-based) from the recordset
2421 function &GetArray($nRows = -1)
2423 global $ADODB_EXTENSION; if ($ADODB_EXTENSION) return adodb_getall($this,$nRows);
2427 while (!$this->EOF && $nRows != $cnt) {
2428 $results[] = $this->fields;
2435 function &GetAll($nRows = -1)
2437 $arr =& $this->GetArray($nRows);
2442 * Some databases allow multiple recordsets to be returned. This function
2443 * will return true if there is a next recordset, or false if no more.
2445 function NextRecordSet()
2451 * return recordset as a 2-dimensional array.
2452 * Helper function for ADOConnection->SelectLimit()
2454 * @param offset is the row to start calculations from (1-based)
2455 * @param [nrows] is the number of rows to return
2457 * @return an array indexed by the rows (0-based) from the recordset
2459 function &GetArrayLimit($nrows,$offset=-1)
2462 $arr =& $this->GetArray($nrows);
2466 $this->Move($offset);
2470 while (!$this->EOF && $nrows != $cnt) {
2471 $results[$cnt++] = $this->fields;
2480 * Synonym for GetArray() for compatibility with ADO.
2482 * @param [nRows] is the number of rows to return. -1 means every row.
2484 * @return an array indexed by the rows (0-based) from the recordset
2486 function &GetRows($nRows = -1)
2488 $arr =& $this->GetArray($nRows);
2493 * return whole recordset as a 2-dimensional associative array if there are more than 2 columns.
2494 * The first column is treated as the key and is not included in the array.
2495 * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless
2496 * $force_array == true.
2498 * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional
2499 * array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,
2502 * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and
2503 * instead of returning array[col0] => array(remaining cols), return array[col0] => col1
2505 * @return an associative array indexed by the first column of the array,
2506 * or false if the data has less than 2 cols.
2508 function &GetAssoc($force_array = false, $first2cols = false) {
2509 $cols = $this->_numOfFields;
2513 $numIndex = isset($this->fields[0]);
2516 if (!$first2cols && ($cols > 2 || $force_array)) {
2518 while (!$this->EOF) {
2519 $results[trim($this->fields[0])] = array_slice($this->fields, 1);
2523 while (!$this->EOF) {
2524 $results[trim(reset($this->fields))] = array_slice($this->fields, 1);
2529 // return scalar values
2531 while (!$this->EOF) {
2532 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
2533 $results[trim(($this->fields[0]))] = $this->fields[1];
2537 while (!$this->EOF) {
2538 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
2539 $v1 = trim(reset($this->fields));
2540 $v2 = ''.next($this->fields);
2541 $results[$v1] = $v2;
2552 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
2553 * @param fmt is the format to apply to it, using date()
2555 * @return a timestamp formated as user desires
2557 function UserTimeStamp($v,$fmt='Y-m-d H:i:s')
2559 if (is_numeric($v) && strlen($v)<14) return adodb_date($fmt,$v);
2560 $tt = $this->UnixTimeStamp($v);
2561 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2562 if (($tt === false || $tt == -1) && $v != false) return $v;
2563 if ($tt === 0) return $this->emptyTimeStamp;
2564 return adodb_date($fmt,$tt);
2569 * @param v is the character date in YYYY-MM-DD format, returned by database
2570 * @param fmt is the format to apply to it, using date()
2572 * @return a date formated as user desires
2574 function UserDate($v,$fmt='Y-m-d')
2576 $tt = $this->UnixDate($v);
2577 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2578 if (($tt === false || $tt == -1) && $v != false) return $v;
2579 else if ($tt == 0) return $this->emptyDate;
2580 else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
2582 return adodb_date($fmt,$tt);
2588 * @param $v is a date string in YYYY-MM-DD format
2590 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2592 function UnixDate($v)
2595 if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|",
2596 ($v), $rr)) return false;
2598 if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;
2600 return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2605 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
2607 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2609 function UnixTimeStamp($v)
2613 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
2614 ($v), $rr)) return false;
2615 if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) return 0;
2618 if (!isset($rr[5])) return adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2619 return @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
2624 * PEAR DB Compat - do not use internally
2628 return $this->Close();
2633 * PEAR DB compat, number of rows
2637 return $this->_numOfRows;
2642 * PEAR DB compat, number of cols
2646 return $this->_numOfFields;
2650 * Fetch a row, returning false if no more rows.
2651 * This is PEAR DB compat mode.
2653 * @return false or array containing the current record
2655 function &FetchRow()
2657 if ($this->EOF) return false;
2658 $arr = $this->fields;
2659 $this->_currentRow++;
2660 if (!$this->_fetch()) $this->EOF = true;
2666 * Fetch a row, returning PEAR_Error if no more rows.
2667 * This is PEAR DB compat mode.
2669 * @return DB_OK or error object
2671 function FetchInto(&$arr)
2673 if ($this->EOF) return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false;
2674 $arr = $this->fields;
2681 * Move to the first row in the recordset. Many databases do NOT support this.
2683 * @return true or false
2685 function MoveFirst()
2687 if ($this->_currentRow == 0) return true;
2688 return $this->Move(0);
2693 * Move to the last row in the recordset.
2695 * @return true or false
2699 if ($this->_numOfRows >= 0) return $this->Move($this->_numOfRows-1);
2700 if ($this->EOF) return false;
2701 while (!$this->EOF) {
2712 * Move to next record in the recordset.
2714 * @return true if there still rows available, or false if there are no more rows (EOF).
2719 $this->_currentRow++;
2720 if ($this->_fetch()) return true;
2723 /* -- tested error handling when scrolling cursor -- seems useless.
2724 $conn = $this->connection;
2725 if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
2726 $fn = $conn->raiseErrorFn;
2727 $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
2734 * Random access to a specific row in the recordset. Some databases do not support
2735 * access to previous rows in the databases (no scrolling backwards).
2737 * @param rowNumber is the row to move to (0-based)
2739 * @return true if there still rows available, or false if there are no more rows (EOF).
2741 function Move($rowNumber = 0)
2744 if ($rowNumber == $this->_currentRow) return true;
2745 if ($rowNumber >= $this->_numOfRows)
2746 if ($this->_numOfRows != -1) $rowNumber = $this->_numOfRows-2;
2748 if ($this->canSeek) {
2750 if ($this->_seek($rowNumber)) {
2751 $this->_currentRow = $rowNumber;
2752 if ($this->_fetch()) {
2760 if ($rowNumber < $this->_currentRow) return false;
2761 global $ADODB_EXTENSION;
2762 if ($ADODB_EXTENSION) {
2763 while (!$this->EOF && $this->_currentRow < $rowNumber) {
2764 adodb_movenext($this);
2768 while (! $this->EOF && $this->_currentRow < $rowNumber) {
2769 $this->_currentRow++;
2771 if (!$this->_fetch()) $this->EOF = true;
2774 return !($this->EOF);
2777 $this->fields = false;
2784 * Get the value of a field in the current row by column name.
2785 * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
2787 * @param colname is the field to access
2789 * @return the value of $colname column
2791 function Fields($colname)
2793 return $this->fields[$colname];
2796 function GetAssocKeys($upper=true)
2798 $this->bind = array();
2799 for ($i=0; $i < $this->_numOfFields; $i++) {
2800 $o =& $this->FetchField($i);
2801 if ($upper === 2) $this->bind[$o->name] = $i;
2802 else $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $i;
2807 * Use associative array to get fields array for databases that do not support
2808 * associative arrays. Submitted by Paolo S. Asioli paolo.asioli@libero.it
2810 * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC
2811 * before you execute your SQL statement, and access $rs->fields['col'] directly.
2813 * $upper 0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField
2815 function &GetRowAssoc($upper=1)
2818 // if (!$this->fields) return $record;
2821 $this->GetAssocKeys($upper);
2824 foreach($this->bind as $k => $v) {
2825 $record[$k] = $this->fields[$v];
2833 * Clean up recordset
2835 * @return true or false
2839 // free connection object - this seems to globally free the object
2840 // and not merely the reference, so don't do this...
2841 // $this->connection = false;
2842 if (!$this->_closed) {
2843 $this->_closed = true;
2844 return $this->_close();
2850 * synonyms RecordCount and RowCount
2852 * @return the number of rows or -1 if this is not supported
2854 function RecordCount() {return $this->_numOfRows;}
2858 * If we are using PageExecute(), this will return the maximum possible rows
2859 * that can be returned when paging a recordset.
2861 function MaxRecordCount()
2863 return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();
2867 * synonyms RecordCount and RowCount
2869 * @return the number of rows or -1 if this is not supported
2871 function RowCount() {return $this->_numOfRows;}
2875 * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
2877 * @return the number of records from a previous SELECT. All databases support this.
2879 * But aware possible problems in multiuser environments. For better speed the table
2880 * must be indexed by the condition. Heavy test this before deploying.
2882 function PO_RecordCount($table="", $condition="") {
2884 $lnumrows = $this->_numOfRows;
2885 // the database doesn't support native recordcount, so we do a workaround
2886 if ($lnumrows == -1 && $this->connection) {
2888 if ($condition) $condition = " WHERE " . $condition;
2889 $resultrows = &$this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
2890 if ($resultrows) $lnumrows = reset($resultrows->fields);
2897 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
2899 function CurrentRow() {return $this->_currentRow;}
2902 * synonym for CurrentRow -- for ADO compat
2904 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
2906 function AbsolutePosition() {return $this->_currentRow;}
2909 * @return the number of columns in the recordset. Some databases will set this to 0
2910 * if no records are returned, others will return the number of columns in the query.
2912 function FieldCount() {return $this->_numOfFields;}
2916 * Get the ADOFieldObject of a specific column.
2918 * @param fieldoffset is the column position to access(0-based).
2920 * @return the ADOFieldObject for that column, or false.
2922 function &FetchField($fieldoffset)
2924 // must be defined by child class
2928 * Get the ADOFieldObjects of all columns in an array.
2931 function FieldTypesArray()
2934 for ($i=0, $max=$this->_numOfFields; $i < $max; $i++)
2935 $arr[] = $this->FetchField($i);
2940 * Return the fields array of the current row as an object for convenience.
2941 * The default case is lowercase field names.
2943 * @return the object with the properties set to the fields of the current row
2945 function &FetchObj()
2947 $o =& $this->FetchObject(false);
2952 * Return the fields array of the current row as an object for convenience.
2953 * The default case is uppercase.
2955 * @param $isupper to set the object property names to uppercase
2957 * @return the object with the properties set to the fields of the current row
2959 function &FetchObject($isupper=true)
2961 if (empty($this->_obj)) {
2962 $this->_obj =& new ADOFetchObj();
2963 $this->_names = array();
2964 for ($i=0; $i <$this->_numOfFields; $i++) {
2965 $f = $this->FetchField($i);
2966 $this->_names[] = $f->name;
2971 for ($i=0; $i <$this->_numOfFields; $i++) {
2972 $name = $this->_names[$i];
2973 if ($isupper) $n = strtoupper($name);
2976 $o->$n = $this->Fields($name);
2982 * Return the fields array of the current row as an object for convenience.
2983 * The default is lower-case field names.
2985 * @return the object with the properties set to the fields of the current row,
2988 * Fixed bug reported by tim@orotech.net
2990 function &FetchNextObj()
2992 return $this->FetchNextObject(false);
2997 * Return the fields array of the current row as an object for convenience.
2998 * The default is upper case field names.
3000 * @param $isupper to set the object property names to uppercase
3002 * @return the object with the properties set to the fields of the current row,
3005 * Fixed bug reported by tim@orotech.net
3007 function &FetchNextObject($isupper=true)
3010 if ($this->_numOfRows != 0 && !$this->EOF) {
3011 $o = $this->FetchObject($isupper);
3012 $this->_currentRow++;
3013 if ($this->_fetch()) return $o;
3020 * Get the metatype of the column. This is used for formatting. This is because
3021 * many databases use different names for the same type, so we transform the original
3022 * type to our standardised version which uses 1 character codes:
3024 * @param t is the type passed in. Normally is ADOFieldObject->type.
3025 * @param len is the maximum length of that field. This is because we treat character
3026 * fields bigger than a certain size as a 'B' (blob).
3027 * @param fieldobj is the field object returned by the database driver. Can hold
3028 * additional info (eg. primary_key for mysql).
3030 * @return the general type of the data:
3031 * C for character < 200 chars
3032 * X for teXt (>= 200 chars)
3034 * N for numeric floating point
3037 * L for logical/Boolean
3039 * R for autoincrement counter/integer
3043 function MetaType($t,$len=-1,$fieldobj=false)
3045 if (is_object($t)) {
3047 $t = $fieldobj->type;
3048 $len = $fieldobj->max_length;
3050 // changed in 2.32 to hashing instead of switch stmt for speed...
3051 static $typeMap = array(
3062 'INTERVAL' => 'C', # Postgres
3077 'LONGBINARY' => 'B',
3080 'YEAR' => 'D', // mysql
3087 'TIMESTAMPTZ' => 'T',
3097 'SERIAL' => 'R', // ifx
3098 'INT IDENTITY' => 'R',
3102 'INTEGER UNSIGNED' => 'I',
3108 'LONG' => 'N', // interbase is numeric, oci8 is blob
3109 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
3114 'DOUBLE PRECISION' => 'N',
3115 'SMALLFLOAT' => 'N',
3126 'SQLSMFLOAT' => 'N',
3129 'SQLDECIMAL' => 'N',
3134 'SQLINTERVAL' => 'N',
3140 $t = strtoupper($t);
3141 $tmap = @$typeMap[$t];
3145 // is the char field is too long, return as text field...
3146 if ($this->blobSize >= 0) {
3147 if ($len > $this->blobSize) return 'X';
3148 } else if ($len > 250) {
3154 if (!empty($fieldobj->primary_key)) return 'R';
3161 if (isset($fieldobj->binary))
3162 return ($fieldobj->binary) ? 'B' : 'X';
3166 if (!empty($this->datetime)) return 'T';
3170 if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B';
3175 function _close() {}
3178 * set/returns the current recordset page when paginating
3180 function AbsolutePage($page=-1)
3182 if ($page != -1) $this->_currentPage = $page;
3183 return $this->_currentPage;
3187 * set/returns the status of the atFirstPage flag when paginating
3189 function AtFirstPage($status=false)
3191 if ($status != false) $this->_atFirstPage = $status;
3192 return $this->_atFirstPage;
3195 function LastPageNo($page = false)
3197 if ($page != false) $this->_lastPageNo = $page;
3198 return $this->_lastPageNo;
3202 * set/returns the status of the atLastPage flag when paginating
3204 function AtLastPage($status=false)
3206 if ($status != false) $this->_atLastPage = $status;
3207 return $this->_atLastPage;
3210 } // end class ADORecordSet
3212 //==============================================================================================
3213 // CLASS ADORecordSet_array
3214 //==============================================================================================
3217 * This class encapsulates the concept of a recordset created in memory
3218 * as an array. This is useful for the creation of cached recordsets.
3220 * Note that the constructor is different from the standard ADORecordSet
3223 class ADORecordSet_array extends ADORecordSet
3225 var $databaseType = 'array';
3227 var $_array; // holds the 2-dimensional data array
3228 var $_types; // the array of types of each column (C B I L M)
3229 var $_colnames; // names of each column in array
3230 var $_skiprow1; // skip 1st row because it holds column names
3231 var $_fieldarr; // holds array of field objects
3232 var $canSeek = true;
3233 var $affectedrows = false;
3234 var $insertid = false;
3236 var $compat = false;
3241 function ADORecordSet_array($fakeid=1)
3243 global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;
3245 // fetch() on EOF does not delete $this->fields
3246 $this->compat = !empty($ADODB_COMPAT_FETCH);
3247 $this->ADORecordSet($fakeid); // fake queryID
3248 $this->fetchMode = $ADODB_FETCH_MODE;
3255 * @param array is a 2-dimensional array holding the data.
3256 * The first row should hold the column names
3257 * unless paramter $colnames is used.
3258 * @param typearr holds an array of types. These are the same types
3259 * used in MetaTypes (C,B,L,I,N).
3260 * @param [colnames] array of column names. If set, then the first row of
3261 * $array should not hold the column names.
3263 function InitArray($array,$typearr,$colnames=false)
3265 $this->_array = $array;
3266 $this->_types = $typearr;
3268 $this->_skiprow1 = false;
3269 $this->_colnames = $colnames;
3271 $this->_skiprow1 = true;
3272 $this->_colnames = $array[0];
3277 * Setup the Array and datatype file objects
3279 * @param array is a 2-dimensional array holding the data.
3280 * The first row should hold the column names
3281 * unless paramter $colnames is used.
3282 * @param fieldarr holds an array of ADOFieldObject's.
3284 function InitArrayFields(&$array,&$fieldarr)
3286 $this->_array =& $array;
3287 $this->_skiprow1= false;
3289 $this->_fieldobjects =& $fieldarr;
3294 function &GetArray($nRows=-1)
3296 if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) {
3297 return $this->_array;
3299 $arr =& ADORecordSet::GetArray($nRows);
3306 $this->_numOfRows = sizeof($this->_array);
3307 if ($this->_skiprow1) $this->_numOfRows -= 1;
3309 $this->_numOfFields =(isset($this->_fieldobjects)) ?
3310 sizeof($this->_fieldobjects):sizeof($this->_types);
3313 /* Use associative array to get fields array */
3314 function Fields($colname)
3316 if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
3319 $this->bind = array();
3320 for ($i=0; $i < $this->_numOfFields; $i++) {
3321 $o = $this->FetchField($i);
3322 $this->bind[strtoupper($o->name)] = $i;
3325 return $this->fields[$this->bind[strtoupper($colname)]];
3328 function &FetchField($fieldOffset = -1)
3330 if (isset($this->_fieldobjects)) {
3331 return $this->_fieldobjects[$fieldOffset];
3333 $o = new ADOFieldObject();
3334 $o->name = $this->_colnames[$fieldOffset];
3335 $o->type = $this->_types[$fieldOffset];
3336 $o->max_length = -1; // length not known
3341 function _seek($row)
3343 if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) {
3344 $this->_currentRow = $row;
3345 if ($this->_skiprow1) $row += 1;
3346 $this->fields = $this->_array[$row];
3355 $this->_currentRow++;
3357 $pos = $this->_currentRow;
3359 if ($this->_numOfRows <= $pos) {
3360 if (!$this->compat) $this->fields = false;
3362 if ($this->_skiprow1) $pos += 1;
3363 $this->fields = $this->_array[$pos];
3374 $pos = $this->_currentRow;
3376 if ($this->_numOfRows <= $pos) {
3377 if (!$this->compat) $this->fields = false;
3380 if ($this->_skiprow1) $pos += 1;
3381 $this->fields = $this->_array[$pos];
3390 } // ADORecordSet_array
3392 //==============================================================================================
3394 //==============================================================================================
3397 * Synonym for ADOLoadCode. Private function. Do not use.
3401 function ADOLoadDB($dbType)
3403 return ADOLoadCode($dbType);
3407 * Load the code for a specific database driver. Private function. Do not use.
3409 function ADOLoadCode($dbType)
3411 global $ADODB_LASTDB;
3413 if (!$dbType) return false;
3414 $db = strtolower($dbType);
3416 case 'maxsql': $db = 'mysqlt'; break;
3418 case 'pgsql': $db = 'postgres7'; break;
3420 @include_once(ADODB_DIR."/drivers/adodb-".$db.".inc.php");
3421 $ADODB_LASTDB = $db;
3423 $ok = class_exists("ADODB_" . $db);
3424 if ($ok) return $db;
3426 $file = ADODB_DIR."/drivers/adodb-".$db.".inc.php";
3427 if (!file_exists($file)) ADOConnection::outp("Missing file: $file");
3428 else ADOConnection::outp("Syntax error in file: $file");
3433 * synonym for ADONewConnection for people like me who cannot remember the correct name
3435 function &NewADOConnection($db='')
3437 $tmp =& ADONewConnection($db);
3442 * Instantiate a new Connection class for a specific database driver.
3444 * @param [db] is the database Connection object to create. If undefined,
3445 * use the last database driver that was loaded by ADOLoadCode().
3447 * @return the freshly created instance of the Connection class.
3449 function &ADONewConnection($db='')
3451 GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB;
3453 if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
3454 $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false;
3456 if (!empty($ADODB_NEWCONNECTION)) {
3457 $obj = $ADODB_NEWCONNECTION($db);
3459 if ($errorfn) $obj->raiseErrorFn = $errorfn;
3464 if (!isset($ADODB_LASTDB)) $ADODB_LASTDB = '';
3465 if (empty($db)) $db = $ADODB_LASTDB;
3467 if ($db != $ADODB_LASTDB) $db = ADOLoadCode($db);
3473 $errorfn('ADONewConnection', 'ADONewConnection', -998,
3474 "could not load the database driver for '$db",
3477 ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false);
3482 $cls = 'ADODB_'.$db;
3483 if (!class_exists($cls)) {
3489 if ($errorfn) $obj->raiseErrorFn = $errorfn;
3494 // $perf == true means called by NewPerfMonitor()
3495 function _adodb_getdriver($provider,$drivername,$perf=false)
3497 if ($provider !== 'native' && $provider != 'odbc' && $provider != 'ado')
3498 $drivername = $provider;
3500 if (substr($drivername,0,5) == 'odbc_') $drivername = substr($drivername,5);
3501 else if (substr($drivername,0,4) == 'ado_') $drivername = substr($drivername,4);
3503 switch($drivername) {
3504 case 'oracle': $drivername = 'oci8';break;
3505 //case 'sybase': $drivername = 'mssql';break;
3507 if ($perf) $drivername = '';
3512 $drivername = 'generic';
3520 function &NewPerfMonitor(&$conn)
3522 $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType,true);
3523 if (!$drivername || $drivername == 'generic') return false;
3524 include_once(ADODB_DIR.'/adodb-perf.inc.php');
3525 @include_once(ADODB_DIR."/perf/perf-$drivername.inc.php");
3526 $class = "Perf_$drivername";
3527 if (!class_exists($class)) return false;
3528 $perf =& new $class($conn);
3533 function &NewDataDictionary(&$conn)
3535 $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType);
3537 include_once(ADODB_DIR.'/adodb-lib.inc.php');
3538 include_once(ADODB_DIR.'/adodb-datadict.inc.php');
3539 $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php";
3541 if (!file_exists($path)) {
3542 ADOConnection::outp("Database driver '$path' not available");
3545 include_once($path);
3546 $class = "ADODB2_$drivername";
3547 $dict =& new $class();
3548 $dict->dataProvider = $conn->dataProvider;
3549 $dict->connection = &$conn;
3550 $dict->upperName = strtoupper($drivername);
3551 $dict->quote = $conn->nameQuote;
3552 if (is_resource($conn->_connectionID))
3553 $dict->serverInfo = $conn->ServerInfo();
3560 * Save a file $filename and its $contents (normally for caching) with file locking
3562 function adodb_write_file($filename, $contents,$debug=false)
3564 # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
3565 # So to simulate locking, we assume that rename is an atomic operation.
3566 # First we delete $filename, then we create a $tempfile write to it and
3567 # rename to the desired $filename. If the rename works, then we successfully
3568 # modified the file exclusively.
3569 # What a stupid need - having to simulate locking.
3571 # 1. $tempfile name is not unique -- very very low
3572 # 2. unlink($filename) fails -- ok, rename will fail
3573 # 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs
3574 # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and cache updated
3575 if (strncmp(PHP_OS,'WIN',3) === 0) {
3576 // skip the decimal place
3577 $mtime = substr(str_replace(' ','_',microtime()),2);
3578 // getmypid() actually returns 0 on Win98 - never mind!
3579 $tmpname = $filename.uniqid($mtime).getmypid();
3580 if (!($fd = fopen($tmpname,'a'))) return false;
3581 $ok = ftruncate($fd,0);
3582 if (!fwrite($fd,$contents)) $ok = false;
3584 chmod($tmpname,0644);
3585 // the tricky moment
3587 if (!@rename($tmpname,$filename)) {
3592 if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));
3596 if (!($fd = fopen($filename, 'a'))) return false;
3597 if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
3598 $ok = fwrite( $fd, $contents );
3600 chmod($filename,0644);
3603 if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n");
3611 Perform a print_r, with pre tags for better formatting.
3613 function adodb_pr($var)
3615 if (isset($_SERVER['HTTP_USER_AGENT'])) {
3616 echo " <pre>\n";print_r($var);echo "</pre>\n";
3622 Perform a stack-crawl and pretty print it.
3624 @param printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then).
3625 @param levels Number of levels to display
3627 function adodb_backtrace($printOrArr=true,$levels=9999)
3630 if (PHPVERSION() < 4.3) return;
3632 $html = (isset($_SERVER['HTTP_USER_AGENT']));
3633 $fmt = ($html) ? "</font><font color=#808080 size=-1> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s";
3637 $s = ($html) ? '<pre align=left>' : '';
3639 if (is_array($printOrArr)) $traceArr = $printOrArr;
3640 else $traceArr = debug_backtrace();
3641 array_shift($traceArr);
3642 $tabs = sizeof($traceArr)-1;
3644 foreach ($traceArr as $arr) {
3646 if ($levels < 0) break;
3649 for ($i=0; $i < $tabs; $i++) $s .= ($html) ? ' ' : "\t";
3651 if ($html) $s .= '<font face="Courier New,Courier">';
3652 if (isset($arr['class'])) $s .= $arr['class'].'.';
3653 if (isset($arr['args']))
3654 foreach($arr['args'] as $v) {
3655 if (is_null($v)) $args[] = 'null';
3656 else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
3657 else if (is_object($v)) $args[] = 'Object:'.get_class($v);
3658 else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
3661 $str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
3662 if (strlen($v) > $MAXSTRLEN) $str .= '...';
3666 $s .= $arr['function'].'('.implode(', ',$args).')';
3669 $s .= @sprintf($fmt, $arr['line'],$arr['file'],basename($arr['file']));
3673 if ($html) $s .= '</pre>';
3674 if ($printOrArr) print $s;
3685 // c-basic-offset: 4
3686 // c-hanging-comment-ender-p: nil
3687 // indent-tabs-mode: nil