baseline
[omp.pkp.sfu.ca.git] / lib / pkp / lib / adodb / adodb.inc.php
blobcc9117ff3c8c9c79a2775ff600333b14d899575d
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.90 8 June 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
276 var $sysDate = false; /// name of function that returns the current date
277 var $sysTimeStamp = false; /// name of function that returns the current timestamp
278 var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets
280 var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' '
281 var $numQueries = 0;
282 var $numCacheHits = 0;
283 var $numCacheMisses = 0;
284 var $pageExecuteCountRows = true;
285 var $uniqueSort = false; /// indicates that all fields in order by must be unique
286 var $leftOuter = false; /// operator to use for left outer join in WHERE clause
287 var $rightOuter = false; /// operator to use for right outer join in WHERE clause
288 var $ansiOuter = false; /// whether ansi outer join syntax supported
289 var $autoRollback = false; // autoRollback on PConnect().
290 var $poorAffectedRows = false; // affectedRows not working or unreliable
292 var $fnExecute = false;
293 var $fnCacheExecute = false;
294 var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char
295 var $rsPrefix = "ADORecordSet_";
297 var $autoCommit = true; /// do not modify this yourself - actually private
298 var $transOff = 0; /// temporarily disable transactions
299 var $transCnt = 0; /// count of nested transactions
301 var $fetchMode=false;
303 // PRIVATE VARS
305 var $_oldRaiseFn = false;
306 var $_transOK = null;
307 var $_connectionID = false; /// The returned link identifier whenever a successful database connection is made.
308 var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will
309 /// then returned by the errorMsg() function
310 var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8
311 var $_queryID = false; /// This variable keeps the last created result link identifier
313 var $_isPersistentConnection = false; /// A boolean variable to state whether its a persistent connection or normal connection. */
314 var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.
315 var $_evalAll = false;
316 var $_affected = false;
317 var $_logsql = false;
318 var $_transmode = ''; // transaction mode
321 * Constructor
323 function ADOConnection()
325 die('Virtual Class -- cannot instantiate');
328 function Version()
330 global $ADODB_vers;
332 return (float) substr($ADODB_vers,1);
336 Get server version info...
338 @returns An array with 2 elements: $arr['string'] is the description string,
339 and $arr[version] is the version (also a string).
341 function ServerInfo()
343 return array('description' => '', 'version' => '');
346 function IsConnected()
348 return !empty($this->_connectionID);
351 function _findvers($str)
353 if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) return $arr[1];
354 else return '';
358 * All error messages go through this bottleneck function.
359 * You can define your own handler by defining the function name in ADODB_OUTP.
361 function outp($msg,$newline=true)
363 global $ADODB_FLUSH,$ADODB_OUTP;
365 if (defined('ADODB_OUTP')) {
366 $fn = ADODB_OUTP;
367 $fn($msg,$newline);
368 return;
369 } else if (isset($ADODB_OUTP)) {
370 $fn = $ADODB_OUTP;
371 $fn($msg,$newline);
372 return;
375 if ($newline) $msg .= "<br>\n";
377 if (isset($_SERVER['HTTP_USER_AGENT']) || !$newline) echo $msg;
378 else echo strip_tags($msg);
381 if (!empty($ADODB_FLUSH) && ob_get_length() !== false) flush(); // do not flush if output buffering enabled - useless - thx to Jesse Mullan
385 function Time()
387 $rs =& $this->_Execute("select $this->sysTimeStamp");
388 if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields));
390 return false;
394 * Connect to database
396 * @param [argHostname] Host to connect to
397 * @param [argUsername] Userid to login
398 * @param [argPassword] Associated password
399 * @param [argDatabaseName] database
400 * @param [forceNew] force new connection
402 * @return true or false
404 function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false)
406 if ($argHostname != "") $this->host = $argHostname;
407 if ($argUsername != "") $this->user = $argUsername;
408 if ($argPassword != "") $this->password = $argPassword; // not stored for security reasons
409 if ($argDatabaseName != "") $this->database = $argDatabaseName;
411 $this->_isPersistentConnection = false;
412 if ($forceNew) {
413 if ($rez=$this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
414 } else {
415 if ($rez=$this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
417 if (isset($rez)) {
418 $err = $this->ErrorMsg();
419 if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
420 $ret = false;
421 } else {
422 $err = "Missing extension for ".$this->dataProvider;
423 $ret = 0;
425 if ($fn = $this->raiseErrorFn)
426 $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
429 $this->_connectionID = false;
430 if ($this->debug) ADOConnection::outp( $this->host.': '.$err);
431 return $ret;
434 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
436 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
441 * Always force a new connection to database - currently only works with oracle
443 * @param [argHostname] Host to connect to
444 * @param [argUsername] Userid to login
445 * @param [argPassword] Associated password
446 * @param [argDatabaseName] database
448 * @return true or false
450 function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
452 return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
456 * Establish persistent connect to database
458 * @param [argHostname] Host to connect to
459 * @param [argUsername] Userid to login
460 * @param [argPassword] Associated password
461 * @param [argDatabaseName] database
463 * @return return true or false
465 function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
467 if (defined('ADODB_NEVER_PERSIST'))
468 return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
470 if ($argHostname != "") $this->host = $argHostname;
471 if ($argUsername != "") $this->user = $argUsername;
472 if ($argPassword != "") $this->password = $argPassword;
473 if ($argDatabaseName != "") $this->database = $argDatabaseName;
475 $this->_isPersistentConnection = true;
476 if ($rez = $this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
477 if (isset($rez)) {
478 $err = $this->ErrorMsg();
479 if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
480 $ret = false;
481 } else {
482 $err = "Missing extension for ".$this->dataProvider;
483 $ret = 0;
485 if ($fn = $this->raiseErrorFn) {
486 $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
489 $this->_connectionID = false;
490 if ($this->debug) ADOConnection::outp( $this->host.': '.$err);
491 return $ret;
494 // Format date column in sql string given an input format that understands Y M D
495 function SQLDate($fmt, $col=false)
497 if (!$col) $col = $this->sysDate;
498 return $col; // child class implement
502 * Should prepare the sql statement and return the stmt resource.
503 * For databases that do not support this, we return the $sql. To ensure
504 * compatibility with databases that do not support prepare:
506 * $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
507 * $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
508 * $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
510 * @param sql SQL to send to database
512 * @return return FALSE, or the prepared statement, or the original sql if
513 * if the database does not support prepare.
516 function Prepare($sql)
518 return $sql;
522 * Some databases, eg. mssql require a different function for preparing
523 * stored procedures. So we cannot use Prepare().
525 * Should prepare the stored procedure and return the stmt resource.
526 * For databases that do not support this, we return the $sql. To ensure
527 * compatibility with databases that do not support prepare:
529 * @param sql SQL to send to database
531 * @return return FALSE, or the prepared statement, or the original sql if
532 * if the database does not support prepare.
535 function PrepareSP($sql,$param=true)
537 return $this->Prepare($sql,$param);
541 * PEAR DB Compat
543 function Quote($s)
545 return $this->qstr($s,false);
549 Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de>
551 function QMagic($s)
553 return $this->qstr($s,get_magic_quotes_gpc());
556 function q(&$s)
558 #if (!empty($this->qNull)) if ($s == 'null') return $s;
559 $s = $this->qstr($s,false);
563 * PEAR DB Compat - do not use internally.
565 function ErrorNative()
567 return $this->ErrorNo();
572 * PEAR DB Compat - do not use internally.
574 function nextId($seq_name)
576 return $this->GenID($seq_name);
580 * Lock a row, will escalate and lock the table if row locking not supported
581 * will normally free the lock at the end of the transaction
583 * @param $table name of table to lock
584 * @param $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
586 function RowLock($table,$where)
588 return false;
591 function CommitLock($table)
593 return $this->CommitTrans();
596 function RollbackLock($table)
598 return $this->RollbackTrans();
602 * PEAR DB Compat - do not use internally.
604 * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
605 * for easy porting :-)
607 * @param mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
608 * @returns The previous fetch mode
610 function SetFetchMode($mode)
612 $old = $this->fetchMode;
613 $this->fetchMode = $mode;
615 if ($old === false) {
616 global $ADODB_FETCH_MODE;
617 return $ADODB_FETCH_MODE;
619 return $old;
624 * PEAR DB Compat - do not use internally.
626 function &Query($sql, $inputarr=false)
628 $rs = &$this->Execute($sql, $inputarr);
629 if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
630 return $rs;
635 * PEAR DB Compat - do not use internally
637 function &LimitQuery($sql, $offset, $count, $params=false)
639 $rs = &$this->SelectLimit($sql, $count, $offset, $params);
640 if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
641 return $rs;
646 * PEAR DB Compat - do not use internally
648 function Disconnect()
650 return $this->Close();
654 Returns placeholder for parameter, eg.
655 $DB->Param('a')
657 will return ':a' for Oracle, and '?' for most other databases...
659 For databases that require positioned params, eg $1, $2, $3 for postgresql,
660 pass in Param(false) before setting the first parameter.
662 function Param($name,$type='C')
664 return '?';
668 InParameter and OutParameter are self-documenting versions of Parameter().
670 function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
672 return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
677 function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
679 return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);
684 Usage in oracle
685 $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
686 $db->Parameter($stmt,$id,'myid');
687 $db->Parameter($stmt,$group,'group',64);
688 $db->Execute();
690 @param $stmt Statement returned by Prepare() or PrepareSP().
691 @param $var PHP variable to bind to
692 @param $name Name of stored procedure variable name to bind to.
693 @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
694 @param [$maxLen] Holds an maximum length of the variable.
695 @param [$type] The data type of $var. Legal values depend on driver.
698 function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
700 return false;
704 Improved method of initiating a transaction. Used together with CompleteTrans().
705 Advantages include:
707 a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.
708 Only the outermost block is treated as a transaction.<br>
709 b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>
710 c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block
711 are disabled, making it backward compatible.
713 function StartTrans($errfn = 'ADODB_TransMonitor')
715 if ($this->transOff > 0) {
716 $this->transOff += 1;
717 return;
720 $this->_oldRaiseFn = $this->raiseErrorFn;
721 $this->raiseErrorFn = $errfn;
722 $this->_transOK = true;
724 if ($this->debug && $this->transCnt > 0) ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
725 $this->BeginTrans();
726 $this->transOff = 1;
731 Used together with StartTrans() to end a transaction. Monitors connection
732 for sql errors, and will commit or rollback as appropriate.
734 @autoComplete if true, monitor sql errors and commit and rollback as appropriate,
735 and if set to false force rollback even if no SQL error detected.
736 @returns true on commit, false on rollback.
738 function CompleteTrans($autoComplete = true)
740 if ($this->transOff > 1) {
741 $this->transOff -= 1;
742 return true;
744 $this->raiseErrorFn = $this->_oldRaiseFn;
746 $this->transOff = 0;
747 if ($this->_transOK && $autoComplete) {
748 if (!$this->CommitTrans()) {
749 $this->_transOK = false;
750 if ($this->debug) ADOConnection::outp("Smart Commit failed");
751 } else
752 if ($this->debug) ADOConnection::outp("Smart Commit occurred");
753 } else {
754 $this->_transOK = false;
755 $this->RollbackTrans();
756 if ($this->debug) ADOCOnnection::outp("Smart Rollback occurred");
759 return $this->_transOK;
763 At the end of a StartTrans/CompleteTrans block, perform a rollback.
765 function FailTrans()
767 if ($this->debug)
768 if ($this->transOff == 0) {
769 ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
770 } else {
771 ADOConnection::outp("FailTrans was called");
772 adodb_backtrace();
774 $this->_transOK = false;
778 Check if transaction has failed, only for Smart Transactions.
780 function HasFailedTrans()
782 if ($this->transOff > 0) return $this->_transOK == false;
783 return false;
787 * Execute SQL
789 * @param sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
790 * @param [inputarr] holds the input data to bind to. Null elements will be set to null.
791 * @return RecordSet or false
793 function &Execute($sql,$inputarr=false)
795 $this->numQueries++;
797 if ($this->fnExecute) {
798 $fn = $this->fnExecute;
799 $ret =& $fn($this,$sql,$inputarr);
800 if (isset($ret)) return $ret;
802 if ($inputarr) {
803 if (!is_array($inputarr)) $inputarr = array($inputarr);
805 $element0 = reset($inputarr);
806 # is_object check because oci8 descriptors can be passed in
807 $array_2d = is_array($element0) && !is_object(reset($element0));
808 //remove extra memory copy of input -mikefedyk
809 unset($element0);
811 if (!is_array($sql) && !$this->_bindInputArray) {
812 $sqlarr = explode('?',$sql);
814 if (!$array_2d) $inputarr = array($inputarr);
815 foreach($inputarr as $arr) {
816 $sql = ''; $i = 0;
817 //Use each() instead of foreach to reduce memory usage -mikefedyk
818 while(list(, $v) = each($arr)) {
819 $sql .= $sqlarr[$i];
820 // from Ron Baldwin <ron.baldwin#sourceprose.com>
821 // Only quote string types
822 $typ = gettype($v);
823 if ($typ == 'string')
824 //New memory copy of input created here -mikefedyk
825 $sql .= $this->qstr($v);
826 else if ($typ == 'double')
827 $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1
828 else if ($typ == 'boolean')
829 $sql .= $v ? $this->true : $this->false;
830 else if ($typ == 'object') {
831 if (method_exists($v, '__toString')) $sql .= $this->qstr($v->__toString());
832 else $sql .= $this->qstr((string) $v);
833 } else if ($v === null)
834 $sql .= 'NULL';
835 else
836 $sql .= $v;
837 $i += 1;
839 if (isset($sqlarr[$i])) {
840 $sql .= $sqlarr[$i];
841 if ($i+1 != sizeof($sqlarr)) ADOConnection::outp( "Input Array does not match ?: ".htmlspecialchars($sql));
842 } else if ($i != sizeof($sqlarr))
843 ADOConnection::outp( "Input array does not match ?: ".htmlspecialchars($sql));
845 $ret =& $this->_Execute($sql);
846 if (!$ret) return $ret;
848 } else {
849 if ($array_2d) {
850 if (is_string($sql))
851 $stmt = $this->Prepare($sql);
852 else
853 $stmt = $sql;
855 foreach($inputarr as $arr) {
856 $ret =& $this->_Execute($stmt,$arr);
857 if (!$ret) return $ret;
859 } else {
860 $ret =& $this->_Execute($sql,$inputarr);
863 } else {
864 $ret =& $this->_Execute($sql,false);
867 return $ret;
871 function &_Execute($sql,$inputarr=false)
873 if ($this->debug) {
874 global $ADODB_INCLUDED_LIB;
875 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
876 $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr);
877 } else {
878 $this->_queryID = @$this->_query($sql,$inputarr);
881 /************************
882 // OK, query executed
883 *************************/
885 if ($this->_queryID === false) { // error handling if query fails
886 if ($this->debug == 99) adodb_backtrace(true,5);
887 $fn = $this->raiseErrorFn;
888 if ($fn) {
889 $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
891 $false = false;
892 return $false;
895 if ($this->_queryID === true) { // return simplified recordset for inserts/updates/deletes with lower overhead
896 $rs = new ADORecordSet_empty();
897 return $rs;
900 // return real recordset from select statement
901 $rsclass = $this->rsPrefix.$this->databaseType;
902 $rs = new $rsclass($this->_queryID,$this->fetchMode);
903 $rs->connection = &$this; // Pablo suggestion
904 $rs->Init();
905 if (is_array($sql)) $rs->sql = $sql[0];
906 else $rs->sql = $sql;
907 if ($rs->_numOfRows <= 0) {
908 global $ADODB_COUNTRECS;
909 if ($ADODB_COUNTRECS) {
910 if (!$rs->EOF) {
911 $rs = &$this->_rs2rs($rs,-1,-1,!is_array($sql));
912 $rs->_queryID = $this->_queryID;
913 } else
914 $rs->_numOfRows = 0;
917 return $rs;
920 function CreateSequence($seqname='adodbseq',$startID=1)
922 if (empty($this->_genSeqSQL)) return false;
923 return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
926 function DropSequence($seqname='adodbseq')
928 if (empty($this->_dropSeqSQL)) return false;
929 return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
933 * Generates a sequence id and stores it in $this->genID;
934 * GenID is only available if $this->hasGenID = true;
936 * @param seqname name of sequence to use
937 * @param startID if sequence does not exist, start at this ID
938 * @return 0 if not supported, otherwise a sequence id
940 function GenID($seqname='adodbseq',$startID=1)
942 if (!$this->hasGenID) {
943 return 0; // formerly returns false pre 1.60
946 $getnext = sprintf($this->_genIDSQL,$seqname);
948 $holdtransOK = $this->_transOK;
950 $save_handler = $this->raiseErrorFn;
951 $this->raiseErrorFn = '';
952 @($rs = $this->Execute($getnext));
953 $this->raiseErrorFn = $save_handler;
955 if (!$rs) {
956 $this->_transOK = $holdtransOK; //if the status was ok before reset
957 $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
958 $rs = $this->Execute($getnext);
960 if ($rs && !$rs->EOF) $this->genID = reset($rs->fields);
961 else $this->genID = 0; // false
963 if ($rs) $rs->Close();
965 return $this->genID;
969 * @param $table string name of the table, not needed by all databases (eg. mysql), default ''
970 * @param $column string name of the column, not needed by all databases (eg. mysql), default ''
971 * @return the last inserted ID. Not all databases support this.
973 function Insert_ID($table='',$column='')
975 if ($this->_logsql && $this->lastInsID) return $this->lastInsID;
976 if ($this->hasInsertID) return $this->_insertid($table,$column);
977 if ($this->debug) {
978 ADOConnection::outp( '<p>Insert_ID error</p>');
979 adodb_backtrace();
981 return false;
986 * Portable Insert ID. Pablo Roca <pabloroca#mvps.org>
988 * @return the last inserted ID. All databases support this. But aware possible
989 * problems in multiuser environments. Heavy test this before deploying.
991 function PO_Insert_ID($table="", $id="")
993 if ($this->hasInsertID){
994 return $this->Insert_ID($table,$id);
995 } else {
996 return $this->GetOne("SELECT MAX($id) FROM $table");
1001 * @return # rows affected by UPDATE/DELETE
1003 function Affected_Rows()
1005 if ($this->hasAffectedRows) {
1006 if ($this->fnExecute === 'adodb_log_sql') {
1007 if ($this->_logsql && $this->_affected !== false) return $this->_affected;
1009 $val = $this->_affectedrows();
1010 return ($val < 0) ? false : $val;
1013 if ($this->debug) ADOConnection::outp( '<p>Affected_Rows error</p>',false);
1014 return false;
1019 * @return the last error message
1021 function ErrorMsg()
1023 if ($this->_errorMsg) return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
1024 else return '';
1029 * @return the last error number. Normally 0 means no error.
1031 function ErrorNo()
1033 return ($this->_errorMsg) ? -1 : 0;
1036 function MetaError($err=false)
1038 include_once(ADODB_DIR."/adodb-error.inc.php");
1039 if ($err === false) $err = $this->ErrorNo();
1040 return adodb_error($this->dataProvider,$this->databaseType,$err);
1043 function MetaErrorMsg($errno)
1045 include_once(ADODB_DIR."/adodb-error.inc.php");
1046 return adodb_errormsg($errno);
1050 * @returns an array with the primary key columns in it.
1052 function MetaPrimaryKeys($table, $owner=false)
1054 // owner not used in base class - see oci8
1055 $p = array();
1056 $objs =& $this->MetaColumns($table);
1057 if ($objs) {
1058 foreach($objs as $v) {
1059 if (!empty($v->primary_key))
1060 $p[] = $v->name;
1063 if (sizeof($p)) return $p;
1064 if (function_exists('ADODB_VIEW_PRIMARYKEYS'))
1065 return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);
1066 return false;
1070 * @returns assoc array where keys are tables, and values are foreign keys
1072 function MetaForeignKeys($table, $owner=false, $upper=false)
1074 return false;
1077 * Choose a database to connect to. Many databases do not support this.
1079 * @param dbName is the name of the database to select
1080 * @return true or false
1082 function SelectDB($dbName)
1083 {return false;}
1087 * Will select, getting rows from $offset (1-based), for $nrows.
1088 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1089 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1090 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1091 * eg.
1092 * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
1093 * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
1095 * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
1096 * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
1098 * @param sql
1099 * @param [offset] is the row to start calculations from (1-based)
1100 * @param [nrows] is the number of rows to get
1101 * @param [inputarr] array of bind variables
1102 * @param [secs2cache] is a private parameter only used by jlim
1103 * @return the recordset ($rs->databaseType == 'array')
1105 function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
1107 if ($this->hasTop && $nrows > 0) {
1108 // suggested by Reinhard Balling. Access requires top after distinct
1109 // Informix requires first before distinct - F Riosa
1110 $ismssql = (strpos($this->databaseType,'mssql') !== false);
1111 if ($ismssql) $isaccess = false;
1112 else $isaccess = (strpos($this->databaseType,'access') !== false);
1114 if ($offset <= 0) {
1116 // access includes ties in result
1117 if ($isaccess) {
1118 $sql = preg_replace(
1119 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1121 if ($secs2cache>0) {
1122 $ret =& $this->CacheExecute($secs2cache, $sql,$inputarr);
1123 } else {
1124 $ret =& $this->Execute($sql,$inputarr);
1126 return $ret; // PHP5 fix
1127 } else if ($ismssql){
1128 $sql = preg_replace(
1129 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1130 } else {
1131 $sql = preg_replace(
1132 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1134 } else {
1135 $nn = $nrows + $offset;
1136 if ($isaccess || $ismssql) {
1137 $sql = preg_replace(
1138 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1139 } else {
1140 $sql = preg_replace(
1141 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1146 // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows
1147 // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.
1148 global $ADODB_COUNTRECS;
1150 $savec = $ADODB_COUNTRECS;
1151 $ADODB_COUNTRECS = false;
1153 if ($offset>0){
1154 if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1155 else $rs = &$this->Execute($sql,$inputarr);
1156 } else {
1157 if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1158 else $rs = &$this->Execute($sql,$inputarr);
1160 $ADODB_COUNTRECS = $savec;
1161 if ($rs && !$rs->EOF) {
1162 $rs =& $this->_rs2rs($rs,$nrows,$offset);
1164 //print_r($rs);
1165 return $rs;
1169 * Create serializable recordset. Breaks rs link to connection.
1171 * @param rs the recordset to serialize
1173 function &SerializableRS(&$rs)
1175 $rs2 =& $this->_rs2rs($rs);
1176 $ignore = false;
1177 $rs2->connection =& $ignore;
1179 return $rs2;
1183 * Convert database recordset to an array recordset
1184 * input recordset's cursor should be at beginning, and
1185 * old $rs will be closed.
1187 * @param rs the recordset to copy
1188 * @param [nrows] number of rows to retrieve (optional)
1189 * @param [offset] offset by number of rows (optional)
1190 * @return the new recordset
1192 function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true)
1194 if (! $rs) {
1195 $false = false;
1196 return $false;
1198 $dbtype = $rs->databaseType;
1199 if (!$dbtype) {
1200 $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?
1201 return $rs;
1203 if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {
1204 $rs->MoveFirst();
1205 $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?
1206 return $rs;
1208 $flds = array();
1209 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
1210 $flds[] = $rs->FetchField($i);
1213 $arr =& $rs->GetArrayLimit($nrows,$offset);
1214 //print_r($arr);
1215 if ($close) $rs->Close();
1217 $arrayClass = $this->arrayClass;
1219 $rs2 = new $arrayClass();
1220 $rs2->connection = &$this;
1221 $rs2->sql = $rs->sql;
1222 $rs2->dataProvider = $this->dataProvider;
1223 $rs2->InitArrayFields($arr,$flds);
1224 $rs2->fetchMode = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
1225 return $rs2;
1229 * Return all rows. Compat with PEAR DB
1231 function &GetAll($sql, $inputarr=false)
1233 $arr =& $this->GetArray($sql,$inputarr);
1234 return $arr;
1237 function &GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false)
1239 $rs =& $this->Execute($sql, $inputarr);
1240 if (!$rs) {
1241 $false = false;
1242 return $false;
1244 $arr =& $rs->GetAssoc($force_array,$first2cols);
1245 return $arr;
1248 function &CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false)
1250 if (!is_numeric($secs2cache)) {
1251 $first2cols = $force_array;
1252 $force_array = $inputarr;
1254 $rs =& $this->CacheExecute($secs2cache, $sql, $inputarr);
1255 if (!$rs) {
1256 $false = false;
1257 return $false;
1259 $arr =& $rs->GetAssoc($force_array,$first2cols);
1260 return $arr;
1264 * Return first element of first row of sql statement. Recordset is disposed
1265 * for you.
1267 * @param sql SQL statement
1268 * @param [inputarr] input bind array
1270 function GetOne($sql,$inputarr=false)
1272 global $ADODB_COUNTRECS;
1273 $crecs = $ADODB_COUNTRECS;
1274 $ADODB_COUNTRECS = false;
1276 $ret = false;
1277 $rs = &$this->Execute($sql,$inputarr);
1278 if ($rs) {
1279 if (!$rs->EOF) $ret = reset($rs->fields);
1280 $rs->Close();
1282 $ADODB_COUNTRECS = $crecs;
1283 return $ret;
1286 function CacheGetOne($secs2cache,$sql=false,$inputarr=false)
1288 $ret = false;
1289 $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1290 if ($rs) {
1291 if (!$rs->EOF) $ret = reset($rs->fields);
1292 $rs->Close();
1295 return $ret;
1298 function GetCol($sql, $inputarr = false, $trim = false)
1300 $rv = false;
1301 $rs = &$this->Execute($sql, $inputarr);
1302 if ($rs) {
1303 $rv = array();
1304 if ($trim) {
1305 while (!$rs->EOF) {
1306 $rv[] = trim(reset($rs->fields));
1307 $rs->MoveNext();
1309 } else {
1310 while (!$rs->EOF) {
1311 $rv[] = reset($rs->fields);
1312 $rs->MoveNext();
1315 $rs->Close();
1317 return $rv;
1320 function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false)
1322 $rv = false;
1323 $rs = &$this->CacheExecute($secs, $sql, $inputarr);
1324 if ($rs) {
1325 if ($trim) {
1326 while (!$rs->EOF) {
1327 $rv[] = trim(reset($rs->fields));
1328 $rs->MoveNext();
1330 } else {
1331 while (!$rs->EOF) {
1332 $rv[] = reset($rs->fields);
1333 $rs->MoveNext();
1336 $rs->Close();
1338 return $rv;
1342 Calculate the offset of a date for a particular database and generate
1343 appropriate SQL. Useful for calculating future/past dates and storing
1344 in a database.
1346 If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
1348 function OffsetDate($dayFraction,$date=false)
1350 if (!$date) $date = $this->sysDate;
1351 return '('.$date.'+'.$dayFraction.')';
1357 * @param sql SQL statement
1358 * @param [inputarr] input bind array
1360 function &GetArray($sql,$inputarr=false)
1362 global $ADODB_COUNTRECS;
1364 $savec = $ADODB_COUNTRECS;
1365 $ADODB_COUNTRECS = false;
1366 $rs =& $this->Execute($sql,$inputarr);
1367 $ADODB_COUNTRECS = $savec;
1368 if (!$rs)
1369 if (defined('ADODB_PEAR')) {
1370 $cls = ADODB_PEAR_Error();
1371 return $cls;
1372 } else {
1373 $false = false;
1374 return $false;
1376 $arr =& $rs->GetArray();
1377 $rs->Close();
1378 return $arr;
1381 function &CacheGetAll($secs2cache,$sql=false,$inputarr=false)
1383 return $this->CacheGetArray($secs2cache,$sql,$inputarr);
1386 function &CacheGetArray($secs2cache,$sql=false,$inputarr=false)
1388 global $ADODB_COUNTRECS;
1390 $savec = $ADODB_COUNTRECS;
1391 $ADODB_COUNTRECS = false;
1392 $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1393 $ADODB_COUNTRECS = $savec;
1395 if (!$rs)
1396 if (defined('ADODB_PEAR')) {
1397 $cls = ADODB_PEAR_Error();
1398 return $cls;
1399 } else {
1400 $false = false;
1401 return $false;
1403 $arr =& $rs->GetArray();
1404 $rs->Close();
1405 return $arr;
1411 * Return one row of sql statement. Recordset is disposed for you.
1413 * @param sql SQL statement
1414 * @param [inputarr] input bind array
1416 function &GetRow($sql,$inputarr=false)
1418 global $ADODB_COUNTRECS;
1419 $crecs = $ADODB_COUNTRECS;
1420 $ADODB_COUNTRECS = false;
1422 $rs =& $this->Execute($sql,$inputarr);
1424 $ADODB_COUNTRECS = $crecs;
1425 if ($rs) {
1426 if (!$rs->EOF) $arr = $rs->fields;
1427 else $arr = array();
1428 $rs->Close();
1429 return $arr;
1432 $false = false;
1433 return $false;
1436 function &CacheGetRow($secs2cache,$sql=false,$inputarr=false)
1438 $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1439 if ($rs) {
1440 $arr = false;
1441 if (!$rs->EOF) $arr = $rs->fields;
1442 $rs->Close();
1443 return $arr;
1445 $false = false;
1446 return $false;
1450 * Insert or replace a single record. Note: this is not the same as MySQL's replace.
1451 * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
1452 * Also note that no table locking is done currently, so it is possible that the
1453 * record be inserted twice by two programs...
1455 * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
1457 * $table table name
1458 * $fieldArray associative array of data (you must quote strings yourself).
1459 * $keyCol the primary key field name or if compound key, array of field names
1460 * autoQuote set to true to use a hueristic to quote strings. Works with nulls and numbers
1461 * but does not work with dates nor SQL functions.
1462 * has_autoinc the primary key is an auto-inc field, so skip in insert.
1464 * Currently blob replace not supported
1466 * returns 0 = fail, 1 = update, 2 = insert
1469 function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false)
1471 global $ADODB_INCLUDED_LIB;
1472 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
1474 return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);
1479 * Will select, getting rows from $offset (1-based), for $nrows.
1480 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1481 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1482 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1483 * eg.
1484 * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
1485 * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
1487 * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
1489 * @param [secs2cache] seconds to cache data, set to 0 to force query. This is optional
1490 * @param sql
1491 * @param [offset] is the row to start calculations from (1-based)
1492 * @param [nrows] is the number of rows to get
1493 * @param [inputarr] array of bind variables
1494 * @return the recordset ($rs->databaseType == 'array')
1496 function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false)
1498 if (!is_numeric($secs2cache)) {
1499 if ($sql === false) $sql = -1;
1500 if ($offset == -1) $offset = false;
1501 // sql, nrows, offset,inputarr
1502 $rs =& $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs);
1503 } else {
1504 if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()");
1505 $rs =& $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
1507 return $rs;
1512 * Flush cached recordsets that match a particular $sql statement.
1513 * If $sql == false, then we purge all files in the cache.
1517 * Flush cached recordsets that match a particular $sql statement.
1518 * If $sql == false, then we purge all files in the cache.
1520 function CacheFlush($sql=false,$inputarr=false)
1522 global $ADODB_CACHE_DIR;
1524 if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
1525 /*if (strncmp(PHP_OS,'WIN',3) === 0)
1526 $dir = str_replace('/', '\\', $ADODB_CACHE_DIR);
1527 else */
1528 $dir = $ADODB_CACHE_DIR;
1530 if ($this->debug) {
1531 ADOConnection::outp( "CacheFlush: $dir<br><pre>\n", $this->_dirFlush($dir),"</pre>");
1532 } else {
1533 $this->_dirFlush($dir);
1535 return;
1538 global $ADODB_INCLUDED_CSV;
1539 if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
1541 $f = $this->_gencachename($sql.serialize($inputarr),false);
1542 adodb_write_file($f,''); // is adodb_write_file needed?
1543 if (!@unlink($f)) {
1544 if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f");
1549 * Private function to erase all of the files and subdirectories in a directory.
1551 * Just specify the directory, and tell it if you want to delete the directory or just clear it out.
1552 * Note: $kill_top_level is used internally in the function to flush subdirectories.
1554 function _dirFlush($dir, $kill_top_level = false) {
1555 if(!$dh = @opendir($dir)) return;
1557 while (($obj = readdir($dh))) {
1558 if($obj=='.' || $obj=='..')
1559 continue;
1561 if (!@unlink($dir.'/'.$obj))
1562 $this->_dirFlush($dir.'/'.$obj, true);
1564 if ($kill_top_level === true)
1565 @rmdir($dir);
1566 return true;
1570 function xCacheFlush($sql=false,$inputarr=false)
1572 global $ADODB_CACHE_DIR;
1574 if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
1575 if (strncmp(PHP_OS,'WIN',3) === 0) {
1576 $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
1577 } else {
1578 //$cmd = 'find "'.$ADODB_CACHE_DIR.'" -type f -maxdepth 1 -print0 | xargs -0 rm -f';
1579 $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/[0-9a-f][0-9a-f]/';
1580 // old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`';
1582 if ($this->debug) {
1583 ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>");
1584 } else {
1585 exec($cmd);
1587 return;
1590 global $ADODB_INCLUDED_CSV;
1591 if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
1593 $f = $this->_gencachename($sql.serialize($inputarr),false);
1594 adodb_write_file($f,''); // is adodb_write_file needed?
1595 if (!@unlink($f)) {
1596 if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f");
1601 * Private function to generate filename for caching.
1602 * Filename is generated based on:
1604 * - sql statement
1605 * - database type (oci8, ibase, ifx, etc)
1606 * - database name
1607 * - userid
1608 * - setFetchMode (adodb 4.23)
1610 * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
1611 * Assuming that we can have 50,000 files per directory with good performance,
1612 * then we can scale to 12.8 million unique cached recordsets. Wow!
1614 function _gencachename($sql,$createdir)
1616 global $ADODB_CACHE_DIR;
1617 static $notSafeMode;
1619 if ($this->fetchMode === false) {
1620 global $ADODB_FETCH_MODE;
1621 $mode = $ADODB_FETCH_MODE;
1622 } else {
1623 $mode = $this->fetchMode;
1625 $m = md5($sql.$this->databaseType.$this->database.$this->user.$mode);
1627 if (!isset($notSafeMode)) $notSafeMode = !ini_get('safe_mode');
1628 $dir = ($notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($m,0,2) : $ADODB_CACHE_DIR;
1630 if ($createdir && $notSafeMode && !file_exists($dir)) {
1631 $oldu = umask(0);
1632 if (!mkdir($dir,0771))
1633 if ($this->debug) ADOConnection::outp( "Unable to mkdir $dir for $sql");
1634 umask($oldu);
1636 return $dir.'/adodb_'.$m.'.cache';
1641 * Execute SQL, caching recordsets.
1643 * @param [secs2cache] seconds to cache data, set to 0 to force query.
1644 * This is an optional parameter.
1645 * @param sql SQL statement to execute
1646 * @param [inputarr] holds the input data to bind to
1647 * @return RecordSet or false
1649 function &CacheExecute($secs2cache,$sql=false,$inputarr=false)
1653 if (!is_numeric($secs2cache)) {
1654 $inputarr = $sql;
1655 $sql = $secs2cache;
1656 $secs2cache = $this->cacheSecs;
1659 if (is_array($sql)) {
1660 $sqlparam = $sql;
1661 $sql = $sql[0];
1662 } else
1663 $sqlparam = $sql;
1665 global $ADODB_INCLUDED_CSV;
1666 if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
1668 $md5file = $this->_gencachename($sql.serialize($inputarr),true);
1669 $err = '';
1671 if ($secs2cache > 0){
1672 $rs = &csv2rs($md5file,$err,$secs2cache,$this->arrayClass);
1673 $this->numCacheHits += 1;
1674 } else {
1675 $err='Timeout 1';
1676 $rs = false;
1677 $this->numCacheMisses += 1;
1679 if (!$rs) {
1680 // no cached rs found
1681 if ($this->debug) {
1682 if (get_magic_quotes_runtime()) {
1683 ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
1685 if ($this->debug !== -1) ADOConnection::outp( " $md5file cache failure: $err (see sql below)");
1688 $rs = &$this->Execute($sqlparam,$inputarr);
1690 if ($rs) {
1691 $eof = $rs->EOF;
1692 $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately
1693 $txt = _rs2serialize($rs,false,$sql); // serialize
1695 if (!adodb_write_file($md5file,$txt,$this->debug)) {
1696 if ($fn = $this->raiseErrorFn) {
1697 $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);
1699 if ($this->debug) ADOConnection::outp( " Cache write error");
1701 if ($rs->EOF && !$eof) {
1702 $rs->MoveFirst();
1703 //$rs = &csv2rs($md5file,$err);
1704 $rs->connection = &$this; // Pablo suggestion
1707 } else
1708 @unlink($md5file);
1709 } else {
1710 $this->_errorMsg = '';
1711 $this->_errorCode = 0;
1713 if ($this->fnCacheExecute) {
1714 $fn = $this->fnCacheExecute;
1715 $fn($this, $secs2cache, $sql, $inputarr);
1717 // ok, set cached object found
1718 $rs->connection = &$this; // Pablo suggestion
1719 if ($this->debug){
1721 $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
1722 $ttl = $rs->timeCreated + $secs2cache - time();
1723 $s = is_array($sql) ? $sql[0] : $sql;
1724 if ($inBrowser) $s = '<i>'.htmlspecialchars($s).'</i>';
1726 ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
1729 return $rs;
1734 Similar to PEAR DB's autoExecute(), except that
1735 $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
1736 If $mode == 'UPDATE', then $where is compulsory as a safety measure.
1738 $forceUpdate means that even if the data has not changed, perform update.
1740 function& AutoExecute($table, $fields_values, $mode = 'INSERT', $where = FALSE, $forceUpdate=true, $magicq=false)
1742 $false = false;
1743 $sql = 'SELECT * FROM '.$table;
1744 if ($where!==FALSE) $sql .= ' WHERE '.$where;
1745 else if ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) {
1746 ADOConnection::outp('AutoExecute: Illegal mode=UPDATE with empty WHERE clause');
1747 return $false;
1750 $rs =& $this->SelectLimit($sql,1);
1751 if (!$rs) return $false; // table does not exist
1752 $rs->tableName = $table;
1754 switch((string) $mode) {
1755 case 'UPDATE':
1756 case '2':
1757 $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq);
1758 break;
1759 case 'INSERT':
1760 case '1':
1761 $sql = $this->GetInsertSQL($rs, $fields_values, $magicq);
1762 break;
1763 default:
1764 ADOConnection::outp("AutoExecute: Unknown mode=$mode");
1765 return $false;
1767 $ret = false;
1768 if ($sql) $ret = $this->Execute($sql);
1769 if ($ret) $ret = true;
1770 return $ret;
1775 * Generates an Update Query based on an existing recordset.
1776 * $arrFields is an associative array of fields with the value
1777 * that should be assigned.
1779 * Note: This function should only be used on a recordset
1780 * that is run against a single table and sql should only
1781 * be a simple select stmt with no groupby/orderby/limit
1783 * "Jonathan Younger" <jyounger@unilab.com>
1785 function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null)
1787 global $ADODB_INCLUDED_LIB;
1789 //********************************************************//
1790 //This is here to maintain compatibility
1791 //with older adodb versions. Sets force type to force nulls if $forcenulls is set.
1792 if (!isset($force)) {
1793 global $ADODB_FORCE_TYPE;
1794 $force = $ADODB_FORCE_TYPE;
1796 //********************************************************//
1798 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
1799 return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
1803 * Generates an Insert Query based on an existing recordset.
1804 * $arrFields is an associative array of fields with the value
1805 * that should be assigned.
1807 * Note: This function should only be used on a recordset
1808 * that is run against a single table.
1810 function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null)
1812 global $ADODB_INCLUDED_LIB;
1813 if (!isset($force)) {
1814 global $ADODB_FORCE_TYPE;
1815 $force = $ADODB_FORCE_TYPE;
1818 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
1819 return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
1824 * Update a blob column, given a where clause. There are more sophisticated
1825 * blob handling functions that we could have implemented, but all require
1826 * a very complex API. Instead we have chosen something that is extremely
1827 * simple to understand and use.
1829 * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
1831 * Usage to update a $blobvalue which has a primary key blob_id=1 into a
1832 * field blobtable.blobcolumn:
1834 * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
1836 * Insert example:
1838 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
1839 * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
1842 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
1844 return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
1848 * Usage:
1849 * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
1851 * $blobtype supports 'BLOB' and 'CLOB'
1853 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
1854 * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
1856 function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
1858 $fd = fopen($path,'rb');
1859 if ($fd === false) return false;
1860 $val = fread($fd,filesize($path));
1861 fclose($fd);
1862 return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
1865 function BlobDecode($blob)
1867 return $blob;
1870 function BlobEncode($blob)
1872 return $blob;
1875 function SetCharSet($charset)
1877 return false;
1880 function IfNull( $field, $ifNull )
1882 return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
1885 function LogSQL($enable=true)
1887 include_once(ADODB_DIR.'/adodb-perf.inc.php');
1889 if ($enable) $this->fnExecute = 'adodb_log_sql';
1890 else $this->fnExecute = false;
1892 $old = $this->_logsql;
1893 $this->_logsql = $enable;
1894 if ($enable && !$old) $this->_affected = false;
1895 return $old;
1898 function GetCharSet()
1900 return false;
1904 * Usage:
1905 * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
1907 * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
1908 * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
1910 function UpdateClob($table,$column,$val,$where)
1912 return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
1915 // not the fastest implementation - quick and dirty - jlim
1916 // for best performance, use the actual $rs->MetaType().
1917 function MetaType($t,$len=-1,$fieldobj=false)
1920 if (empty($this->_metars)) {
1921 $rsclass = $this->rsPrefix.$this->databaseType;
1922 $this->_metars = new $rsclass(false,$this->fetchMode);
1923 $this->_metars->connection =& $this;
1925 return $this->_metars->MetaType($t,$len,$fieldobj);
1930 * Change the SQL connection locale to a specified locale.
1931 * This is used to get the date formats written depending on the client locale.
1933 function SetDateLocale($locale = 'En')
1935 $this->locale = $locale;
1936 switch (strtoupper($locale))
1938 case 'EN':
1939 $this->fmtDate="'Y-m-d'";
1940 $this->fmtTimeStamp = "'Y-m-d H:i:s'";
1941 break;
1943 case 'US':
1944 $this->fmtDate = "'m-d-Y'";
1945 $this->fmtTimeStamp = "'m-d-Y H:i:s'";
1946 break;
1948 case 'NL':
1949 case 'FR':
1950 case 'RO':
1951 case 'IT':
1952 $this->fmtDate="'d-m-Y'";
1953 $this->fmtTimeStamp = "'d-m-Y H:i:s'";
1954 break;
1956 case 'GE':
1957 $this->fmtDate="'d.m.Y'";
1958 $this->fmtTimeStamp = "'d.m.Y H:i:s'";
1959 break;
1961 default:
1962 $this->fmtDate="'Y-m-d'";
1963 $this->fmtTimeStamp = "'Y-m-d H:i:s'";
1964 break;
1968 function &GetActiveRecordsClass($class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false)
1970 global $_ADODB_ACTIVE_DBS;
1972 $save = $this->SetFetchMode(ADODB_FETCH_NUM);
1973 if (empty($whereOrderBy)) $whereOrderBy = '1=1';
1974 $rows = $this->GetAll("select * from ".$table.' WHERE '.$whereOrderBy,$bindarr);
1975 $this->SetFetchMode($save);
1977 $false = false;
1979 if ($rows === false) {
1980 return $false;
1984 if (!isset($_ADODB_ACTIVE_DBS)) {
1985 include(ADODB_DIR.'/adodb-active-record.inc.php');
1987 if (!class_exists($class)) {
1988 ADOConnection::outp("Unknown class $class in GetActiveRcordsClass()");
1989 return $false;
1991 $arr = array();
1992 foreach($rows as $row) {
1994 $obj = new $class($table,$primkeyArr,$this);
1995 if ($obj->ErrorMsg()){
1996 $this->_errorMsg = $obj->ErrorMsg();
1997 return $false;
1999 $obj->Set($row);
2000 $arr[] =& $obj;
2002 return $arr;
2005 function &GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false)
2007 $arr =& $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr);
2008 return $arr;
2012 * Close Connection
2014 function Close()
2016 $rez = $this->_close();
2017 $this->_connectionID = false;
2018 return $rez;
2022 * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
2024 * @return true if succeeded or false if database does not support transactions
2026 function BeginTrans() {return false;}
2028 /* set transaction mode */
2029 function SetTransactionMode( $transaction_mode )
2031 $transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider);
2032 $this->_transmode = $transaction_mode;
2035 http://msdn2.microsoft.com/en-US/ms173763.aspx
2036 http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html
2037 http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html
2038 http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm
2040 function MetaTransaction($mode,$db)
2042 $mode = strtoupper($mode);
2043 $mode = str_replace('ISOLATION LEVEL ','',$mode);
2045 switch($mode) {
2047 case 'READ UNCOMMITTED':
2048 switch($db) {
2049 case 'oci8':
2050 case 'oracle':
2051 return 'ISOLATION LEVEL READ COMMITTED';
2052 default:
2053 return 'ISOLATION LEVEL READ UNCOMMITTED';
2055 break;
2057 case 'READ COMMITTED':
2058 return 'ISOLATION LEVEL READ COMMITTED';
2059 break;
2061 case 'REPEATABLE READ':
2062 switch($db) {
2063 case 'oci8':
2064 case 'oracle':
2065 return 'ISOLATION LEVEL SERIALIZABLE';
2066 default:
2067 return 'ISOLATION LEVEL REPEATABLE READ';
2069 break;
2071 case 'SERIALIZABLE':
2072 return 'ISOLATION LEVEL SERIALIZABLE';
2073 break;
2075 default:
2076 return $mode;
2081 * If database does not support transactions, always return true as data always commited
2083 * @param $ok set to false to rollback transaction, true to commit
2085 * @return true/false.
2087 function CommitTrans($ok=true)
2088 { return true;}
2092 * If database does not support transactions, rollbacks always fail, so return false
2094 * @return true/false.
2096 function RollbackTrans()
2097 { return false;}
2101 * return the databases that the driver can connect to.
2102 * Some databases will return an empty array.
2104 * @return an array of database names.
2106 function MetaDatabases()
2108 global $ADODB_FETCH_MODE;
2110 if ($this->metaDatabasesSQL) {
2111 $save = $ADODB_FETCH_MODE;
2112 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2114 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
2116 $arr = $this->GetCol($this->metaDatabasesSQL);
2117 if (isset($savem)) $this->SetFetchMode($savem);
2118 $ADODB_FETCH_MODE = $save;
2120 return $arr;
2123 return false;
2128 * @param ttype can either be 'VIEW' or 'TABLE' or false.
2129 * If false, both views and tables are returned.
2130 * "VIEW" returns only views
2131 * "TABLE" returns only tables
2132 * @param showSchema returns the schema/user with the table name, eg. USER.TABLE
2133 * @param mask is the input mask - only supported by oci8 and postgresql
2135 * @return array of tables for current database.
2137 function &MetaTables($ttype=false,$showSchema=false,$mask=false)
2139 global $ADODB_FETCH_MODE;
2142 $false = false;
2143 if ($mask) {
2144 return $false;
2146 if ($this->metaTablesSQL) {
2147 $save = $ADODB_FETCH_MODE;
2148 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2150 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
2152 $rs = $this->Execute($this->metaTablesSQL);
2153 if (isset($savem)) $this->SetFetchMode($savem);
2154 $ADODB_FETCH_MODE = $save;
2156 if ($rs === false) return $false;
2157 $arr =& $rs->GetArray();
2158 $arr2 = array();
2160 if ($hast = ($ttype && isset($arr[0][1]))) {
2161 $showt = strncmp($ttype,'T',1);
2164 for ($i=0; $i < sizeof($arr); $i++) {
2165 if ($hast) {
2166 if ($showt == 0) {
2167 if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]);
2168 } else {
2169 if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]);
2171 } else
2172 $arr2[] = trim($arr[$i][0]);
2174 $rs->Close();
2175 return $arr2;
2177 return $false;
2181 function _findschema(&$table,&$schema)
2183 if (!$schema && ($at = strpos($table,'.')) !== false) {
2184 $schema = substr($table,0,$at);
2185 $table = substr($table,$at+1);
2190 * List columns in a database as an array of ADOFieldObjects.
2191 * See top of file for definition of object.
2193 * @param $table table name to query
2194 * @param $normalize makes table name case-insensitive (required by some databases)
2195 * @schema is optional database schema to use - not supported by all databases.
2197 * @return array of ADOFieldObjects for current table.
2199 function &MetaColumns($table,$normalize=true)
2201 global $ADODB_FETCH_MODE;
2203 $false = false;
2205 if (!empty($this->metaColumnsSQL)) {
2207 $schema = false;
2208 $this->_findschema($table,$schema);
2210 $save = $ADODB_FETCH_MODE;
2211 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2212 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
2213 $rs = $this->Execute(sprintf($this->metaColumnsSQL,($normalize)?strtoupper($table):$table));
2214 if (isset($savem)) $this->SetFetchMode($savem);
2215 $ADODB_FETCH_MODE = $save;
2216 if ($rs === false || $rs->EOF) return $false;
2218 $retarr = array();
2219 while (!$rs->EOF) { //print_r($rs->fields);
2220 $fld = new ADOFieldObject();
2221 $fld->name = $rs->fields[0];
2222 $fld->type = $rs->fields[1];
2223 if (isset($rs->fields[3]) && $rs->fields[3]) {
2224 if ($rs->fields[3]>0) $fld->max_length = $rs->fields[3];
2225 $fld->scale = $rs->fields[4];
2226 if ($fld->scale>0) $fld->max_length += 1;
2227 } else
2228 $fld->max_length = $rs->fields[2];
2230 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
2231 else $retarr[strtoupper($fld->name)] = $fld;
2232 $rs->MoveNext();
2234 $rs->Close();
2235 return $retarr;
2237 return $false;
2241 * List indexes on a table as an array.
2242 * @param table table name to query
2243 * @param primary true to only show primary keys. Not actually used for most databases
2245 * @return array of indexes on current table. Each element represents an index, and is itself an associative array.
2247 Array (
2248 [name_of_index] => Array
2250 [unique] => true or false
2251 [columns] => Array
2253 [0] => firstname
2254 [1] => lastname
2258 function &MetaIndexes($table, $primary = false, $owner = false)
2260 $false = false;
2261 return $false;
2265 * List columns names in a table as an array.
2266 * @param table table name to query
2268 * @return array of column names for current table.
2270 function &MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */)
2272 $objarr =& $this->MetaColumns($table);
2273 if (!is_array($objarr)) {
2274 $false = false;
2275 return $false;
2277 $arr = array();
2278 if ($numIndexes) {
2279 $i = 0;
2280 if ($useattnum) {
2281 foreach($objarr as $v)
2282 $arr[$v->attnum] = $v->name;
2284 } else
2285 foreach($objarr as $v) $arr[$i++] = $v->name;
2286 } else
2287 foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name;
2289 return $arr;
2293 * Different SQL databases used different methods to combine strings together.
2294 * This function provides a wrapper.
2296 * param s variable number of string parameters
2298 * Usage: $db->Concat($str1,$str2);
2300 * @return concatenated string
2302 function Concat()
2304 $arr = func_get_args();
2305 return implode($this->concat_operator, $arr);
2310 * Converts a date "d" to a string that the database can understand.
2312 * @param d a date in Unix date time format.
2314 * @return date string in database date format
2316 function DBDate($d)
2318 if (empty($d) && $d !== 0) return 'null';
2320 if (is_string($d) && !is_numeric($d)) {
2321 if ($d === 'null' || strncmp($d,"'",1) === 0) return $d;
2322 if ($this->isoDates) return "'$d'";
2323 $d = ADOConnection::UnixDate($d);
2326 return adodb_date($this->fmtDate,$d);
2329 function BindDate($d)
2331 $d = $this->DBDate($d);
2332 if (strncmp($d,"'",1)) return $d;
2334 return substr($d,1,strlen($d)-2);
2337 function BindTimeStamp($d)
2339 $d = $this->DBTimeStamp($d);
2340 if (strncmp($d,"'",1)) return $d;
2342 return substr($d,1,strlen($d)-2);
2347 * Converts a timestamp "ts" to a string that the database can understand.
2349 * @param ts a timestamp in Unix date time format.
2351 * @return timestamp string in database timestamp format
2353 function DBTimeStamp($ts)
2355 if (empty($ts) && $ts !== 0) return 'null';
2357 # strlen(14) allows YYYYMMDDHHMMSS format
2358 if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14))
2359 return adodb_date($this->fmtTimeStamp,$ts);
2361 if ($ts === 'null') return $ts;
2362 if ($this->isoDates && strlen($ts) !== 14) return "'$ts'";
2364 $ts = ADOConnection::UnixTimeStamp($ts);
2365 return adodb_date($this->fmtTimeStamp,$ts);
2369 * Also in ADORecordSet.
2370 * @param $v is a date string in YYYY-MM-DD format
2372 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2374 function UnixDate($v)
2376 if (is_object($v)) {
2377 // odbtp support
2378 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2379 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2382 if (is_numeric($v) && strlen($v) !== 8) return $v;
2383 if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|",
2384 ($v), $rr)) return false;
2386 if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;
2387 // h-m-s-MM-DD-YY
2388 return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2393 * Also in ADORecordSet.
2394 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
2396 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2398 function UnixTimeStamp($v)
2400 if (is_object($v)) {
2401 // odbtp support
2402 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2403 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2406 if (!preg_match(
2407 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
2408 ($v), $rr)) return false;
2410 if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) return 0;
2412 // h-m-s-MM-DD-YY
2413 if (!isset($rr[5])) return adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2414 return @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
2418 * Also in ADORecordSet.
2420 * Format database date based on user defined format.
2422 * @param v is the character date in YYYY-MM-DD format, returned by database
2423 * @param fmt is the format to apply to it, using date()
2425 * @return a date formated as user desires
2428 function UserDate($v,$fmt='Y-m-d',$gmt=false)
2430 $tt = $this->UnixDate($v);
2432 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2433 if (($tt === false || $tt == -1) && $v != false) return $v;
2434 else if ($tt == 0) return $this->emptyDate;
2435 else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
2438 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2444 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
2445 * @param fmt is the format to apply to it, using date()
2447 * @return a timestamp formated as user desires
2449 function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false)
2451 if (!isset($v)) return $this->emptyTimeStamp;
2452 # strlen(14) allows YYYYMMDDHHMMSS format
2453 if (is_numeric($v) && strlen($v)<14) return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v);
2454 $tt = $this->UnixTimeStamp($v);
2455 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2456 if (($tt === false || $tt == -1) && $v != false) return $v;
2457 if ($tt == 0) return $this->emptyTimeStamp;
2458 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2461 function escape($s,$magic_quotes=false)
2463 return $this->addq($s,$magic_quotes);
2467 * Quotes a string, without prefixing nor appending quotes.
2469 function addq($s,$magic_quotes=false)
2471 if (!$magic_quotes) {
2473 if ($this->replaceQuote[0] == '\\'){
2474 // only since php 4.0.5
2475 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2476 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2478 return str_replace("'",$this->replaceQuote,$s);
2481 // undo magic quotes for "
2482 $s = str_replace('\\"','"',$s);
2484 if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything
2485 return $s;
2486 else {// change \' to '' for sybase/mssql
2487 $s = str_replace('\\\\','\\',$s);
2488 return str_replace("\\'",$this->replaceQuote,$s);
2493 * Correctly quotes a string so that all strings are escaped. We prefix and append
2494 * to the string single-quotes.
2495 * An example is $db->qstr("Don't bother",magic_quotes_runtime());
2497 * @param s the string to quote
2498 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
2499 * This undoes the stupidity of magic quotes for GPC.
2501 * @return quoted string to be sent back to database
2503 function qstr($s,$magic_quotes=false)
2505 if (!$magic_quotes) {
2507 if ($this->replaceQuote[0] == '\\'){
2508 // only since php 4.0.5
2509 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2510 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2512 return "'".str_replace("'",$this->replaceQuote,$s)."'";
2515 // undo magic quotes for "
2516 $s = str_replace('\\"','"',$s);
2518 if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything
2519 return "'$s'";
2520 else {// change \' to '' for sybase/mssql
2521 $s = str_replace('\\\\','\\',$s);
2522 return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
2528 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2529 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2530 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2532 * See readme.htm#ex8 for an example of usage.
2534 * @param sql
2535 * @param nrows is the number of rows per page to get
2536 * @param page is the page number to get (1-based)
2537 * @param [inputarr] array of bind variables
2538 * @param [secs2cache] is a private parameter only used by jlim
2539 * @return the recordset ($rs->databaseType == 'array')
2541 * NOTE: phpLens uses a different algorithm and does not use PageExecute().
2544 function &PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0)
2546 global $ADODB_INCLUDED_LIB;
2547 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
2548 if ($this->pageExecuteCountRows) $rs =& _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2549 else $rs =& _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2550 return $rs;
2555 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2556 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2557 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2559 * @param secs2cache seconds to cache data, set to 0 to force query
2560 * @param sql
2561 * @param nrows is the number of rows per page to get
2562 * @param page is the page number to get (1-based)
2563 * @param [inputarr] array of bind variables
2564 * @return the recordset ($rs->databaseType == 'array')
2566 function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false)
2568 /*switch($this->dataProvider) {
2569 case 'postgres':
2570 case 'mysql':
2571 break;
2572 default: $secs2cache = 0; break;
2574 $rs =& $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
2575 return $rs;
2578 } // end class ADOConnection
2582 //==============================================================================================
2583 // CLASS ADOFetchObj
2584 //==============================================================================================
2587 * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
2589 class ADOFetchObj {
2592 //==============================================================================================
2593 // CLASS ADORecordSet_empty
2594 //==============================================================================================
2597 * Lightweight recordset when there are no records to be returned
2599 class ADORecordSet_empty
2601 var $dataProvider = 'empty';
2602 var $databaseType = false;
2603 var $EOF = true;
2604 var $_numOfRows = 0;
2605 var $fields = false;
2606 var $connection = false;
2607 function RowCount() {return 0;}
2608 function RecordCount() {return 0;}
2609 function PO_RecordCount(){return 0;}
2610 function Close(){return true;}
2611 function FetchRow() {return false;}
2612 function FieldCount(){ return 0;}
2613 function Init() {}
2616 //==============================================================================================
2617 // DATE AND TIME FUNCTIONS
2618 //==============================================================================================
2619 if (!defined('ADODB_DATE_VERSION')) include(ADODB_DIR.'/adodb-time.inc.php');
2621 //==============================================================================================
2622 // CLASS ADORecordSet
2623 //==============================================================================================
2625 if (PHP_VERSION < 5) include_once(ADODB_DIR.'/adodb-php4.inc.php');
2626 else include_once(ADODB_DIR.'/adodb-iterator.inc.php');
2628 * RecordSet class that represents the dataset returned by the database.
2629 * To keep memory overhead low, this class holds only the current row in memory.
2630 * No prefetching of data is done, so the RecordCount() can return -1 ( which
2631 * means recordcount not known).
2633 class ADORecordSet extends ADODB_BASE_RS {
2635 * public variables
2637 var $dataProvider = "native";
2638 var $fields = false; /// holds the current row data
2639 var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob
2640 /// in other words, we use a text area for editing.
2641 var $canSeek = false; /// indicates that seek is supported
2642 var $sql; /// sql text
2643 var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object.
2645 var $emptyTimeStamp = '&nbsp;'; /// what to display when $time==0
2646 var $emptyDate = '&nbsp;'; /// what to display when $time==0
2647 var $debug = false;
2648 var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsets
2650 var $bind = false; /// used by Fields() to hold array - should be private?
2651 var $fetchMode; /// default fetch mode
2652 var $connection = false; /// the parent connection
2654 * private variables
2656 var $_numOfRows = -1; /** number of rows, or -1 */
2657 var $_numOfFields = -1; /** number of fields in recordset */
2658 var $_queryID = -1; /** This variable keeps the result link identifier. */
2659 var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */
2660 var $_closed = false; /** has recordset been closed */
2661 var $_inited = false; /** Init() should only be called once */
2662 var $_obj; /** Used by FetchObj */
2663 var $_names; /** Used by FetchObj */
2665 var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */
2666 var $_atFirstPage = false; /** Added by Iván Oliva to implement recordset pagination */
2667 var $_atLastPage = false; /** Added by Iván Oliva to implement recordset pagination */
2668 var $_lastPageNo = -1;
2669 var $_maxRecordCount = 0;
2670 var $datetime = false;
2673 * Constructor
2675 * @param queryID this is the queryID returned by ADOConnection->_query()
2678 function ADORecordSet($queryID)
2680 $this->_queryID = $queryID;
2685 function Init()
2687 if ($this->_inited) return;
2688 $this->_inited = true;
2689 if ($this->_queryID) @$this->_initrs();
2690 else {
2691 $this->_numOfRows = 0;
2692 $this->_numOfFields = 0;
2694 if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
2696 $this->_currentRow = 0;
2697 if ($this->EOF = ($this->_fetch() === false)) {
2698 $this->_numOfRows = 0; // _numOfRows could be -1
2700 } else {
2701 $this->EOF = true;
2707 * Generate a SELECT tag string from a recordset, and return the string.
2708 * If the recordset has 2 cols, we treat the 1st col as the containing
2709 * the text to display to the user, and 2nd col as the return value. Default
2710 * strings are compared with the FIRST column.
2712 * @param name name of SELECT tag
2713 * @param [defstr] the value to hilite. Use an array for multiple hilites for listbox.
2714 * @param [blank1stItem] true to leave the 1st item in list empty
2715 * @param [multiple] true for listbox, false for popup
2716 * @param [size] #rows to show for listbox. not used by popup
2717 * @param [selectAttr] additional attributes to defined for SELECT tag.
2718 * useful for holding javascript onChange='...' handlers.
2719 & @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with
2720 * column 0 (1st col) if this is true. This is not documented.
2722 * @return HTML
2724 * changes by glen.davies@cce.ac.nz to support multiple hilited items
2726 function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
2727 $size=0, $selectAttr='',$compareFields0=true)
2729 global $ADODB_INCLUDED_LIB;
2730 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
2731 return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
2732 $size, $selectAttr,$compareFields0);
2738 * Generate a SELECT tag string from a recordset, and return the string.
2739 * If the recordset has 2 cols, we treat the 1st col as the containing
2740 * the text to display to the user, and 2nd col as the return value. Default
2741 * strings are compared with the SECOND column.
2744 function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='')
2746 return $this->GetMenu($name,$defstr,$blank1stItem,$multiple,
2747 $size, $selectAttr,false);
2751 Grouped Menu
2753 function GetMenu3($name,$defstr='',$blank1stItem=true,$multiple=false,
2754 $size=0, $selectAttr='')
2756 global $ADODB_INCLUDED_LIB;
2757 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
2758 return _adodb_getmenu_gp($this, $name,$defstr,$blank1stItem,$multiple,
2759 $size, $selectAttr,false);
2763 * return recordset as a 2-dimensional array.
2765 * @param [nRows] is the number of rows to return. -1 means every row.
2767 * @return an array indexed by the rows (0-based) from the recordset
2769 function &GetArray($nRows = -1)
2771 global $ADODB_EXTENSION; if ($ADODB_EXTENSION) {
2772 $results = adodb_getall($this,$nRows);
2773 return $results;
2775 $results = array();
2776 $cnt = 0;
2777 while (!$this->EOF && $nRows != $cnt) {
2778 $results[] = $this->fields;
2779 $this->MoveNext();
2780 $cnt++;
2782 return $results;
2785 function &GetAll($nRows = -1)
2787 $arr =& $this->GetArray($nRows);
2788 return $arr;
2792 * Some databases allow multiple recordsets to be returned. This function
2793 * will return true if there is a next recordset, or false if no more.
2795 function NextRecordSet()
2797 return false;
2801 * return recordset as a 2-dimensional array.
2802 * Helper function for ADOConnection->SelectLimit()
2804 * @param offset is the row to start calculations from (1-based)
2805 * @param [nrows] is the number of rows to return
2807 * @return an array indexed by the rows (0-based) from the recordset
2809 function &GetArrayLimit($nrows,$offset=-1)
2811 if ($offset <= 0) {
2812 $arr =& $this->GetArray($nrows);
2813 return $arr;
2816 $this->Move($offset);
2818 $results = array();
2819 $cnt = 0;
2820 while (!$this->EOF && $nrows != $cnt) {
2821 $results[$cnt++] = $this->fields;
2822 $this->MoveNext();
2825 return $results;
2830 * Synonym for GetArray() for compatibility with ADO.
2832 * @param [nRows] is the number of rows to return. -1 means every row.
2834 * @return an array indexed by the rows (0-based) from the recordset
2836 function &GetRows($nRows = -1)
2838 $arr =& $this->GetArray($nRows);
2839 return $arr;
2843 * return whole recordset as a 2-dimensional associative array if there are more than 2 columns.
2844 * The first column is treated as the key and is not included in the array.
2845 * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless
2846 * $force_array == true.
2848 * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional
2849 * array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,
2850 * read the source.
2852 * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and
2853 * instead of returning array[col0] => array(remaining cols), return array[col0] => col1
2855 * @return an associative array indexed by the first column of the array,
2856 * or false if the data has less than 2 cols.
2858 function &GetAssoc($force_array = false, $first2cols = false)
2860 global $ADODB_EXTENSION;
2862 $cols = $this->_numOfFields;
2863 if ($cols < 2) {
2864 $false = false;
2865 return $false;
2867 $numIndex = isset($this->fields[0]);
2868 $results = array();
2870 if (!$first2cols && ($cols > 2 || $force_array)) {
2871 if ($ADODB_EXTENSION) {
2872 if ($numIndex) {
2873 while (!$this->EOF) {
2874 $results[trim($this->fields[0])] = array_slice($this->fields, 1);
2875 adodb_movenext($this);
2877 } else {
2878 while (!$this->EOF) {
2879 $results[trim(reset($this->fields))] = array_slice($this->fields, 1);
2880 adodb_movenext($this);
2883 } else {
2884 if ($numIndex) {
2885 while (!$this->EOF) {
2886 $results[trim($this->fields[0])] = array_slice($this->fields, 1);
2887 $this->MoveNext();
2889 } else {
2890 while (!$this->EOF) {
2891 $results[trim(reset($this->fields))] = array_slice($this->fields, 1);
2892 $this->MoveNext();
2896 } else {
2897 if ($ADODB_EXTENSION) {
2898 // return scalar values
2899 if ($numIndex) {
2900 while (!$this->EOF) {
2901 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
2902 $results[trim(($this->fields[0]))] = $this->fields[1];
2903 adodb_movenext($this);
2905 } else {
2906 while (!$this->EOF) {
2907 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
2908 $v1 = trim(reset($this->fields));
2909 $v2 = ''.next($this->fields);
2910 $results[$v1] = $v2;
2911 adodb_movenext($this);
2914 } else {
2915 if ($numIndex) {
2916 while (!$this->EOF) {
2917 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
2918 $results[trim(($this->fields[0]))] = $this->fields[1];
2919 $this->MoveNext();
2921 } else {
2922 while (!$this->EOF) {
2923 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
2924 $v1 = trim(reset($this->fields));
2925 $v2 = ''.next($this->fields);
2926 $results[$v1] = $v2;
2927 $this->MoveNext();
2933 $ref =& $results; # workaround accelerator incompat with PHP 4.4 :(
2934 return $ref;
2940 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
2941 * @param fmt is the format to apply to it, using date()
2943 * @return a timestamp formated as user desires
2945 function UserTimeStamp($v,$fmt='Y-m-d H:i:s')
2947 if (is_numeric($v) && strlen($v)<14) return adodb_date($fmt,$v);
2948 $tt = $this->UnixTimeStamp($v);
2949 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2950 if (($tt === false || $tt == -1) && $v != false) return $v;
2951 if ($tt === 0) return $this->emptyTimeStamp;
2952 return adodb_date($fmt,$tt);
2957 * @param v is the character date in YYYY-MM-DD format, returned by database
2958 * @param fmt is the format to apply to it, using date()
2960 * @return a date formated as user desires
2962 function UserDate($v,$fmt='Y-m-d')
2964 $tt = $this->UnixDate($v);
2965 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2966 if (($tt === false || $tt == -1) && $v != false) return $v;
2967 else if ($tt == 0) return $this->emptyDate;
2968 else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
2970 return adodb_date($fmt,$tt);
2975 * @param $v is a date string in YYYY-MM-DD format
2977 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2979 function UnixDate($v)
2981 return ADOConnection::UnixDate($v);
2986 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
2988 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2990 function UnixTimeStamp($v)
2992 return ADOConnection::UnixTimeStamp($v);
2997 * PEAR DB Compat - do not use internally
2999 function Free()
3001 return $this->Close();
3006 * PEAR DB compat, number of rows
3008 function NumRows()
3010 return $this->_numOfRows;
3015 * PEAR DB compat, number of cols
3017 function NumCols()
3019 return $this->_numOfFields;
3023 * Fetch a row, returning false if no more rows.
3024 * This is PEAR DB compat mode.
3026 * @return false or array containing the current record
3028 function &FetchRow()
3030 if ($this->EOF) {
3031 $false = false;
3032 return $false;
3034 $arr = $this->fields;
3035 $this->_currentRow++;
3036 if (!$this->_fetch()) $this->EOF = true;
3037 return $arr;
3042 * Fetch a row, returning PEAR_Error if no more rows.
3043 * This is PEAR DB compat mode.
3045 * @return DB_OK or error object
3047 function FetchInto(&$arr)
3049 if ($this->EOF) return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false;
3050 $arr = $this->fields;
3051 $this->MoveNext();
3052 return 1; // DB_OK
3057 * Move to the first row in the recordset. Many databases do NOT support this.
3059 * @return true or false
3061 function MoveFirst()
3063 if ($this->_currentRow == 0) return true;
3064 return $this->Move(0);
3069 * Move to the last row in the recordset.
3071 * @return true or false
3073 function MoveLast()
3075 if ($this->_numOfRows >= 0) return $this->Move($this->_numOfRows-1);
3076 if ($this->EOF) return false;
3077 while (!$this->EOF) {
3078 $f = $this->fields;
3079 $this->MoveNext();
3081 $this->fields = $f;
3082 $this->EOF = false;
3083 return true;
3088 * Move to next record in the recordset.
3090 * @return true if there still rows available, or false if there are no more rows (EOF).
3092 function MoveNext()
3094 if (!$this->EOF) {
3095 $this->_currentRow++;
3096 if ($this->_fetch()) return true;
3098 $this->EOF = true;
3099 /* -- tested error handling when scrolling cursor -- seems useless.
3100 $conn = $this->connection;
3101 if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
3102 $fn = $conn->raiseErrorFn;
3103 $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
3106 return false;
3111 * Random access to a specific row in the recordset. Some databases do not support
3112 * access to previous rows in the databases (no scrolling backwards).
3114 * @param rowNumber is the row to move to (0-based)
3116 * @return true if there still rows available, or false if there are no more rows (EOF).
3118 function Move($rowNumber = 0)
3120 $this->EOF = false;
3121 if ($rowNumber == $this->_currentRow) return true;
3122 if ($rowNumber >= $this->_numOfRows)
3123 if ($this->_numOfRows != -1) $rowNumber = $this->_numOfRows-2;
3125 if ($this->canSeek) {
3127 if ($this->_seek($rowNumber)) {
3128 $this->_currentRow = $rowNumber;
3129 if ($this->_fetch()) {
3130 return true;
3132 } else {
3133 $this->EOF = true;
3134 return false;
3136 } else {
3137 if ($rowNumber < $this->_currentRow) return false;
3138 global $ADODB_EXTENSION;
3139 if ($ADODB_EXTENSION) {
3140 while (!$this->EOF && $this->_currentRow < $rowNumber) {
3141 adodb_movenext($this);
3143 } else {
3145 while (! $this->EOF && $this->_currentRow < $rowNumber) {
3146 $this->_currentRow++;
3148 if (!$this->_fetch()) $this->EOF = true;
3151 return !($this->EOF);
3154 $this->fields = false;
3155 $this->EOF = true;
3156 return false;
3161 * Get the value of a field in the current row by column name.
3162 * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
3164 * @param colname is the field to access
3166 * @return the value of $colname column
3168 function Fields($colname)
3170 return $this->fields[$colname];
3173 function GetAssocKeys($upper=true)
3175 $this->bind = array();
3176 for ($i=0; $i < $this->_numOfFields; $i++) {
3177 $o = $this->FetchField($i);
3178 if ($upper === 2) $this->bind[$o->name] = $i;
3179 else $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $i;
3184 * Use associative array to get fields array for databases that do not support
3185 * associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it
3187 * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC
3188 * before you execute your SQL statement, and access $rs->fields['col'] directly.
3190 * $upper 0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField
3192 function &GetRowAssoc($upper=1)
3194 $record = array();
3195 // if (!$this->fields) return $record;
3197 if (!$this->bind) {
3198 $this->GetAssocKeys($upper);
3201 foreach($this->bind as $k => $v) {
3202 $record[$k] = $this->fields[$v];
3205 return $record;
3210 * Clean up recordset
3212 * @return true or false
3214 function Close()
3216 // free connection object - this seems to globally free the object
3217 // and not merely the reference, so don't do this...
3218 // $this->connection = false;
3219 if (!$this->_closed) {
3220 $this->_closed = true;
3221 return $this->_close();
3222 } else
3223 return true;
3227 * synonyms RecordCount and RowCount
3229 * @return the number of rows or -1 if this is not supported
3231 function RecordCount() {return $this->_numOfRows;}
3235 * If we are using PageExecute(), this will return the maximum possible rows
3236 * that can be returned when paging a recordset.
3238 function MaxRecordCount()
3240 return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();
3244 * synonyms RecordCount and RowCount
3246 * @return the number of rows or -1 if this is not supported
3248 function RowCount() {return $this->_numOfRows;}
3252 * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
3254 * @return the number of records from a previous SELECT. All databases support this.
3256 * But aware possible problems in multiuser environments. For better speed the table
3257 * must be indexed by the condition. Heavy test this before deploying.
3259 function PO_RecordCount($table="", $condition="") {
3261 $lnumrows = $this->_numOfRows;
3262 // the database doesn't support native recordcount, so we do a workaround
3263 if ($lnumrows == -1 && $this->connection) {
3264 IF ($table) {
3265 if ($condition) $condition = " WHERE " . $condition;
3266 $resultrows = &$this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
3267 if ($resultrows) $lnumrows = reset($resultrows->fields);
3270 return $lnumrows;
3275 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
3277 function CurrentRow() {return $this->_currentRow;}
3280 * synonym for CurrentRow -- for ADO compat
3282 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
3284 function AbsolutePosition() {return $this->_currentRow;}
3287 * @return the number of columns in the recordset. Some databases will set this to 0
3288 * if no records are returned, others will return the number of columns in the query.
3290 function FieldCount() {return $this->_numOfFields;}
3294 * Get the ADOFieldObject of a specific column.
3296 * @param fieldoffset is the column position to access(0-based).
3298 * @return the ADOFieldObject for that column, or false.
3300 function &FetchField($fieldoffset)
3302 // must be defined by child class
3306 * Get the ADOFieldObjects of all columns in an array.
3309 function& FieldTypesArray()
3311 $arr = array();
3312 for ($i=0, $max=$this->_numOfFields; $i < $max; $i++)
3313 $arr[] = $this->FetchField($i);
3314 return $arr;
3318 * Return the fields array of the current row as an object for convenience.
3319 * The default case is lowercase field names.
3321 * @return the object with the properties set to the fields of the current row
3323 function &FetchObj()
3325 $o =& $this->FetchObject(false);
3326 return $o;
3330 * Return the fields array of the current row as an object for convenience.
3331 * The default case is uppercase.
3333 * @param $isupper to set the object property names to uppercase
3335 * @return the object with the properties set to the fields of the current row
3337 function &FetchObject($isupper=true)
3339 if (empty($this->_obj)) {
3340 $this->_obj = new ADOFetchObj();
3341 $this->_names = array();
3342 for ($i=0; $i <$this->_numOfFields; $i++) {
3343 $f = $this->FetchField($i);
3344 $this->_names[] = $f->name;
3347 $i = 0;
3348 if (PHP_VERSION >= 5) $o = clone($this->_obj);
3349 else $o = $this->_obj;
3351 for ($i=0; $i <$this->_numOfFields; $i++) {
3352 $name = $this->_names[$i];
3353 if ($isupper) $n = strtoupper($name);
3354 else $n = $name;
3356 $o->$n = $this->Fields($name);
3358 return $o;
3362 * Return the fields array of the current row as an object for convenience.
3363 * The default is lower-case field names.
3365 * @return the object with the properties set to the fields of the current row,
3366 * or false if EOF
3368 * Fixed bug reported by tim@orotech.net
3370 function &FetchNextObj()
3372 $o =& $this->FetchNextObject(false);
3373 return $o;
3378 * Return the fields array of the current row as an object for convenience.
3379 * The default is upper case field names.
3381 * @param $isupper to set the object property names to uppercase
3383 * @return the object with the properties set to the fields of the current row,
3384 * or false if EOF
3386 * Fixed bug reported by tim@orotech.net
3388 function &FetchNextObject($isupper=true)
3390 $o = false;
3391 if ($this->_numOfRows != 0 && !$this->EOF) {
3392 $o = $this->FetchObject($isupper);
3393 $this->_currentRow++;
3394 if ($this->_fetch()) return $o;
3396 $this->EOF = true;
3397 return $o;
3401 * Get the metatype of the column. This is used for formatting. This is because
3402 * many databases use different names for the same type, so we transform the original
3403 * type to our standardised version which uses 1 character codes:
3405 * @param t is the type passed in. Normally is ADOFieldObject->type.
3406 * @param len is the maximum length of that field. This is because we treat character
3407 * fields bigger than a certain size as a 'B' (blob).
3408 * @param fieldobj is the field object returned by the database driver. Can hold
3409 * additional info (eg. primary_key for mysql).
3411 * @return the general type of the data:
3412 * C for character < 250 chars
3413 * X for teXt (>= 250 chars)
3414 * B for Binary
3415 * N for numeric or floating point
3416 * D for date
3417 * T for timestamp
3418 * L for logical/Boolean
3419 * I for integer
3420 * R for autoincrement counter/integer
3424 function MetaType($t,$len=-1,$fieldobj=false)
3426 if (is_object($t)) {
3427 $fieldobj = $t;
3428 $t = $fieldobj->type;
3429 $len = $fieldobj->max_length;
3431 // changed in 2.32 to hashing instead of switch stmt for speed...
3432 static $typeMap = array(
3433 'VARCHAR' => 'C',
3434 'VARCHAR2' => 'C',
3435 'CHAR' => 'C',
3436 'C' => 'C',
3437 'STRING' => 'C',
3438 'NCHAR' => 'C',
3439 'NVARCHAR' => 'C',
3440 'VARYING' => 'C',
3441 'BPCHAR' => 'C',
3442 'CHARACTER' => 'C',
3443 'INTERVAL' => 'C', # Postgres
3444 'MACADDR' => 'C', # postgres
3446 'LONGCHAR' => 'X',
3447 'TEXT' => 'X',
3448 'NTEXT' => 'X',
3449 'M' => 'X',
3450 'X' => 'X',
3451 'CLOB' => 'X',
3452 'NCLOB' => 'X',
3453 'LVARCHAR' => 'X',
3455 'BLOB' => 'B',
3456 'IMAGE' => 'B',
3457 'BINARY' => 'B',
3458 'VARBINARY' => 'B',
3459 'LONGBINARY' => 'B',
3460 'B' => 'B',
3462 'YEAR' => 'D', // mysql
3463 'DATE' => 'D',
3464 'D' => 'D',
3466 'TIME' => 'T',
3467 'TIMESTAMP' => 'T',
3468 'DATETIME' => 'T',
3469 'TIMESTAMPTZ' => 'T',
3470 'T' => 'T',
3471 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
3473 'BOOL' => 'L',
3474 'BOOLEAN' => 'L',
3475 'BIT' => 'L',
3476 'L' => 'L',
3478 'COUNTER' => 'R',
3479 'R' => 'R',
3480 'SERIAL' => 'R', // ifx
3481 'INT IDENTITY' => 'R',
3483 'INT' => 'I',
3484 'INT2' => 'I',
3485 'INT4' => 'I',
3486 'INT8' => 'I',
3487 'INTEGER' => 'I',
3488 'INTEGER UNSIGNED' => 'I',
3489 'SHORT' => 'I',
3490 'TINYINT' => 'I',
3491 'SMALLINT' => 'I',
3492 'I' => 'I',
3494 'LONG' => 'N', // interbase is numeric, oci8 is blob
3495 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
3496 'DECIMAL' => 'N',
3497 'DEC' => 'N',
3498 'REAL' => 'N',
3499 'DOUBLE' => 'N',
3500 'DOUBLE PRECISION' => 'N',
3501 'SMALLFLOAT' => 'N',
3502 'FLOAT' => 'N',
3503 'NUMBER' => 'N',
3504 'NUM' => 'N',
3505 'NUMERIC' => 'N',
3506 'MONEY' => 'N',
3508 ## informix 9.2
3509 'SQLINT' => 'I',
3510 'SQLSERIAL' => 'I',
3511 'SQLSMINT' => 'I',
3512 'SQLSMFLOAT' => 'N',
3513 'SQLFLOAT' => 'N',
3514 'SQLMONEY' => 'N',
3515 'SQLDECIMAL' => 'N',
3516 'SQLDATE' => 'D',
3517 'SQLVCHAR' => 'C',
3518 'SQLCHAR' => 'C',
3519 'SQLDTIME' => 'T',
3520 'SQLINTERVAL' => 'N',
3521 'SQLBYTES' => 'B',
3522 'SQLTEXT' => 'X'
3525 $tmap = false;
3526 $t = strtoupper($t);
3527 $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N';
3528 switch ($tmap) {
3529 case 'C':
3531 // is the char field is too long, return as text field...
3532 if ($this->blobSize >= 0) {
3533 if ($len > $this->blobSize) return 'X';
3534 } else if ($len > 250) {
3535 return 'X';
3537 return 'C';
3539 case 'I':
3540 if (!empty($fieldobj->primary_key)) return 'R';
3541 return 'I';
3543 case false:
3544 return 'N';
3546 case 'B':
3547 if (isset($fieldobj->binary))
3548 return ($fieldobj->binary) ? 'B' : 'X';
3549 return 'B';
3551 case 'D':
3552 if (!empty($this->connection) && !empty($this->connection->datetime)) return 'T';
3553 return 'D';
3555 default:
3556 if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B';
3557 return $tmap;
3561 function _close() {}
3564 * set/returns the current recordset page when paginating
3566 function AbsolutePage($page=-1)
3568 if ($page != -1) $this->_currentPage = $page;
3569 return $this->_currentPage;
3573 * set/returns the status of the atFirstPage flag when paginating
3575 function AtFirstPage($status=false)
3577 if ($status != false) $this->_atFirstPage = $status;
3578 return $this->_atFirstPage;
3581 function LastPageNo($page = false)
3583 if ($page != false) $this->_lastPageNo = $page;
3584 return $this->_lastPageNo;
3588 * set/returns the status of the atLastPage flag when paginating
3590 function AtLastPage($status=false)
3592 if ($status != false) $this->_atLastPage = $status;
3593 return $this->_atLastPage;
3596 } // end class ADORecordSet
3598 //==============================================================================================
3599 // CLASS ADORecordSet_array
3600 //==============================================================================================
3603 * This class encapsulates the concept of a recordset created in memory
3604 * as an array. This is useful for the creation of cached recordsets.
3606 * Note that the constructor is different from the standard ADORecordSet
3609 class ADORecordSet_array extends ADORecordSet
3611 var $databaseType = 'array';
3613 var $_array; // holds the 2-dimensional data array
3614 var $_types; // the array of types of each column (C B I L M)
3615 var $_colnames; // names of each column in array
3616 var $_skiprow1; // skip 1st row because it holds column names
3617 var $_fieldarr; // holds array of field objects
3618 var $canSeek = true;
3619 var $affectedrows = false;
3620 var $insertid = false;
3621 var $sql = '';
3622 var $compat = false;
3624 * Constructor
3627 function ADORecordSet_array($fakeid=1)
3629 global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;
3631 // fetch() on EOF does not delete $this->fields
3632 $this->compat = !empty($ADODB_COMPAT_FETCH);
3633 $this->ADORecordSet($fakeid); // fake queryID
3634 $this->fetchMode = $ADODB_FETCH_MODE;
3639 * Setup the array.
3641 * @param array is a 2-dimensional array holding the data.
3642 * The first row should hold the column names
3643 * unless paramter $colnames is used.
3644 * @param typearr holds an array of types. These are the same types
3645 * used in MetaTypes (C,B,L,I,N).
3646 * @param [colnames] array of column names. If set, then the first row of
3647 * $array should not hold the column names.
3649 function InitArray($array,$typearr,$colnames=false)
3651 $this->_array = $array;
3652 $this->_types = $typearr;
3653 if ($colnames) {
3654 $this->_skiprow1 = false;
3655 $this->_colnames = $colnames;
3656 } else {
3657 $this->_skiprow1 = true;
3658 $this->_colnames = $array[0];
3660 $this->Init();
3663 * Setup the Array and datatype file objects
3665 * @param array is a 2-dimensional array holding the data.
3666 * The first row should hold the column names
3667 * unless paramter $colnames is used.
3668 * @param fieldarr holds an array of ADOFieldObject's.
3670 function InitArrayFields(&$array,&$fieldarr)
3672 $this->_array =& $array;
3673 $this->_skiprow1= false;
3674 if ($fieldarr) {
3675 $this->_fieldobjects =& $fieldarr;
3677 $this->Init();
3680 function &GetArray($nRows=-1)
3682 if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) {
3683 return $this->_array;
3684 } else {
3685 $arr =& ADORecordSet::GetArray($nRows);
3686 return $arr;
3690 function _initrs()
3692 $this->_numOfRows = sizeof($this->_array);
3693 if ($this->_skiprow1) $this->_numOfRows -= 1;
3695 $this->_numOfFields =(isset($this->_fieldobjects)) ?
3696 sizeof($this->_fieldobjects):sizeof($this->_types);
3699 /* Use associative array to get fields array */
3700 function Fields($colname)
3702 $mode = isset($this->adodbFetchMode) ? $this->adodbFetchMode : $this->fetchMode;
3704 if ($mode & ADODB_FETCH_ASSOC) {
3705 if (!isset($this->fields[$colname])) $colname = strtolower($colname);
3706 return $this->fields[$colname];
3708 if (!$this->bind) {
3709 $this->bind = array();
3710 for ($i=0; $i < $this->_numOfFields; $i++) {
3711 $o = $this->FetchField($i);
3712 $this->bind[strtoupper($o->name)] = $i;
3715 return $this->fields[$this->bind[strtoupper($colname)]];
3718 function &FetchField($fieldOffset = -1)
3720 if (isset($this->_fieldobjects)) {
3721 return $this->_fieldobjects[$fieldOffset];
3723 $o = new ADOFieldObject();
3724 $o->name = $this->_colnames[$fieldOffset];
3725 $o->type = $this->_types[$fieldOffset];
3726 $o->max_length = -1; // length not known
3728 return $o;
3731 function _seek($row)
3733 if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) {
3734 $this->_currentRow = $row;
3735 if ($this->_skiprow1) $row += 1;
3736 $this->fields = $this->_array[$row];
3737 return true;
3739 return false;
3742 function MoveNext()
3744 if (!$this->EOF) {
3745 $this->_currentRow++;
3747 $pos = $this->_currentRow;
3749 if ($this->_numOfRows <= $pos) {
3750 if (!$this->compat) $this->fields = false;
3751 } else {
3752 if ($this->_skiprow1) $pos += 1;
3753 $this->fields = $this->_array[$pos];
3754 return true;
3756 $this->EOF = true;
3759 return false;
3762 function _fetch()
3764 $pos = $this->_currentRow;
3766 if ($this->_numOfRows <= $pos) {
3767 if (!$this->compat) $this->fields = false;
3768 return false;
3770 if ($this->_skiprow1) $pos += 1;
3771 $this->fields = $this->_array[$pos];
3772 return true;
3775 function _close()
3777 return true;
3780 } // ADORecordSet_array
3782 //==============================================================================================
3783 // HELPER FUNCTIONS
3784 //==============================================================================================
3787 * Synonym for ADOLoadCode. Private function. Do not use.
3789 * @deprecated
3791 function ADOLoadDB($dbType)
3793 return ADOLoadCode($dbType);
3797 * Load the code for a specific database driver. Private function. Do not use.
3799 function ADOLoadCode($dbType)
3801 global $ADODB_LASTDB;
3803 if (!$dbType) return false;
3804 $db = strtolower($dbType);
3805 switch ($db) {
3806 case 'ado':
3807 if (PHP_VERSION >= 5) $db = 'ado5';
3808 $class = 'ado';
3809 break;
3810 case 'ifx':
3811 case 'maxsql': $class = $db = 'mysqlt'; break;
3812 case 'postgres':
3813 case 'postgres8':
3814 case 'pgsql': $class = $db = 'postgres7'; break;
3815 default:
3816 $class = $db; break;
3819 $file = ADODB_DIR."/drivers/adodb-".$db.".inc.php";
3820 @include_once($file);
3821 $ADODB_LASTDB = $class;
3822 if (class_exists("ADODB_" . $class)) return $class;
3824 //ADOConnection::outp(adodb_pr(get_declared_classes(),true));
3825 if (!file_exists($file)) ADOConnection::outp("Missing file: $file");
3826 else ADOConnection::outp("Syntax error in file: $file");
3827 return false;
3831 * synonym for ADONewConnection for people like me who cannot remember the correct name
3833 function &NewADOConnection($db='')
3835 $tmp =& ADONewConnection($db);
3836 return $tmp;
3840 * Instantiate a new Connection class for a specific database driver.
3842 * @param [db] is the database Connection object to create. If undefined,
3843 * use the last database driver that was loaded by ADOLoadCode().
3845 * @return the freshly created instance of the Connection class.
3847 function &ADONewConnection($db='')
3849 GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB;
3851 if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
3852 $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false;
3853 $false = false;
3854 if ($at = strpos($db,'://')) {
3855 $origdsn = $db;
3856 if (PHP_VERSION < 5) $dsna = @parse_url($db);
3857 else {
3858 $fakedsn = 'fake'.substr($db,$at);
3859 $dsna = @parse_url($fakedsn);
3860 $dsna['scheme'] = substr($db,0,$at);
3862 if (strncmp($db,'pdo',3) == 0) {
3863 $sch = explode('_',$dsna['scheme']);
3864 if (sizeof($sch)>1) {
3865 $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : '';
3866 $dsna['host'] = rawurlencode($sch[1].':host='.rawurldecode($dsna['host']));
3867 $dsna['scheme'] = 'pdo';
3872 if (!$dsna) {
3873 // special handling of oracle, which might not have host
3874 $db = str_replace('@/','@adodb-fakehost/',$db);
3875 $dsna = parse_url($db);
3876 if (!$dsna) return $false;
3877 $dsna['host'] = '';
3879 $db = @$dsna['scheme'];
3880 if (!$db) return $false;
3881 $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : '';
3882 $dsna['user'] = isset($dsna['user']) ? rawurldecode($dsna['user']) : '';
3883 $dsna['pass'] = isset($dsna['pass']) ? rawurldecode($dsna['pass']) : '';
3884 $dsna['path'] = isset($dsna['path']) ? rawurldecode(substr($dsna['path'],1)) : ''; # strip off initial /
3886 if (isset($dsna['query'])) {
3887 $opt1 = explode('&',$dsna['query']);
3888 foreach($opt1 as $k => $v) {
3889 $arr = explode('=',$v);
3890 $opt[$arr[0]] = isset($arr[1]) ? rawurldecode($arr[1]) : 1;
3892 } else $opt = array();
3895 * phptype: Database backend used in PHP (mysql, odbc etc.)
3896 * dbsyntax: Database used with regards to SQL syntax etc.
3897 * protocol: Communication protocol to use (tcp, unix etc.)
3898 * hostspec: Host specification (hostname[:port])
3899 * database: Database to use on the DBMS server
3900 * username: User name for login
3901 * password: Password for login
3903 if (!empty($ADODB_NEWCONNECTION)) {
3904 $obj = $ADODB_NEWCONNECTION($db);
3906 } else {
3908 if (!isset($ADODB_LASTDB)) $ADODB_LASTDB = '';
3909 if (empty($db)) $db = $ADODB_LASTDB;
3911 if ($db != $ADODB_LASTDB) $db = ADOLoadCode($db);
3913 if (!$db) {
3914 if (isset($origdsn)) $db = $origdsn;
3915 if ($errorfn) {
3916 // raise an error
3917 $ignore = false;
3918 $errorfn('ADONewConnection', 'ADONewConnection', -998,
3919 "could not load the database driver for '$db'",
3920 $db,false,$ignore);
3921 } else
3922 ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false);
3924 return $false;
3927 $cls = 'ADODB_'.$db;
3928 if (!class_exists($cls)) {
3929 adodb_backtrace();
3930 return $false;
3933 $obj = new $cls();
3936 # constructor should not fail
3937 if ($obj) {
3938 if ($errorfn) $obj->raiseErrorFn = $errorfn;
3939 if (isset($dsna)) {
3940 if (isset($dsna['port'])) $obj->port = $dsna['port'];
3941 foreach($opt as $k => $v) {
3942 switch(strtolower($k)) {
3943 case 'new':
3944 $nconnect = true; $persist = true; break;
3945 case 'persist':
3946 case 'persistent': $persist = $v; break;
3947 case 'debug': $obj->debug = (integer) $v; break;
3948 #ibase
3949 case 'role': $obj->role = $v; break;
3950 case 'dialect': $obj->dialect = (integer) $v; break;
3951 case 'charset': $obj->charset = $v; $obj->charSet=$v; break;
3952 case 'buffers': $obj->buffers = $v; break;
3953 case 'fetchmode': $obj->SetFetchMode($v); break;
3954 #ado
3955 case 'charpage': $obj->charPage = $v; break;
3956 #mysql, mysqli
3957 case 'clientflags': $obj->clientFlags = $v; break;
3958 #mysql, mysqli, postgres
3959 case 'port': $obj->port = $v; break;
3960 #mysqli
3961 case 'socket': $obj->socket = $v; break;
3962 #oci8
3963 case 'nls_date_format': $obj->NLS_DATE_FORMAT = $v; break;
3966 if (empty($persist))
3967 $ok = $obj->Connect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
3968 else if (empty($nconnect))
3969 $ok = $obj->PConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
3970 else
3971 $ok = $obj->NConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
3973 if (!$ok) return $false;
3976 return $obj;
3981 // $perf == true means called by NewPerfMonitor(), otherwise for data dictionary
3982 function _adodb_getdriver($provider,$drivername,$perf=false)
3984 switch ($provider) {
3985 case 'odbtp': if (strncmp('odbtp_',$drivername,6)==0) return substr($drivername,6);
3986 case 'odbc' : if (strncmp('odbc_',$drivername,5)==0) return substr($drivername,5);
3987 case 'ado' : if (strncmp('ado_',$drivername,4)==0) return substr($drivername,4);
3988 case 'native': break;
3989 default:
3990 return $provider;
3993 switch($drivername) {
3994 case 'mysqlt':
3995 case 'mysqli':
3996 $drivername='mysql';
3997 break;
3998 case 'postgres7':
3999 case 'postgres8':
4000 $drivername = 'postgres';
4001 break;
4002 case 'firebird15': $drivername = 'firebird'; break;
4003 case 'oracle': $drivername = 'oci8'; break;
4004 case 'access': if ($perf) $drivername = ''; break;
4005 case 'db2' : break;
4006 case 'sapdb' : break;
4007 default:
4008 $drivername = 'generic';
4009 break;
4011 return $drivername;
4014 function &NewPerfMonitor(&$conn)
4016 $false = false;
4017 $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType,true);
4018 if (!$drivername || $drivername == 'generic') return $false;
4019 include_once(ADODB_DIR.'/adodb-perf.inc.php');
4020 @include_once(ADODB_DIR."/perf/perf-$drivername.inc.php");
4021 $class = "Perf_$drivername";
4022 if (!class_exists($class)) return $false;
4023 $perf = new $class($conn);
4025 return $perf;
4028 function &NewDataDictionary(&$conn,$drivername=false)
4030 $false = false;
4031 if (!$drivername) $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType);
4033 include_once(ADODB_DIR.'/adodb-lib.inc.php');
4034 include_once(ADODB_DIR.'/adodb-datadict.inc.php');
4035 $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php";
4037 if (!file_exists($path)) {
4038 ADOConnection::outp("Dictionary driver '$path' not available");
4039 return $false;
4041 include_once($path);
4042 $class = "ADODB2_$drivername";
4043 $dict = new $class();
4044 $dict->dataProvider = $conn->dataProvider;
4045 $dict->connection = &$conn;
4046 $dict->upperName = strtoupper($drivername);
4047 $dict->quote = $conn->nameQuote;
4048 if (!empty($conn->_connectionID))
4049 $dict->serverInfo = $conn->ServerInfo();
4051 return $dict;
4057 Perform a print_r, with pre tags for better formatting.
4059 function adodb_pr($var,$as_string=false)
4061 if ($as_string) ob_start();
4063 if (isset($_SERVER['HTTP_USER_AGENT'])) {
4064 echo " <pre>\n";print_r($var);echo "</pre>\n";
4065 } else
4066 print_r($var);
4068 if ($as_string) {
4069 $s = ob_get_contents();
4070 ob_end_clean();
4071 return $s;
4076 Perform a stack-crawl and pretty print it.
4078 @param printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then).
4079 @param levels Number of levels to display
4081 function adodb_backtrace($printOrArr=true,$levels=9999)
4083 global $ADODB_INCLUDED_LIB;
4084 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
4085 return _adodb_backtrace($printOrArr,$levels);