3 * Set tabs to 4 for best viewing.
5 * Latest version is available at http://adodb.sourceforge.net
7 * This is the main include file for ADOdb.
8 * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php
10 * The ADOdb files are formatted so that doxygen can be used to generate documentation.
11 * Doxygen is a documentation generation tool and can be downloaded from http://doxygen.org/
17 @version V4.92a 29 Aug 2006 (c) 2000-2006 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://adodb.sourceforge.net/
35 if (!defined('_ADODB_LAYER')) {
36 define('_ADODB_LAYER',1);
38 //==============================================================================================
39 // CONSTANT DEFINITIONS
40 //==============================================================================================
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_FETCH, // 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');
67 //********************************************************//
69 Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).
70 Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi
72 0 = ignore empty fields. All empty fields in array are ignored.
73 1 = force null. All empty, php null and string 'null' fields are changed to sql NULL values.
74 2 = force empty. All empty, php null and string 'null' fields are changed to sql empty '' or 0 values.
75 3 = force value. Value is left as it is. Php null and string 'null' are set to sql NULL values and empty fields '' are set to empty '' sql values.
77 define('ADODB_FORCE_IGNORE',0);
78 define('ADODB_FORCE_NULL',1);
79 define('ADODB_FORCE_EMPTY',2);
80 define('ADODB_FORCE_VALUE',3);
81 //********************************************************//
84 if (!$ADODB_EXTENSION || ADODB_EXTENSION
< 4.0) {
86 define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');
88 // allow [ ] @ ` " and . in table names
89 define('ADODB_TABLE_REGEX','([]0-9a-z_\:\"\`\.\@\[-]*)');
91 // prefetching used by oracle
92 if (!defined('ADODB_PREFETCH_ROWS')) define('ADODB_PREFETCH_ROWS',10);
96 Controls ADODB_FETCH_ASSOC field-name case. Default is 2, use native case-names.
97 This currently works only with mssql, odbc, oci8po and ibase derived drivers.
99 0 = assoc lowercase field names. $rs->fields['orderid']
100 1 = assoc uppercase field names. $rs->fields['ORDERID']
101 2 = use native-case field names. $rs->fields['OrderID']
104 define('ADODB_FETCH_DEFAULT',0);
105 define('ADODB_FETCH_NUM',1);
106 define('ADODB_FETCH_ASSOC',2);
107 define('ADODB_FETCH_BOTH',3);
109 if (!defined('TIMESTAMP_FIRST_YEAR')) define('TIMESTAMP_FIRST_YEAR',100);
111 // PHP's version scheme makes converting to numbers difficult - workaround
112 $_adodb_ver = (float) PHP_VERSION
;
113 if ($_adodb_ver >= 5.0) {
114 define('ADODB_PHPVER',0x5000);
115 } else if ($_adodb_ver > 4.299999) { # 4.3
116 define('ADODB_PHPVER',0x4300);
117 } else if ($_adodb_ver > 4.199999) { # 4.2
118 define('ADODB_PHPVER',0x4200);
119 } else if (strnatcmp(PHP_VERSION
,'4.0.5')>=0) {
120 define('ADODB_PHPVER',0x4050);
122 define('ADODB_PHPVER',0x4000);
126 //if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
130 Accepts $src and $dest arrays, replacing string $data
132 function ADODB_str_replace($src, $dest, $data)
134 if (ADODB_PHPVER
>= 0x4050) return str_replace($src,$dest,$data);
138 while ($s !== false) {
139 $data = str_replace($s,$d,$data);
146 function ADODB_Setup()
149 $ADODB_vers, // database version
150 $ADODB_COUNTRECS, // count number of records returned - slows down query
151 $ADODB_CACHE_DIR, // directory to cache recordsets
155 $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT
;
156 $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE
;
159 if (!isset($ADODB_CACHE_DIR)) {
160 $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp';
162 // do not accept url based paths, eg. http:/ or ftp:/
163 if (strpos($ADODB_CACHE_DIR,'://') !== false)
164 die("Illegal path http:// or ftp://");
168 // Initialize random number generator for randomizing cache flushes
169 srand(((double)microtime())*1000000);
172 * ADODB version as a string.
174 $ADODB_vers = 'V4.90 8 June 2006 (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved. Released BSD & LGPL.';
177 * Determines whether recordset->RecordCount() is used.
178 * Set to false for highest performance -- RecordCount() will always return -1 then
179 * for databases that provide "virtual" recordcounts...
181 if (!isset($ADODB_COUNTRECS)) $ADODB_COUNTRECS = true;
185 //==============================================================================================
186 // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB
187 //==============================================================================================
191 //==============================================================================================
192 // CLASS ADOFieldObject
193 //==============================================================================================
195 * Helper class for FetchFields -- holds info on a column
197 class ADOFieldObject
{
202 // additional fields by dannym... (danny_milo@yahoo.com)
203 var $not_null = false;
204 // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^
205 // so we can as well make not_null standard (leaving it at "false" does not harm anyways)
207 var $has_default = false; // this one I have done only in mysql and postgres for now ...
208 // others to come (dannym)
209 var $default_value; // default, if any, and supported. Check has_default first.
215 function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection)
217 //print "Errorno ($fn errno=$errno m=$errmsg) ";
218 $thisConnection->_transOK
= false;
219 if ($thisConnection->_oldRaiseFn
) {
220 $fn = $thisConnection->_oldRaiseFn
;
221 $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
225 //==============================================================================================
226 // CLASS ADOConnection
227 //==============================================================================================
230 * Connection object. For connecting to databases, and executing queries.
232 class ADOConnection
{
236 var $dataProvider = 'native';
237 var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql
238 var $database = ''; /// Name of database to be used.
239 var $host = ''; /// The hostname of the database server
240 var $user = ''; /// The username which is used to connect to the database server.
241 var $password = ''; /// Password for the username. For security, we no longer store it.
242 var $debug = false; /// if set to true will output sql statements
243 var $maxblobsize = 262144; /// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxpro
244 var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase
245 var $substr = 'substr'; /// substring operator
246 var $length = 'length'; /// string length ofperator
247 var $random = 'rand()'; /// random function
248 var $upperCase = 'upper'; /// uppercase function
249 var $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the database
250 var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt.
251 var $true = '1'; /// string that represents TRUE for a database
252 var $false = '0'; /// string that represents FALSE for a database
253 var $replaceQuote = "\\'"; /// string to use to replace quotes
254 var $nameQuote = '"'; /// string to use to quote identifiers and names
255 var $charSet=false; /// character set to use - only for interbase, postgres and oci8
256 var $metaDatabasesSQL = '';
257 var $metaTablesSQL = '';
258 var $uniqueOrderBy = false; /// All order by columns have to be unique
259 var $emptyDate = ' ';
260 var $emptyTimeStamp = ' ';
261 var $lastInsID = false;
263 var $hasInsertID = false; /// supports autoincrement ID?
264 var $hasAffectedRows = false; /// supports affected rows for update/delete?
265 var $hasTop = false; /// support mssql/access SELECT TOP 10 * FROM TABLE
266 var $hasLimit = false; /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10
267 var $readOnly = false; /// this is a readonly database - used by phpLens
268 var $hasMoveFirst = false; /// has ability to run MoveFirst(), scrolling backwards
269 var $hasGenID = false; /// can generate sequences using GenID();
270 var $hasTransactions = true; /// has transactions
272 var $genID = 0; /// sequence id used by GenID();
273 var $raiseErrorFn = false; /// error function to call
274 var $isoDates = false; /// accepts dates in ISO format
275 var $cacheSecs = 3600; /// cache for 1 hour
278 var $memCache = false; /// should we use memCache instead of caching in files
279 var $memCacheHost; /// memCache host
280 var $memCachePort = 11211; /// memCache port
281 var $memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib)
283 var $sysDate = false; /// name of function that returns the current date
284 var $sysTimeStamp = false; /// name of function that returns the current timestamp
285 var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets
287 var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' '
288 var $numCacheHits = 0;
289 var $numCacheMisses = 0;
290 var $pageExecuteCountRows = true;
291 var $uniqueSort = false; /// indicates that all fields in order by must be unique
292 var $leftOuter = false; /// operator to use for left outer join in WHERE clause
293 var $rightOuter = false; /// operator to use for right outer join in WHERE clause
294 var $ansiOuter = false; /// whether ansi outer join syntax supported
295 var $autoRollback = false; // autoRollback on PConnect().
296 var $poorAffectedRows = false; // affectedRows not working or unreliable
298 var $fnExecute = false;
299 var $fnCacheExecute = false;
300 var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char
301 var $rsPrefix = "ADORecordSet_";
303 var $autoCommit = true; /// do not modify this yourself - actually private
304 var $transOff = 0; /// temporarily disable transactions
305 var $transCnt = 0; /// count of nested transactions
307 var $fetchMode=false;
311 var $_oldRaiseFn = false;
312 var $_transOK = null;
313 var $_connectionID = false; /// The returned link identifier whenever a successful database connection is made.
314 var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will
315 /// then returned by the errorMsg() function
316 var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8
317 var $_queryID = false; /// This variable keeps the last created result link identifier
319 var $_isPersistentConnection = false; /// A boolean variable to state whether its a persistent connection or normal connection. */
320 var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.
321 var $_evalAll = false;
322 var $_affected = false;
323 var $_logsql = false;
324 var $_transmode = ''; // transaction mode
329 function ADOConnection()
331 die('Virtual Class -- cannot instantiate');
338 return (float) substr($ADODB_vers,1);
342 Get server version info...
344 @returns An array with 2 elements: $arr['string'] is the description string,
345 and $arr[version] is the version (also a string).
347 function ServerInfo()
349 return array('description' => '', 'version' => '');
352 function IsConnected()
354 return !empty($this->_connectionID
);
357 function _findvers($str)
359 if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) return $arr[1];
364 * All error messages go through this bottleneck function.
365 * You can define your own handler by defining the function name in ADODB_OUTP.
367 function outp($msg,$newline=true)
369 global $ADODB_FLUSH,$ADODB_OUTP;
371 if (defined('ADODB_OUTP')) {
375 } else if (isset($ADODB_OUTP)) {
381 if ($newline) $msg .= "<br>\n";
383 if (isset($_SERVER['HTTP_USER_AGENT']) ||
!$newline) echo $msg;
384 else echo strip_tags($msg);
387 if (!empty($ADODB_FLUSH) && ob_get_length() !== false) flush(); // do not flush if output buffering enabled - useless - thx to Jesse Mullan
393 $rs =& $this->_Execute("select $this->sysTimeStamp");
394 if ($rs && !$rs->EOF
) return $this->UnixTimeStamp(reset($rs->fields
));
400 * Connect to database
402 * @param [argHostname] Host to connect to
403 * @param [argUsername] Userid to login
404 * @param [argPassword] Associated password
405 * @param [argDatabaseName] database
406 * @param [forceNew] force new connection
408 * @return true or false
410 function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false)
412 if ($argHostname != "") $this->host
= $argHostname;
413 if ($argUsername != "") $this->user
= $argUsername;
414 if ($argPassword != "") $this->password
= $argPassword; // not stored for security reasons
415 if ($argDatabaseName != "") $this->database
= $argDatabaseName;
417 $this->_isPersistentConnection
= false;
419 if ($rez=$this->_nconnect($this->host
, $this->user
, $this->password
, $this->database
)) return true;
421 if ($rez=$this->_connect($this->host
, $this->user
, $this->password
, $this->database
)) return true;
424 $err = $this->ErrorMsg();
425 if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
428 $err = "Missing extension for ".$this->dataProvider
;
431 if ($fn = $this->raiseErrorFn
)
432 $fn($this->databaseType
,'CONNECT',$this->ErrorNo(),$err,$this->host
,$this->database
,$this);
435 $this->_connectionID
= false;
436 if ($this->debug
) ADOConnection
::outp( $this->host
.': '.$err);
440 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
442 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
447 * Always force a new connection to database - currently only works with oracle
449 * @param [argHostname] Host to connect to
450 * @param [argUsername] Userid to login
451 * @param [argPassword] Associated password
452 * @param [argDatabaseName] database
454 * @return true or false
456 function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
458 return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
462 * Establish persistent connect to database
464 * @param [argHostname] Host to connect to
465 * @param [argUsername] Userid to login
466 * @param [argPassword] Associated password
467 * @param [argDatabaseName] database
469 * @return return true or false
471 function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
473 if (defined('ADODB_NEVER_PERSIST'))
474 return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
476 if ($argHostname != "") $this->host
= $argHostname;
477 if ($argUsername != "") $this->user
= $argUsername;
478 if ($argPassword != "") $this->password
= $argPassword;
479 if ($argDatabaseName != "") $this->database
= $argDatabaseName;
481 $this->_isPersistentConnection
= true;
482 if ($rez = $this->_pconnect($this->host
, $this->user
, $this->password
, $this->database
)) return true;
484 $err = $this->ErrorMsg();
485 if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
488 $err = "Missing extension for ".$this->dataProvider
;
491 if ($fn = $this->raiseErrorFn
) {
492 $fn($this->databaseType
,'PCONNECT',$this->ErrorNo(),$err,$this->host
,$this->database
,$this);
495 $this->_connectionID
= false;
496 if ($this->debug
) ADOConnection
::outp( $this->host
.': '.$err);
500 // Format date column in sql string given an input format that understands Y M D
501 function SQLDate($fmt, $col=false)
503 if (!$col) $col = $this->sysDate
;
504 return $col; // child class implement
508 * Should prepare the sql statement and return the stmt resource.
509 * For databases that do not support this, we return the $sql. To ensure
510 * compatibility with databases that do not support prepare:
512 * $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
513 * $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
514 * $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
516 * @param sql SQL to send to database
518 * @return return FALSE, or the prepared statement, or the original sql if
519 * if the database does not support prepare.
522 function Prepare($sql)
528 * Some databases, eg. mssql require a different function for preparing
529 * stored procedures. So we cannot use Prepare().
531 * Should prepare the stored procedure and return the stmt resource.
532 * For databases that do not support this, we return the $sql. To ensure
533 * compatibility with databases that do not support prepare:
535 * @param sql SQL to send to database
537 * @return return FALSE, or the prepared statement, or the original sql if
538 * if the database does not support prepare.
541 function PrepareSP($sql,$param=true)
543 return $this->Prepare($sql,$param);
551 return $this->qstr($s,false);
555 Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de>
559 return $this->qstr($s,get_magic_quotes_gpc());
564 #if (!empty($this->qNull)) if ($s == 'null') return $s;
565 $s = $this->qstr($s,false);
569 * PEAR DB Compat - do not use internally.
571 function ErrorNative()
573 return $this->ErrorNo();
578 * PEAR DB Compat - do not use internally.
580 function nextId($seq_name)
582 return $this->GenID($seq_name);
586 * Lock a row, will escalate and lock the table if row locking not supported
587 * will normally free the lock at the end of the transaction
589 * @param $table name of table to lock
590 * @param $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
592 function RowLock($table,$where)
597 function CommitLock($table)
599 return $this->CommitTrans();
602 function RollbackLock($table)
604 return $this->RollbackTrans();
608 * PEAR DB Compat - do not use internally.
610 * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
611 * for easy porting :-)
613 * @param mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
614 * @returns The previous fetch mode
616 function SetFetchMode($mode)
618 $old = $this->fetchMode
;
619 $this->fetchMode
= $mode;
621 if ($old === false) {
622 global $ADODB_FETCH_MODE;
623 return $ADODB_FETCH_MODE;
630 * PEAR DB Compat - do not use internally.
632 function &Query($sql, $inputarr=false)
634 $rs = &$this->Execute($sql, $inputarr);
635 if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
641 * PEAR DB Compat - do not use internally
643 function &LimitQuery($sql, $offset, $count, $params=false)
645 $rs = &$this->SelectLimit($sql, $count, $offset, $params);
646 if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
652 * PEAR DB Compat - do not use internally
654 function Disconnect()
656 return $this->Close();
660 Returns placeholder for parameter, eg.
663 will return ':a' for Oracle, and '?' for most other databases...
665 For databases that require positioned params, eg $1, $2, $3 for postgresql,
666 pass in Param(false) before setting the first parameter.
668 function Param($name,$type='C')
674 InParameter and OutParameter are self-documenting versions of Parameter().
676 function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
678 return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
683 function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
685 return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);
692 $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
693 $db->Parameter($stmt,$id,'myid');
694 $db->Parameter($stmt,$group,'group',64);
697 @param $stmt Statement returned by Prepare() or PrepareSP().
698 @param $var PHP variable to bind to
699 @param $name Name of stored procedure variable name to bind to.
700 @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
701 @param [$maxLen] Holds an maximum length of the variable.
702 @param [$type] The data type of $var. Legal values depend on driver.
705 function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
711 function IgnoreErrors($saveErrs=false)
714 $saveErrs = array($this->raiseErrorFn
,$this->_transOK
);
715 $this->raiseErrorFn
= false;
718 $this->raiseErrorFn
= $saveErrs[0];
719 $this->_transOK
= $saveErrs[1];
724 Improved method of initiating a transaction. Used together with CompleteTrans().
727 a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.
728 Only the outermost block is treated as a transaction.<br>
729 b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>
730 c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block
731 are disabled, making it backward compatible.
733 function StartTrans($errfn = 'ADODB_TransMonitor')
735 if ($this->transOff
> 0) {
736 $this->transOff +
= 1;
740 $this->_oldRaiseFn
= $this->raiseErrorFn
;
741 $this->raiseErrorFn
= $errfn;
742 $this->_transOK
= true;
744 if ($this->debug
&& $this->transCnt
> 0) ADOConnection
::outp("Bad Transaction: StartTrans called within BeginTrans");
751 Used together with StartTrans() to end a transaction. Monitors connection
752 for sql errors, and will commit or rollback as appropriate.
754 @autoComplete if true, monitor sql errors and commit and rollback as appropriate,
755 and if set to false force rollback even if no SQL error detected.
756 @returns true on commit, false on rollback.
758 function CompleteTrans($autoComplete = true)
760 if ($this->transOff
> 1) {
761 $this->transOff
-= 1;
764 $this->raiseErrorFn
= $this->_oldRaiseFn
;
767 if ($this->_transOK
&& $autoComplete) {
768 if (!$this->CommitTrans()) {
769 $this->_transOK
= false;
770 if ($this->debug
) ADOConnection
::outp("Smart Commit failed");
772 if ($this->debug
) ADOConnection
::outp("Smart Commit occurred");
774 $this->_transOK
= false;
775 $this->RollbackTrans();
776 if ($this->debug
) ADOCOnnection
::outp("Smart Rollback occurred");
779 return $this->_transOK
;
783 At the end of a StartTrans/CompleteTrans block, perform a rollback.
788 if ($this->transOff
== 0) {
789 ADOConnection
::outp("FailTrans outside StartTrans/CompleteTrans");
791 ADOConnection
::outp("FailTrans was called");
794 $this->_transOK
= false;
798 Check if transaction has failed, only for Smart Transactions.
800 function HasFailedTrans()
802 if ($this->transOff
> 0) return $this->_transOK
== false;
809 * @param sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
810 * @param [inputarr] holds the input data to bind to. Null elements will be set to null.
811 * @return RecordSet or false
813 function &Execute($sql,$inputarr=false)
815 if ($this->fnExecute
) {
816 $fn = $this->fnExecute
;
817 $ret =& $fn($this,$sql,$inputarr);
818 if (isset($ret)) return $ret;
821 if (!is_array($inputarr)) $inputarr = array($inputarr);
823 $element0 = reset($inputarr);
824 # is_object check because oci8 descriptors can be passed in
825 $array_2d = is_array($element0) && !is_object(reset($element0));
826 //remove extra memory copy of input -mikefedyk
829 if (!is_array($sql) && !$this->_bindInputArray
) {
830 $sqlarr = explode('?',$sql);
832 if (!$array_2d) $inputarr = array($inputarr);
833 foreach($inputarr as $arr) {
835 //Use each() instead of foreach to reduce memory usage -mikefedyk
836 while(list(, $v) = each($arr)) {
838 // from Ron Baldwin <ron.baldwin#sourceprose.com>
839 // Only quote string types
841 if ($typ == 'string')
842 //New memory copy of input created here -mikefedyk
843 $sql .= $this->qstr($v);
844 else if ($typ == 'double')
845 $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1
846 else if ($typ == 'boolean')
847 $sql .= $v ?
$this->true : $this->false;
848 else if ($typ == 'object') {
849 if (method_exists($v, '__toString')) $sql .= $this->qstr($v->__toString());
850 else $sql .= $this->qstr((string) $v);
851 } else if ($v === null)
857 if (isset($sqlarr[$i])) {
859 if ($i+
1 != sizeof($sqlarr)) ADOConnection
::outp( "Input Array does not match ?: ".htmlspecialchars($sql));
860 } else if ($i != sizeof($sqlarr))
861 ADOConnection
::outp( "Input array does not match ?: ".htmlspecialchars($sql));
863 $ret =& $this->_Execute($sql);
864 if (!$ret) return $ret;
869 $stmt = $this->Prepare($sql);
873 foreach($inputarr as $arr) {
874 $ret =& $this->_Execute($stmt,$arr);
875 if (!$ret) return $ret;
878 $ret =& $this->_Execute($sql,$inputarr);
882 $ret =& $this->_Execute($sql,false);
889 function &_Execute($sql,$inputarr=false)
892 global $ADODB_INCLUDED_LIB;
893 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR
.'/adodb-lib.inc.php');
894 $this->_queryID
= _adodb_debug_execute($this, $sql,$inputarr);
896 $this->_queryID
= @$this->_query($sql,$inputarr);
899 /************************
900 // OK, query executed
901 *************************/
903 if ($this->_queryID
=== false) { // error handling if query fails
904 if ($this->debug
== 99) adodb_backtrace(true,5);
905 $fn = $this->raiseErrorFn
;
907 $fn($this->databaseType
,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
913 if ($this->_queryID
=== true) { // return simplified recordset for inserts/updates/deletes with lower overhead
914 $rs =& new ADORecordSet_empty();
918 // return real recordset from select statement
919 $rsclass = $this->rsPrefix
.$this->databaseType
;
920 $rs = new $rsclass($this->_queryID
,$this->fetchMode
);
921 $rs->connection
= &$this; // Pablo suggestion
923 if (is_array($sql)) $rs->sql
= $sql[0];
924 else $rs->sql
= $sql;
925 if ($rs->_numOfRows
<= 0) {
926 global $ADODB_COUNTRECS;
927 if ($ADODB_COUNTRECS) {
929 $rs = &$this->_rs2rs($rs,-1,-1,!is_array($sql));
930 $rs->_queryID
= $this->_queryID
;
938 function CreateSequence($seqname='adodbseq',$startID=1)
940 if (empty($this->_genSeqSQL
)) return false;
941 return $this->Execute(sprintf($this->_genSeqSQL
,$seqname,$startID));
944 function DropSequence($seqname='adodbseq')
946 if (empty($this->_dropSeqSQL
)) return false;
947 return $this->Execute(sprintf($this->_dropSeqSQL
,$seqname));
951 * Generates a sequence id and stores it in $this->genID;
952 * GenID is only available if $this->hasGenID = true;
954 * @param seqname name of sequence to use
955 * @param startID if sequence does not exist, start at this ID
956 * @return 0 if not supported, otherwise a sequence id
958 function GenID($seqname='adodbseq',$startID=1)
960 if (!$this->hasGenID
) {
961 return 0; // formerly returns false pre 1.60
964 $getnext = sprintf($this->_genIDSQL
,$seqname);
966 $holdtransOK = $this->_transOK
;
968 $save_handler = $this->raiseErrorFn
;
969 $this->raiseErrorFn
= '';
970 @($rs = $this->Execute($getnext));
971 $this->raiseErrorFn
= $save_handler;
974 $this->_transOK
= $holdtransOK; //if the status was ok before reset
975 $createseq = $this->Execute(sprintf($this->_genSeqSQL
,$seqname,$startID));
976 $rs = $this->Execute($getnext);
978 if ($rs && !$rs->EOF
) $this->genID
= reset($rs->fields
);
979 else $this->genID
= 0; // false
981 if ($rs) $rs->Close();
987 * @param $table string name of the table, not needed by all databases (eg. mysql), default ''
988 * @param $column string name of the column, not needed by all databases (eg. mysql), default ''
989 * @return the last inserted ID. Not all databases support this.
991 function Insert_ID($table='',$column='')
993 if ($this->_logsql
&& $this->lastInsID
) return $this->lastInsID
;
994 if ($this->hasInsertID
) return $this->_insertid($table,$column);
996 ADOConnection
::outp( '<p>Insert_ID error</p>');
1004 * Portable Insert ID. Pablo Roca <pabloroca#mvps.org>
1006 * @return the last inserted ID. All databases support this. But aware possible
1007 * problems in multiuser environments. Heavy test this before deploying.
1009 function PO_Insert_ID($table="", $id="")
1011 if ($this->hasInsertID
){
1012 return $this->Insert_ID($table,$id);
1014 return $this->GetOne("SELECT MAX($id) FROM $table");
1019 * @return # rows affected by UPDATE/DELETE
1021 function Affected_Rows()
1023 if ($this->hasAffectedRows
) {
1024 if ($this->fnExecute
=== 'adodb_log_sql') {
1025 if ($this->_logsql
&& $this->_affected
!== false) return $this->_affected
;
1027 $val = $this->_affectedrows();
1028 return ($val < 0) ?
false : $val;
1031 if ($this->debug
) ADOConnection
::outp( '<p>Affected_Rows error</p>',false);
1037 * @return the last error message
1041 if ($this->_errorMsg
) return '!! '.strtoupper($this->dataProvider
.' '.$this->databaseType
).': '.$this->_errorMsg
;
1047 * @return the last error number. Normally 0 means no error.
1051 return ($this->_errorMsg
) ?
-1 : 0;
1054 function MetaError($err=false)
1056 include_once(ADODB_DIR
."/adodb-error.inc.php");
1057 if ($err === false) $err = $this->ErrorNo();
1058 return adodb_error($this->dataProvider
,$this->databaseType
,$err);
1061 function MetaErrorMsg($errno)
1063 include_once(ADODB_DIR
."/adodb-error.inc.php");
1064 return adodb_errormsg($errno);
1068 * @returns an array with the primary key columns in it.
1070 function MetaPrimaryKeys($table, $owner=false)
1072 // owner not used in base class - see oci8
1074 $objs =& $this->MetaColumns($table);
1076 foreach($objs as $v) {
1077 if (!empty($v->primary_key
))
1081 if (sizeof($p)) return $p;
1082 if (function_exists('ADODB_VIEW_PRIMARYKEYS'))
1083 return ADODB_VIEW_PRIMARYKEYS($this->databaseType
, $this->database
, $table, $owner);
1088 * @returns assoc array where keys are tables, and values are foreign keys
1090 function MetaForeignKeys($table, $owner=false, $upper=false)
1095 * Choose a database to connect to. Many databases do not support this.
1097 * @param dbName is the name of the database to select
1098 * @return true or false
1100 function SelectDB($dbName)
1105 * Will select, getting rows from $offset (1-based), for $nrows.
1106 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1107 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1108 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1110 * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
1111 * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
1113 * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
1114 * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
1117 * @param [offset] is the row to start calculations from (1-based)
1118 * @param [nrows] is the number of rows to get
1119 * @param [inputarr] array of bind variables
1120 * @param [secs2cache] is a private parameter only used by jlim
1121 * @return the recordset ($rs->databaseType == 'array')
1123 function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
1125 if ($this->hasTop
&& $nrows > 0) {
1126 // suggested by Reinhard Balling. Access requires top after distinct
1127 // Informix requires first before distinct - F Riosa
1128 $ismssql = (strpos($this->databaseType
,'mssql') !== false);
1129 if ($ismssql) $isaccess = false;
1130 else $isaccess = (strpos($this->databaseType
,'access') !== false);
1134 // access includes ties in result
1136 $sql = preg_replace(
1137 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop
.' '.((integer)$nrows).' ',$sql);
1139 if ($secs2cache != 0) {
1140 $ret =& $this->CacheExecute($secs2cache, $sql,$inputarr);
1142 $ret =& $this->Execute($sql,$inputarr);
1144 return $ret; // PHP5 fix
1145 } else if ($ismssql){
1146 $sql = preg_replace(
1147 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop
.' '.((integer)$nrows).' ',$sql);
1149 $sql = preg_replace(
1150 '/(^\s*select\s)/i','\\1 '.$this->hasTop
.' '.((integer)$nrows).' ',$sql);
1153 $nn = $nrows +
$offset;
1154 if ($isaccess ||
$ismssql) {
1155 $sql = preg_replace(
1156 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop
.' '.$nn.' ',$sql);
1158 $sql = preg_replace(
1159 '/(^\s*select\s)/i','\\1 '.$this->hasTop
.' '.$nn.' ',$sql);
1164 // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows
1165 // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.
1166 global $ADODB_COUNTRECS;
1168 $savec = $ADODB_COUNTRECS;
1169 $ADODB_COUNTRECS = false;
1172 if ($secs2cache != 0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1173 else $rs = &$this->Execute($sql,$inputarr);
1175 if ($secs2cache != 0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1176 else $rs = &$this->Execute($sql,$inputarr);
1178 $ADODB_COUNTRECS = $savec;
1179 if ($rs && !$rs->EOF
) {
1180 $rs =& $this->_rs2rs($rs,$nrows,$offset);
1187 * Create serializable recordset. Breaks rs link to connection.
1189 * @param rs the recordset to serialize
1191 function &SerializableRS(&$rs)
1193 $rs2 =& $this->_rs2rs($rs);
1195 $rs2->connection
=& $ignore;
1201 * Convert database recordset to an array recordset
1202 * input recordset's cursor should be at beginning, and
1203 * old $rs will be closed.
1205 * @param rs the recordset to copy
1206 * @param [nrows] number of rows to retrieve (optional)
1207 * @param [offset] offset by number of rows (optional)
1208 * @return the new recordset
1210 function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true)
1216 $dbtype = $rs->databaseType
;
1218 $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?
1221 if (($dbtype == 'array' ||
$dbtype == 'csv') && $nrows == -1 && $offset == -1) {
1223 $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?
1227 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++
) {
1228 $flds[] = $rs->FetchField($i);
1231 $arr =& $rs->GetArrayLimit($nrows,$offset);
1233 if ($close) $rs->Close();
1235 $arrayClass = $this->arrayClass
;
1237 $rs2 = new $arrayClass();
1238 $rs2->connection
= &$this;
1239 $rs2->sql
= $rs->sql
;
1240 $rs2->dataProvider
= $this->dataProvider
;
1241 $rs2->InitArrayFields($arr,$flds);
1242 $rs2->fetchMode
= isset($rs->adodbFetchMode
) ?
$rs->adodbFetchMode
: $rs->fetchMode
;
1247 * Return all rows. Compat with PEAR DB
1249 function &GetAll($sql, $inputarr=false)
1251 $arr =& $this->GetArray($sql,$inputarr);
1255 function &GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false)
1257 $rs =& $this->Execute($sql, $inputarr);
1262 $arr =& $rs->GetAssoc($force_array,$first2cols);
1266 function &CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false)
1268 if (!is_numeric($secs2cache)) {
1269 $first2cols = $force_array;
1270 $force_array = $inputarr;
1272 $rs =& $this->CacheExecute($secs2cache, $sql, $inputarr);
1277 $arr =& $rs->GetAssoc($force_array,$first2cols);
1282 * Return first element of first row of sql statement. Recordset is disposed
1285 * @param sql SQL statement
1286 * @param [inputarr] input bind array
1288 function GetOne($sql,$inputarr=false)
1290 global $ADODB_COUNTRECS;
1291 $crecs = $ADODB_COUNTRECS;
1292 $ADODB_COUNTRECS = false;
1295 $rs = &$this->Execute($sql,$inputarr);
1297 if (!$rs->EOF
) $ret = reset($rs->fields
);
1300 $ADODB_COUNTRECS = $crecs;
1304 function CacheGetOne($secs2cache,$sql=false,$inputarr=false)
1307 $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1309 if (!$rs->EOF
) $ret = reset($rs->fields
);
1316 function GetCol($sql, $inputarr = false, $trim = false)
1319 $rs = &$this->Execute($sql, $inputarr);
1324 $rv[] = trim(reset($rs->fields
));
1329 $rv[] = reset($rs->fields
);
1338 function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false)
1341 $rs = &$this->CacheExecute($secs, $sql, $inputarr);
1345 $rv[] = trim(reset($rs->fields
));
1350 $rv[] = reset($rs->fields
);
1359 function &Transpose(&$rs)
1361 $rs2 =& $this->_rs2rs($rs);
1363 if (!$rs2) return $false;
1370 Calculate the offset of a date for a particular database and generate
1371 appropriate SQL. Useful for calculating future/past dates and storing
1374 If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
1376 function OffsetDate($dayFraction,$date=false)
1378 if (!$date) $date = $this->sysDate
;
1379 return '('.$date.'+'.$dayFraction.')';
1385 * @param sql SQL statement
1386 * @param [inputarr] input bind array
1388 function &GetArray($sql,$inputarr=false)
1390 global $ADODB_COUNTRECS;
1392 $savec = $ADODB_COUNTRECS;
1393 $ADODB_COUNTRECS = false;
1394 $rs =& $this->Execute($sql,$inputarr);
1395 $ADODB_COUNTRECS = $savec;
1397 if (defined('ADODB_PEAR')) {
1398 $cls = ADODB_PEAR_Error();
1404 $arr =& $rs->GetArray();
1409 function &CacheGetAll($secs2cache,$sql=false,$inputarr=false)
1411 return $this->CacheGetArray($secs2cache,$sql,$inputarr);
1414 function &CacheGetArray($secs2cache,$sql=false,$inputarr=false)
1416 global $ADODB_COUNTRECS;
1418 $savec = $ADODB_COUNTRECS;
1419 $ADODB_COUNTRECS = false;
1420 $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1421 $ADODB_COUNTRECS = $savec;
1424 if (defined('ADODB_PEAR')) {
1425 $cls = ADODB_PEAR_Error();
1431 $arr =& $rs->GetArray();
1439 * Return one row of sql statement. Recordset is disposed for you.
1441 * @param sql SQL statement
1442 * @param [inputarr] input bind array
1444 function &GetRow($sql,$inputarr=false)
1446 global $ADODB_COUNTRECS;
1447 $crecs = $ADODB_COUNTRECS;
1448 $ADODB_COUNTRECS = false;
1450 $rs =& $this->Execute($sql,$inputarr);
1452 $ADODB_COUNTRECS = $crecs;
1454 if (!$rs->EOF
) $arr = $rs->fields
;
1455 else $arr = array();
1464 function &CacheGetRow($secs2cache,$sql=false,$inputarr=false)
1466 $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1469 if (!$rs->EOF
) $arr = $rs->fields
;
1478 * Insert or replace a single record. Note: this is not the same as MySQL's replace.
1479 * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
1480 * Also note that no table locking is done currently, so it is possible that the
1481 * record be inserted twice by two programs...
1483 * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
1486 * $fieldArray associative array of data (you must quote strings yourself).
1487 * $keyCol the primary key field name or if compound key, array of field names
1488 * autoQuote set to true to use a hueristic to quote strings. Works with nulls and numbers
1489 * but does not work with dates nor SQL functions.
1490 * has_autoinc the primary key is an auto-inc field, so skip in insert.
1492 * Currently blob replace not supported
1494 * returns 0 = fail, 1 = update, 2 = insert
1497 function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false)
1499 global $ADODB_INCLUDED_LIB;
1500 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR
.'/adodb-lib.inc.php');
1502 return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);
1507 * Will select, getting rows from $offset (1-based), for $nrows.
1508 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1509 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1510 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1512 * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
1513 * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
1515 * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
1517 * @param [secs2cache] seconds to cache data, set to 0 to force query. This is optional
1519 * @param [offset] is the row to start calculations from (1-based)
1520 * @param [nrows] is the number of rows to get
1521 * @param [inputarr] array of bind variables
1522 * @return the recordset ($rs->databaseType == 'array')
1524 function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false)
1526 if (!is_numeric($secs2cache)) {
1527 if ($sql === false) $sql = -1;
1528 if ($offset == -1) $offset = false;
1529 // sql, nrows, offset,inputarr
1530 $rs =& $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs
);
1532 if ($sql === false) ADOConnection
::outp( "Warning: \$sql missing from CacheSelectLimit()");
1533 $rs =& $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
1540 * Flush cached recordsets that match a particular $sql statement.
1541 * If $sql == false, then we purge all files in the cache.
1545 * Flush cached recordsets that match a particular $sql statement.
1546 * If $sql == false, then we purge all files in the cache.
1548 function CacheFlush($sql=false,$inputarr=false)
1550 global $ADODB_CACHE_DIR;
1552 if ($this->memCache
) {
1553 global $ADODB_INCLUDED_MEMCACHE;
1556 if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR
.'/adodb-memcache.lib.inc.php');
1557 if ($sql) $key = $this->_gencachename($sql.serialize($inputarr),false,true);
1558 FlushMemCache($key, $this->memCacheHost
, $this->memCachePort
, $this->debug
);
1562 if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
1563 /*if (strncmp(PHP_OS,'WIN',3) === 0)
1564 $dir = str_replace('/', '\\', $ADODB_CACHE_DIR);
1566 $dir = $ADODB_CACHE_DIR;
1569 ADOConnection
::outp( "CacheFlush: $dir<br><pre>\n", $this->_dirFlush($dir),"</pre>");
1571 $this->_dirFlush($dir);
1576 global $ADODB_INCLUDED_CSV;
1577 if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR
.'/adodb-csvlib.inc.php');
1579 $f = $this->_gencachename($sql.serialize($inputarr),false);
1580 adodb_write_file($f,''); // is adodb_write_file needed?
1582 if ($this->debug
) ADOConnection
::outp( "CacheFlush: failed for $f");
1587 * Private function to erase all of the files and subdirectories in a directory.
1589 * Just specify the directory, and tell it if you want to delete the directory or just clear it out.
1590 * Note: $kill_top_level is used internally in the function to flush subdirectories.
1592 function _dirFlush($dir, $kill_top_level = false) {
1593 if(!$dh = @opendir
($dir)) return;
1595 while (($obj = readdir($dh))) {
1596 if($obj=='.' ||
$obj=='..')
1599 if (!@unlink
($dir.'/'.$obj))
1600 $this->_dirFlush($dir.'/'.$obj, true);
1602 if ($kill_top_level === true)
1608 function xCacheFlush($sql=false,$inputarr=false)
1610 global $ADODB_CACHE_DIR;
1612 if ($this->memCache
) {
1613 global $ADODB_INCLUDED_MEMCACHE;
1615 if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR
.'/adodb-memcache.lib.inc.php');
1616 if ($sql) $key = $this->_gencachename($sql.serialize($inputarr),false,true);
1617 flushmemCache($key, $this->memCacheHost
, $this->memCachePort
, $this->debug
);
1621 if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
1622 if (strncmp(PHP_OS
,'WIN',3) === 0) {
1623 $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
1625 //$cmd = 'find "'.$ADODB_CACHE_DIR.'" -type f -maxdepth 1 -print0 | xargs -0 rm -f';
1626 $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/[0-9a-f][0-9a-f]/';
1627 // old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`';
1630 ADOConnection
::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>");
1637 global $ADODB_INCLUDED_CSV;
1638 if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR
.'/adodb-csvlib.inc.php');
1640 $f = $this->_gencachename($sql.serialize($inputarr),false);
1641 adodb_write_file($f,''); // is adodb_write_file needed?
1643 if ($this->debug
) ADOConnection
::outp( "CacheFlush: failed for $f");
1648 * Private function to generate filename for caching.
1649 * Filename is generated based on:
1652 * - database type (oci8, ibase, ifx, etc)
1655 * - setFetchMode (adodb 4.23)
1657 * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
1658 * Assuming that we can have 50,000 files per directory with good performance,
1659 * then we can scale to 12.8 million unique cached recordsets. Wow!
1661 function _gencachename($sql,$createdir,$memcache=false)
1663 global $ADODB_CACHE_DIR;
1664 static $notSafeMode;
1666 if ($this->fetchMode
=== false) {
1667 global $ADODB_FETCH_MODE;
1668 $mode = $ADODB_FETCH_MODE;
1670 $mode = $this->fetchMode
;
1672 $m = md5($sql.$this->databaseType
.$this->database
.$this->user
.$mode);
1673 if ($memcache) return $m;
1675 if (!isset($notSafeMode)) $notSafeMode = !ini_get('safe_mode');
1676 $dir = ($notSafeMode) ?
$ADODB_CACHE_DIR.'/'.substr($m,0,2) : $ADODB_CACHE_DIR;
1678 if ($createdir && $notSafeMode && !file_exists($dir)) {
1680 if (!mkdir($dir,0771))
1681 if ($this->debug
) ADOConnection
::outp( "Unable to mkdir $dir for $sql");
1684 return $dir.'/adodb_'.$m.'.cache';
1689 * Execute SQL, caching recordsets.
1691 * @param [secs2cache] seconds to cache data, set to 0 to force query.
1692 * This is an optional parameter.
1693 * @param sql SQL statement to execute
1694 * @param [inputarr] holds the input data to bind to
1695 * @return RecordSet or false
1697 function &CacheExecute($secs2cache,$sql=false,$inputarr=false)
1701 if (!is_numeric($secs2cache)) {
1704 $secs2cache = $this->cacheSecs
;
1707 if (is_array($sql)) {
1713 if ($this->memCache
) {
1714 global $ADODB_INCLUDED_MEMCACHE;
1715 if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR
.'/adodb-memcache.lib.inc.php');
1716 $md5file = $this->_gencachename($sql.serialize($inputarr),false,true);
1718 global $ADODB_INCLUDED_CSV;
1719 if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR
.'/adodb-csvlib.inc.php');
1720 $md5file = $this->_gencachename($sql.serialize($inputarr),true);
1725 if ($secs2cache > 0){
1726 if ($this->memCache
)
1727 $rs = &getmemCache($md5file,$err,$secs2cache, $this->memCacheHost
, $this->memCachePort
);
1729 $rs = &csv2rs($md5file,$err,$secs2cache,$this->arrayClass
);
1730 $this->numCacheHits +
= 1;
1734 $this->numCacheMisses +
= 1;
1737 // no cached rs found
1739 if (get_magic_quotes_runtime() && !$this->memCache
) {
1740 ADOConnection
::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
1742 if ($this->debug
!== -1) ADOConnection
::outp( " $md5file cache failure: $err (see sql below)");
1745 $rs = &$this->Execute($sqlparam,$inputarr);
1747 if ($rs && $this->memCache
) {
1748 $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately
1749 if(!putmemCache($md5file, $rs, $this->memCacheHost
, $this->memCachePort
, $this->memCacheCompress
, $this->debug
)) {
1750 if ($fn = $this->raiseErrorFn
)
1751 $fn($this->databaseType
,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);
1752 if ($this->debug
) ADOConnection
::outp( " Cache write error");
1757 $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately
1758 $txt = _rs2serialize($rs,false,$sql); // serialize
1760 if (!adodb_write_file($md5file,$txt,$this->debug
)) {
1761 if ($fn = $this->raiseErrorFn
) {
1762 $fn($this->databaseType
,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);
1764 if ($this->debug
) ADOConnection
::outp( " Cache write error");
1766 if ($rs->EOF
&& !$eof) {
1768 //$rs = &csv2rs($md5file,$err);
1769 $rs->connection
= &$this; // Pablo suggestion
1773 if (!$this->memCache
)
1776 $this->_errorMsg
= '';
1777 $this->_errorCode
= 0;
1779 if ($this->fnCacheExecute
) {
1780 $fn = $this->fnCacheExecute
;
1781 $fn($this, $secs2cache, $sql, $inputarr);
1783 // ok, set cached object found
1784 $rs->connection
= &$this; // Pablo suggestion
1787 $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
1788 $ttl = $rs->timeCreated +
$secs2cache - time();
1789 $s = is_array($sql) ?
$sql[0] : $sql;
1790 if ($inBrowser) $s = '<i>'.htmlspecialchars($s).'</i>';
1792 ADOConnection
::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
1800 Similar to PEAR DB's autoExecute(), except that
1801 $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
1802 If $mode == 'UPDATE', then $where is compulsory as a safety measure.
1804 $forceUpdate means that even if the data has not changed, perform update.
1806 function& AutoExecute($table, $fields_values, $mode = 'INSERT', $where = FALSE, $forceUpdate=true, $magicq=false)
1809 $sql = 'SELECT * FROM '.$table;
1810 if ($where!==FALSE) $sql .= ' WHERE '.$where;
1811 else if ($mode == 'UPDATE' ||
$mode == 2 /* DB_AUTOQUERY_UPDATE */) {
1812 ADOConnection
::outp('AutoExecute: Illegal mode=UPDATE with empty WHERE clause');
1816 $rs =& $this->SelectLimit($sql,1);
1817 if (!$rs) return $false; // table does not exist
1818 $rs->tableName
= $table;
1820 switch((string) $mode) {
1823 $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq);
1827 $sql = $this->GetInsertSQL($rs, $fields_values, $magicq);
1830 ADOConnection
::outp("AutoExecute: Unknown mode=$mode");
1834 if ($sql) $ret = $this->Execute($sql);
1835 if ($ret) $ret = true;
1841 * Generates an Update Query based on an existing recordset.
1842 * $arrFields is an associative array of fields with the value
1843 * that should be assigned.
1845 * Note: This function should only be used on a recordset
1846 * that is run against a single table and sql should only
1847 * be a simple select stmt with no groupby/orderby/limit
1849 * "Jonathan Younger" <jyounger@unilab.com>
1851 function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null)
1853 global $ADODB_INCLUDED_LIB;
1855 //********************************************************//
1856 //This is here to maintain compatibility
1857 //with older adodb versions. Sets force type to force nulls if $forcenulls is set.
1858 if (!isset($force)) {
1859 global $ADODB_FORCE_TYPE;
1860 $force = $ADODB_FORCE_TYPE;
1862 //********************************************************//
1864 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR
.'/adodb-lib.inc.php');
1865 return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
1869 * Generates an Insert Query based on an existing recordset.
1870 * $arrFields is an associative array of fields with the value
1871 * that should be assigned.
1873 * Note: This function should only be used on a recordset
1874 * that is run against a single table.
1876 function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null)
1878 global $ADODB_INCLUDED_LIB;
1879 if (!isset($force)) {
1880 global $ADODB_FORCE_TYPE;
1881 $force = $ADODB_FORCE_TYPE;
1884 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR
.'/adodb-lib.inc.php');
1885 return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
1890 * Update a blob column, given a where clause. There are more sophisticated
1891 * blob handling functions that we could have implemented, but all require
1892 * a very complex API. Instead we have chosen something that is extremely
1893 * simple to understand and use.
1895 * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
1897 * Usage to update a $blobvalue which has a primary key blob_id=1 into a
1898 * field blobtable.blobcolumn:
1900 * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
1904 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
1905 * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
1908 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
1910 return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
1915 * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
1917 * $blobtype supports 'BLOB' and 'CLOB'
1919 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
1920 * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
1922 function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
1924 $fd = fopen($path,'rb');
1925 if ($fd === false) return false;
1926 $val = fread($fd,filesize($path));
1928 return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
1931 function BlobDecode($blob)
1936 function BlobEncode($blob)
1941 function SetCharSet($charset)
1946 function IfNull( $field, $ifNull )
1948 return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
1951 function LogSQL($enable=true)
1953 include_once(ADODB_DIR
.'/adodb-perf.inc.php');
1955 if ($enable) $this->fnExecute
= 'adodb_log_sql';
1956 else $this->fnExecute
= false;
1958 $old = $this->_logsql
;
1959 $this->_logsql
= $enable;
1960 if ($enable && !$old) $this->_affected
= false;
1964 function GetCharSet()
1971 * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
1973 * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
1974 * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
1976 function UpdateClob($table,$column,$val,$where)
1978 return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
1981 // not the fastest implementation - quick and dirty - jlim
1982 // for best performance, use the actual $rs->MetaType().
1983 function MetaType($t,$len=-1,$fieldobj=false)
1986 if (empty($this->_metars
)) {
1987 $rsclass = $this->rsPrefix
.$this->databaseType
;
1988 $this->_metars
=& new $rsclass(false,$this->fetchMode
);
1989 $this->_metars
->connection
=& $this;
1991 return $this->_metars
->MetaType($t,$len,$fieldobj);
1996 * Change the SQL connection locale to a specified locale.
1997 * This is used to get the date formats written depending on the client locale.
1999 function SetDateLocale($locale = 'En')
2001 $this->locale
= $locale;
2002 switch (strtoupper($locale))
2005 $this->fmtDate
="'Y-m-d'";
2006 $this->fmtTimeStamp
= "'Y-m-d H:i:s'";
2010 $this->fmtDate
= "'m-d-Y'";
2011 $this->fmtTimeStamp
= "'m-d-Y H:i:s'";
2018 $this->fmtDate
="'d-m-Y'";
2019 $this->fmtTimeStamp
= "'d-m-Y H:i:s'";
2023 $this->fmtDate
="'d.m.Y'";
2024 $this->fmtTimeStamp
= "'d.m.Y H:i:s'";
2028 $this->fmtDate
="'Y-m-d'";
2029 $this->fmtTimeStamp
= "'Y-m-d H:i:s'";
2034 function &GetActiveRecordsClass($class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false)
2036 global $_ADODB_ACTIVE_DBS;
2038 $save = $this->SetFetchMode(ADODB_FETCH_NUM
);
2039 if (empty($whereOrderBy)) $whereOrderBy = '1=1';
2040 $rows = $this->GetAll("select * from ".$table.' WHERE '.$whereOrderBy,$bindarr);
2041 $this->SetFetchMode($save);
2045 if ($rows === false) {
2050 if (!isset($_ADODB_ACTIVE_DBS)) {
2051 include(ADODB_DIR
.'/adodb-active-record.inc.php');
2053 if (!class_exists($class)) {
2054 ADOConnection
::outp("Unknown class $class in GetActiveRcordsClass()");
2058 foreach($rows as $row) {
2060 $obj =& new $class($table,$primkeyArr,$this);
2061 if ($obj->ErrorMsg()){
2062 $this->_errorMsg
= $obj->ErrorMsg();
2071 function &GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false)
2073 $arr =& $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr);
2082 $rez = $this->_close();
2083 $this->_connectionID
= false;
2088 * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
2090 * @return true if succeeded or false if database does not support transactions
2092 function BeginTrans() {return false;}
2094 /* set transaction mode */
2095 function SetTransactionMode( $transaction_mode )
2097 $transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider
);
2098 $this->_transmode
= $transaction_mode;
2101 http://msdn2.microsoft.com/en-US/ms173763.aspx
2102 http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html
2103 http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html
2104 http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm
2106 function MetaTransaction($mode,$db)
2108 $mode = strtoupper($mode);
2109 $mode = str_replace('ISOLATION LEVEL ','',$mode);
2113 case 'READ UNCOMMITTED':
2117 return 'ISOLATION LEVEL READ COMMITTED';
2119 return 'ISOLATION LEVEL READ UNCOMMITTED';
2123 case 'READ COMMITTED':
2124 return 'ISOLATION LEVEL READ COMMITTED';
2127 case 'REPEATABLE READ':
2131 return 'ISOLATION LEVEL SERIALIZABLE';
2133 return 'ISOLATION LEVEL REPEATABLE READ';
2137 case 'SERIALIZABLE':
2138 return 'ISOLATION LEVEL SERIALIZABLE';
2147 * If database does not support transactions, always return true as data always commited
2149 * @param $ok set to false to rollback transaction, true to commit
2151 * @return true/false.
2153 function CommitTrans($ok=true)
2158 * If database does not support transactions, rollbacks always fail, so return false
2160 * @return true/false.
2162 function RollbackTrans()
2167 * return the databases that the driver can connect to.
2168 * Some databases will return an empty array.
2170 * @return an array of database names.
2172 function MetaDatabases()
2174 global $ADODB_FETCH_MODE;
2176 if ($this->metaDatabasesSQL
) {
2177 $save = $ADODB_FETCH_MODE;
2178 $ADODB_FETCH_MODE = ADODB_FETCH_NUM
;
2180 if ($this->fetchMode
!== false) $savem = $this->SetFetchMode(false);
2182 $arr = $this->GetCol($this->metaDatabasesSQL
);
2183 if (isset($savem)) $this->SetFetchMode($savem);
2184 $ADODB_FETCH_MODE = $save;
2194 * @param ttype can either be 'VIEW' or 'TABLE' or false.
2195 * If false, both views and tables are returned.
2196 * "VIEW" returns only views
2197 * "TABLE" returns only tables
2198 * @param showSchema returns the schema/user with the table name, eg. USER.TABLE
2199 * @param mask is the input mask - only supported by oci8 and postgresql
2201 * @return array of tables for current database.
2203 function &MetaTables($ttype=false,$showSchema=false,$mask=false)
2205 global $ADODB_FETCH_MODE;
2212 if ($this->metaTablesSQL
) {
2213 $save = $ADODB_FETCH_MODE;
2214 $ADODB_FETCH_MODE = ADODB_FETCH_NUM
;
2216 if ($this->fetchMode
!== false) $savem = $this->SetFetchMode(false);
2218 $rs = $this->Execute($this->metaTablesSQL
);
2219 if (isset($savem)) $this->SetFetchMode($savem);
2220 $ADODB_FETCH_MODE = $save;
2222 if ($rs === false) return $false;
2223 $arr =& $rs->GetArray();
2226 if ($hast = ($ttype && isset($arr[0][1]))) {
2227 $showt = strncmp($ttype,'T',1);
2230 for ($i=0; $i < sizeof($arr); $i++
) {
2233 if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]);
2235 if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]);
2238 $arr2[] = trim($arr[$i][0]);
2247 function _findschema(&$table,&$schema)
2249 if (!$schema && ($at = strpos($table,'.')) !== false) {
2250 $schema = substr($table,0,$at);
2251 $table = substr($table,$at+
1);
2256 * List columns in a database as an array of ADOFieldObjects.
2257 * See top of file for definition of object.
2259 * @param $table table name to query
2260 * @param $normalize makes table name case-insensitive (required by some databases)
2261 * @schema is optional database schema to use - not supported by all databases.
2263 * @return array of ADOFieldObjects for current table.
2265 function &MetaColumns($table,$normalize=true)
2267 global $ADODB_FETCH_MODE;
2271 if (!empty($this->metaColumnsSQL
)) {
2274 $this->_findschema($table,$schema);
2276 $save = $ADODB_FETCH_MODE;
2277 $ADODB_FETCH_MODE = ADODB_FETCH_NUM
;
2278 if ($this->fetchMode
!== false) $savem = $this->SetFetchMode(false);
2279 $rs = $this->Execute(sprintf($this->metaColumnsSQL
,($normalize)?
strtoupper($table):$table));
2280 if (isset($savem)) $this->SetFetchMode($savem);
2281 $ADODB_FETCH_MODE = $save;
2282 if ($rs === false ||
$rs->EOF
) return $false;
2285 while (!$rs->EOF
) { //print_r($rs->fields);
2286 $fld = new ADOFieldObject();
2287 $fld->name
= $rs->fields
[0];
2288 $fld->type
= $rs->fields
[1];
2289 if (isset($rs->fields
[3]) && $rs->fields
[3]) {
2290 if ($rs->fields
[3]>0) $fld->max_length
= $rs->fields
[3];
2291 $fld->scale
= $rs->fields
[4];
2292 if ($fld->scale
>0) $fld->max_length +
= 1;
2294 $fld->max_length
= $rs->fields
[2];
2296 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM
) $retarr[] = $fld;
2297 else $retarr[strtoupper($fld->name
)] = $fld;
2307 * List indexes on a table as an array.
2308 * @param table table name to query
2309 * @param primary true to only show primary keys. Not actually used for most databases
2311 * @return array of indexes on current table. Each element represents an index, and is itself an associative array.
2314 [name_of_index] => Array
2316 [unique] => true or false
2324 function &MetaIndexes($table, $primary = false, $owner = false)
2331 * List columns names in a table as an array.
2332 * @param table table name to query
2334 * @return array of column names for current table.
2336 function &MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */)
2338 $objarr =& $this->MetaColumns($table);
2339 if (!is_array($objarr)) {
2347 foreach($objarr as $v)
2348 $arr[$v->attnum
] = $v->name
;
2351 foreach($objarr as $v) $arr[$i++
] = $v->name
;
2353 foreach($objarr as $v) $arr[strtoupper($v->name
)] = $v->name
;
2359 * Different SQL databases used different methods to combine strings together.
2360 * This function provides a wrapper.
2362 * param s variable number of string parameters
2364 * Usage: $db->Concat($str1,$str2);
2366 * @return concatenated string
2370 $arr = func_get_args();
2371 return implode($this->concat_operator
, $arr);
2376 * Converts a date "d" to a string that the database can understand.
2378 * @param d a date in Unix date time format.
2380 * @return date string in database date format
2384 if (empty($d) && $d !== 0) return 'null';
2386 if (is_string($d) && !is_numeric($d)) {
2387 if ($d === 'null' ||
strncmp($d,"'",1) === 0) return $d;
2388 if ($this->isoDates
) return "'$d'";
2389 $d = ADOConnection
::UnixDate($d);
2392 return adodb_date($this->fmtDate
,$d);
2395 function BindDate($d)
2397 $d = $this->DBDate($d);
2398 if (strncmp($d,"'",1)) return $d;
2400 return substr($d,1,strlen($d)-2);
2403 function BindTimeStamp($d)
2405 $d = $this->DBTimeStamp($d);
2406 if (strncmp($d,"'",1)) return $d;
2408 return substr($d,1,strlen($d)-2);
2413 * Converts a timestamp "ts" to a string that the database can understand.
2415 * @param ts a timestamp in Unix date time format.
2417 * @return timestamp string in database timestamp format
2419 function DBTimeStamp($ts)
2421 if (empty($ts) && $ts !== 0) return 'null';
2423 # strlen(14) allows YYYYMMDDHHMMSS format
2424 if (!is_string($ts) ||
(is_numeric($ts) && strlen($ts)<14))
2425 return adodb_date($this->fmtTimeStamp
,$ts);
2427 if ($ts === 'null') return $ts;
2428 if ($this->isoDates
&& strlen($ts) !== 14) return "'$ts'";
2430 $ts = ADOConnection
::UnixTimeStamp($ts);
2431 return adodb_date($this->fmtTimeStamp
,$ts);
2435 * Also in ADORecordSet.
2436 * @param $v is a date string in YYYY-MM-DD format
2438 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2440 function UnixDate($v)
2442 if (is_object($v)) {
2444 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2445 return adodb_mktime($v->hour
,$v->minute
,$v->second
,$v->month
,$v->day
, $v->year
);
2448 if (is_numeric($v) && strlen($v) !== 8) return $v;
2449 if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|",
2450 ($v), $rr)) return false;
2452 if ($rr[1] <= TIMESTAMP_FIRST_YEAR
) return 0;
2454 return @adodb_mktime
(0,0,0,$rr[2],$rr[3],$rr[1]);
2459 * Also in ADORecordSet.
2460 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
2462 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2464 function UnixTimeStamp($v)
2466 if (is_object($v)) {
2468 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2469 return adodb_mktime($v->hour
,$v->minute
,$v->second
,$v->month
,$v->day
, $v->year
);
2473 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
2474 ($v), $rr)) return false;
2476 if ($rr[1] <= TIMESTAMP_FIRST_YEAR
&& $rr[2]<= 1) return 0;
2479 if (!isset($rr[5])) return adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2480 return @adodb_mktime
($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
2484 * Also in ADORecordSet.
2486 * Format database date based on user defined format.
2488 * @param v is the character date in YYYY-MM-DD format, returned by database
2489 * @param fmt is the format to apply to it, using date()
2491 * @return a date formated as user desires
2494 function UserDate($v,$fmt='Y-m-d',$gmt=false)
2496 $tt = $this->UnixDate($v);
2498 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2499 if (($tt === false ||
$tt == -1) && $v != false) return $v;
2500 else if ($tt == 0) return $this->emptyDate
;
2501 else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
2504 return ($gmt) ?
adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2510 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
2511 * @param fmt is the format to apply to it, using date()
2513 * @return a timestamp formated as user desires
2515 function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false)
2517 if (!isset($v)) return $this->emptyTimeStamp
;
2518 # strlen(14) allows YYYYMMDDHHMMSS format
2519 if (is_numeric($v) && strlen($v)<14) return ($gmt) ?
adodb_gmdate($fmt,$v) : adodb_date($fmt,$v);
2520 $tt = $this->UnixTimeStamp($v);
2521 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2522 if (($tt === false ||
$tt == -1) && $v != false) return $v;
2523 if ($tt == 0) return $this->emptyTimeStamp
;
2524 return ($gmt) ?
adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2527 function escape($s,$magic_quotes=false)
2529 return $this->addq($s,$magic_quotes);
2533 * Quotes a string, without prefixing nor appending quotes.
2535 function addq($s,$magic_quotes=false)
2537 if (!$magic_quotes) {
2539 if ($this->replaceQuote
[0] == '\\'){
2540 // only since php 4.0.5
2541 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2542 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2544 return str_replace("'",$this->replaceQuote
,$s);
2547 // undo magic quotes for "
2548 $s = str_replace('\\"','"',$s);
2550 if ($this->replaceQuote
== "\\'") // ' already quoted, no need to change anything
2552 else {// change \' to '' for sybase/mssql
2553 $s = str_replace('\\\\','\\',$s);
2554 return str_replace("\\'",$this->replaceQuote
,$s);
2559 * Correctly quotes a string so that all strings are escaped. We prefix and append
2560 * to the string single-quotes.
2561 * An example is $db->qstr("Don't bother",magic_quotes_runtime());
2563 * @param s the string to quote
2564 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
2565 * This undoes the stupidity of magic quotes for GPC.
2567 * @return quoted string to be sent back to database
2569 function qstr($s,$magic_quotes=false)
2571 if (!$magic_quotes) {
2573 if ($this->replaceQuote
[0] == '\\'){
2574 // only since php 4.0.5
2575 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2576 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2578 return "'".str_replace("'",$this->replaceQuote
,$s)."'";
2581 // undo magic quotes for "
2582 $s = str_replace('\\"','"',$s);
2584 if ($this->replaceQuote
== "\\'") // ' already quoted, no need to change anything
2586 else {// change \' to '' for sybase/mssql
2587 $s = str_replace('\\\\','\\',$s);
2588 return "'".str_replace("\\'",$this->replaceQuote
,$s)."'";
2594 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2595 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2596 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2598 * See readme.htm#ex8 for an example of usage.
2601 * @param nrows is the number of rows per page to get
2602 * @param page is the page number to get (1-based)
2603 * @param [inputarr] array of bind variables
2604 * @param [secs2cache] is a private parameter only used by jlim
2605 * @return the recordset ($rs->databaseType == 'array')
2607 * NOTE: phpLens uses a different algorithm and does not use PageExecute().
2610 function &PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0)
2612 global $ADODB_INCLUDED_LIB;
2613 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR
.'/adodb-lib.inc.php');
2614 if ($this->pageExecuteCountRows
) $rs =& _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2615 else $rs =& _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2621 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2622 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2623 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2625 * @param secs2cache seconds to cache data, set to 0 to force query
2627 * @param nrows is the number of rows per page to get
2628 * @param page is the page number to get (1-based)
2629 * @param [inputarr] array of bind variables
2630 * @return the recordset ($rs->databaseType == 'array')
2632 function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false)
2634 /*switch($this->dataProvider) {
2638 default: $secs2cache = 0; break;
2640 $rs =& $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
2644 } // end class ADOConnection
2648 //==============================================================================================
2649 // CLASS ADOFetchObj
2650 //==============================================================================================
2653 * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
2658 //==============================================================================================
2659 // CLASS ADORecordSet_empty
2660 //==============================================================================================
2663 * Lightweight recordset when there are no records to be returned
2665 class ADORecordSet_empty
2667 var $dataProvider = 'empty';
2668 var $databaseType = false;
2670 var $_numOfRows = 0;
2671 var $fields = false;
2672 var $connection = false;
2673 function RowCount() {return 0;}
2674 function RecordCount() {return 0;}
2675 function PO_RecordCount(){return 0;}
2676 function Close(){return true;}
2677 function FetchRow() {return false;}
2678 function FieldCount(){ return 0;}
2682 //==============================================================================================
2683 // DATE AND TIME FUNCTIONS
2684 //==============================================================================================
2685 if (!defined('ADODB_DATE_VERSION')) include(ADODB_DIR
.'/adodb-time.inc.php');
2687 //==============================================================================================
2688 // CLASS ADORecordSet
2689 //==============================================================================================
2691 if (PHP_VERSION
< 5) include_once(ADODB_DIR
.'/adodb-php4.inc.php');
2692 else include_once(ADODB_DIR
.'/adodb-iterator.inc.php');
2694 * RecordSet class that represents the dataset returned by the database.
2695 * To keep memory overhead low, this class holds only the current row in memory.
2696 * No prefetching of data is done, so the RecordCount() can return -1 ( which
2697 * means recordcount not known).
2699 class ADORecordSet
extends ADODB_BASE_RS
{
2703 var $dataProvider = "native";
2704 var $fields = false; /// holds the current row data
2705 var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob
2706 /// in other words, we use a text area for editing.
2707 var $canSeek = false; /// indicates that seek is supported
2708 var $sql; /// sql text
2709 var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object.
2711 var $emptyTimeStamp = ' '; /// what to display when $time==0
2712 var $emptyDate = ' '; /// what to display when $time==0
2714 var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsets
2716 var $bind = false; /// used by Fields() to hold array - should be private?
2717 var $fetchMode; /// default fetch mode
2718 var $connection = false; /// the parent connection
2722 var $_numOfRows = -1; /** number of rows, or -1 */
2723 var $_numOfFields = -1; /** number of fields in recordset */
2724 var $_queryID = -1; /** This variable keeps the result link identifier. */
2725 var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */
2726 var $_closed = false; /** has recordset been closed */
2727 var $_inited = false; /** Init() should only be called once */
2728 var $_obj; /** Used by FetchObj */
2729 var $_names; /** Used by FetchObj */
2731 var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */
2732 var $_atFirstPage = false; /** Added by Iván Oliva to implement recordset pagination */
2733 var $_atLastPage = false; /** Added by Iván Oliva to implement recordset pagination */
2734 var $_lastPageNo = -1;
2735 var $_maxRecordCount = 0;
2736 var $datetime = false;
2741 * @param queryID this is the queryID returned by ADOConnection->_query()
2744 function ADORecordSet($queryID)
2746 $this->_queryID
= $queryID;
2753 if ($this->_inited
) return;
2754 $this->_inited
= true;
2755 if ($this->_queryID
) @$this->_initrs();
2757 $this->_numOfRows
= 0;
2758 $this->_numOfFields
= 0;
2760 if ($this->_numOfRows
!= 0 && $this->_numOfFields
&& $this->_currentRow
== -1) {
2762 $this->_currentRow
= 0;
2763 if ($this->EOF
= ($this->_fetch() === false)) {
2764 $this->_numOfRows
= 0; // _numOfRows could be -1
2773 * Generate a SELECT tag string from a recordset, and return the string.
2774 * If the recordset has 2 cols, we treat the 1st col as the containing
2775 * the text to display to the user, and 2nd col as the return value. Default
2776 * strings are compared with the FIRST column.
2778 * @param name name of SELECT tag
2779 * @param [defstr] the value to hilite. Use an array for multiple hilites for listbox.
2780 * @param [blank1stItem] true to leave the 1st item in list empty
2781 * @param [multiple] true for listbox, false for popup
2782 * @param [size] #rows to show for listbox. not used by popup
2783 * @param [selectAttr] additional attributes to defined for SELECT tag.
2784 * useful for holding javascript onChange='...' handlers.
2785 & @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with
2786 * column 0 (1st col) if this is true. This is not documented.
2790 * changes by glen.davies@cce.ac.nz to support multiple hilited items
2792 function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
2793 $size=0, $selectAttr='',$compareFields0=true)
2795 global $ADODB_INCLUDED_LIB;
2796 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR
.'/adodb-lib.inc.php');
2797 return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
2798 $size, $selectAttr,$compareFields0);
2804 * Generate a SELECT tag string from a recordset, and return the string.
2805 * If the recordset has 2 cols, we treat the 1st col as the containing
2806 * the text to display to the user, and 2nd col as the return value. Default
2807 * strings are compared with the SECOND column.
2810 function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='')
2812 return $this->GetMenu($name,$defstr,$blank1stItem,$multiple,
2813 $size, $selectAttr,false);
2819 function GetMenu3($name,$defstr='',$blank1stItem=true,$multiple=false,
2820 $size=0, $selectAttr='')
2822 global $ADODB_INCLUDED_LIB;
2823 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR
.'/adodb-lib.inc.php');
2824 return _adodb_getmenu_gp($this, $name,$defstr,$blank1stItem,$multiple,
2825 $size, $selectAttr,false);
2829 * return recordset as a 2-dimensional array.
2831 * @param [nRows] is the number of rows to return. -1 means every row.
2833 * @return an array indexed by the rows (0-based) from the recordset
2835 function &GetArray($nRows = -1)
2837 global $ADODB_EXTENSION; if ($ADODB_EXTENSION) {
2838 $results = adodb_getall($this,$nRows);
2843 while (!$this->EOF
&& $nRows != $cnt) {
2844 $results[] = $this->fields
;
2851 function &GetAll($nRows = -1)
2853 $arr =& $this->GetArray($nRows);
2858 * Some databases allow multiple recordsets to be returned. This function
2859 * will return true if there is a next recordset, or false if no more.
2861 function NextRecordSet()
2867 * return recordset as a 2-dimensional array.
2868 * Helper function for ADOConnection->SelectLimit()
2870 * @param offset is the row to start calculations from (1-based)
2871 * @param [nrows] is the number of rows to return
2873 * @return an array indexed by the rows (0-based) from the recordset
2875 function &GetArrayLimit($nrows,$offset=-1)
2878 $arr =& $this->GetArray($nrows);
2882 $this->Move($offset);
2886 while (!$this->EOF
&& $nrows != $cnt) {
2887 $results[$cnt++
] = $this->fields
;
2896 * Synonym for GetArray() for compatibility with ADO.
2898 * @param [nRows] is the number of rows to return. -1 means every row.
2900 * @return an array indexed by the rows (0-based) from the recordset
2902 function &GetRows($nRows = -1)
2904 $arr =& $this->GetArray($nRows);
2909 * return whole recordset as a 2-dimensional associative array if there are more than 2 columns.
2910 * The first column is treated as the key and is not included in the array.
2911 * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless
2912 * $force_array == true.
2914 * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional
2915 * array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,
2918 * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and
2919 * instead of returning array[col0] => array(remaining cols), return array[col0] => col1
2921 * @return an associative array indexed by the first column of the array,
2922 * or false if the data has less than 2 cols.
2924 function &GetAssoc($force_array = false, $first2cols = false)
2926 global $ADODB_EXTENSION;
2928 $cols = $this->_numOfFields
;
2933 $numIndex = isset($this->fields
[0]);
2936 if (!$first2cols && ($cols > 2 ||
$force_array)) {
2937 if ($ADODB_EXTENSION) {
2939 while (!$this->EOF
) {
2940 // $results[trim($this->fields[0])] = array_slice($this->fields, 1);
2941 // Fix for array_slice re-numbering numeric associative keys in PHP5
2942 $keys = array_slice(array_keys($this->fields
), 1);
2943 $sliced_array = array();
2945 foreach($keys as $key) {
2946 $sliced_array[$key] = $this->fields
[$key];
2949 $results[trim(reset($this->fields
))] = $sliced_array;
2951 adodb_movenext($this);
2954 while (!$this->EOF
) {
2955 $results[trim(reset($this->fields
))] = array_slice($this->fields
, 1);
2956 adodb_movenext($this);
2961 while (!$this->EOF
) {
2962 //$results[trim($this->fields[0])] = array_slice($this->fields, 1);
2963 // Fix for array_slice re-numbering numeric associative keys in PHP5
2964 $keys = array_slice(array_keys($this->fields
), 1);
2965 $sliced_array = array();
2967 foreach($keys as $key) {
2968 $sliced_array[$key] = $this->fields
[$key];
2971 $results[trim(reset($this->fields
))] = $sliced_array;
2975 while (!$this->EOF
) {
2976 $results[trim(reset($this->fields
))] = array_slice($this->fields
, 1);
2982 if ($ADODB_EXTENSION) {
2983 // return scalar values
2985 while (!$this->EOF
) {
2986 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
2987 $results[trim(($this->fields
[0]))] = $this->fields
[1];
2988 adodb_movenext($this);
2991 while (!$this->EOF
) {
2992 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
2993 $v1 = trim(reset($this->fields
));
2994 $v2 = ''.next($this->fields
);
2995 $results[$v1] = $v2;
2996 adodb_movenext($this);
3001 while (!$this->EOF
) {
3002 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3003 $results[trim(($this->fields
[0]))] = $this->fields
[1];
3007 while (!$this->EOF
) {
3008 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3009 $v1 = trim(reset($this->fields
));
3010 $v2 = ''.next($this->fields
);
3011 $results[$v1] = $v2;
3018 $ref =& $results; # workaround accelerator incompat with PHP 4.4 :(
3025 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
3026 * @param fmt is the format to apply to it, using date()
3028 * @return a timestamp formated as user desires
3030 function UserTimeStamp($v,$fmt='Y-m-d H:i:s')
3032 if (is_numeric($v) && strlen($v)<14) return adodb_date($fmt,$v);
3033 $tt = $this->UnixTimeStamp($v);
3034 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
3035 if (($tt === false ||
$tt == -1) && $v != false) return $v;
3036 if ($tt === 0) return $this->emptyTimeStamp
;
3037 return adodb_date($fmt,$tt);
3042 * @param v is the character date in YYYY-MM-DD format, returned by database
3043 * @param fmt is the format to apply to it, using date()
3045 * @return a date formated as user desires
3047 function UserDate($v,$fmt='Y-m-d')
3049 $tt = $this->UnixDate($v);
3050 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
3051 if (($tt === false ||
$tt == -1) && $v != false) return $v;
3052 else if ($tt == 0) return $this->emptyDate
;
3053 else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
3055 return adodb_date($fmt,$tt);
3060 * @param $v is a date string in YYYY-MM-DD format
3062 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
3064 function UnixDate($v)
3066 return ADOConnection
::UnixDate($v);
3071 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
3073 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
3075 function UnixTimeStamp($v)
3077 return ADOConnection
::UnixTimeStamp($v);
3082 * PEAR DB Compat - do not use internally
3086 return $this->Close();
3091 * PEAR DB compat, number of rows
3095 return $this->_numOfRows
;
3100 * PEAR DB compat, number of cols
3104 return $this->_numOfFields
;
3108 * Fetch a row, returning false if no more rows.
3109 * This is PEAR DB compat mode.
3111 * @return false or array containing the current record
3113 function &FetchRow()
3119 $arr = $this->fields
;
3120 $this->_currentRow++
;
3121 if (!$this->_fetch()) $this->EOF
= true;
3127 * Fetch a row, returning PEAR_Error if no more rows.
3128 * This is PEAR DB compat mode.
3130 * @return DB_OK or error object
3132 function FetchInto(&$arr)
3134 if ($this->EOF
) return (defined('PEAR_ERROR_RETURN')) ?
new PEAR_Error('EOF',-1): false;
3135 $arr = $this->fields
;
3142 * Move to the first row in the recordset. Many databases do NOT support this.
3144 * @return true or false
3146 function MoveFirst()
3148 if ($this->_currentRow
== 0) return true;
3149 return $this->Move(0);
3154 * Move to the last row in the recordset.
3156 * @return true or false
3160 if ($this->_numOfRows
>= 0) return $this->Move($this->_numOfRows
-1);
3161 if ($this->EOF
) return false;
3162 while (!$this->EOF
) {
3173 * Move to next record in the recordset.
3175 * @return true if there still rows available, or false if there are no more rows (EOF).
3180 $this->_currentRow++
;
3181 if ($this->_fetch()) return true;
3184 /* -- tested error handling when scrolling cursor -- seems useless.
3185 $conn = $this->connection;
3186 if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
3187 $fn = $conn->raiseErrorFn;
3188 $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
3196 * Random access to a specific row in the recordset. Some databases do not support
3197 * access to previous rows in the databases (no scrolling backwards).
3199 * @param rowNumber is the row to move to (0-based)
3201 * @return true if there still rows available, or false if there are no more rows (EOF).
3203 function Move($rowNumber = 0)
3206 if ($rowNumber == $this->_currentRow
) return true;
3207 if ($rowNumber >= $this->_numOfRows
)
3208 if ($this->_numOfRows
!= -1) $rowNumber = $this->_numOfRows
-2;
3210 if ($this->canSeek
) {
3212 if ($this->_seek($rowNumber)) {
3213 $this->_currentRow
= $rowNumber;
3214 if ($this->_fetch()) {
3222 if ($rowNumber < $this->_currentRow
) return false;
3223 global $ADODB_EXTENSION;
3224 if ($ADODB_EXTENSION) {
3225 while (!$this->EOF
&& $this->_currentRow
< $rowNumber) {
3226 adodb_movenext($this);
3230 while (! $this->EOF
&& $this->_currentRow
< $rowNumber) {
3231 $this->_currentRow++
;
3233 if (!$this->_fetch()) $this->EOF
= true;
3236 return !($this->EOF
);
3239 $this->fields
= false;
3246 * Get the value of a field in the current row by column name.
3247 * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
3249 * @param colname is the field to access
3251 * @return the value of $colname column
3253 function Fields($colname)
3255 return $this->fields
[$colname];
3258 function GetAssocKeys($upper=true)
3260 $this->bind
= array();
3261 for ($i=0; $i < $this->_numOfFields
; $i++
) {
3262 $o = $this->FetchField($i);
3263 if ($upper === 2) $this->bind
[$o->name
] = $i;
3264 else $this->bind
[($upper) ?
strtoupper($o->name
) : strtolower($o->name
)] = $i;
3269 * Use associative array to get fields array for databases that do not support
3270 * associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it
3272 * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC
3273 * before you execute your SQL statement, and access $rs->fields['col'] directly.
3275 * $upper 0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField
3277 function &GetRowAssoc($upper=1)
3280 // if (!$this->fields) return $record;
3283 $this->GetAssocKeys($upper);
3286 foreach($this->bind
as $k => $v) {
3287 $record[$k] = $this->fields
[$v];
3295 * Clean up recordset
3297 * @return true or false
3301 // free connection object - this seems to globally free the object
3302 // and not merely the reference, so don't do this...
3303 // $this->connection = false;
3304 if (!$this->_closed
) {
3305 $this->_closed
= true;
3306 return $this->_close();
3312 * synonyms RecordCount and RowCount
3314 * @return the number of rows or -1 if this is not supported
3316 function RecordCount() {return $this->_numOfRows
;}
3320 * If we are using PageExecute(), this will return the maximum possible rows
3321 * that can be returned when paging a recordset.
3323 function MaxRecordCount()
3325 return ($this->_maxRecordCount
) ?
$this->_maxRecordCount
: $this->RecordCount();
3329 * synonyms RecordCount and RowCount
3331 * @return the number of rows or -1 if this is not supported
3333 function RowCount() {return $this->_numOfRows
;}
3337 * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
3339 * @return the number of records from a previous SELECT. All databases support this.
3341 * But aware possible problems in multiuser environments. For better speed the table
3342 * must be indexed by the condition. Heavy test this before deploying.
3344 function PO_RecordCount($table="", $condition="") {
3346 $lnumrows = $this->_numOfRows
;
3347 // the database doesn't support native recordcount, so we do a workaround
3348 if ($lnumrows == -1 && $this->connection
) {
3350 if ($condition) $condition = " WHERE " . $condition;
3351 $resultrows = &$this->connection
->Execute("SELECT COUNT(*) FROM $table $condition");
3352 if ($resultrows) $lnumrows = reset($resultrows->fields
);
3360 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
3362 function CurrentRow() {return $this->_currentRow
;}
3365 * synonym for CurrentRow -- for ADO compat
3367 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
3369 function AbsolutePosition() {return $this->_currentRow
;}
3372 * @return the number of columns in the recordset. Some databases will set this to 0
3373 * if no records are returned, others will return the number of columns in the query.
3375 function FieldCount() {return $this->_numOfFields
;}
3379 * Get the ADOFieldObject of a specific column.
3381 * @param fieldoffset is the column position to access(0-based).
3383 * @return the ADOFieldObject for that column, or false.
3385 function &FetchField($fieldoffset)
3387 // must be defined by child class
3391 * Get the ADOFieldObjects of all columns in an array.
3394 function& FieldTypesArray()
3397 for ($i=0, $max=$this->_numOfFields
; $i < $max; $i++
)
3398 $arr[] = $this->FetchField($i);
3403 * Return the fields array of the current row as an object for convenience.
3404 * The default case is lowercase field names.
3406 * @return the object with the properties set to the fields of the current row
3408 function &FetchObj()
3410 $o =& $this->FetchObject(false);
3415 * Return the fields array of the current row as an object for convenience.
3416 * The default case is uppercase.
3418 * @param $isupper to set the object property names to uppercase
3420 * @return the object with the properties set to the fields of the current row
3422 function &FetchObject($isupper=true)
3424 if (empty($this->_obj
)) {
3425 $this->_obj
= new ADOFetchObj();
3426 $this->_names
= array();
3427 for ($i=0; $i <$this->_numOfFields
; $i++
) {
3428 $f = $this->FetchField($i);
3429 $this->_names
[] = $f->name
;
3433 if (PHP_VERSION
>= 5) $o = clone($this->_obj
);
3434 else $o = $this->_obj
;
3436 for ($i=0; $i <$this->_numOfFields
; $i++
) {
3437 $name = $this->_names
[$i];
3438 if ($isupper) $n = strtoupper($name);
3441 $o->$n = $this->Fields($name);
3447 * Return the fields array of the current row as an object for convenience.
3448 * The default is lower-case field names.
3450 * @return the object with the properties set to the fields of the current row,
3453 * Fixed bug reported by tim@orotech.net
3455 function &FetchNextObj()
3457 $o =& $this->FetchNextObject(false);
3463 * Return the fields array of the current row as an object for convenience.
3464 * The default is upper case field names.
3466 * @param $isupper to set the object property names to uppercase
3468 * @return the object with the properties set to the fields of the current row,
3471 * Fixed bug reported by tim@orotech.net
3473 function &FetchNextObject($isupper=true)
3476 if ($this->_numOfRows
!= 0 && !$this->EOF
) {
3477 $o = $this->FetchObject($isupper);
3478 $this->_currentRow++
;
3479 if ($this->_fetch()) return $o;
3486 * Get the metatype of the column. This is used for formatting. This is because
3487 * many databases use different names for the same type, so we transform the original
3488 * type to our standardised version which uses 1 character codes:
3490 * @param t is the type passed in. Normally is ADOFieldObject->type.
3491 * @param len is the maximum length of that field. This is because we treat character
3492 * fields bigger than a certain size as a 'B' (blob).
3493 * @param fieldobj is the field object returned by the database driver. Can hold
3494 * additional info (eg. primary_key for mysql).
3496 * @return the general type of the data:
3497 * C for character < 250 chars
3498 * X for teXt (>= 250 chars)
3500 * N for numeric or floating point
3503 * L for logical/Boolean
3505 * R for autoincrement counter/integer
3509 function MetaType($t,$len=-1,$fieldobj=false)
3511 if (is_object($t)) {
3513 $t = $fieldobj->type
;
3514 $len = $fieldobj->max_length
;
3516 // changed in 2.32 to hashing instead of switch stmt for speed...
3517 static $typeMap = array(
3528 'INTERVAL' => 'C', # Postgres
3529 'MACADDR' => 'C', # postgres
3544 'LONGBINARY' => 'B',
3547 'YEAR' => 'D', // mysql
3554 'TIMESTAMPTZ' => 'T',
3556 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
3565 'SERIAL' => 'R', // ifx
3566 'INT IDENTITY' => 'R',
3573 'INTEGER UNSIGNED' => 'I',
3579 'LONG' => 'N', // interbase is numeric, oci8 is blob
3580 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
3585 'DOUBLE PRECISION' => 'N',
3586 'SMALLFLOAT' => 'N',
3597 'SQLSMFLOAT' => 'N',
3600 'SQLDECIMAL' => 'N',
3605 'SQLINTERVAL' => 'N',
3610 "SQLSERIAL8" => 'I8',
3613 "SQLLVARCHAR" => 'X',
3618 $t = strtoupper($t);
3619 $tmap = (isset($typeMap[$t])) ?
$typeMap[$t] : 'N';
3623 // is the char field is too long, return as text field...
3624 if ($this->blobSize
>= 0) {
3625 if ($len > $this->blobSize
) return 'X';
3626 } else if ($len > 250) {
3632 if (!empty($fieldobj->primary_key
)) return 'R';
3639 if (isset($fieldobj->binary
))
3640 return ($fieldobj->binary
) ?
'B' : 'X';
3644 if (!empty($this->connection
) && !empty($this->connection
->datetime
)) return 'T';
3648 if ($t == 'LONG' && $this->dataProvider
== 'oci8') return 'B';
3654 function _close() {}
3657 * set/returns the current recordset page when paginating
3659 function AbsolutePage($page=-1)
3661 if ($page != -1) $this->_currentPage
= $page;
3662 return $this->_currentPage
;
3666 * set/returns the status of the atFirstPage flag when paginating
3668 function AtFirstPage($status=false)
3670 if ($status != false) $this->_atFirstPage
= $status;
3671 return $this->_atFirstPage
;
3674 function LastPageNo($page = false)
3676 if ($page != false) $this->_lastPageNo
= $page;
3677 return $this->_lastPageNo
;
3681 * set/returns the status of the atLastPage flag when paginating
3683 function AtLastPage($status=false)
3685 if ($status != false) $this->_atLastPage
= $status;
3686 return $this->_atLastPage
;
3689 } // end class ADORecordSet
3691 //==============================================================================================
3692 // CLASS ADORecordSet_array
3693 //==============================================================================================
3696 * This class encapsulates the concept of a recordset created in memory
3697 * as an array. This is useful for the creation of cached recordsets.
3699 * Note that the constructor is different from the standard ADORecordSet
3702 class ADORecordSet_array
extends ADORecordSet
3704 var $databaseType = 'array';
3706 var $_array; // holds the 2-dimensional data array
3707 var $_types; // the array of types of each column (C B I L M)
3708 var $_colnames; // names of each column in array
3709 var $_skiprow1; // skip 1st row because it holds column names
3710 var $_fieldobjects; // holds array of field objects
3711 var $canSeek = true;
3712 var $affectedrows = false;
3713 var $insertid = false;
3715 var $compat = false;
3720 function ADORecordSet_array($fakeid=1)
3722 global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;
3724 // fetch() on EOF does not delete $this->fields
3725 $this->compat
= !empty($ADODB_COMPAT_FETCH);
3726 $this->ADORecordSet($fakeid); // fake queryID
3727 $this->fetchMode
= $ADODB_FETCH_MODE;
3730 function _transpose()
3732 global $ADODB_INCLUDED_LIB;
3734 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR
.'/adodb-lib.inc.php');
3737 adodb_transpose($this->_array
, $newarr, $hdr);
3738 //adodb_pr($newarr);
3740 $this->_skiprow1
= false;
3741 $this->_array
=& $newarr;
3742 $this->_colnames
= $hdr;
3744 adodb_probetypes($newarr,$this->_types
);
3746 $this->_fieldobjects
= array();
3748 foreach($hdr as $k => $name) {
3749 $f = new ADOFieldObject();
3751 $f->type
= $this->_types
[$k];
3752 $f->max_length
= -1;
3753 $this->_fieldobjects
[] = $f;
3756 $this->fields
= reset($this->_array
);
3765 * @param array is a 2-dimensional array holding the data.
3766 * The first row should hold the column names
3767 * unless paramter $colnames is used.
3768 * @param typearr holds an array of types. These are the same types
3769 * used in MetaTypes (C,B,L,I,N).
3770 * @param [colnames] array of column names. If set, then the first row of
3771 * $array should not hold the column names.
3773 function InitArray($array,$typearr,$colnames=false)
3775 $this->_array
= $array;
3776 $this->_types
= $typearr;
3778 $this->_skiprow1
= false;
3779 $this->_colnames
= $colnames;
3781 $this->_skiprow1
= true;
3782 $this->_colnames
= $array[0];
3787 * Setup the Array and datatype file objects
3789 * @param array is a 2-dimensional array holding the data.
3790 * The first row should hold the column names
3791 * unless paramter $colnames is used.
3792 * @param fieldarr holds an array of ADOFieldObject's.
3794 function InitArrayFields(&$array,&$fieldarr)
3796 $this->_array
=& $array;
3797 $this->_skiprow1
= false;
3799 $this->_fieldobjects
=& $fieldarr;
3804 function &GetArray($nRows=-1)
3806 if ($nRows == -1 && $this->_currentRow
<= 0 && !$this->_skiprow1
) {
3807 return $this->_array
;
3809 $arr =& ADORecordSet
::GetArray($nRows);
3816 $this->_numOfRows
= sizeof($this->_array
);
3817 if ($this->_skiprow1
) $this->_numOfRows
-= 1;
3819 $this->_numOfFields
=(isset($this->_fieldobjects
)) ?
3820 sizeof($this->_fieldobjects
):sizeof($this->_types
);
3823 /* Use associative array to get fields array */
3824 function Fields($colname)
3826 $mode = isset($this->adodbFetchMode
) ?
$this->adodbFetchMode
: $this->fetchMode
;
3828 if ($mode & ADODB_FETCH_ASSOC
) {
3829 if (!isset($this->fields
[$colname])) $colname = strtolower($colname);
3830 return $this->fields
[$colname];
3833 $this->bind
= array();
3834 for ($i=0; $i < $this->_numOfFields
; $i++
) {
3835 $o = $this->FetchField($i);
3836 $this->bind
[strtoupper($o->name
)] = $i;
3839 return $this->fields
[$this->bind
[strtoupper($colname)]];
3842 function &FetchField($fieldOffset = -1)
3844 if (isset($this->_fieldobjects
)) {
3845 return $this->_fieldobjects
[$fieldOffset];
3847 $o = new ADOFieldObject();
3848 $o->name
= $this->_colnames
[$fieldOffset];
3849 $o->type
= $this->_types
[$fieldOffset];
3850 $o->max_length
= -1; // length not known
3855 function _seek($row)
3857 if (sizeof($this->_array
) && 0 <= $row && $row < $this->_numOfRows
) {
3858 $this->_currentRow
= $row;
3859 if ($this->_skiprow1
) $row +
= 1;
3860 $this->fields
= $this->_array
[$row];
3869 $this->_currentRow++
;
3871 $pos = $this->_currentRow
;
3873 if ($this->_numOfRows
<= $pos) {
3874 if (!$this->compat
) $this->fields
= false;
3876 if ($this->_skiprow1
) $pos +
= 1;
3877 $this->fields
= $this->_array
[$pos];
3888 $pos = $this->_currentRow
;
3890 if ($this->_numOfRows
<= $pos) {
3891 if (!$this->compat
) $this->fields
= false;
3894 if ($this->_skiprow1
) $pos +
= 1;
3895 $this->fields
= $this->_array
[$pos];
3904 } // ADORecordSet_array
3906 //==============================================================================================
3908 //==============================================================================================
3911 * Synonym for ADOLoadCode. Private function. Do not use.
3915 function ADOLoadDB($dbType)
3917 return ADOLoadCode($dbType);
3921 * Load the code for a specific database driver. Private function. Do not use.
3923 function ADOLoadCode($dbType)
3925 global $ADODB_LASTDB;
3927 if (!$dbType) return false;
3928 $db = strtolower($dbType);
3931 if (PHP_VERSION
>= 5) $db = 'ado5';
3935 case 'maxsql': $class = $db = 'mysqlt'; break;
3938 case 'pgsql': $class = $db = 'postgres7'; break;
3940 $class = $db; break;
3943 $file = ADODB_DIR
."/drivers/adodb-".$db.".inc.php";
3944 @include_once
($file);
3945 $ADODB_LASTDB = $class;
3946 if (class_exists("ADODB_" . $class)) return $class;
3948 //ADOConnection::outp(adodb_pr(get_declared_classes(),true));
3949 if (!file_exists($file)) ADOConnection
::outp("Missing file: $file");
3950 else ADOConnection
::outp("Syntax error in file: $file");
3955 * synonym for ADONewConnection for people like me who cannot remember the correct name
3957 function &NewADOConnection($db='')
3959 $tmp =& ADONewConnection($db);
3964 * Instantiate a new Connection class for a specific database driver.
3966 * @param [db] is the database Connection object to create. If undefined,
3967 * use the last database driver that was loaded by ADOLoadCode().
3969 * @return the freshly created instance of the Connection class.
3971 function &ADONewConnection($db='')
3973 GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB;
3975 if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
3976 $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER
: false;
3978 if ($at = strpos($db,'://')) {
3980 if (PHP_VERSION
< 5) $dsna = @parse_url
($db);
3982 $fakedsn = 'fake'.substr($db,$at);
3983 $dsna = @parse_url
($fakedsn);
3984 $dsna['scheme'] = substr($db,0,$at);
3986 if (strncmp($db,'pdo',3) == 0) {
3987 $sch = explode('_',$dsna['scheme']);
3988 if (sizeof($sch)>1) {
3989 $dsna['host'] = isset($dsna['host']) ?
rawurldecode($dsna['host']) : '';
3990 $dsna['host'] = rawurlencode($sch[1].':host='.rawurldecode($dsna['host']));
3991 $dsna['scheme'] = 'pdo';
3997 // special handling of oracle, which might not have host
3998 $db = str_replace('@/','@adodb-fakehost/',$db);
3999 $dsna = parse_url($db);
4000 if (!$dsna) return $false;
4003 $db = @$dsna['scheme'];
4004 if (!$db) return $false;
4005 $dsna['host'] = isset($dsna['host']) ?
rawurldecode($dsna['host']) : '';
4006 $dsna['user'] = isset($dsna['user']) ?
rawurldecode($dsna['user']) : '';
4007 $dsna['pass'] = isset($dsna['pass']) ?
rawurldecode($dsna['pass']) : '';
4008 $dsna['path'] = isset($dsna['path']) ?
rawurldecode(substr($dsna['path'],1)) : ''; # strip off initial /
4010 if (isset($dsna['query'])) {
4011 $opt1 = explode('&',$dsna['query']);
4012 foreach($opt1 as $k => $v) {
4013 $arr = explode('=',$v);
4014 $opt[$arr[0]] = isset($arr[1]) ?
rawurldecode($arr[1]) : 1;
4016 } else $opt = array();
4019 * phptype: Database backend used in PHP (mysql, odbc etc.)
4020 * dbsyntax: Database used with regards to SQL syntax etc.
4021 * protocol: Communication protocol to use (tcp, unix etc.)
4022 * hostspec: Host specification (hostname[:port])
4023 * database: Database to use on the DBMS server
4024 * username: User name for login
4025 * password: Password for login
4027 if (!empty($ADODB_NEWCONNECTION)) {
4028 $obj = $ADODB_NEWCONNECTION($db);
4032 if (!isset($ADODB_LASTDB)) $ADODB_LASTDB = '';
4033 if (empty($db)) $db = $ADODB_LASTDB;
4035 if ($db != $ADODB_LASTDB) $db = ADOLoadCode($db);
4038 if (isset($origdsn)) $db = $origdsn;
4042 $errorfn('ADONewConnection', 'ADONewConnection', -998,
4043 "could not load the database driver for '$db'",
4046 ADOConnection
::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false);
4051 $cls = 'ADODB_'.$db;
4052 if (!class_exists($cls)) {
4060 # constructor should not fail
4062 if ($errorfn) $obj->raiseErrorFn
= $errorfn;
4064 if (isset($dsna['port'])) $obj->port
= $dsna['port'];
4065 foreach($opt as $k => $v) {
4066 switch(strtolower($k)) {
4068 $nconnect = true; $persist = true; break;
4070 case 'persistent': $persist = $v; break;
4071 case 'debug': $obj->debug
= (integer) $v; break;
4073 case 'role': $obj->role
= $v; break;
4074 case 'dialect': $obj->dialect
= (integer) $v; break;
4075 case 'charset': $obj->charset
= $v; $obj->charSet
=$v; break;
4076 case 'buffers': $obj->buffers
= $v; break;
4077 case 'fetchmode': $obj->SetFetchMode($v); break;
4079 case 'charpage': $obj->charPage
= $v; break;
4081 case 'clientflags': $obj->clientFlags
= $v; break;
4082 #mysql, mysqli, postgres
4083 case 'port': $obj->port
= $v; break;
4085 case 'socket': $obj->socket
= $v; break;
4087 case 'nls_date_format': $obj->NLS_DATE_FORMAT
= $v; break;
4090 if (empty($persist))
4091 $ok = $obj->Connect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4092 else if (empty($nconnect))
4093 $ok = $obj->PConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4095 $ok = $obj->NConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4097 if (!$ok) return $false;
4105 // $perf == true means called by NewPerfMonitor(), otherwise for data dictionary
4106 function _adodb_getdriver($provider,$drivername,$perf=false)
4108 switch ($provider) {
4109 case 'odbtp': if (strncmp('odbtp_',$drivername,6)==0) return substr($drivername,6);
4110 case 'odbc' : if (strncmp('odbc_',$drivername,5)==0) return substr($drivername,5);
4111 case 'ado' : if (strncmp('ado_',$drivername,4)==0) return substr($drivername,4);
4112 case 'native': break;
4117 switch($drivername) {
4120 $drivername='mysql';
4124 $drivername = 'postgres';
4126 case 'firebird15': $drivername = 'firebird'; break;
4127 case 'oracle': $drivername = 'oci8'; break;
4128 case 'access': if ($perf) $drivername = ''; break;
4130 case 'sapdb' : break;
4132 $drivername = 'generic';
4138 function &NewPerfMonitor(&$conn)
4141 $drivername = _adodb_getdriver($conn->dataProvider
,$conn->databaseType
,true);
4142 if (!$drivername ||
$drivername == 'generic') return $false;
4143 include_once(ADODB_DIR
.'/adodb-perf.inc.php');
4144 @include_once
(ADODB_DIR
."/perf/perf-$drivername.inc.php");
4145 $class = "Perf_$drivername";
4146 if (!class_exists($class)) return $false;
4147 $perf = new $class($conn);
4152 function &NewDataDictionary(&$conn,$drivername=false)
4155 if (!$drivername) $drivername = _adodb_getdriver($conn->dataProvider
,$conn->databaseType
);
4157 include_once(ADODB_DIR
.'/adodb-lib.inc.php');
4158 include_once(ADODB_DIR
.'/adodb-datadict.inc.php');
4159 $path = ADODB_DIR
."/datadict/datadict-$drivername.inc.php";
4161 if (!file_exists($path)) {
4162 ADOConnection
::outp("Dictionary driver '$path' not available");
4165 include_once($path);
4166 $class = "ADODB2_$drivername";
4167 $dict = new $class();
4168 $dict->dataProvider
= $conn->dataProvider
;
4169 $dict->connection
= &$conn;
4170 $dict->upperName
= strtoupper($drivername);
4171 $dict->quote
= $conn->nameQuote
;
4172 if (!empty($conn->_connectionID
))
4173 $dict->serverInfo
= $conn->ServerInfo();
4181 Perform a print_r, with pre tags for better formatting.
4183 function adodb_pr($var,$as_string=false)
4185 if ($as_string) ob_start();
4187 if (isset($_SERVER['HTTP_USER_AGENT'])) {
4188 echo " <pre>\n";print_r($var);echo "</pre>\n";
4193 $s = ob_get_contents();
4200 Perform a stack-crawl and pretty print it.
4202 @param printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then).
4203 @param levels Number of levels to display
4205 function adodb_backtrace($printOrArr=true,$levels=9999)
4207 global $ADODB_INCLUDED_LIB;
4208 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR
.'/adodb-lib.inc.php');
4209 return _adodb_backtrace($printOrArr,$levels);