bug fix for developer demos
[openemr.git] / gacl / adodb / adodb.inc.php
blobd8bec49030caf6bb9d9c04b5e039e33917d361ab
1 <?php
2 /*
3 * Set tabs to 4 for best viewing.
4 *
5 * Latest version is available at http://adodb.sourceforge.net
6 *
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/
14 /**
15 \mainpage
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
20 you prefer.
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 //==============================================================================================
43 /**
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 //==============================================================================================
50 // GLOBAL VARIABLES
51 //==============================================================================================
53 GLOBAL
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 //==============================================================================================
62 // GLOBAL SETUP
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);
121 } else {
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);
136 $s = reset($src);
137 $d = reset($dest);
138 while ($s !== false) {
139 $data = str_replace($s,$d,$data);
140 $s = next($src);
141 $d = next($dest);
143 return $data;
146 function ADODB_Setup()
148 GLOBAL
149 $ADODB_vers, // database version
150 $ADODB_COUNTRECS, // count number of records returned - slows down query
151 $ADODB_CACHE_DIR, // directory to cache recordsets
152 $ADODB_FETCH_MODE,
153 $ADODB_FORCE_TYPE;
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';
161 } else {
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 //==============================================================================================
189 ADODB_Setup();
191 //==============================================================================================
192 // CLASS ADOFieldObject
193 //==============================================================================================
195 * Helper class for FetchFields -- holds info on a column
197 class ADOFieldObject {
198 var $name = '';
199 var $max_length=0;
200 var $type="";
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 {
234 // PUBLIC VARS
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 = '&nbsp;';
260 var $emptyTimeStamp = '&nbsp;';
261 var $lastInsID = false;
262 //--
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
271 //--
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
277 // memcache
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;
309 // PRIVATE VARS
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
327 * Constructor
329 function ADOConnection()
331 die('Virtual Class -- cannot instantiate');
334 function Version()
336 global $ADODB_vers;
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];
360 else return '';
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')) {
372 $fn = ADODB_OUTP;
373 $fn($msg,$newline);
374 return;
375 } else if (isset($ADODB_OUTP)) {
376 $fn = $ADODB_OUTP;
377 $fn($msg,$newline);
378 return;
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
391 function Time()
393 $rs =& $this->_Execute("select $this->sysTimeStamp");
394 if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields));
396 return false;
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;
418 if ($forceNew) {
419 if ($rez=$this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
420 } else {
421 if ($rez=$this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
423 if (isset($rez)) {
424 $err = $this->ErrorMsg();
425 if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
426 $ret = false;
427 } else {
428 $err = "Missing extension for ".$this->dataProvider;
429 $ret = 0;
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);
437 return $ret;
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;
483 if (isset($rez)) {
484 $err = $this->ErrorMsg();
485 if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
486 $ret = false;
487 } else {
488 $err = "Missing extension for ".$this->dataProvider;
489 $ret = 0;
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);
497 return $ret;
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)
524 return $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);
547 * PEAR DB Compat
549 function Quote($s)
551 return $this->qstr($s,false);
555 Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de>
557 function QMagic($s)
559 return $this->qstr($s,get_magic_quotes_gpc());
562 function q(&$s)
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)
594 return false;
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;
625 return $old;
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();
636 return $rs;
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();
647 return $rs;
652 * PEAR DB Compat - do not use internally
654 function Disconnect()
656 return $this->Close();
660 Returns placeholder for parameter, eg.
661 $DB->Param('a')
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')
670 return '?';
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);
691 Usage in oracle
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);
695 $db->Execute();
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)
707 return false;
711 function IgnoreErrors($saveErrs=false)
713 if (!$saveErrs) {
714 $saveErrs = array($this->raiseErrorFn,$this->_transOK);
715 $this->raiseErrorFn = false;
716 return $saveErrs;
717 } else {
718 $this->raiseErrorFn = $saveErrs[0];
719 $this->_transOK = $saveErrs[1];
724 Improved method of initiating a transaction. Used together with CompleteTrans().
725 Advantages include:
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;
737 return;
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");
745 $this->BeginTrans();
746 $this->transOff = 1;
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;
762 return true;
764 $this->raiseErrorFn = $this->_oldRaiseFn;
766 $this->transOff = 0;
767 if ($this->_transOK && $autoComplete) {
768 if (!$this->CommitTrans()) {
769 $this->_transOK = false;
770 if ($this->debug) ADOConnection::outp("Smart Commit failed");
771 } else
772 if ($this->debug) ADOConnection::outp("Smart Commit occurred");
773 } else {
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.
785 function FailTrans()
787 if ($this->debug)
788 if ($this->transOff == 0) {
789 ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
790 } else {
791 ADOConnection::outp("FailTrans was called");
792 adodb_backtrace();
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;
803 return false;
807 * Execute SQL
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;
820 if ($inputarr) {
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
827 unset($element0);
829 if (!is_array($sql) && !$this->_bindInputArray) {
830 $sqlarr = explode('?',$sql);
832 if (!$array_2d) $inputarr = array($inputarr);
833 foreach($inputarr as $arr) {
834 $sql = ''; $i = 0;
835 //Use each() instead of foreach to reduce memory usage -mikefedyk
836 while(list(, $v) = each($arr)) {
837 $sql .= $sqlarr[$i];
838 // from Ron Baldwin <ron.baldwin#sourceprose.com>
839 // Only quote string types
840 $typ = gettype($v);
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)
852 $sql .= 'NULL';
853 else
854 $sql .= $v;
855 $i += 1;
857 if (isset($sqlarr[$i])) {
858 $sql .= $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;
866 } else {
867 if ($array_2d) {
868 if (is_string($sql))
869 $stmt = $this->Prepare($sql);
870 else
871 $stmt = $sql;
873 foreach($inputarr as $arr) {
874 $ret =& $this->_Execute($stmt,$arr);
875 if (!$ret) return $ret;
877 } else {
878 $ret =& $this->_Execute($sql,$inputarr);
881 } else {
882 $ret =& $this->_Execute($sql,false);
885 return $ret;
889 function &_Execute($sql,$inputarr=false)
891 if ($this->debug) {
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);
895 } else {
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;
906 if ($fn) {
907 $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
909 $false = false;
910 return $false;
913 if ($this->_queryID === true) { // return simplified recordset for inserts/updates/deletes with lower overhead
914 $rs =& new ADORecordSet_empty();
915 return $rs;
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
922 $rs->Init();
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) {
928 if (!$rs->EOF) {
929 $rs = &$this->_rs2rs($rs,-1,-1,!is_array($sql));
930 $rs->_queryID = $this->_queryID;
931 } else
932 $rs->_numOfRows = 0;
935 return $rs;
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;
973 if (!$rs) {
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();
983 return $this->genID;
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);
995 if ($this->debug) {
996 ADOConnection::outp( '<p>Insert_ID error</p>');
997 adodb_backtrace();
999 return false;
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);
1013 } else {
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);
1032 return false;
1037 * @return the last error message
1039 function ErrorMsg()
1041 if ($this->_errorMsg) return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
1042 else return '';
1047 * @return the last error number. Normally 0 means no error.
1049 function ErrorNo()
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
1073 $p = array();
1074 $objs =& $this->MetaColumns($table);
1075 if ($objs) {
1076 foreach($objs as $v) {
1077 if (!empty($v->primary_key))
1078 $p[] = $v->name;
1081 if (sizeof($p)) return $p;
1082 if (function_exists('ADODB_VIEW_PRIMARYKEYS'))
1083 return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);
1084 return false;
1088 * @returns assoc array where keys are tables, and values are foreign keys
1090 function MetaForeignKeys($table, $owner=false, $upper=false)
1092 return 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)
1101 {return false;}
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.
1109 * eg.
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
1116 * @param sql
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);
1132 if ($offset <= 0) {
1134 // access includes ties in result
1135 if ($isaccess) {
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);
1141 } else {
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);
1148 } else {
1149 $sql = preg_replace(
1150 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1152 } else {
1153 $nn = $nrows + $offset;
1154 if ($isaccess || $ismssql) {
1155 $sql = preg_replace(
1156 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1157 } else {
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;
1171 if ($offset>0){
1172 if ($secs2cache != 0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1173 else $rs = &$this->Execute($sql,$inputarr);
1174 } else {
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);
1182 //print_r($rs);
1183 return $rs;
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);
1194 $ignore = false;
1195 $rs2->connection =& $ignore;
1197 return $rs2;
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)
1212 if (! $rs) {
1213 $false = false;
1214 return $false;
1216 $dbtype = $rs->databaseType;
1217 if (!$dbtype) {
1218 $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?
1219 return $rs;
1221 if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {
1222 $rs->MoveFirst();
1223 $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?
1224 return $rs;
1226 $flds = array();
1227 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
1228 $flds[] = $rs->FetchField($i);
1231 $arr =& $rs->GetArrayLimit($nrows,$offset);
1232 //print_r($arr);
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;
1243 return $rs2;
1247 * Return all rows. Compat with PEAR DB
1249 function &GetAll($sql, $inputarr=false)
1251 $arr =& $this->GetArray($sql,$inputarr);
1252 return $arr;
1255 function &GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false)
1257 $rs =& $this->Execute($sql, $inputarr);
1258 if (!$rs) {
1259 $false = false;
1260 return $false;
1262 $arr =& $rs->GetAssoc($force_array,$first2cols);
1263 return $arr;
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);
1273 if (!$rs) {
1274 $false = false;
1275 return $false;
1277 $arr =& $rs->GetAssoc($force_array,$first2cols);
1278 return $arr;
1282 * Return first element of first row of sql statement. Recordset is disposed
1283 * for you.
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;
1294 $ret = false;
1295 $rs = &$this->Execute($sql,$inputarr);
1296 if ($rs) {
1297 if (!$rs->EOF) $ret = reset($rs->fields);
1298 $rs->Close();
1300 $ADODB_COUNTRECS = $crecs;
1301 return $ret;
1304 function CacheGetOne($secs2cache,$sql=false,$inputarr=false)
1306 $ret = false;
1307 $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1308 if ($rs) {
1309 if (!$rs->EOF) $ret = reset($rs->fields);
1310 $rs->Close();
1313 return $ret;
1316 function GetCol($sql, $inputarr = false, $trim = false)
1318 $rv = false;
1319 $rs = &$this->Execute($sql, $inputarr);
1320 if ($rs) {
1321 $rv = array();
1322 if ($trim) {
1323 while (!$rs->EOF) {
1324 $rv[] = trim(reset($rs->fields));
1325 $rs->MoveNext();
1327 } else {
1328 while (!$rs->EOF) {
1329 $rv[] = reset($rs->fields);
1330 $rs->MoveNext();
1333 $rs->Close();
1335 return $rv;
1338 function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false)
1340 $rv = false;
1341 $rs = &$this->CacheExecute($secs, $sql, $inputarr);
1342 if ($rs) {
1343 if ($trim) {
1344 while (!$rs->EOF) {
1345 $rv[] = trim(reset($rs->fields));
1346 $rs->MoveNext();
1348 } else {
1349 while (!$rs->EOF) {
1350 $rv[] = reset($rs->fields);
1351 $rs->MoveNext();
1354 $rs->Close();
1356 return $rv;
1359 function &Transpose(&$rs)
1361 $rs2 =& $this->_rs2rs($rs);
1362 $false = false;
1363 if (!$rs2) return $false;
1365 $rs2->_transpose();
1366 return $rs2;
1370 Calculate the offset of a date for a particular database and generate
1371 appropriate SQL. Useful for calculating future/past dates and storing
1372 in a database.
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;
1396 if (!$rs)
1397 if (defined('ADODB_PEAR')) {
1398 $cls = ADODB_PEAR_Error();
1399 return $cls;
1400 } else {
1401 $false = false;
1402 return $false;
1404 $arr =& $rs->GetArray();
1405 $rs->Close();
1406 return $arr;
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;
1423 if (!$rs)
1424 if (defined('ADODB_PEAR')) {
1425 $cls = ADODB_PEAR_Error();
1426 return $cls;
1427 } else {
1428 $false = false;
1429 return $false;
1431 $arr =& $rs->GetArray();
1432 $rs->Close();
1433 return $arr;
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;
1453 if ($rs) {
1454 if (!$rs->EOF) $arr = $rs->fields;
1455 else $arr = array();
1456 $rs->Close();
1457 return $arr;
1460 $false = false;
1461 return $false;
1464 function &CacheGetRow($secs2cache,$sql=false,$inputarr=false)
1466 $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1467 if ($rs) {
1468 $arr = false;
1469 if (!$rs->EOF) $arr = $rs->fields;
1470 $rs->Close();
1471 return $arr;
1473 $false = false;
1474 return $false;
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');
1485 * $table table name
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.
1511 * eg.
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
1518 * @param sql
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);
1531 } else {
1532 if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()");
1533 $rs =& $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
1535 return $rs;
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;
1555 $key = false;
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);
1559 return;
1562 if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
1563 /*if (strncmp(PHP_OS,'WIN',3) === 0)
1564 $dir = str_replace('/', '\\', $ADODB_CACHE_DIR);
1565 else */
1566 $dir = $ADODB_CACHE_DIR;
1568 if ($this->debug) {
1569 ADOConnection::outp( "CacheFlush: $dir<br><pre>\n", $this->_dirFlush($dir),"</pre>");
1570 } else {
1571 $this->_dirFlush($dir);
1573 return;
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?
1581 if (!@unlink($f)) {
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=='..')
1597 continue;
1599 if (!@unlink($dir.'/'.$obj))
1600 $this->_dirFlush($dir.'/'.$obj, true);
1602 if ($kill_top_level === true)
1603 @rmdir($dir);
1604 return true;
1608 function xCacheFlush($sql=false,$inputarr=false)
1610 global $ADODB_CACHE_DIR;
1612 if ($this->memCache) {
1613 global $ADODB_INCLUDED_MEMCACHE;
1614 $key = false;
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);
1618 return;
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';
1624 } else {
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`';
1629 if ($this->debug) {
1630 ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>");
1631 } else {
1632 exec($cmd);
1634 return;
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?
1642 if (!@unlink($f)) {
1643 if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f");
1648 * Private function to generate filename for caching.
1649 * Filename is generated based on:
1651 * - sql statement
1652 * - database type (oci8, ibase, ifx, etc)
1653 * - database name
1654 * - userid
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;
1669 } else {
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)) {
1679 $oldu = umask(0);
1680 if (!mkdir($dir,0771))
1681 if ($this->debug) ADOConnection::outp( "Unable to mkdir $dir for $sql");
1682 umask($oldu);
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)) {
1702 $inputarr = $sql;
1703 $sql = $secs2cache;
1704 $secs2cache = $this->cacheSecs;
1707 if (is_array($sql)) {
1708 $sqlparam = $sql;
1709 $sql = $sql[0];
1710 } else
1711 $sqlparam = $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);
1717 } else {
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);
1723 $err = '';
1725 if ($secs2cache > 0){
1726 if ($this->memCache)
1727 $rs = &getmemCache($md5file,$err,$secs2cache, $this->memCacheHost, $this->memCachePort);
1728 else
1729 $rs = &csv2rs($md5file,$err,$secs2cache,$this->arrayClass);
1730 $this->numCacheHits += 1;
1731 } else {
1732 $err='Timeout 1';
1733 $rs = false;
1734 $this->numCacheMisses += 1;
1736 if (!$rs) {
1737 // no cached rs found
1738 if ($this->debug) {
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");
1754 } else
1755 if ($rs) {
1756 $eof = $rs->EOF;
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) {
1767 $rs->MoveFirst();
1768 //$rs = &csv2rs($md5file,$err);
1769 $rs->connection = &$this; // Pablo suggestion
1772 } else
1773 if (!$this->memCache)
1774 @unlink($md5file);
1775 } else {
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
1785 if ($this->debug){
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 ]");
1795 return $rs;
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)
1808 $false = 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');
1813 return $false;
1816 $rs =& $this->SelectLimit($sql,1);
1817 if (!$rs) return $false; // table does not exist
1818 $rs->tableName = $table;
1820 switch((string) $mode) {
1821 case 'UPDATE':
1822 case '2':
1823 $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq);
1824 break;
1825 case 'INSERT':
1826 case '1':
1827 $sql = $this->GetInsertSQL($rs, $fields_values, $magicq);
1828 break;
1829 default:
1830 ADOConnection::outp("AutoExecute: Unknown mode=$mode");
1831 return $false;
1833 $ret = false;
1834 if ($sql) $ret = $this->Execute($sql);
1835 if ($ret) $ret = true;
1836 return $ret;
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');
1902 * Insert example:
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;
1914 * Usage:
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));
1927 fclose($fd);
1928 return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
1931 function BlobDecode($blob)
1933 return $blob;
1936 function BlobEncode($blob)
1938 return $blob;
1941 function SetCharSet($charset)
1943 return false;
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;
1961 return $old;
1964 function GetCharSet()
1966 return false;
1970 * Usage:
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))
2004 case 'EN':
2005 $this->fmtDate="'Y-m-d'";
2006 $this->fmtTimeStamp = "'Y-m-d H:i:s'";
2007 break;
2009 case 'US':
2010 $this->fmtDate = "'m-d-Y'";
2011 $this->fmtTimeStamp = "'m-d-Y H:i:s'";
2012 break;
2014 case 'NL':
2015 case 'FR':
2016 case 'RO':
2017 case 'IT':
2018 $this->fmtDate="'d-m-Y'";
2019 $this->fmtTimeStamp = "'d-m-Y H:i:s'";
2020 break;
2022 case 'GE':
2023 $this->fmtDate="'d.m.Y'";
2024 $this->fmtTimeStamp = "'d.m.Y H:i:s'";
2025 break;
2027 default:
2028 $this->fmtDate="'Y-m-d'";
2029 $this->fmtTimeStamp = "'Y-m-d H:i:s'";
2030 break;
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);
2043 $false = false;
2045 if ($rows === false) {
2046 return $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()");
2055 return $false;
2057 $arr = array();
2058 foreach($rows as $row) {
2060 $obj =& new $class($table,$primkeyArr,$this);
2061 if ($obj->ErrorMsg()){
2062 $this->_errorMsg = $obj->ErrorMsg();
2063 return $false;
2065 $obj->Set($row);
2066 $arr[] =& $obj;
2068 return $arr;
2071 function &GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false)
2073 $arr =& $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr);
2074 return $arr;
2078 * Close Connection
2080 function Close()
2082 $rez = $this->_close();
2083 $this->_connectionID = false;
2084 return $rez;
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);
2111 switch($mode) {
2113 case 'READ UNCOMMITTED':
2114 switch($db) {
2115 case 'oci8':
2116 case 'oracle':
2117 return 'ISOLATION LEVEL READ COMMITTED';
2118 default:
2119 return 'ISOLATION LEVEL READ UNCOMMITTED';
2121 break;
2123 case 'READ COMMITTED':
2124 return 'ISOLATION LEVEL READ COMMITTED';
2125 break;
2127 case 'REPEATABLE READ':
2128 switch($db) {
2129 case 'oci8':
2130 case 'oracle':
2131 return 'ISOLATION LEVEL SERIALIZABLE';
2132 default:
2133 return 'ISOLATION LEVEL REPEATABLE READ';
2135 break;
2137 case 'SERIALIZABLE':
2138 return 'ISOLATION LEVEL SERIALIZABLE';
2139 break;
2141 default:
2142 return $mode;
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)
2154 { return true;}
2158 * If database does not support transactions, rollbacks always fail, so return false
2160 * @return true/false.
2162 function RollbackTrans()
2163 { return false;}
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;
2186 return $arr;
2189 return false;
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;
2208 $false = false;
2209 if ($mask) {
2210 return $false;
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();
2224 $arr2 = array();
2226 if ($hast = ($ttype && isset($arr[0][1]))) {
2227 $showt = strncmp($ttype,'T',1);
2230 for ($i=0; $i < sizeof($arr); $i++) {
2231 if ($hast) {
2232 if ($showt == 0) {
2233 if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]);
2234 } else {
2235 if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]);
2237 } else
2238 $arr2[] = trim($arr[$i][0]);
2240 $rs->Close();
2241 return $arr2;
2243 return $false;
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;
2269 $false = false;
2271 if (!empty($this->metaColumnsSQL)) {
2273 $schema = false;
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;
2284 $retarr = array();
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;
2293 } else
2294 $fld->max_length = $rs->fields[2];
2296 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
2297 else $retarr[strtoupper($fld->name)] = $fld;
2298 $rs->MoveNext();
2300 $rs->Close();
2301 return $retarr;
2303 return $false;
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.
2313 Array (
2314 [name_of_index] => Array
2316 [unique] => true or false
2317 [columns] => Array
2319 [0] => firstname
2320 [1] => lastname
2324 function &MetaIndexes($table, $primary = false, $owner = false)
2326 $false = false;
2327 return $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)) {
2340 $false = false;
2341 return $false;
2343 $arr = array();
2344 if ($numIndexes) {
2345 $i = 0;
2346 if ($useattnum) {
2347 foreach($objarr as $v)
2348 $arr[$v->attnum] = $v->name;
2350 } else
2351 foreach($objarr as $v) $arr[$i++] = $v->name;
2352 } else
2353 foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name;
2355 return $arr;
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
2368 function Concat()
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
2382 function DBDate($d)
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)) {
2443 // odbtp support
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;
2453 // h-m-s-MM-DD-YY
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)) {
2467 // odbtp support
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);
2472 if (!preg_match(
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;
2478 // h-m-s-MM-DD-YY
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
2551 return $s;
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
2585 return "'$s'";
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.
2600 * @param sql
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);
2616 return $rs;
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
2626 * @param sql
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) {
2635 case 'postgres':
2636 case 'mysql':
2637 break;
2638 default: $secs2cache = 0; break;
2640 $rs =& $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
2641 return $rs;
2644 } // end class ADOConnection
2648 //==============================================================================================
2649 // CLASS ADOFetchObj
2650 //==============================================================================================
2653 * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
2655 class ADOFetchObj {
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;
2669 var $EOF = true;
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;}
2679 function Init() {}
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 {
2701 * public variables
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 = '&nbsp;'; /// what to display when $time==0
2712 var $emptyDate = '&nbsp;'; /// what to display when $time==0
2713 var $debug = false;
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
2720 * private variables
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;
2739 * Constructor
2741 * @param queryID this is the queryID returned by ADOConnection->_query()
2744 function ADORecordSet($queryID)
2746 $this->_queryID = $queryID;
2751 function Init()
2753 if ($this->_inited) return;
2754 $this->_inited = true;
2755 if ($this->_queryID) @$this->_initrs();
2756 else {
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
2766 } else {
2767 $this->EOF = true;
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.
2788 * @return HTML
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);
2817 Grouped Menu
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);
2839 return $results;
2841 $results = array();
2842 $cnt = 0;
2843 while (!$this->EOF && $nRows != $cnt) {
2844 $results[] = $this->fields;
2845 $this->MoveNext();
2846 $cnt++;
2848 return $results;
2851 function &GetAll($nRows = -1)
2853 $arr =& $this->GetArray($nRows);
2854 return $arr;
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()
2863 return false;
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)
2877 if ($offset <= 0) {
2878 $arr =& $this->GetArray($nrows);
2879 return $arr;
2882 $this->Move($offset);
2884 $results = array();
2885 $cnt = 0;
2886 while (!$this->EOF && $nrows != $cnt) {
2887 $results[$cnt++] = $this->fields;
2888 $this->MoveNext();
2891 return $results;
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);
2905 return $arr;
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,
2916 * read the source.
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;
2929 if ($cols < 2) {
2930 $false = false;
2931 return $false;
2933 $numIndex = isset($this->fields[0]);
2934 $results = array();
2936 if (!$first2cols && ($cols > 2 || $force_array)) {
2937 if ($ADODB_EXTENSION) {
2938 if ($numIndex) {
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);
2953 } else {
2954 while (!$this->EOF) {
2955 $results[trim(reset($this->fields))] = array_slice($this->fields, 1);
2956 adodb_movenext($this);
2959 } else {
2960 if ($numIndex) {
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;
2972 $this->MoveNext();
2974 } else {
2975 while (!$this->EOF) {
2976 $results[trim(reset($this->fields))] = array_slice($this->fields, 1);
2977 $this->MoveNext();
2981 } else {
2982 if ($ADODB_EXTENSION) {
2983 // return scalar values
2984 if ($numIndex) {
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);
2990 } else {
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);
2999 } else {
3000 if ($numIndex) {
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];
3004 $this->MoveNext();
3006 } else {
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;
3012 $this->MoveNext();
3018 $ref =& $results; # workaround accelerator incompat with PHP 4.4 :(
3019 return $ref;
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
3084 function Free()
3086 return $this->Close();
3091 * PEAR DB compat, number of rows
3093 function NumRows()
3095 return $this->_numOfRows;
3100 * PEAR DB compat, number of cols
3102 function NumCols()
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()
3115 if ($this->EOF) {
3116 $false = false;
3117 return $false;
3119 $arr = $this->fields;
3120 $this->_currentRow++;
3121 if (!$this->_fetch()) $this->EOF = true;
3122 return $arr;
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;
3136 $this->MoveNext();
3137 return 1; // DB_OK
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
3158 function MoveLast()
3160 if ($this->_numOfRows >= 0) return $this->Move($this->_numOfRows-1);
3161 if ($this->EOF) return false;
3162 while (!$this->EOF) {
3163 $f = $this->fields;
3164 $this->MoveNext();
3166 $this->fields = $f;
3167 $this->EOF = false;
3168 return true;
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).
3177 function MoveNext()
3179 if (!$this->EOF) {
3180 $this->_currentRow++;
3181 if ($this->_fetch()) return true;
3183 $this->EOF = 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);
3191 return false;
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)
3205 $this->EOF = false;
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()) {
3215 return true;
3217 } else {
3218 $this->EOF = true;
3219 return false;
3221 } else {
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);
3228 } else {
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;
3240 $this->EOF = true;
3241 return 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)
3279 $record = array();
3280 // if (!$this->fields) return $record;
3282 if (!$this->bind) {
3283 $this->GetAssocKeys($upper);
3286 foreach($this->bind as $k => $v) {
3287 $record[$k] = $this->fields[$v];
3290 return $record;
3295 * Clean up recordset
3297 * @return true or false
3299 function Close()
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();
3307 } else
3308 return true;
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) {
3349 IF ($table) {
3350 if ($condition) $condition = " WHERE " . $condition;
3351 $resultrows = &$this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
3352 if ($resultrows) $lnumrows = reset($resultrows->fields);
3355 return $lnumrows;
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()
3396 $arr = array();
3397 for ($i=0, $max=$this->_numOfFields; $i < $max; $i++)
3398 $arr[] = $this->FetchField($i);
3399 return $arr;
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);
3411 return $o;
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;
3432 $i = 0;
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);
3439 else $n = $name;
3441 $o->$n = $this->Fields($name);
3443 return $o;
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,
3451 * or false if EOF
3453 * Fixed bug reported by tim@orotech.net
3455 function &FetchNextObj()
3457 $o =& $this->FetchNextObject(false);
3458 return $o;
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,
3469 * or false if EOF
3471 * Fixed bug reported by tim@orotech.net
3473 function &FetchNextObject($isupper=true)
3475 $o = false;
3476 if ($this->_numOfRows != 0 && !$this->EOF) {
3477 $o = $this->FetchObject($isupper);
3478 $this->_currentRow++;
3479 if ($this->_fetch()) return $o;
3481 $this->EOF = true;
3482 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)
3499 * B for Binary
3500 * N for numeric or floating point
3501 * D for date
3502 * T for timestamp
3503 * L for logical/Boolean
3504 * I for integer
3505 * R for autoincrement counter/integer
3509 function MetaType($t,$len=-1,$fieldobj=false)
3511 if (is_object($t)) {
3512 $fieldobj = $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(
3518 'VARCHAR' => 'C',
3519 'VARCHAR2' => 'C',
3520 'CHAR' => 'C',
3521 'C' => 'C',
3522 'STRING' => 'C',
3523 'NCHAR' => 'C',
3524 'NVARCHAR' => 'C',
3525 'VARYING' => 'C',
3526 'BPCHAR' => 'C',
3527 'CHARACTER' => 'C',
3528 'INTERVAL' => 'C', # Postgres
3529 'MACADDR' => 'C', # postgres
3531 'LONGCHAR' => 'X',
3532 'TEXT' => 'X',
3533 'NTEXT' => 'X',
3534 'M' => 'X',
3535 'X' => 'X',
3536 'CLOB' => 'X',
3537 'NCLOB' => 'X',
3538 'LVARCHAR' => 'X',
3540 'BLOB' => 'B',
3541 'IMAGE' => 'B',
3542 'BINARY' => 'B',
3543 'VARBINARY' => 'B',
3544 'LONGBINARY' => 'B',
3545 'B' => 'B',
3547 'YEAR' => 'D', // mysql
3548 'DATE' => 'D',
3549 'D' => 'D',
3551 'TIME' => 'T',
3552 'TIMESTAMP' => 'T',
3553 'DATETIME' => 'T',
3554 'TIMESTAMPTZ' => 'T',
3555 'T' => 'T',
3556 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
3558 'BOOL' => 'L',
3559 'BOOLEAN' => 'L',
3560 'BIT' => 'L',
3561 'L' => 'L',
3563 'COUNTER' => 'R',
3564 'R' => 'R',
3565 'SERIAL' => 'R', // ifx
3566 'INT IDENTITY' => 'R',
3568 'INT' => 'I',
3569 'INT2' => 'I',
3570 'INT4' => 'I',
3571 'INT8' => 'I',
3572 'INTEGER' => 'I',
3573 'INTEGER UNSIGNED' => 'I',
3574 'SHORT' => 'I',
3575 'TINYINT' => 'I',
3576 'SMALLINT' => 'I',
3577 'I' => 'I',
3579 'LONG' => 'N', // interbase is numeric, oci8 is blob
3580 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
3581 'DECIMAL' => 'N',
3582 'DEC' => 'N',
3583 'REAL' => 'N',
3584 'DOUBLE' => 'N',
3585 'DOUBLE PRECISION' => 'N',
3586 'SMALLFLOAT' => 'N',
3587 'FLOAT' => 'N',
3588 'NUMBER' => 'N',
3589 'NUM' => 'N',
3590 'NUMERIC' => 'N',
3591 'MONEY' => 'N',
3593 ## informix 9.2
3594 'SQLINT' => 'I',
3595 'SQLSERIAL' => 'I',
3596 'SQLSMINT' => 'I',
3597 'SQLSMFLOAT' => 'N',
3598 'SQLFLOAT' => 'N',
3599 'SQLMONEY' => 'N',
3600 'SQLDECIMAL' => 'N',
3601 'SQLDATE' => 'D',
3602 'SQLVCHAR' => 'C',
3603 'SQLCHAR' => 'C',
3604 'SQLDTIME' => 'T',
3605 'SQLINTERVAL' => 'N',
3606 'SQLBYTES' => 'B',
3607 'SQLTEXT' => 'X',
3608 ## informix 10
3609 "SQLINT8" => 'I8',
3610 "SQLSERIAL8" => 'I8',
3611 "SQLNCHAR" => 'C',
3612 "SQLNVCHAR" => 'C',
3613 "SQLLVARCHAR" => 'X',
3614 "SQLBOOL" => 'L'
3617 $tmap = false;
3618 $t = strtoupper($t);
3619 $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N';
3620 switch ($tmap) {
3621 case 'C':
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) {
3627 return 'X';
3629 return 'C';
3631 case 'I':
3632 if (!empty($fieldobj->primary_key)) return 'R';
3633 return 'I';
3635 case false:
3636 return 'N';
3638 case 'B':
3639 if (isset($fieldobj->binary))
3640 return ($fieldobj->binary) ? 'B' : 'X';
3641 return 'B';
3643 case 'D':
3644 if (!empty($this->connection) && !empty($this->connection->datetime)) return 'T';
3645 return 'D';
3647 default:
3648 if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B';
3649 return $tmap;
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;
3714 var $sql = '';
3715 var $compat = false;
3717 * Constructor
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');
3735 $hdr = true;
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();
3750 $f->name = $name;
3751 $f->type = $this->_types[$k];
3752 $f->max_length = -1;
3753 $this->_fieldobjects[] = $f;
3756 $this->fields = reset($this->_array);
3758 $this->_initrs();
3763 * Setup the 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;
3777 if ($colnames) {
3778 $this->_skiprow1 = false;
3779 $this->_colnames = $colnames;
3780 } else {
3781 $this->_skiprow1 = true;
3782 $this->_colnames = $array[0];
3784 $this->Init();
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;
3798 if ($fieldarr) {
3799 $this->_fieldobjects =& $fieldarr;
3801 $this->Init();
3804 function &GetArray($nRows=-1)
3806 if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) {
3807 return $this->_array;
3808 } else {
3809 $arr =& ADORecordSet::GetArray($nRows);
3810 return $arr;
3814 function _initrs()
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];
3832 if (!$this->bind) {
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
3852 return $o;
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];
3861 return true;
3863 return false;
3866 function MoveNext()
3868 if (!$this->EOF) {
3869 $this->_currentRow++;
3871 $pos = $this->_currentRow;
3873 if ($this->_numOfRows <= $pos) {
3874 if (!$this->compat) $this->fields = false;
3875 } else {
3876 if ($this->_skiprow1) $pos += 1;
3877 $this->fields = $this->_array[$pos];
3878 return true;
3880 $this->EOF = true;
3883 return false;
3886 function _fetch()
3888 $pos = $this->_currentRow;
3890 if ($this->_numOfRows <= $pos) {
3891 if (!$this->compat) $this->fields = false;
3892 return false;
3894 if ($this->_skiprow1) $pos += 1;
3895 $this->fields = $this->_array[$pos];
3896 return true;
3899 function _close()
3901 return true;
3904 } // ADORecordSet_array
3906 //==============================================================================================
3907 // HELPER FUNCTIONS
3908 //==============================================================================================
3911 * Synonym for ADOLoadCode. Private function. Do not use.
3913 * @deprecated
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);
3929 switch ($db) {
3930 case 'ado':
3931 if (PHP_VERSION >= 5) $db = 'ado5';
3932 $class = 'ado';
3933 break;
3934 case 'ifx':
3935 case 'maxsql': $class = $db = 'mysqlt'; break;
3936 case 'postgres':
3937 case 'postgres8':
3938 case 'pgsql': $class = $db = 'postgres7'; break;
3939 default:
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");
3951 return false;
3955 * synonym for ADONewConnection for people like me who cannot remember the correct name
3957 function &NewADOConnection($db='')
3959 $tmp =& ADONewConnection($db);
3960 return $tmp;
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;
3977 $false = false;
3978 if ($at = strpos($db,'://')) {
3979 $origdsn = $db;
3980 if (PHP_VERSION < 5) $dsna = @parse_url($db);
3981 else {
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';
3996 if (!$dsna) {
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;
4001 $dsna['host'] = '';
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);
4030 } else {
4032 if (!isset($ADODB_LASTDB)) $ADODB_LASTDB = '';
4033 if (empty($db)) $db = $ADODB_LASTDB;
4035 if ($db != $ADODB_LASTDB) $db = ADOLoadCode($db);
4037 if (!$db) {
4038 if (isset($origdsn)) $db = $origdsn;
4039 if ($errorfn) {
4040 // raise an error
4041 $ignore = false;
4042 $errorfn('ADONewConnection', 'ADONewConnection', -998,
4043 "could not load the database driver for '$db'",
4044 $db,false,$ignore);
4045 } else
4046 ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false);
4048 return $false;
4051 $cls = 'ADODB_'.$db;
4052 if (!class_exists($cls)) {
4053 adodb_backtrace();
4054 return $false;
4057 $obj = new $cls();
4060 # constructor should not fail
4061 if ($obj) {
4062 if ($errorfn) $obj->raiseErrorFn = $errorfn;
4063 if (isset($dsna)) {
4064 if (isset($dsna['port'])) $obj->port = $dsna['port'];
4065 foreach($opt as $k => $v) {
4066 switch(strtolower($k)) {
4067 case 'new':
4068 $nconnect = true; $persist = true; break;
4069 case 'persist':
4070 case 'persistent': $persist = $v; break;
4071 case 'debug': $obj->debug = (integer) $v; break;
4072 #ibase
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;
4078 #ado
4079 case 'charpage': $obj->charPage = $v; break;
4080 #mysql, mysqli
4081 case 'clientflags': $obj->clientFlags = $v; break;
4082 #mysql, mysqli, postgres
4083 case 'port': $obj->port = $v; break;
4084 #mysqli
4085 case 'socket': $obj->socket = $v; break;
4086 #oci8
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']);
4094 else
4095 $ok = $obj->NConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4097 if (!$ok) return $false;
4100 return $obj;
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;
4113 default:
4114 return $provider;
4117 switch($drivername) {
4118 case 'mysqlt':
4119 case 'mysqli':
4120 $drivername='mysql';
4121 break;
4122 case 'postgres7':
4123 case 'postgres8':
4124 $drivername = 'postgres';
4125 break;
4126 case 'firebird15': $drivername = 'firebird'; break;
4127 case 'oracle': $drivername = 'oci8'; break;
4128 case 'access': if ($perf) $drivername = ''; break;
4129 case 'db2' : break;
4130 case 'sapdb' : break;
4131 default:
4132 $drivername = 'generic';
4133 break;
4135 return $drivername;
4138 function &NewPerfMonitor(&$conn)
4140 $false = false;
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);
4149 return $perf;
4152 function &NewDataDictionary(&$conn,$drivername=false)
4154 $false = 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");
4163 return $false;
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();
4175 return $dict;
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";
4189 } else
4190 print_r($var);
4192 if ($as_string) {
4193 $s = ob_get_contents();
4194 ob_end_clean();
4195 return $s;
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);