Merge branch 'MDL-57742_master' of git://github.com/markn86/moodle
[moodle.git] / lib / adodb / adodb.inc.php
blobb01b0af8d7bc8f84780e2de43ec3ce6a07c3b290
1 <?php
2 /*
3 * Set tabs to 4 for best viewing.
5 * Latest version is available at http://adodb.sourceforge.net
7 * This is the main include file for ADOdb.
8 * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php
10 * The ADOdb files are formatted so that doxygen can be used to generate documentation.
11 * Doxygen is a documentation generation tool and can be downloaded from http://doxygen.org/
14 /**
15 \mainpage
17 @version v5.20.9 21-Dec-2016
18 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
19 @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community
21 Released under both BSD license and Lesser GPL library license. You can choose which license
22 you prefer.
24 PHP's database access functions are not standardised. This creates a need for a database
25 class library to hide the differences between the different database API's (encapsulate
26 the differences) so we can easily switch databases.
28 We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, DB2,
29 Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access,
30 ADO, SAP DB, SQLite and ODBC. We have had successful reports of connecting to Progress and
31 other databases via ODBC.
33 Latest Download at http://adodb.sourceforge.net/
37 if (!defined('_ADODB_LAYER')) {
38 define('_ADODB_LAYER',1);
40 // The ADOdb extension is no longer maintained and effectively unsupported
41 // since v5.04. The library will not function properly if it is present.
42 if(defined('ADODB_EXTENSION')) {
43 $msg = "Unsupported ADOdb Extension (v" . ADODB_EXTENSION . ") detected! "
44 . "Disable it to use ADOdb";
46 $errorfn = defined('ADODB_ERROR_HANDLER') ? ADODB_ERROR_HANDLER : false;
47 if ($errorfn) {
48 $conn = false;
49 $errorfn('ADOdb', basename(__FILE__), -9999, $msg, null, null, $conn);
50 } else {
51 die($msg . PHP_EOL);
55 //==============================================================================================
56 // CONSTANT DEFINITIONS
57 //==============================================================================================
60 /**
61 * Set ADODB_DIR to the directory where this file resides...
62 * This constant was formerly called $ADODB_RootPath
64 if (!defined('ADODB_DIR')) {
65 define('ADODB_DIR',dirname(__FILE__));
68 //==============================================================================================
69 // GLOBAL VARIABLES
70 //==============================================================================================
72 GLOBAL
73 $ADODB_vers, // database version
74 $ADODB_COUNTRECS, // count number of records returned - slows down query
75 $ADODB_CACHE_DIR, // directory to cache recordsets
76 $ADODB_CACHE,
77 $ADODB_CACHE_CLASS,
78 $ADODB_EXTENSION, // ADODB extension installed
79 $ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF
80 $ADODB_FETCH_MODE, // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...
81 $ADODB_GETONE_EOF,
82 $ADODB_QUOTE_FIELDNAMES; // Allows you to force quotes (backticks) around field names in queries generated by getinsertsql and getupdatesql.
84 //==============================================================================================
85 // GLOBAL SETUP
86 //==============================================================================================
88 $ADODB_EXTENSION = defined('ADODB_EXTENSION');
90 // ********************************************************
91 // Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).
92 // Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi
94 // 0 = ignore empty fields. All empty fields in array are ignored.
95 // 1 = force null. All empty, php null and string 'null' fields are changed to sql NULL values.
96 // 2 = force empty. All empty, php null and string 'null' fields are changed to sql empty '' or 0 values.
97 // 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.
99 define('ADODB_FORCE_IGNORE',0);
100 define('ADODB_FORCE_NULL',1);
101 define('ADODB_FORCE_EMPTY',2);
102 define('ADODB_FORCE_VALUE',3);
103 // ********************************************************
106 if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) {
108 define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');
110 // allow [ ] @ ` " and . in table names
111 define('ADODB_TABLE_REGEX','([]0-9a-z_\:\"\`\.\@\[-]*)');
113 // prefetching used by oracle
114 if (!defined('ADODB_PREFETCH_ROWS')) {
115 define('ADODB_PREFETCH_ROWS',10);
120 * Fetch mode
122 * Set global variable $ADODB_FETCH_MODE to one of these constants or use
123 * the SetFetchMode() method to control how recordset fields are returned
124 * when fetching data.
126 * - NUM: array()
127 * - ASSOC: array('id' => 456, 'name' => 'john')
128 * - BOTH: array(0 => 456, 'id' => 456, 1 => 'john', 'name' => 'john')
129 * - DEFAULT: driver-dependent
131 define('ADODB_FETCH_DEFAULT', 0);
132 define('ADODB_FETCH_NUM', 1);
133 define('ADODB_FETCH_ASSOC', 2);
134 define('ADODB_FETCH_BOTH', 3);
137 * Associative array case constants
139 * By defining the ADODB_ASSOC_CASE constant to one of these values, it is
140 * possible to control the case of field names (associative array's keys)
141 * when operating in ADODB_FETCH_ASSOC fetch mode.
142 * - LOWER: $rs->fields['orderid']
143 * - UPPER: $rs->fields['ORDERID']
144 * - NATIVE: $rs->fields['OrderID'] (or whatever the RDBMS will return)
146 * The default is to use native case-names.
148 * NOTE: This functionality is not implemented everywhere, it currently
149 * works only with: mssql, odbc, oci8 and ibase derived drivers
151 define('ADODB_ASSOC_CASE_LOWER', 0);
152 define('ADODB_ASSOC_CASE_UPPER', 1);
153 define('ADODB_ASSOC_CASE_NATIVE', 2);
156 if (!defined('TIMESTAMP_FIRST_YEAR')) {
157 define('TIMESTAMP_FIRST_YEAR',100);
161 * AutoExecute constants
162 * (moved from adodb-pear.inc.php since they are only used in here)
164 define('DB_AUTOQUERY_INSERT', 1);
165 define('DB_AUTOQUERY_UPDATE', 2);
168 // PHP's version scheme makes converting to numbers difficult - workaround
169 $_adodb_ver = (float) PHP_VERSION;
170 if ($_adodb_ver >= 5.2) {
171 define('ADODB_PHPVER',0x5200);
172 } else if ($_adodb_ver >= 5.0) {
173 define('ADODB_PHPVER',0x5000);
174 } else {
175 die("PHP5 or later required. You are running ".PHP_VERSION);
177 unset($_adodb_ver);
182 Accepts $src and $dest arrays, replacing string $data
184 function ADODB_str_replace($src, $dest, $data) {
185 if (ADODB_PHPVER >= 0x4050) {
186 return str_replace($src,$dest,$data);
189 $s = reset($src);
190 $d = reset($dest);
191 while ($s !== false) {
192 $data = str_replace($s,$d,$data);
193 $s = next($src);
194 $d = next($dest);
196 return $data;
199 function ADODB_Setup() {
200 GLOBAL
201 $ADODB_vers, // database version
202 $ADODB_COUNTRECS, // count number of records returned - slows down query
203 $ADODB_CACHE_DIR, // directory to cache recordsets
204 $ADODB_FETCH_MODE,
205 $ADODB_CACHE,
206 $ADODB_CACHE_CLASS,
207 $ADODB_FORCE_TYPE,
208 $ADODB_GETONE_EOF,
209 $ADODB_QUOTE_FIELDNAMES;
211 if (empty($ADODB_CACHE_CLASS)) {
212 $ADODB_CACHE_CLASS = 'ADODB_Cache_File' ;
214 $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
215 $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE;
216 $ADODB_GETONE_EOF = null;
218 if (!isset($ADODB_CACHE_DIR)) {
219 $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp';
220 } else {
221 // do not accept url based paths, eg. http:/ or ftp:/
222 if (strpos($ADODB_CACHE_DIR,'://') !== false) {
223 die("Illegal path http:// or ftp://");
228 // Initialize random number generator for randomizing cache flushes
229 // -- note Since PHP 4.2.0, the seed becomes optional and defaults to a random value if omitted.
230 // MDL-41198 Removed random seed initialization.
231 // srand(((double)microtime())*1000000);
234 * ADODB version as a string.
236 $ADODB_vers = 'v5.20.9 21-Dec-2016';
239 * Determines whether recordset->RecordCount() is used.
240 * Set to false for highest performance -- RecordCount() will always return -1 then
241 * for databases that provide "virtual" recordcounts...
243 if (!isset($ADODB_COUNTRECS)) {
244 $ADODB_COUNTRECS = true;
249 //==============================================================================================
250 // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB
251 //==============================================================================================
253 ADODB_Setup();
255 //==============================================================================================
256 // CLASS ADOFieldObject
257 //==============================================================================================
259 * Helper class for FetchFields -- holds info on a column
261 class ADOFieldObject {
262 var $name = '';
263 var $max_length=0;
264 var $type="";
266 // additional fields by dannym... (danny_milo@yahoo.com)
267 var $not_null = false;
268 // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^
269 // so we can as well make not_null standard (leaving it at "false" does not harm anyways)
271 var $has_default = false; // this one I have done only in mysql and postgres for now ...
272 // others to come (dannym)
273 var $default_value; // default, if any, and supported. Check has_default first.
278 function _adodb_safedate($s) {
279 return str_replace(array("'", '\\'), '', $s);
282 // parse date string to prevent injection attack
283 // date string will have one quote at beginning e.g. '3434343'
284 function _adodb_safedateq($s) {
285 $len = strlen($s);
286 if ($s[0] !== "'") {
287 $s2 = "'".$s[0];
288 } else {
289 $s2 = "'";
291 for($i=1; $i<$len; $i++) {
292 $ch = $s[$i];
293 if ($ch === '\\') {
294 $s2 .= "'";
295 break;
296 } elseif ($ch === "'") {
297 $s2 .= $ch;
298 break;
301 $s2 .= $ch;
304 return strlen($s2) == 0 ? 'null' : $s2;
308 // for transaction handling
310 function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection) {
311 //print "Errorno ($fn errno=$errno m=$errmsg) ";
312 $thisConnection->_transOK = false;
313 if ($thisConnection->_oldRaiseFn) {
314 $fn = $thisConnection->_oldRaiseFn;
315 $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
319 //------------------
320 // class for caching
321 class ADODB_Cache_File {
323 var $createdir = true; // requires creation of temp dirs
325 function __construct() {
326 global $ADODB_INCLUDED_CSV;
327 if (empty($ADODB_INCLUDED_CSV)) {
328 include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
332 // write serialised recordset to cache item/file
333 function writecache($filename, $contents, $debug, $secs2cache) {
334 return adodb_write_file($filename, $contents,$debug);
337 // load serialised recordset and unserialise it
338 function &readcache($filename, &$err, $secs2cache, $rsClass) {
339 $rs = csv2rs($filename,$err,$secs2cache,$rsClass);
340 return $rs;
343 // flush all items in cache
344 function flushall($debug=false) {
345 global $ADODB_CACHE_DIR;
347 $rez = false;
349 if (strlen($ADODB_CACHE_DIR) > 1) {
350 $rez = $this->_dirFlush($ADODB_CACHE_DIR);
351 if ($debug) {
352 ADOConnection::outp( "flushall: $ADODB_CACHE_DIR<br><pre>\n". $rez."</pre>");
355 return $rez;
358 // flush one file in cache
359 function flushcache($f, $debug=false) {
360 if (!@unlink($f)) {
361 if ($debug) {
362 ADOConnection::outp( "flushcache: failed for $f");
367 function getdirname($hash) {
368 global $ADODB_CACHE_DIR;
369 if (!isset($this->notSafeMode)) {
370 $this->notSafeMode = !ini_get('safe_mode');
372 return ($this->notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($hash,0,2) : $ADODB_CACHE_DIR;
375 // create temp directories
376 function createdir($hash, $debug) {
377 global $ADODB_CACHE_PERMS;
379 $dir = $this->getdirname($hash);
380 if ($this->notSafeMode && !file_exists($dir)) {
381 $oldu = umask(0);
382 if (!@mkdir($dir, empty($ADODB_CACHE_PERMS) ? 0771 : $ADODB_CACHE_PERMS)) {
383 if(!is_dir($dir) && $debug) {
384 ADOConnection::outp("Cannot create $dir");
387 umask($oldu);
390 return $dir;
394 * Private function to erase all of the files and subdirectories in a directory.
396 * Just specify the directory, and tell it if you want to delete the directory or just clear it out.
397 * Note: $kill_top_level is used internally in the function to flush subdirectories.
399 function _dirFlush($dir, $kill_top_level = false) {
400 if(!$dh = @opendir($dir)) return;
402 while (($obj = readdir($dh))) {
403 if($obj=='.' || $obj=='..') continue;
404 $f = $dir.'/'.$obj;
406 if (strpos($obj,'.cache')) {
407 @unlink($f);
409 if (is_dir($f)) {
410 $this->_dirFlush($f, true);
413 if ($kill_top_level === true) {
414 @rmdir($dir);
416 return true;
420 //==============================================================================================
421 // CLASS ADOConnection
422 //==============================================================================================
425 * Connection object. For connecting to databases, and executing queries.
427 abstract class ADOConnection {
429 // PUBLIC VARS
431 var $dataProvider = 'native';
432 var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql
433 var $database = ''; /// Name of database to be used.
434 var $host = ''; /// The hostname of the database server
435 var $user = ''; /// The username which is used to connect to the database server.
436 var $password = ''; /// Password for the username. For security, we no longer store it.
437 var $debug = false; /// if set to true will output sql statements
438 var $maxblobsize = 262144; /// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxpro
439 var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase
440 var $substr = 'substr'; /// substring operator
441 var $length = 'length'; /// string length ofperator
442 var $random = 'rand()'; /// random function
443 var $upperCase = 'upper'; /// uppercase function
444 var $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the database
445 var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt.
446 var $true = '1'; /// string that represents TRUE for a database
447 var $false = '0'; /// string that represents FALSE for a database
448 var $replaceQuote = "\\'"; /// string to use to replace quotes
449 var $nameQuote = '"'; /// string to use to quote identifiers and names
450 var $charSet=false; /// character set to use - only for interbase, postgres and oci8
451 var $metaDatabasesSQL = '';
452 var $metaTablesSQL = '';
453 var $uniqueOrderBy = false; /// All order by columns have to be unique
454 var $emptyDate = '&nbsp;';
455 var $emptyTimeStamp = '&nbsp;';
456 var $lastInsID = false;
457 //--
458 var $hasInsertID = false; /// supports autoincrement ID?
459 var $hasAffectedRows = false; /// supports affected rows for update/delete?
460 var $hasTop = false; /// support mssql/access SELECT TOP 10 * FROM TABLE
461 var $hasLimit = false; /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10
462 var $readOnly = false; /// this is a readonly database - used by phpLens
463 var $hasMoveFirst = false; /// has ability to run MoveFirst(), scrolling backwards
464 var $hasGenID = false; /// can generate sequences using GenID();
465 var $hasTransactions = true; /// has transactions
466 //--
467 var $genID = 0; /// sequence id used by GenID();
468 var $raiseErrorFn = false; /// error function to call
469 var $isoDates = false; /// accepts dates in ISO format
470 var $cacheSecs = 3600; /// cache for 1 hour
472 // memcache
473 var $memCache = false; /// should we use memCache instead of caching in files
474 var $memCacheHost; /// memCache host
475 var $memCachePort = 11211; /// memCache port
476 var $memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib)
478 var $sysDate = false; /// name of function that returns the current date
479 var $sysTimeStamp = false; /// name of function that returns the current timestamp
480 var $sysUTimeStamp = false; // name of function that returns the current timestamp accurate to the microsecond or nearest fraction
481 var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets
483 var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' '
484 var $numCacheHits = 0;
485 var $numCacheMisses = 0;
486 var $pageExecuteCountRows = true;
487 var $uniqueSort = false; /// indicates that all fields in order by must be unique
488 var $leftOuter = false; /// operator to use for left outer join in WHERE clause
489 var $rightOuter = false; /// operator to use for right outer join in WHERE clause
490 var $ansiOuter = false; /// whether ansi outer join syntax supported
491 var $autoRollback = false; // autoRollback on PConnect().
492 var $poorAffectedRows = false; // affectedRows not working or unreliable
494 var $fnExecute = false;
495 var $fnCacheExecute = false;
496 var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char
497 var $rsPrefix = "ADORecordSet_";
499 var $autoCommit = true; /// do not modify this yourself - actually private
500 var $transOff = 0; /// temporarily disable transactions
501 var $transCnt = 0; /// count of nested transactions
503 var $fetchMode=false;
505 var $null2null = 'null'; // in autoexecute/getinsertsql/getupdatesql, this value will be converted to a null
506 var $bulkBind = false; // enable 2D Execute array
508 // PRIVATE VARS
510 var $_oldRaiseFn = false;
511 var $_transOK = null;
512 var $_connectionID = false; /// The returned link identifier whenever a successful database connection is made.
513 var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will
514 /// then returned by the errorMsg() function
515 var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8
516 var $_queryID = false; /// This variable keeps the last created result link identifier
518 var $_isPersistentConnection = false; /// A boolean variable to state whether its a persistent connection or normal connection. */
519 var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.
520 var $_evalAll = false;
521 var $_affected = false;
522 var $_logsql = false;
523 var $_transmode = ''; // transaction mode
526 * Additional parameters that may be passed to drivers in the connect string
527 * Driver must be coded to accept the parameters
529 protected $connectionParameters = array();
532 * Adds a parameter to the connection string.
534 * These parameters are added to the connection string when connecting,
535 * if the driver is coded to use it.
537 * @param string $parameter The name of the parameter to set
538 * @param string $value The value of the parameter
540 * @return null
542 * @example, for mssqlnative driver ('CharacterSet','UTF-8')
544 final public function setConnectionParameter($parameter,$value)
547 $this->connectionParameters[$parameter] = $value;
551 static function Version() {
552 global $ADODB_vers;
554 // Semantic Version number matching regex
555 $regex = '^[vV]?(\d+\.\d+\.\d+' // Version number (X.Y.Z) with optional 'V'
556 . '(?:-(?:' // Optional preprod version: a '-'
557 . 'dev|' // followed by 'dev'
558 . '(?:(?:alpha|beta|rc)(?:\.\d+))' // or a preprod suffix and version number
559 . '))?)(?:\s|$)'; // Whitespace or end of string
561 if (!preg_match("/$regex/", $ADODB_vers, $matches)) {
562 // This should normally not happen... Return whatever is between the start
563 // of the string and the first whitespace (or the end of the string).
564 self::outp("Invalid version number: '$ADODB_vers'", 'Version');
565 $regex = '^[vV]?(.*?)(?:\s|$)';
566 preg_match("/$regex/", $ADODB_vers, $matches);
568 return $matches[1];
572 Get server version info...
574 @returns An array with 2 elements: $arr['string'] is the description string,
575 and $arr[version] is the version (also a string).
577 function ServerInfo() {
578 return array('description' => '', 'version' => '');
581 function IsConnected() {
582 return !empty($this->_connectionID);
585 function _findvers($str) {
586 if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) {
587 return $arr[1];
588 } else {
589 return '';
594 * All error messages go through this bottleneck function.
595 * You can define your own handler by defining the function name in ADODB_OUTP.
597 static function outp($msg,$newline=true) {
598 global $ADODB_FLUSH,$ADODB_OUTP;
600 if (defined('ADODB_OUTP')) {
601 $fn = ADODB_OUTP;
602 $fn($msg,$newline);
603 return;
604 } else if (isset($ADODB_OUTP)) {
605 $fn = $ADODB_OUTP;
606 $fn($msg,$newline);
607 return;
610 if ($newline) {
611 $msg .= "<br>\n";
614 if (isset($_SERVER['HTTP_USER_AGENT']) || !$newline) {
615 echo $msg;
616 } else {
617 echo strip_tags($msg);
621 if (!empty($ADODB_FLUSH) && ob_get_length() !== false) {
622 flush(); // do not flush if output buffering enabled - useless - thx to Jesse Mullan
627 function Time() {
628 $rs = $this->_Execute("select $this->sysTimeStamp");
629 if ($rs && !$rs->EOF) {
630 return $this->UnixTimeStamp(reset($rs->fields));
633 return false;
637 * Connect to database
639 * @param [argHostname] Host to connect to
640 * @param [argUsername] Userid to login
641 * @param [argPassword] Associated password
642 * @param [argDatabaseName] database
643 * @param [forceNew] force new connection
645 * @return true or false
647 function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) {
648 if ($argHostname != "") {
649 $this->host = $argHostname;
651 if ( strpos($this->host, ':') > 0 && isset($this->port) ) {
652 list($this->host, $this->port) = explode(":", $this->host, 2);
654 if ($argUsername != "") {
655 $this->user = $argUsername;
657 if ($argPassword != "") {
658 $this->password = 'not stored'; // not stored for security reasons
660 if ($argDatabaseName != "") {
661 $this->database = $argDatabaseName;
664 $this->_isPersistentConnection = false;
666 if ($forceNew) {
667 if ($rez=$this->_nconnect($this->host, $this->user, $argPassword, $this->database)) {
668 return true;
670 } else {
671 if ($rez=$this->_connect($this->host, $this->user, $argPassword, $this->database)) {
672 return true;
675 if (isset($rez)) {
676 $err = $this->ErrorMsg();
677 $errno = $this->ErrorNo();
678 if (empty($err)) {
679 $err = "Connection error to server '$argHostname' with user '$argUsername'";
681 } else {
682 $err = "Missing extension for ".$this->dataProvider;
683 $errno = 0;
685 if ($fn = $this->raiseErrorFn) {
686 $fn($this->databaseType, 'CONNECT', $errno, $err, $this->host, $this->database, $this);
689 $this->_connectionID = false;
690 if ($this->debug) {
691 ADOConnection::outp( $this->host.': '.$err);
693 return false;
696 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) {
697 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
702 * Always force a new connection to database - currently only works with oracle
704 * @param [argHostname] Host to connect to
705 * @param [argUsername] Userid to login
706 * @param [argPassword] Associated password
707 * @param [argDatabaseName] database
709 * @return true or false
711 function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {
712 return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
716 * Establish persistent connect to database
718 * @param [argHostname] Host to connect to
719 * @param [argUsername] Userid to login
720 * @param [argPassword] Associated password
721 * @param [argDatabaseName] database
723 * @return return true or false
725 function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {
727 if (defined('ADODB_NEVER_PERSIST')) {
728 return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
731 if ($argHostname != "") {
732 $this->host = $argHostname;
734 if ( strpos($this->host, ':') > 0 && isset($this->port) ) {
735 list($this->host, $this->port) = explode(":", $this->host, 2);
737 if ($argUsername != "") {
738 $this->user = $argUsername;
740 if ($argPassword != "") {
741 $this->password = 'not stored';
743 if ($argDatabaseName != "") {
744 $this->database = $argDatabaseName;
747 $this->_isPersistentConnection = true;
749 if ($rez = $this->_pconnect($this->host, $this->user, $argPassword, $this->database)) {
750 return true;
752 if (isset($rez)) {
753 $err = $this->ErrorMsg();
754 if (empty($err)) {
755 $err = "Connection error to server '$argHostname' with user '$argUsername'";
757 $ret = false;
758 } else {
759 $err = "Missing extension for ".$this->dataProvider;
760 $ret = 0;
762 if ($fn = $this->raiseErrorFn) {
763 $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
766 $this->_connectionID = false;
767 if ($this->debug) {
768 ADOConnection::outp( $this->host.': '.$err);
770 return $ret;
773 function outp_throw($msg,$src='WARN',$sql='') {
774 if (defined('ADODB_ERROR_HANDLER') && ADODB_ERROR_HANDLER == 'adodb_throw') {
775 adodb_throw($this->databaseType,$src,-9999,$msg,$sql,false,$this);
776 return;
778 ADOConnection::outp($msg);
781 // create cache class. Code is backward compat with old memcache implementation
782 function _CreateCache() {
783 global $ADODB_CACHE, $ADODB_CACHE_CLASS;
785 if ($this->memCache) {
786 global $ADODB_INCLUDED_MEMCACHE;
788 if (empty($ADODB_INCLUDED_MEMCACHE)) {
789 include_once(ADODB_DIR.'/adodb-memcache.lib.inc.php');
791 $ADODB_CACHE = new ADODB_Cache_MemCache($this);
792 } else {
793 $ADODB_CACHE = new $ADODB_CACHE_CLASS($this);
797 // Format date column in sql string given an input format that understands Y M D
798 function SQLDate($fmt, $col=false) {
799 if (!$col) {
800 $col = $this->sysDate;
802 return $col; // child class implement
806 * Should prepare the sql statement and return the stmt resource.
807 * For databases that do not support this, we return the $sql. To ensure
808 * compatibility with databases that do not support prepare:
810 * $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
811 * $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
812 * $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
814 * @param sql SQL to send to database
816 * @return return FALSE, or the prepared statement, or the original sql if
817 * if the database does not support prepare.
820 function Prepare($sql) {
821 return $sql;
825 * Some databases, eg. mssql require a different function for preparing
826 * stored procedures. So we cannot use Prepare().
828 * Should prepare the stored procedure and return the stmt resource.
829 * For databases that do not support this, we return the $sql. To ensure
830 * compatibility with databases that do not support prepare:
832 * @param sql SQL to send to database
834 * @return return FALSE, or the prepared statement, or the original sql if
835 * if the database does not support prepare.
838 function PrepareSP($sql,$param=true) {
839 return $this->Prepare($sql,$param);
843 * PEAR DB Compat
845 function Quote($s) {
846 return $this->qstr($s,false);
850 * Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de>
852 function QMagic($s) {
853 return $this->qstr($s,get_magic_quotes_gpc());
856 function q(&$s) {
857 //if (!empty($this->qNull && $s == 'null') {
858 // return $s;
860 $s = $this->qstr($s,false);
864 * PEAR DB Compat - do not use internally.
866 function ErrorNative() {
867 return $this->ErrorNo();
872 * PEAR DB Compat - do not use internally.
874 function nextId($seq_name) {
875 return $this->GenID($seq_name);
879 * Lock a row, will escalate and lock the table if row locking not supported
880 * will normally free the lock at the end of the transaction
882 * @param $table name of table to lock
883 * @param $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
885 function RowLock($table,$where,$col='1 as adodbignore') {
886 return false;
889 function CommitLock($table) {
890 return $this->CommitTrans();
893 function RollbackLock($table) {
894 return $this->RollbackTrans();
898 * PEAR DB Compat - do not use internally.
900 * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
901 * for easy porting :-)
903 * @param mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
904 * @returns The previous fetch mode
906 function SetFetchMode($mode) {
907 $old = $this->fetchMode;
908 $this->fetchMode = $mode;
910 if ($old === false) {
911 global $ADODB_FETCH_MODE;
912 return $ADODB_FETCH_MODE;
914 return $old;
919 * PEAR DB Compat - do not use internally.
921 function Query($sql, $inputarr=false) {
922 $rs = $this->Execute($sql, $inputarr);
923 if (!$rs && defined('ADODB_PEAR')) {
924 return ADODB_PEAR_Error();
926 return $rs;
931 * PEAR DB Compat - do not use internally
933 function LimitQuery($sql, $offset, $count, $params=false) {
934 $rs = $this->SelectLimit($sql, $count, $offset, $params);
935 if (!$rs && defined('ADODB_PEAR')) {
936 return ADODB_PEAR_Error();
938 return $rs;
943 * PEAR DB Compat - do not use internally
945 function Disconnect() {
946 return $this->Close();
950 * Returns a placeholder for query parameters
951 * e.g. $DB->Param('a') will return
952 * - '?' for most databases
953 * - ':a' for Oracle
954 * - '$1', '$2', etc. for PostgreSQL
955 * @param string $name parameter's name, false to force a reset of the
956 * number to 1 (for databases that require positioned
957 * params such as PostgreSQL; note that ADOdb will
958 * automatically reset this when executing a query )
959 * @param string $type (unused)
960 * @return string query parameter placeholder
962 function Param($name,$type='C') {
963 return '?';
967 InParameter and OutParameter are self-documenting versions of Parameter().
969 function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {
970 return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
975 function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {
976 return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);
982 Usage in oracle
983 $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
984 $db->Parameter($stmt,$id,'myid');
985 $db->Parameter($stmt,$group,'group',64);
986 $db->Execute();
988 @param $stmt Statement returned by Prepare() or PrepareSP().
989 @param $var PHP variable to bind to
990 @param $name Name of stored procedure variable name to bind to.
991 @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
992 @param [$maxLen] Holds an maximum length of the variable.
993 @param [$type] The data type of $var. Legal values depend on driver.
996 function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) {
997 return false;
1001 function IgnoreErrors($saveErrs=false) {
1002 if (!$saveErrs) {
1003 $saveErrs = array($this->raiseErrorFn,$this->_transOK);
1004 $this->raiseErrorFn = false;
1005 return $saveErrs;
1006 } else {
1007 $this->raiseErrorFn = $saveErrs[0];
1008 $this->_transOK = $saveErrs[1];
1013 * Improved method of initiating a transaction. Used together with CompleteTrans().
1014 * Advantages include:
1016 * a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.
1017 * Only the outermost block is treated as a transaction.<br>
1018 * b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>
1019 * c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block
1020 * are disabled, making it backward compatible.
1022 function StartTrans($errfn = 'ADODB_TransMonitor') {
1023 if ($this->transOff > 0) {
1024 $this->transOff += 1;
1025 return true;
1028 $this->_oldRaiseFn = $this->raiseErrorFn;
1029 $this->raiseErrorFn = $errfn;
1030 $this->_transOK = true;
1032 if ($this->debug && $this->transCnt > 0) {
1033 ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
1035 $ok = $this->BeginTrans();
1036 $this->transOff = 1;
1037 return $ok;
1042 Used together with StartTrans() to end a transaction. Monitors connection
1043 for sql errors, and will commit or rollback as appropriate.
1045 @autoComplete if true, monitor sql errors and commit and rollback as appropriate,
1046 and if set to false force rollback even if no SQL error detected.
1047 @returns true on commit, false on rollback.
1049 function CompleteTrans($autoComplete = true) {
1050 if ($this->transOff > 1) {
1051 $this->transOff -= 1;
1052 return true;
1054 $this->raiseErrorFn = $this->_oldRaiseFn;
1056 $this->transOff = 0;
1057 if ($this->_transOK && $autoComplete) {
1058 if (!$this->CommitTrans()) {
1059 $this->_transOK = false;
1060 if ($this->debug) {
1061 ADOConnection::outp("Smart Commit failed");
1063 } else {
1064 if ($this->debug) {
1065 ADOConnection::outp("Smart Commit occurred");
1068 } else {
1069 $this->_transOK = false;
1070 $this->RollbackTrans();
1071 if ($this->debug) {
1072 ADOCOnnection::outp("Smart Rollback occurred");
1076 return $this->_transOK;
1080 At the end of a StartTrans/CompleteTrans block, perform a rollback.
1082 function FailTrans() {
1083 if ($this->debug)
1084 if ($this->transOff == 0) {
1085 ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
1086 } else {
1087 ADOConnection::outp("FailTrans was called");
1088 adodb_backtrace();
1090 $this->_transOK = false;
1094 Check if transaction has failed, only for Smart Transactions.
1096 function HasFailedTrans() {
1097 if ($this->transOff > 0) {
1098 return $this->_transOK == false;
1100 return false;
1104 * Execute SQL
1106 * @param sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
1107 * @param [inputarr] holds the input data to bind to. Null elements will be set to null.
1108 * @return RecordSet or false
1110 function Execute($sql,$inputarr=false) {
1111 if ($this->fnExecute) {
1112 $fn = $this->fnExecute;
1113 $ret = $fn($this,$sql,$inputarr);
1114 if (isset($ret)) {
1115 return $ret;
1118 if ($inputarr !== false) {
1119 if (!is_array($inputarr)) {
1120 $inputarr = array($inputarr);
1123 $element0 = reset($inputarr);
1124 # is_object check because oci8 descriptors can be passed in
1125 $array_2d = $this->bulkBind && is_array($element0) && !is_object(reset($element0));
1127 //remove extra memory copy of input -mikefedyk
1128 unset($element0);
1130 if (!is_array($sql) && !$this->_bindInputArray) {
1131 // @TODO this would consider a '?' within a string as a parameter...
1132 $sqlarr = explode('?',$sql);
1133 $nparams = sizeof($sqlarr)-1;
1135 if (!$array_2d) {
1136 // When not Bind Bulk - convert to array of arguments list
1137 $inputarr = array($inputarr);
1138 } else {
1139 // Bulk bind - Make sure all list of params have the same number of elements
1140 $countElements = array_map('count', $inputarr);
1141 if (1 != count(array_unique($countElements))) {
1142 $this->outp_throw(
1143 "[bulk execute] Input array has different number of params [" . print_r($countElements, true) . "].",
1144 'Execute'
1146 return false;
1148 unset($countElements);
1150 // Make sure the number of parameters provided in the input
1151 // array matches what the query expects
1152 $element0 = reset($inputarr);
1153 if ($nparams != count($element0)) {
1154 $this->outp_throw(
1155 "Input array has " . count($element0) .
1156 " params, does not match query: '" . htmlspecialchars($sql) . "'",
1157 'Execute'
1159 return false;
1162 // clean memory
1163 unset($element0);
1165 foreach($inputarr as $arr) {
1166 $sql = ''; $i = 0;
1167 foreach ($arr as $v) {
1168 $sql .= $sqlarr[$i];
1169 // from Ron Baldwin <ron.baldwin#sourceprose.com>
1170 // Only quote string types
1171 $typ = gettype($v);
1172 if ($typ == 'string') {
1173 //New memory copy of input created here -mikefedyk
1174 $sql .= $this->qstr($v);
1175 } else if ($typ == 'double') {
1176 $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1
1177 } else if ($typ == 'boolean') {
1178 $sql .= $v ? $this->true : $this->false;
1179 } else if ($typ == 'object') {
1180 if (method_exists($v, '__toString')) {
1181 $sql .= $this->qstr($v->__toString());
1182 } else {
1183 $sql .= $this->qstr((string) $v);
1185 } else if ($v === null) {
1186 $sql .= 'NULL';
1187 } else {
1188 $sql .= $v;
1190 $i += 1;
1192 if ($i == $nparams) {
1193 break;
1195 } // while
1196 if (isset($sqlarr[$i])) {
1197 $sql .= $sqlarr[$i];
1198 if ($i+1 != sizeof($sqlarr)) {
1199 $this->outp_throw( "Input Array does not match ?: ".htmlspecialchars($sql),'Execute');
1201 } else if ($i != sizeof($sqlarr)) {
1202 $this->outp_throw( "Input array does not match ?: ".htmlspecialchars($sql),'Execute');
1205 $ret = $this->_Execute($sql);
1206 if (!$ret) {
1207 return $ret;
1210 } else {
1211 if ($array_2d) {
1212 if (is_string($sql)) {
1213 $stmt = $this->Prepare($sql);
1214 } else {
1215 $stmt = $sql;
1218 foreach($inputarr as $arr) {
1219 $ret = $this->_Execute($stmt,$arr);
1220 if (!$ret) {
1221 return $ret;
1224 } else {
1225 $ret = $this->_Execute($sql,$inputarr);
1228 } else {
1229 $ret = $this->_Execute($sql,false);
1232 return $ret;
1235 function _Execute($sql,$inputarr=false) {
1236 // ExecuteCursor() may send non-string queries (such as arrays),
1237 // so we need to ignore those.
1238 if( is_string($sql) ) {
1239 // Strips keyword used to help generate SELECT COUNT(*) queries
1240 // from SQL if it exists.
1241 $sql = ADODB_str_replace( '_ADODB_COUNT', '', $sql );
1244 if ($this->debug) {
1245 global $ADODB_INCLUDED_LIB;
1246 if (empty($ADODB_INCLUDED_LIB)) {
1247 include(ADODB_DIR.'/adodb-lib.inc.php');
1249 $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr);
1250 } else {
1251 $this->_queryID = @$this->_query($sql,$inputarr);
1254 // ************************
1255 // OK, query executed
1256 // ************************
1258 // error handling if query fails
1259 if ($this->_queryID === false) {
1260 if ($this->debug == 99) {
1261 adodb_backtrace(true,5);
1263 $fn = $this->raiseErrorFn;
1264 if ($fn) {
1265 $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
1267 return false;
1270 // return simplified recordset for inserts/updates/deletes with lower overhead
1271 if ($this->_queryID === true) {
1272 $rsclass = $this->rsPrefix.'empty';
1273 $rs = (class_exists($rsclass)) ? new $rsclass(): new ADORecordSet_empty();
1275 return $rs;
1278 // return real recordset from select statement
1279 $rsclass = $this->rsPrefix.$this->databaseType;
1280 $rs = new $rsclass($this->_queryID,$this->fetchMode);
1281 $rs->connection = $this; // Pablo suggestion
1282 $rs->Init();
1283 if (is_array($sql)) {
1284 $rs->sql = $sql[0];
1285 } else {
1286 $rs->sql = $sql;
1288 if ($rs->_numOfRows <= 0) {
1289 global $ADODB_COUNTRECS;
1290 if ($ADODB_COUNTRECS) {
1291 if (!$rs->EOF) {
1292 $rs = $this->_rs2rs($rs,-1,-1,!is_array($sql));
1293 $rs->_queryID = $this->_queryID;
1294 } else
1295 $rs->_numOfRows = 0;
1298 return $rs;
1301 function CreateSequence($seqname='adodbseq',$startID=1) {
1302 if (empty($this->_genSeqSQL)) {
1303 return false;
1305 return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
1308 function DropSequence($seqname='adodbseq') {
1309 if (empty($this->_dropSeqSQL)) {
1310 return false;
1312 return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
1316 * Generates a sequence id and stores it in $this->genID;
1317 * GenID is only available if $this->hasGenID = true;
1319 * @param seqname name of sequence to use
1320 * @param startID if sequence does not exist, start at this ID
1321 * @return 0 if not supported, otherwise a sequence id
1323 function GenID($seqname='adodbseq',$startID=1) {
1324 if (!$this->hasGenID) {
1325 return 0; // formerly returns false pre 1.60
1328 $getnext = sprintf($this->_genIDSQL,$seqname);
1330 $holdtransOK = $this->_transOK;
1332 $save_handler = $this->raiseErrorFn;
1333 $this->raiseErrorFn = '';
1334 @($rs = $this->Execute($getnext));
1335 $this->raiseErrorFn = $save_handler;
1337 if (!$rs) {
1338 $this->_transOK = $holdtransOK; //if the status was ok before reset
1339 $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
1340 $rs = $this->Execute($getnext);
1342 if ($rs && !$rs->EOF) {
1343 $this->genID = reset($rs->fields);
1344 } else {
1345 $this->genID = 0; // false
1348 if ($rs) {
1349 $rs->Close();
1352 return $this->genID;
1356 * @param $table string name of the table, not needed by all databases (eg. mysql), default ''
1357 * @param $column string name of the column, not needed by all databases (eg. mysql), default ''
1358 * @return the last inserted ID. Not all databases support this.
1360 function Insert_ID($table='',$column='') {
1361 if ($this->_logsql && $this->lastInsID) {
1362 return $this->lastInsID;
1364 if ($this->hasInsertID) {
1365 return $this->_insertid($table,$column);
1367 if ($this->debug) {
1368 ADOConnection::outp( '<p>Insert_ID error</p>');
1369 adodb_backtrace();
1371 return false;
1376 * Portable Insert ID. Pablo Roca <pabloroca#mvps.org>
1378 * @return the last inserted ID. All databases support this. But aware possible
1379 * problems in multiuser environments. Heavy test this before deploying.
1381 function PO_Insert_ID($table="", $id="") {
1382 if ($this->hasInsertID){
1383 return $this->Insert_ID($table,$id);
1384 } else {
1385 return $this->GetOne("SELECT MAX($id) FROM $table");
1390 * @return # rows affected by UPDATE/DELETE
1392 function Affected_Rows() {
1393 if ($this->hasAffectedRows) {
1394 if ($this->fnExecute === 'adodb_log_sql') {
1395 if ($this->_logsql && $this->_affected !== false) {
1396 return $this->_affected;
1399 $val = $this->_affectedrows();
1400 return ($val < 0) ? false : $val;
1403 if ($this->debug) {
1404 ADOConnection::outp( '<p>Affected_Rows error</p>',false);
1406 return false;
1411 * @return the last error message
1413 function ErrorMsg() {
1414 if ($this->_errorMsg) {
1415 return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
1416 } else {
1417 return '';
1423 * @return the last error number. Normally 0 means no error.
1425 function ErrorNo() {
1426 return ($this->_errorMsg) ? -1 : 0;
1429 function MetaError($err=false) {
1430 include_once(ADODB_DIR."/adodb-error.inc.php");
1431 if ($err === false) {
1432 $err = $this->ErrorNo();
1434 return adodb_error($this->dataProvider,$this->databaseType,$err);
1437 function MetaErrorMsg($errno) {
1438 include_once(ADODB_DIR."/adodb-error.inc.php");
1439 return adodb_errormsg($errno);
1443 * @returns an array with the primary key columns in it.
1445 function MetaPrimaryKeys($table, $owner=false) {
1446 // owner not used in base class - see oci8
1447 $p = array();
1448 $objs = $this->MetaColumns($table);
1449 if ($objs) {
1450 foreach($objs as $v) {
1451 if (!empty($v->primary_key)) {
1452 $p[] = $v->name;
1456 if (sizeof($p)) {
1457 return $p;
1459 if (function_exists('ADODB_VIEW_PRIMARYKEYS')) {
1460 return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);
1462 return false;
1466 * @returns assoc array where keys are tables, and values are foreign keys
1468 function MetaForeignKeys($table, $owner=false, $upper=false) {
1469 return false;
1472 * Choose a database to connect to. Many databases do not support this.
1474 * @param dbName is the name of the database to select
1475 * @return true or false
1477 function SelectDB($dbName) {return false;}
1481 * Will select, getting rows from $offset (1-based), for $nrows.
1482 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1483 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1484 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1485 * eg.
1486 * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
1487 * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
1489 * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
1490 * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
1492 * @param sql
1493 * @param [offset] is the row to start calculations from (1-based)
1494 * @param [nrows] is the number of rows to get
1495 * @param [inputarr] array of bind variables
1496 * @param [secs2cache] is a private parameter only used by jlim
1497 * @return the recordset ($rs->databaseType == 'array')
1499 function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) {
1500 if ($this->hasTop && $nrows > 0) {
1501 // suggested by Reinhard Balling. Access requires top after distinct
1502 // Informix requires first before distinct - F Riosa
1503 $ismssql = (strpos($this->databaseType,'mssql') !== false);
1504 if ($ismssql) {
1505 $isaccess = false;
1506 } else {
1507 $isaccess = (strpos($this->databaseType,'access') !== false);
1510 if ($offset <= 0) {
1511 // access includes ties in result
1512 if ($isaccess) {
1513 $sql = preg_replace(
1514 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1516 if ($secs2cache != 0) {
1517 $ret = $this->CacheExecute($secs2cache, $sql,$inputarr);
1518 } else {
1519 $ret = $this->Execute($sql,$inputarr);
1521 return $ret; // PHP5 fix
1522 } else if ($ismssql){
1523 $sql = preg_replace(
1524 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1525 } else {
1526 $sql = preg_replace(
1527 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1529 } else {
1530 $nn = $nrows + $offset;
1531 if ($isaccess || $ismssql) {
1532 $sql = preg_replace(
1533 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1534 } else {
1535 $sql = preg_replace(
1536 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1541 // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows
1542 // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.
1543 global $ADODB_COUNTRECS;
1545 $savec = $ADODB_COUNTRECS;
1546 $ADODB_COUNTRECS = false;
1549 if ($secs2cache != 0) {
1550 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1551 } else {
1552 $rs = $this->Execute($sql,$inputarr);
1555 $ADODB_COUNTRECS = $savec;
1556 if ($rs && !$rs->EOF) {
1557 $rs = $this->_rs2rs($rs,$nrows,$offset);
1559 //print_r($rs);
1560 return $rs;
1564 * Create serializable recordset. Breaks rs link to connection.
1566 * @param rs the recordset to serialize
1568 function SerializableRS(&$rs) {
1569 $rs2 = $this->_rs2rs($rs);
1570 $ignore = false;
1571 $rs2->connection = $ignore;
1573 return $rs2;
1577 * Convert database recordset to an array recordset
1578 * input recordset's cursor should be at beginning, and
1579 * old $rs will be closed.
1581 * @param rs the recordset to copy
1582 * @param [nrows] number of rows to retrieve (optional)
1583 * @param [offset] offset by number of rows (optional)
1584 * @return the new recordset
1586 function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true) {
1587 if (! $rs) {
1588 return false;
1590 $dbtype = $rs->databaseType;
1591 if (!$dbtype) {
1592 $rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?
1593 return $rs;
1595 if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {
1596 $rs->MoveFirst();
1597 $rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?
1598 return $rs;
1600 $flds = array();
1601 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
1602 $flds[] = $rs->FetchField($i);
1605 $arr = $rs->GetArrayLimit($nrows,$offset);
1606 //print_r($arr);
1607 if ($close) {
1608 $rs->Close();
1611 $arrayClass = $this->arrayClass;
1613 $rs2 = new $arrayClass();
1614 $rs2->connection = $this;
1615 $rs2->sql = $rs->sql;
1616 $rs2->dataProvider = $this->dataProvider;
1617 $rs2->InitArrayFields($arr,$flds);
1618 $rs2->fetchMode = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
1619 return $rs2;
1623 * Return all rows. Compat with PEAR DB
1625 function GetAll($sql, $inputarr=false) {
1626 $arr = $this->GetArray($sql,$inputarr);
1627 return $arr;
1630 function GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false) {
1631 $rs = $this->Execute($sql, $inputarr);
1632 if (!$rs) {
1633 return false;
1635 $arr = $rs->GetAssoc($force_array,$first2cols);
1636 return $arr;
1639 function CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false) {
1640 if (!is_numeric($secs2cache)) {
1641 $first2cols = $force_array;
1642 $force_array = $inputarr;
1644 $rs = $this->CacheExecute($secs2cache, $sql, $inputarr);
1645 if (!$rs) {
1646 return false;
1648 $arr = $rs->GetAssoc($force_array,$first2cols);
1649 return $arr;
1653 * Return first element of first row of sql statement. Recordset is disposed
1654 * for you.
1656 * @param sql SQL statement
1657 * @param [inputarr] input bind array
1659 function GetOne($sql,$inputarr=false) {
1660 global $ADODB_COUNTRECS,$ADODB_GETONE_EOF;
1662 $crecs = $ADODB_COUNTRECS;
1663 $ADODB_COUNTRECS = false;
1665 $ret = false;
1666 $rs = $this->Execute($sql,$inputarr);
1667 if ($rs) {
1668 if ($rs->EOF) {
1669 $ret = $ADODB_GETONE_EOF;
1670 } else {
1671 $ret = reset($rs->fields);
1674 $rs->Close();
1676 $ADODB_COUNTRECS = $crecs;
1677 return $ret;
1680 // $where should include 'WHERE fld=value'
1681 function GetMedian($table, $field,$where = '') {
1682 $total = $this->GetOne("select count(*) from $table $where");
1683 if (!$total) {
1684 return false;
1687 $midrow = (integer) ($total/2);
1688 $rs = $this->SelectLimit("select $field from $table $where order by 1",1,$midrow);
1689 if ($rs && !$rs->EOF) {
1690 return reset($rs->fields);
1692 return false;
1696 function CacheGetOne($secs2cache,$sql=false,$inputarr=false) {
1697 global $ADODB_GETONE_EOF;
1699 $ret = false;
1700 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1701 if ($rs) {
1702 if ($rs->EOF) {
1703 $ret = $ADODB_GETONE_EOF;
1704 } else {
1705 $ret = reset($rs->fields);
1707 $rs->Close();
1710 return $ret;
1713 function GetCol($sql, $inputarr = false, $trim = false) {
1715 $rs = $this->Execute($sql, $inputarr);
1716 if ($rs) {
1717 $rv = array();
1718 if ($trim) {
1719 while (!$rs->EOF) {
1720 $rv[] = trim(reset($rs->fields));
1721 $rs->MoveNext();
1723 } else {
1724 while (!$rs->EOF) {
1725 $rv[] = reset($rs->fields);
1726 $rs->MoveNext();
1729 $rs->Close();
1730 } else {
1731 $rv = false;
1733 return $rv;
1736 function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false) {
1737 $rs = $this->CacheExecute($secs, $sql, $inputarr);
1738 if ($rs) {
1739 $rv = array();
1740 if ($trim) {
1741 while (!$rs->EOF) {
1742 $rv[] = trim(reset($rs->fields));
1743 $rs->MoveNext();
1745 } else {
1746 while (!$rs->EOF) {
1747 $rv[] = reset($rs->fields);
1748 $rs->MoveNext();
1751 $rs->Close();
1752 } else
1753 $rv = false;
1755 return $rv;
1758 function Transpose(&$rs,$addfieldnames=true) {
1759 $rs2 = $this->_rs2rs($rs);
1760 if (!$rs2) {
1761 return false;
1764 $rs2->_transpose($addfieldnames);
1765 return $rs2;
1769 Calculate the offset of a date for a particular database and generate
1770 appropriate SQL. Useful for calculating future/past dates and storing
1771 in a database.
1773 If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
1775 function OffsetDate($dayFraction,$date=false) {
1776 if (!$date) {
1777 $date = $this->sysDate;
1779 return '('.$date.'+'.$dayFraction.')';
1785 * @param sql SQL statement
1786 * @param [inputarr] input bind array
1788 function GetArray($sql,$inputarr=false) {
1789 global $ADODB_COUNTRECS;
1791 $savec = $ADODB_COUNTRECS;
1792 $ADODB_COUNTRECS = false;
1793 $rs = $this->Execute($sql,$inputarr);
1794 $ADODB_COUNTRECS = $savec;
1795 if (!$rs)
1796 if (defined('ADODB_PEAR')) {
1797 $cls = ADODB_PEAR_Error();
1798 return $cls;
1799 } else {
1800 return false;
1802 $arr = $rs->GetArray();
1803 $rs->Close();
1804 return $arr;
1807 function CacheGetAll($secs2cache,$sql=false,$inputarr=false) {
1808 $arr = $this->CacheGetArray($secs2cache,$sql,$inputarr);
1809 return $arr;
1812 function CacheGetArray($secs2cache,$sql=false,$inputarr=false) {
1813 global $ADODB_COUNTRECS;
1815 $savec = $ADODB_COUNTRECS;
1816 $ADODB_COUNTRECS = false;
1817 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1818 $ADODB_COUNTRECS = $savec;
1820 if (!$rs)
1821 if (defined('ADODB_PEAR')) {
1822 $cls = ADODB_PEAR_Error();
1823 return $cls;
1824 } else {
1825 return false;
1827 $arr = $rs->GetArray();
1828 $rs->Close();
1829 return $arr;
1832 function GetRandRow($sql, $arr= false) {
1833 $rezarr = $this->GetAll($sql, $arr);
1834 $sz = sizeof($rezarr);
1835 return $rezarr[abs(rand()) % $sz];
1839 * Return one row of sql statement. Recordset is disposed for you.
1840 * Note that SelectLimit should not be called.
1842 * @param sql SQL statement
1843 * @param [inputarr] input bind array
1845 function GetRow($sql,$inputarr=false) {
1846 global $ADODB_COUNTRECS;
1848 $crecs = $ADODB_COUNTRECS;
1849 $ADODB_COUNTRECS = false;
1851 $rs = $this->Execute($sql,$inputarr);
1853 $ADODB_COUNTRECS = $crecs;
1854 if ($rs) {
1855 if (!$rs->EOF) {
1856 $arr = $rs->fields;
1857 } else {
1858 $arr = array();
1860 $rs->Close();
1861 return $arr;
1864 return false;
1867 function CacheGetRow($secs2cache,$sql=false,$inputarr=false) {
1868 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1869 if ($rs) {
1870 if (!$rs->EOF) {
1871 $arr = $rs->fields;
1872 } else {
1873 $arr = array();
1876 $rs->Close();
1877 return $arr;
1879 return false;
1883 * Insert or replace a single record. Note: this is not the same as MySQL's replace.
1884 * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
1885 * Also note that no table locking is done currently, so it is possible that the
1886 * record be inserted twice by two programs...
1888 * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
1890 * $table table name
1891 * $fieldArray associative array of data (you must quote strings yourself).
1892 * $keyCol the primary key field name or if compound key, array of field names
1893 * autoQuote set to true to use a hueristic to quote strings. Works with nulls and numbers
1894 * but does not work with dates nor SQL functions.
1895 * has_autoinc the primary key is an auto-inc field, so skip in insert.
1897 * Currently blob replace not supported
1899 * returns 0 = fail, 1 = update, 2 = insert
1902 function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false) {
1903 global $ADODB_INCLUDED_LIB;
1904 if (empty($ADODB_INCLUDED_LIB)) {
1905 include(ADODB_DIR.'/adodb-lib.inc.php');
1908 return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);
1913 * Will select, getting rows from $offset (1-based), for $nrows.
1914 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1915 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1916 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1917 * eg.
1918 * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
1919 * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
1921 * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
1923 * @param [secs2cache] seconds to cache data, set to 0 to force query. This is optional
1924 * @param sql
1925 * @param [offset] is the row to start calculations from (1-based)
1926 * @param [nrows] is the number of rows to get
1927 * @param [inputarr] array of bind variables
1928 * @return the recordset ($rs->databaseType == 'array')
1930 function CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false) {
1931 if (!is_numeric($secs2cache)) {
1932 if ($sql === false) {
1933 $sql = -1;
1935 if ($offset == -1) {
1936 $offset = false;
1938 // sql, nrows, offset,inputarr
1939 $rs = $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs);
1940 } else {
1941 if ($sql === false) {
1942 $this->outp_throw("Warning: \$sql missing from CacheSelectLimit()",'CacheSelectLimit');
1944 $rs = $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
1946 return $rs;
1950 * Flush cached recordsets that match a particular $sql statement.
1951 * If $sql == false, then we purge all files in the cache.
1953 function CacheFlush($sql=false,$inputarr=false) {
1954 global $ADODB_CACHE_DIR, $ADODB_CACHE;
1956 # Create cache if it does not exist
1957 if (empty($ADODB_CACHE)) {
1958 $this->_CreateCache();
1961 if (!$sql) {
1962 $ADODB_CACHE->flushall($this->debug);
1963 return;
1966 $f = $this->_gencachename($sql.serialize($inputarr),false);
1967 return $ADODB_CACHE->flushcache($f, $this->debug);
1972 * Private function to generate filename for caching.
1973 * Filename is generated based on:
1975 * - sql statement
1976 * - database type (oci8, ibase, ifx, etc)
1977 * - database name
1978 * - userid
1979 * - setFetchMode (adodb 4.23)
1981 * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
1982 * Assuming that we can have 50,000 files per directory with good performance,
1983 * then we can scale to 12.8 million unique cached recordsets. Wow!
1985 function _gencachename($sql,$createdir) {
1986 global $ADODB_CACHE, $ADODB_CACHE_DIR;
1988 if ($this->fetchMode === false) {
1989 global $ADODB_FETCH_MODE;
1990 $mode = $ADODB_FETCH_MODE;
1991 } else {
1992 $mode = $this->fetchMode;
1994 $m = md5($sql.$this->databaseType.$this->database.$this->user.$mode);
1995 if (!$ADODB_CACHE->createdir) {
1996 return $m;
1998 if (!$createdir) {
1999 $dir = $ADODB_CACHE->getdirname($m);
2000 } else {
2001 $dir = $ADODB_CACHE->createdir($m, $this->debug);
2004 return $dir.'/adodb_'.$m.'.cache';
2009 * Execute SQL, caching recordsets.
2011 * @param [secs2cache] seconds to cache data, set to 0 to force query.
2012 * This is an optional parameter.
2013 * @param sql SQL statement to execute
2014 * @param [inputarr] holds the input data to bind to
2015 * @return RecordSet or false
2017 function CacheExecute($secs2cache,$sql=false,$inputarr=false) {
2018 global $ADODB_CACHE;
2020 if (empty($ADODB_CACHE)) {
2021 $this->_CreateCache();
2024 if (!is_numeric($secs2cache)) {
2025 $inputarr = $sql;
2026 $sql = $secs2cache;
2027 $secs2cache = $this->cacheSecs;
2030 if (is_array($sql)) {
2031 $sqlparam = $sql;
2032 $sql = $sql[0];
2033 } else
2034 $sqlparam = $sql;
2037 $md5file = $this->_gencachename($sql.serialize($inputarr),true);
2038 $err = '';
2040 if ($secs2cache > 0){
2041 $rs = $ADODB_CACHE->readcache($md5file,$err,$secs2cache,$this->arrayClass);
2042 $this->numCacheHits += 1;
2043 } else {
2044 $err='Timeout 1';
2045 $rs = false;
2046 $this->numCacheMisses += 1;
2049 if (!$rs) {
2050 // no cached rs found
2051 if ($this->debug) {
2052 if (get_magic_quotes_runtime() && !$this->memCache) {
2053 ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
2055 if ($this->debug !== -1) {
2056 ADOConnection::outp( " $md5file cache failure: $err (this is a notice and not an error)");
2060 $rs = $this->Execute($sqlparam,$inputarr);
2062 if ($rs) {
2063 $eof = $rs->EOF;
2064 $rs = $this->_rs2rs($rs); // read entire recordset into memory immediately
2065 $rs->timeCreated = time(); // used by caching
2066 $txt = _rs2serialize($rs,false,$sql); // serialize
2068 $ok = $ADODB_CACHE->writecache($md5file,$txt,$this->debug, $secs2cache);
2069 if (!$ok) {
2070 if ($ok === false) {
2071 $em = 'Cache write error';
2072 $en = -32000;
2074 if ($fn = $this->raiseErrorFn) {
2075 $fn($this->databaseType,'CacheExecute', $en, $em, $md5file,$sql,$this);
2077 } else {
2078 $em = 'Cache file locked warning';
2079 $en = -32001;
2080 // do not call error handling for just a warning
2083 if ($this->debug) {
2084 ADOConnection::outp( " ".$em);
2087 if ($rs->EOF && !$eof) {
2088 $rs->MoveFirst();
2089 //$rs = csv2rs($md5file,$err);
2090 $rs->connection = $this; // Pablo suggestion
2093 } else if (!$this->memCache) {
2094 $ADODB_CACHE->flushcache($md5file);
2096 } else {
2097 $this->_errorMsg = '';
2098 $this->_errorCode = 0;
2100 if ($this->fnCacheExecute) {
2101 $fn = $this->fnCacheExecute;
2102 $fn($this, $secs2cache, $sql, $inputarr);
2104 // ok, set cached object found
2105 $rs->connection = $this; // Pablo suggestion
2106 if ($this->debug){
2107 if ($this->debug == 99) {
2108 adodb_backtrace();
2110 $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
2111 $ttl = $rs->timeCreated + $secs2cache - time();
2112 $s = is_array($sql) ? $sql[0] : $sql;
2113 if ($inBrowser) {
2114 $s = '<i>'.htmlspecialchars($s).'</i>';
2117 ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
2120 return $rs;
2125 Similar to PEAR DB's autoExecute(), except that
2126 $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
2127 If $mode == 'UPDATE', then $where is compulsory as a safety measure.
2129 $forceUpdate means that even if the data has not changed, perform update.
2131 function AutoExecute($table, $fields_values, $mode = 'INSERT', $where = false, $forceUpdate = true, $magicq = false) {
2132 if ($where === false && ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) ) {
2133 $this->outp_throw('AutoExecute: Illegal mode=UPDATE with empty WHERE clause', 'AutoExecute');
2134 return false;
2137 $sql = "SELECT * FROM $table";
2138 $rs = $this->SelectLimit($sql, 1);
2139 if (!$rs) {
2140 return false; // table does not exist
2143 $rs->tableName = $table;
2144 if ($where !== false) {
2145 $sql .= " WHERE $where";
2147 $rs->sql = $sql;
2149 switch($mode) {
2150 case 'UPDATE':
2151 case DB_AUTOQUERY_UPDATE:
2152 $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq);
2153 break;
2154 case 'INSERT':
2155 case DB_AUTOQUERY_INSERT:
2156 $sql = $this->GetInsertSQL($rs, $fields_values, $magicq);
2157 break;
2158 default:
2159 $this->outp_throw("AutoExecute: Unknown mode=$mode", 'AutoExecute');
2160 return false;
2162 return $sql && $this->Execute($sql);
2167 * Generates an Update Query based on an existing recordset.
2168 * $arrFields is an associative array of fields with the value
2169 * that should be assigned.
2171 * Note: This function should only be used on a recordset
2172 * that is run against a single table and sql should only
2173 * be a simple select stmt with no groupby/orderby/limit
2175 * "Jonathan Younger" <jyounger@unilab.com>
2177 function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null) {
2178 global $ADODB_INCLUDED_LIB;
2180 // ********************************************************
2181 // This is here to maintain compatibility
2182 // with older adodb versions. Sets force type to force nulls if $forcenulls is set.
2183 if (!isset($force)) {
2184 global $ADODB_FORCE_TYPE;
2185 $force = $ADODB_FORCE_TYPE;
2187 // ********************************************************
2189 if (empty($ADODB_INCLUDED_LIB)) {
2190 include(ADODB_DIR.'/adodb-lib.inc.php');
2192 return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
2196 * Generates an Insert Query based on an existing recordset.
2197 * $arrFields is an associative array of fields with the value
2198 * that should be assigned.
2200 * Note: This function should only be used on a recordset
2201 * that is run against a single table.
2203 function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null) {
2204 global $ADODB_INCLUDED_LIB;
2205 if (!isset($force)) {
2206 global $ADODB_FORCE_TYPE;
2207 $force = $ADODB_FORCE_TYPE;
2209 if (empty($ADODB_INCLUDED_LIB)) {
2210 include(ADODB_DIR.'/adodb-lib.inc.php');
2212 return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
2217 * Update a blob column, given a where clause. There are more sophisticated
2218 * blob handling functions that we could have implemented, but all require
2219 * a very complex API. Instead we have chosen something that is extremely
2220 * simple to understand and use.
2222 * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
2224 * Usage to update a $blobvalue which has a primary key blob_id=1 into a
2225 * field blobtable.blobcolumn:
2227 * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
2229 * Insert example:
2231 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
2232 * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
2234 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') {
2235 return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
2239 * Usage:
2240 * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
2242 * $blobtype supports 'BLOB' and 'CLOB'
2244 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
2245 * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
2247 function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') {
2248 $fd = fopen($path,'rb');
2249 if ($fd === false) {
2250 return false;
2252 $val = fread($fd,filesize($path));
2253 fclose($fd);
2254 return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
2257 function BlobDecode($blob) {
2258 return $blob;
2261 function BlobEncode($blob) {
2262 return $blob;
2265 function GetCharSet() {
2266 return $this->charSet;
2269 function SetCharSet($charset) {
2270 $this->charSet = $charset;
2271 return true;
2274 function IfNull( $field, $ifNull ) {
2275 return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
2278 function LogSQL($enable=true) {
2279 include_once(ADODB_DIR.'/adodb-perf.inc.php');
2281 if ($enable) {
2282 $this->fnExecute = 'adodb_log_sql';
2283 } else {
2284 $this->fnExecute = false;
2287 $old = $this->_logsql;
2288 $this->_logsql = $enable;
2289 if ($enable && !$old) {
2290 $this->_affected = false;
2292 return $old;
2296 * Usage:
2297 * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
2299 * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
2300 * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
2302 function UpdateClob($table,$column,$val,$where) {
2303 return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
2306 // not the fastest implementation - quick and dirty - jlim
2307 // for best performance, use the actual $rs->MetaType().
2308 function MetaType($t,$len=-1,$fieldobj=false) {
2310 if (empty($this->_metars)) {
2311 $rsclass = $this->rsPrefix.$this->databaseType;
2312 $this->_metars = new $rsclass(false,$this->fetchMode);
2313 $this->_metars->connection = $this;
2315 return $this->_metars->MetaType($t,$len,$fieldobj);
2320 * Change the SQL connection locale to a specified locale.
2321 * This is used to get the date formats written depending on the client locale.
2323 function SetDateLocale($locale = 'En') {
2324 $this->locale = $locale;
2325 switch (strtoupper($locale))
2327 case 'EN':
2328 $this->fmtDate="'Y-m-d'";
2329 $this->fmtTimeStamp = "'Y-m-d H:i:s'";
2330 break;
2332 case 'US':
2333 $this->fmtDate = "'m-d-Y'";
2334 $this->fmtTimeStamp = "'m-d-Y H:i:s'";
2335 break;
2337 case 'PT_BR':
2338 case 'NL':
2339 case 'FR':
2340 case 'RO':
2341 case 'IT':
2342 $this->fmtDate="'d-m-Y'";
2343 $this->fmtTimeStamp = "'d-m-Y H:i:s'";
2344 break;
2346 case 'GE':
2347 $this->fmtDate="'d.m.Y'";
2348 $this->fmtTimeStamp = "'d.m.Y H:i:s'";
2349 break;
2351 default:
2352 $this->fmtDate="'Y-m-d'";
2353 $this->fmtTimeStamp = "'Y-m-d H:i:s'";
2354 break;
2359 * GetActiveRecordsClass Performs an 'ALL' query
2361 * @param mixed $class This string represents the class of the current active record
2362 * @param mixed $table Table used by the active record object
2363 * @param mixed $whereOrderBy Where, order, by clauses
2364 * @param mixed $bindarr
2365 * @param mixed $primkeyArr
2366 * @param array $extra Query extras: limit, offset...
2367 * @param mixed $relations Associative array: table's foreign name, "hasMany", "belongsTo"
2368 * @access public
2369 * @return void
2371 function GetActiveRecordsClass(
2372 $class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false,
2373 $extra=array(),
2374 $relations=array())
2376 global $_ADODB_ACTIVE_DBS;
2377 ## reduce overhead of adodb.inc.php -- moved to adodb-active-record.inc.php
2378 ## if adodb-active-recordx is loaded -- should be no issue as they will probably use Find()
2379 if (!isset($_ADODB_ACTIVE_DBS)) {
2380 include_once(ADODB_DIR.'/adodb-active-record.inc.php');
2382 return adodb_GetActiveRecordsClass($this, $class, $table, $whereOrderBy, $bindarr, $primkeyArr, $extra, $relations);
2385 function GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false) {
2386 $arr = $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr);
2387 return $arr;
2391 * Close Connection
2393 function Close() {
2394 $rez = $this->_close();
2395 $this->_connectionID = false;
2396 return $rez;
2400 * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
2402 * @return true if succeeded or false if database does not support transactions
2404 function BeginTrans() {
2405 if ($this->debug) {
2406 ADOConnection::outp("BeginTrans: Transactions not supported for this driver");
2408 return false;
2411 /* set transaction mode */
2412 function SetTransactionMode( $transaction_mode ) {
2413 $transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider);
2414 $this->_transmode = $transaction_mode;
2417 http://msdn2.microsoft.com/en-US/ms173763.aspx
2418 http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html
2419 http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html
2420 http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm
2422 function MetaTransaction($mode,$db) {
2423 $mode = strtoupper($mode);
2424 $mode = str_replace('ISOLATION LEVEL ','',$mode);
2426 switch($mode) {
2428 case 'READ UNCOMMITTED':
2429 switch($db) {
2430 case 'oci8':
2431 case 'oracle':
2432 return 'ISOLATION LEVEL READ COMMITTED';
2433 default:
2434 return 'ISOLATION LEVEL READ UNCOMMITTED';
2436 break;
2438 case 'READ COMMITTED':
2439 return 'ISOLATION LEVEL READ COMMITTED';
2440 break;
2442 case 'REPEATABLE READ':
2443 switch($db) {
2444 case 'oci8':
2445 case 'oracle':
2446 return 'ISOLATION LEVEL SERIALIZABLE';
2447 default:
2448 return 'ISOLATION LEVEL REPEATABLE READ';
2450 break;
2452 case 'SERIALIZABLE':
2453 return 'ISOLATION LEVEL SERIALIZABLE';
2454 break;
2456 default:
2457 return $mode;
2462 * If database does not support transactions, always return true as data always commited
2464 * @param $ok set to false to rollback transaction, true to commit
2466 * @return true/false.
2468 function CommitTrans($ok=true) {
2469 return true;
2474 * If database does not support transactions, rollbacks always fail, so return false
2476 * @return true/false.
2478 function RollbackTrans() {
2479 return false;
2484 * return the databases that the driver can connect to.
2485 * Some databases will return an empty array.
2487 * @return an array of database names.
2489 function MetaDatabases() {
2490 global $ADODB_FETCH_MODE;
2492 if ($this->metaDatabasesSQL) {
2493 $save = $ADODB_FETCH_MODE;
2494 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2496 if ($this->fetchMode !== false) {
2497 $savem = $this->SetFetchMode(false);
2500 $arr = $this->GetCol($this->metaDatabasesSQL);
2501 if (isset($savem)) {
2502 $this->SetFetchMode($savem);
2504 $ADODB_FETCH_MODE = $save;
2506 return $arr;
2509 return false;
2513 * List procedures or functions in an array.
2514 * @param procedureNamePattern a procedure name pattern; must match the procedure name as it is stored in the database
2515 * @param catalog a catalog name; must match the catalog name as it is stored in the database;
2516 * @param schemaPattern a schema name pattern;
2518 * @return array of procedures on current database.
2520 * Array(
2521 * [name_of_procedure] => Array(
2522 * [type] => PROCEDURE or FUNCTION
2523 * [catalog] => Catalog_name
2524 * [schema] => Schema_name
2525 * [remarks] => explanatory comment on the procedure
2529 function MetaProcedures($procedureNamePattern = null, $catalog = null, $schemaPattern = null) {
2530 return false;
2535 * @param ttype can either be 'VIEW' or 'TABLE' or false.
2536 * If false, both views and tables are returned.
2537 * "VIEW" returns only views
2538 * "TABLE" returns only tables
2539 * @param showSchema returns the schema/user with the table name, eg. USER.TABLE
2540 * @param mask is the input mask - only supported by oci8 and postgresql
2542 * @return array of tables for current database.
2544 function MetaTables($ttype=false,$showSchema=false,$mask=false) {
2545 global $ADODB_FETCH_MODE;
2547 if ($mask) {
2548 return false;
2550 if ($this->metaTablesSQL) {
2551 $save = $ADODB_FETCH_MODE;
2552 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2554 if ($this->fetchMode !== false) {
2555 $savem = $this->SetFetchMode(false);
2558 $rs = $this->Execute($this->metaTablesSQL);
2559 if (isset($savem)) {
2560 $this->SetFetchMode($savem);
2562 $ADODB_FETCH_MODE = $save;
2564 if ($rs === false) {
2565 return false;
2567 $arr = $rs->GetArray();
2568 $arr2 = array();
2570 if ($hast = ($ttype && isset($arr[0][1]))) {
2571 $showt = strncmp($ttype,'T',1);
2574 for ($i=0; $i < sizeof($arr); $i++) {
2575 if ($hast) {
2576 if ($showt == 0) {
2577 if (strncmp($arr[$i][1],'T',1) == 0) {
2578 $arr2[] = trim($arr[$i][0]);
2580 } else {
2581 if (strncmp($arr[$i][1],'V',1) == 0) {
2582 $arr2[] = trim($arr[$i][0]);
2585 } else
2586 $arr2[] = trim($arr[$i][0]);
2588 $rs->Close();
2589 return $arr2;
2591 return false;
2595 function _findschema(&$table,&$schema) {
2596 if (!$schema && ($at = strpos($table,'.')) !== false) {
2597 $schema = substr($table,0,$at);
2598 $table = substr($table,$at+1);
2603 * List columns in a database as an array of ADOFieldObjects.
2604 * See top of file for definition of object.
2606 * @param $table table name to query
2607 * @param $normalize makes table name case-insensitive (required by some databases)
2608 * @schema is optional database schema to use - not supported by all databases.
2610 * @return array of ADOFieldObjects for current table.
2612 function MetaColumns($table,$normalize=true) {
2613 global $ADODB_FETCH_MODE;
2615 if (!empty($this->metaColumnsSQL)) {
2616 $schema = false;
2617 $this->_findschema($table,$schema);
2619 $save = $ADODB_FETCH_MODE;
2620 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2621 if ($this->fetchMode !== false) {
2622 $savem = $this->SetFetchMode(false);
2624 $rs = $this->Execute(sprintf($this->metaColumnsSQL,($normalize)?strtoupper($table):$table));
2625 if (isset($savem)) {
2626 $this->SetFetchMode($savem);
2628 $ADODB_FETCH_MODE = $save;
2629 if ($rs === false || $rs->EOF) {
2630 return false;
2633 $retarr = array();
2634 while (!$rs->EOF) { //print_r($rs->fields);
2635 $fld = new ADOFieldObject();
2636 $fld->name = $rs->fields[0];
2637 $fld->type = $rs->fields[1];
2638 if (isset($rs->fields[3]) && $rs->fields[3]) {
2639 if ($rs->fields[3]>0) {
2640 $fld->max_length = $rs->fields[3];
2642 $fld->scale = $rs->fields[4];
2643 if ($fld->scale>0) {
2644 $fld->max_length += 1;
2646 } else {
2647 $fld->max_length = $rs->fields[2];
2650 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) {
2651 $retarr[] = $fld;
2652 } else {
2653 $retarr[strtoupper($fld->name)] = $fld;
2655 $rs->MoveNext();
2657 $rs->Close();
2658 return $retarr;
2660 return false;
2664 * List indexes on a table as an array.
2665 * @param table table name to query
2666 * @param primary true to only show primary keys. Not actually used for most databases
2668 * @return array of indexes on current table. Each element represents an index, and is itself an associative array.
2670 * Array(
2671 * [name_of_index] => Array(
2672 * [unique] => true or false
2673 * [columns] => Array(
2674 * [0] => firstname
2675 * [1] => lastname
2680 function MetaIndexes($table, $primary = false, $owner = false) {
2681 return false;
2685 * List columns names in a table as an array.
2686 * @param table table name to query
2688 * @return array of column names for current table.
2690 function MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */) {
2691 $objarr = $this->MetaColumns($table);
2692 if (!is_array($objarr)) {
2693 return false;
2695 $arr = array();
2696 if ($numIndexes) {
2697 $i = 0;
2698 if ($useattnum) {
2699 foreach($objarr as $v)
2700 $arr[$v->attnum] = $v->name;
2702 } else
2703 foreach($objarr as $v) $arr[$i++] = $v->name;
2704 } else
2705 foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name;
2707 return $arr;
2711 * Different SQL databases used different methods to combine strings together.
2712 * This function provides a wrapper.
2714 * param s variable number of string parameters
2716 * Usage: $db->Concat($str1,$str2);
2718 * @return concatenated string
2720 function Concat() {
2721 $arr = func_get_args();
2722 return implode($this->concat_operator, $arr);
2727 * Converts a date "d" to a string that the database can understand.
2729 * @param d a date in Unix date time format.
2731 * @return date string in database date format
2733 function DBDate($d, $isfld=false) {
2734 if (empty($d) && $d !== 0) {
2735 return 'null';
2737 if ($isfld) {
2738 return $d;
2740 if (is_object($d)) {
2741 return $d->format($this->fmtDate);
2744 if (is_string($d) && !is_numeric($d)) {
2745 if ($d === 'null') {
2746 return $d;
2748 if (strncmp($d,"'",1) === 0) {
2749 $d = _adodb_safedateq($d);
2750 return $d;
2752 if ($this->isoDates) {
2753 return "'$d'";
2755 $d = ADOConnection::UnixDate($d);
2758 return adodb_date($this->fmtDate,$d);
2761 function BindDate($d) {
2762 $d = $this->DBDate($d);
2763 if (strncmp($d,"'",1)) {
2764 return $d;
2767 return substr($d,1,strlen($d)-2);
2770 function BindTimeStamp($d) {
2771 $d = $this->DBTimeStamp($d);
2772 if (strncmp($d,"'",1)) {
2773 return $d;
2776 return substr($d,1,strlen($d)-2);
2781 * Converts a timestamp "ts" to a string that the database can understand.
2783 * @param ts a timestamp in Unix date time format.
2785 * @return timestamp string in database timestamp format
2787 function DBTimeStamp($ts,$isfld=false) {
2788 if (empty($ts) && $ts !== 0) {
2789 return 'null';
2791 if ($isfld) {
2792 return $ts;
2794 if (is_object($ts)) {
2795 return $ts->format($this->fmtTimeStamp);
2798 # strlen(14) allows YYYYMMDDHHMMSS format
2799 if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) {
2800 return adodb_date($this->fmtTimeStamp,$ts);
2803 if ($ts === 'null') {
2804 return $ts;
2806 if ($this->isoDates && strlen($ts) !== 14) {
2807 $ts = _adodb_safedate($ts);
2808 return "'$ts'";
2810 $ts = ADOConnection::UnixTimeStamp($ts);
2811 return adodb_date($this->fmtTimeStamp,$ts);
2815 * Also in ADORecordSet.
2816 * @param $v is a date string in YYYY-MM-DD format
2818 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2820 static function UnixDate($v) {
2821 if (is_object($v)) {
2822 // odbtp support
2823 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2824 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2827 if (is_numeric($v) && strlen($v) !== 8) {
2828 return $v;
2830 if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", $v, $rr)) {
2831 return false;
2834 if ($rr[1] <= TIMESTAMP_FIRST_YEAR) {
2835 return 0;
2838 // h-m-s-MM-DD-YY
2839 return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2844 * Also in ADORecordSet.
2845 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
2847 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2849 static function UnixTimeStamp($v) {
2850 if (is_object($v)) {
2851 // odbtp support
2852 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2853 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2856 if (!preg_match(
2857 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
2858 ($v), $rr)) return false;
2860 if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) {
2861 return 0;
2864 // h-m-s-MM-DD-YY
2865 if (!isset($rr[5])) {
2866 return adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2868 return @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
2872 * Also in ADORecordSet.
2874 * Format database date based on user defined format.
2876 * @param v is the character date in YYYY-MM-DD format, returned by database
2877 * @param fmt is the format to apply to it, using date()
2879 * @return a date formated as user desires
2881 function UserDate($v,$fmt='Y-m-d',$gmt=false) {
2882 $tt = $this->UnixDate($v);
2884 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2885 if (($tt === false || $tt == -1) && $v != false) {
2886 return $v;
2887 } else if ($tt == 0) {
2888 return $this->emptyDate;
2889 } else if ($tt == -1) {
2890 // pre-TIMESTAMP_FIRST_YEAR
2893 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2899 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
2900 * @param fmt is the format to apply to it, using date()
2902 * @return a timestamp formated as user desires
2904 function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false) {
2905 if (!isset($v)) {
2906 return $this->emptyTimeStamp;
2908 # strlen(14) allows YYYYMMDDHHMMSS format
2909 if (is_numeric($v) && strlen($v)<14) {
2910 return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v);
2912 $tt = $this->UnixTimeStamp($v);
2913 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2914 if (($tt === false || $tt == -1) && $v != false) {
2915 return $v;
2917 if ($tt == 0) {
2918 return $this->emptyTimeStamp;
2920 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2923 function escape($s,$magic_quotes=false) {
2924 return $this->addq($s,$magic_quotes);
2928 * Quotes a string, without prefixing nor appending quotes.
2930 function addq($s,$magic_quotes=false) {
2931 if (!$magic_quotes) {
2932 if ($this->replaceQuote[0] == '\\') {
2933 // only since php 4.0.5
2934 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2935 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2937 return str_replace("'",$this->replaceQuote,$s);
2940 // undo magic quotes for "
2941 $s = str_replace('\\"','"',$s);
2943 if ($this->replaceQuote == "\\'" || ini_get('magic_quotes_sybase')) {
2944 // ' already quoted, no need to change anything
2945 return $s;
2946 } else {
2947 // change \' to '' for sybase/mssql
2948 $s = str_replace('\\\\','\\',$s);
2949 return str_replace("\\'",$this->replaceQuote,$s);
2954 * Correctly quotes a string so that all strings are escaped. We prefix and append
2955 * to the string single-quotes.
2956 * An example is $db->qstr("Don't bother",magic_quotes_runtime());
2958 * @param s the string to quote
2959 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
2960 * This undoes the stupidity of magic quotes for GPC.
2962 * @return quoted string to be sent back to database
2964 function qstr($s,$magic_quotes=false) {
2965 if (!$magic_quotes) {
2966 if ($this->replaceQuote[0] == '\\'){
2967 // only since php 4.0.5
2968 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2969 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2971 return "'".str_replace("'",$this->replaceQuote,$s)."'";
2974 // undo magic quotes for "
2975 $s = str_replace('\\"','"',$s);
2977 if ($this->replaceQuote == "\\'" || ini_get('magic_quotes_sybase')) {
2978 // ' already quoted, no need to change anything
2979 return "'$s'";
2980 } else {
2981 // change \' to '' for sybase/mssql
2982 $s = str_replace('\\\\','\\',$s);
2983 return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
2989 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2990 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2991 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2993 * See docs-adodb.htm#ex8 for an example of usage.
2995 * @param sql
2996 * @param nrows is the number of rows per page to get
2997 * @param page is the page number to get (1-based)
2998 * @param [inputarr] array of bind variables
2999 * @param [secs2cache] is a private parameter only used by jlim
3000 * @return the recordset ($rs->databaseType == 'array')
3002 * NOTE: phpLens uses a different algorithm and does not use PageExecute().
3005 function PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0) {
3006 global $ADODB_INCLUDED_LIB;
3007 if (empty($ADODB_INCLUDED_LIB)) {
3008 include(ADODB_DIR.'/adodb-lib.inc.php');
3010 if ($this->pageExecuteCountRows) {
3011 $rs = _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
3012 } else {
3013 $rs = _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache);
3015 return $rs;
3020 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
3021 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
3022 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
3024 * @param secs2cache seconds to cache data, set to 0 to force query
3025 * @param sql
3026 * @param nrows is the number of rows per page to get
3027 * @param page is the page number to get (1-based)
3028 * @param [inputarr] array of bind variables
3029 * @return the recordset ($rs->databaseType == 'array')
3031 function CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false) {
3032 /*switch($this->dataProvider) {
3033 case 'postgres':
3034 case 'mysql':
3035 break;
3036 default: $secs2cache = 0; break;
3038 $rs = $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
3039 return $rs;
3042 } // end class ADOConnection
3046 //==============================================================================================
3047 // CLASS ADOFetchObj
3048 //==============================================================================================
3051 * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
3053 class ADOFetchObj {
3056 //==============================================================================================
3057 // CLASS ADORecordSet_empty
3058 //==============================================================================================
3060 class ADODB_Iterator_empty implements Iterator {
3062 private $rs;
3064 function __construct($rs) {
3065 $this->rs = $rs;
3068 function rewind() {}
3070 function valid() {
3071 return !$this->rs->EOF;
3074 function key() {
3075 return false;
3078 function current() {
3079 return false;
3082 function next() {}
3084 function __call($func, $params) {
3085 return call_user_func_array(array($this->rs, $func), $params);
3088 function hasMore() {
3089 return false;
3096 * Lightweight recordset when there are no records to be returned
3098 class ADORecordSet_empty implements IteratorAggregate
3100 var $dataProvider = 'empty';
3101 var $databaseType = false;
3102 var $EOF = true;
3103 var $_numOfRows = 0;
3104 var $fields = false;
3105 var $connection = false;
3107 function RowCount() {
3108 return 0;
3111 function RecordCount() {
3112 return 0;
3115 function PO_RecordCount() {
3116 return 0;
3119 function Close() {
3120 return true;
3123 function FetchRow() {
3124 return false;
3127 function FieldCount() {
3128 return 0;
3131 function Init() {}
3133 function getIterator() {
3134 return new ADODB_Iterator_empty($this);
3137 function GetAssoc() {
3138 return array();
3141 function GetArray() {
3142 return array();
3145 function GetAll() {
3146 return array();
3149 function GetArrayLimit() {
3150 return array();
3153 function GetRows() {
3154 return array();
3157 function GetRowAssoc() {
3158 return array();
3161 function MaxRecordCount() {
3162 return 0;
3165 function NumRows() {
3166 return 0;
3169 function NumCols() {
3170 return 0;
3174 //==============================================================================================
3175 // DATE AND TIME FUNCTIONS
3176 //==============================================================================================
3177 if (!defined('ADODB_DATE_VERSION')) {
3178 include(ADODB_DIR.'/adodb-time.inc.php');
3181 //==============================================================================================
3182 // CLASS ADORecordSet
3183 //==============================================================================================
3185 class ADODB_Iterator implements Iterator {
3187 private $rs;
3189 function __construct($rs) {
3190 $this->rs = $rs;
3193 function rewind() {
3194 $this->rs->MoveFirst();
3197 function valid() {
3198 return !$this->rs->EOF;
3201 function key() {
3202 return $this->rs->_currentRow;
3205 function current() {
3206 return $this->rs->fields;
3209 function next() {
3210 $this->rs->MoveNext();
3213 function __call($func, $params) {
3214 return call_user_func_array(array($this->rs, $func), $params);
3217 function hasMore() {
3218 return !$this->rs->EOF;
3225 * RecordSet class that represents the dataset returned by the database.
3226 * To keep memory overhead low, this class holds only the current row in memory.
3227 * No prefetching of data is done, so the RecordCount() can return -1 ( which
3228 * means recordcount not known).
3230 class ADORecordSet implements IteratorAggregate {
3233 * public variables
3235 var $dataProvider = "native";
3236 var $fields = false; /// holds the current row data
3237 var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob
3238 /// in other words, we use a text area for editing.
3239 var $canSeek = false; /// indicates that seek is supported
3240 var $sql; /// sql text
3241 var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object.
3243 var $emptyTimeStamp = '&nbsp;'; /// what to display when $time==0
3244 var $emptyDate = '&nbsp;'; /// what to display when $time==0
3245 var $debug = false;
3246 var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsets
3248 var $bind = false; /// used by Fields() to hold array - should be private?
3249 var $fetchMode; /// default fetch mode
3250 var $connection = false; /// the parent connection
3253 * private variables
3255 var $_numOfRows = -1; /** number of rows, or -1 */
3256 var $_numOfFields = -1; /** number of fields in recordset */
3257 var $_queryID = -1; /** This variable keeps the result link identifier. */
3258 var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */
3259 var $_closed = false; /** has recordset been closed */
3260 var $_inited = false; /** Init() should only be called once */
3261 var $_obj; /** Used by FetchObj */
3262 var $_names; /** Used by FetchObj */
3264 var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */
3265 var $_atFirstPage = false; /** Added by Iván Oliva to implement recordset pagination */
3266 var $_atLastPage = false; /** Added by Iván Oliva to implement recordset pagination */
3267 var $_lastPageNo = -1;
3268 var $_maxRecordCount = 0;
3269 var $datetime = false;
3272 * Constructor
3274 * @param queryID this is the queryID returned by ADOConnection->_query()
3277 function __construct($queryID) {
3278 $this->_queryID = $queryID;
3281 function __destruct() {
3282 @$this->Close();
3285 function getIterator() {
3286 return new ADODB_Iterator($this);
3289 /* this is experimental - i don't really know what to return... */
3290 function __toString() {
3291 include_once(ADODB_DIR.'/toexport.inc.php');
3292 return _adodb_export($this,',',',',false,true);
3295 function Init() {
3296 if ($this->_inited) {
3297 return;
3299 $this->_inited = true;
3300 if ($this->_queryID) {
3301 @$this->_initrs();
3302 } else {
3303 $this->_numOfRows = 0;
3304 $this->_numOfFields = 0;
3306 if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
3307 $this->_currentRow = 0;
3308 if ($this->EOF = ($this->_fetch() === false)) {
3309 $this->_numOfRows = 0; // _numOfRows could be -1
3311 } else {
3312 $this->EOF = true;
3318 * Generate a SELECT tag string from a recordset, and return the string.
3319 * If the recordset has 2 cols, we treat the 1st col as the containing
3320 * the text to display to the user, and 2nd col as the return value. Default
3321 * strings are compared with the FIRST column.
3323 * @param name name of SELECT tag
3324 * @param [defstr] the value to hilite. Use an array for multiple hilites for listbox.
3325 * @param [blank1stItem] true to leave the 1st item in list empty
3326 * @param [multiple] true for listbox, false for popup
3327 * @param [size] #rows to show for listbox. not used by popup
3328 * @param [selectAttr] additional attributes to defined for SELECT tag.
3329 * useful for holding javascript onChange='...' handlers.
3330 & @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with
3331 * column 0 (1st col) if this is true. This is not documented.
3333 * @return HTML
3335 * changes by glen.davies@cce.ac.nz to support multiple hilited items
3337 function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
3338 $size=0, $selectAttr='',$compareFields0=true)
3340 global $ADODB_INCLUDED_LIB;
3341 if (empty($ADODB_INCLUDED_LIB)) {
3342 include(ADODB_DIR.'/adodb-lib.inc.php');
3344 return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
3345 $size, $selectAttr,$compareFields0);
3351 * Generate a SELECT tag string from a recordset, and return the string.
3352 * If the recordset has 2 cols, we treat the 1st col as the containing
3353 * the text to display to the user, and 2nd col as the return value. Default
3354 * strings are compared with the SECOND column.
3357 function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='') {
3358 return $this->GetMenu($name,$defstr,$blank1stItem,$multiple,
3359 $size, $selectAttr,false);
3363 Grouped Menu
3365 function GetMenu3($name,$defstr='',$blank1stItem=true,$multiple=false,
3366 $size=0, $selectAttr='')
3368 global $ADODB_INCLUDED_LIB;
3369 if (empty($ADODB_INCLUDED_LIB)) {
3370 include(ADODB_DIR.'/adodb-lib.inc.php');
3372 return _adodb_getmenu_gp($this, $name,$defstr,$blank1stItem,$multiple,
3373 $size, $selectAttr,false);
3377 * return recordset as a 2-dimensional array.
3379 * @param [nRows] is the number of rows to return. -1 means every row.
3381 * @return an array indexed by the rows (0-based) from the recordset
3383 function GetArray($nRows = -1) {
3384 global $ADODB_EXTENSION; if ($ADODB_EXTENSION) {
3385 $results = adodb_getall($this,$nRows);
3386 return $results;
3388 $results = array();
3389 $cnt = 0;
3390 while (!$this->EOF && $nRows != $cnt) {
3391 $results[] = $this->fields;
3392 $this->MoveNext();
3393 $cnt++;
3395 return $results;
3398 function GetAll($nRows = -1) {
3399 $arr = $this->GetArray($nRows);
3400 return $arr;
3404 * Some databases allow multiple recordsets to be returned. This function
3405 * will return true if there is a next recordset, or false if no more.
3407 function NextRecordSet() {
3408 return false;
3412 * return recordset as a 2-dimensional array.
3413 * Helper function for ADOConnection->SelectLimit()
3415 * @param offset is the row to start calculations from (1-based)
3416 * @param [nrows] is the number of rows to return
3418 * @return an array indexed by the rows (0-based) from the recordset
3420 function GetArrayLimit($nrows,$offset=-1) {
3421 if ($offset <= 0) {
3422 $arr = $this->GetArray($nrows);
3423 return $arr;
3426 $this->Move($offset);
3428 $results = array();
3429 $cnt = 0;
3430 while (!$this->EOF && $nrows != $cnt) {
3431 $results[$cnt++] = $this->fields;
3432 $this->MoveNext();
3435 return $results;
3440 * Synonym for GetArray() for compatibility with ADO.
3442 * @param [nRows] is the number of rows to return. -1 means every row.
3444 * @return an array indexed by the rows (0-based) from the recordset
3446 function GetRows($nRows = -1) {
3447 $arr = $this->GetArray($nRows);
3448 return $arr;
3452 * return whole recordset as a 2-dimensional associative array if there are more than 2 columns.
3453 * The first column is treated as the key and is not included in the array.
3454 * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless
3455 * $force_array == true.
3457 * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional
3458 * array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,
3459 * read the source.
3461 * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and
3462 * instead of returning array[col0] => array(remaining cols), return array[col0] => col1
3464 * @return an associative array indexed by the first column of the array,
3465 * or false if the data has less than 2 cols.
3467 function GetAssoc($force_array = false, $first2cols = false) {
3468 global $ADODB_EXTENSION;
3470 $cols = $this->_numOfFields;
3471 if ($cols < 2) {
3472 return false;
3475 // Empty recordset
3476 if (!$this->fields) {
3477 return array();
3480 // Determine whether the array is associative or 0-based numeric
3481 $numIndex = array_keys($this->fields) == range(0, count($this->fields) - 1);
3483 $results = array();
3485 if (!$first2cols && ($cols > 2 || $force_array)) {
3486 if ($ADODB_EXTENSION) {
3487 if ($numIndex) {
3488 while (!$this->EOF) {
3489 $results[trim($this->fields[0])] = array_slice($this->fields, 1);
3490 adodb_movenext($this);
3492 } else {
3493 while (!$this->EOF) {
3494 // Fix for array_slice re-numbering numeric associative keys
3495 $keys = array_slice(array_keys($this->fields), 1);
3496 $sliced_array = array();
3498 foreach($keys as $key) {
3499 $sliced_array[$key] = $this->fields[$key];
3502 $results[trim(reset($this->fields))] = $sliced_array;
3503 adodb_movenext($this);
3506 } else {
3507 if ($numIndex) {
3508 while (!$this->EOF) {
3509 $results[trim($this->fields[0])] = array_slice($this->fields, 1);
3510 $this->MoveNext();
3512 } else {
3513 while (!$this->EOF) {
3514 // Fix for array_slice re-numbering numeric associative keys
3515 $keys = array_slice(array_keys($this->fields), 1);
3516 $sliced_array = array();
3518 foreach($keys as $key) {
3519 $sliced_array[$key] = $this->fields[$key];
3522 $results[trim(reset($this->fields))] = $sliced_array;
3523 $this->MoveNext();
3527 } else {
3528 if ($ADODB_EXTENSION) {
3529 // return scalar values
3530 if ($numIndex) {
3531 while (!$this->EOF) {
3532 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3533 $results[trim(($this->fields[0]))] = $this->fields[1];
3534 adodb_movenext($this);
3536 } else {
3537 while (!$this->EOF) {
3538 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3539 $v1 = trim(reset($this->fields));
3540 $v2 = ''.next($this->fields);
3541 $results[$v1] = $v2;
3542 adodb_movenext($this);
3545 } else {
3546 if ($numIndex) {
3547 while (!$this->EOF) {
3548 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3549 $results[trim(($this->fields[0]))] = $this->fields[1];
3550 $this->MoveNext();
3552 } else {
3553 while (!$this->EOF) {
3554 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3555 $v1 = trim(reset($this->fields));
3556 $v2 = ''.next($this->fields);
3557 $results[$v1] = $v2;
3558 $this->MoveNext();
3564 $ref = $results; # workaround accelerator incompat with PHP 4.4 :(
3565 return $ref;
3571 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
3572 * @param fmt is the format to apply to it, using date()
3574 * @return a timestamp formated as user desires
3576 function UserTimeStamp($v,$fmt='Y-m-d H:i:s') {
3577 if (is_numeric($v) && strlen($v)<14) {
3578 return adodb_date($fmt,$v);
3580 $tt = $this->UnixTimeStamp($v);
3581 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
3582 if (($tt === false || $tt == -1) && $v != false) {
3583 return $v;
3585 if ($tt === 0) {
3586 return $this->emptyTimeStamp;
3588 return adodb_date($fmt,$tt);
3593 * @param v is the character date in YYYY-MM-DD format, returned by database
3594 * @param fmt is the format to apply to it, using date()
3596 * @return a date formated as user desires
3598 function UserDate($v,$fmt='Y-m-d') {
3599 $tt = $this->UnixDate($v);
3600 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
3601 if (($tt === false || $tt == -1) && $v != false) {
3602 return $v;
3603 } else if ($tt == 0) {
3604 return $this->emptyDate;
3605 } else if ($tt == -1) {
3606 // pre-TIMESTAMP_FIRST_YEAR
3608 return adodb_date($fmt,$tt);
3613 * @param $v is a date string in YYYY-MM-DD format
3615 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
3617 static function UnixDate($v) {
3618 return ADOConnection::UnixDate($v);
3623 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
3625 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
3627 static function UnixTimeStamp($v) {
3628 return ADOConnection::UnixTimeStamp($v);
3633 * PEAR DB Compat - do not use internally
3635 function Free() {
3636 return $this->Close();
3641 * PEAR DB compat, number of rows
3643 function NumRows() {
3644 return $this->_numOfRows;
3649 * PEAR DB compat, number of cols
3651 function NumCols() {
3652 return $this->_numOfFields;
3656 * Fetch a row, returning false if no more rows.
3657 * This is PEAR DB compat mode.
3659 * @return false or array containing the current record
3661 function FetchRow() {
3662 if ($this->EOF) {
3663 return false;
3665 $arr = $this->fields;
3666 $this->_currentRow++;
3667 if (!$this->_fetch()) {
3668 $this->EOF = true;
3670 return $arr;
3675 * Fetch a row, returning PEAR_Error if no more rows.
3676 * This is PEAR DB compat mode.
3678 * @return DB_OK or error object
3680 function FetchInto(&$arr) {
3681 if ($this->EOF) {
3682 return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false;
3684 $arr = $this->fields;
3685 $this->MoveNext();
3686 return 1; // DB_OK
3691 * Move to the first row in the recordset. Many databases do NOT support this.
3693 * @return true or false
3695 function MoveFirst() {
3696 if ($this->_currentRow == 0) {
3697 return true;
3699 return $this->Move(0);
3704 * Move to the last row in the recordset.
3706 * @return true or false
3708 function MoveLast() {
3709 if ($this->_numOfRows >= 0) {
3710 return $this->Move($this->_numOfRows-1);
3712 if ($this->EOF) {
3713 return false;
3715 while (!$this->EOF) {
3716 $f = $this->fields;
3717 $this->MoveNext();
3719 $this->fields = $f;
3720 $this->EOF = false;
3721 return true;
3726 * Move to next record in the recordset.
3728 * @return true if there still rows available, or false if there are no more rows (EOF).
3730 function MoveNext() {
3731 if (!$this->EOF) {
3732 $this->_currentRow++;
3733 if ($this->_fetch()) {
3734 return true;
3737 $this->EOF = true;
3738 /* -- tested error handling when scrolling cursor -- seems useless.
3739 $conn = $this->connection;
3740 if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
3741 $fn = $conn->raiseErrorFn;
3742 $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
3745 return false;
3750 * Random access to a specific row in the recordset. Some databases do not support
3751 * access to previous rows in the databases (no scrolling backwards).
3753 * @param rowNumber is the row to move to (0-based)
3755 * @return true if there still rows available, or false if there are no more rows (EOF).
3757 function Move($rowNumber = 0) {
3758 $this->EOF = false;
3759 if ($rowNumber == $this->_currentRow) {
3760 return true;
3762 if ($rowNumber >= $this->_numOfRows) {
3763 if ($this->_numOfRows != -1) {
3764 $rowNumber = $this->_numOfRows-2;
3768 if ($rowNumber < 0) {
3769 $this->EOF = true;
3770 return false;
3773 if ($this->canSeek) {
3774 if ($this->_seek($rowNumber)) {
3775 $this->_currentRow = $rowNumber;
3776 if ($this->_fetch()) {
3777 return true;
3779 } else {
3780 $this->EOF = true;
3781 return false;
3783 } else {
3784 if ($rowNumber < $this->_currentRow) {
3785 return false;
3787 global $ADODB_EXTENSION;
3788 if ($ADODB_EXTENSION) {
3789 while (!$this->EOF && $this->_currentRow < $rowNumber) {
3790 adodb_movenext($this);
3792 } else {
3793 while (! $this->EOF && $this->_currentRow < $rowNumber) {
3794 $this->_currentRow++;
3796 if (!$this->_fetch()) {
3797 $this->EOF = true;
3801 return !($this->EOF);
3804 $this->fields = false;
3805 $this->EOF = true;
3806 return false;
3811 * Get the value of a field in the current row by column name.
3812 * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
3814 * @param colname is the field to access
3816 * @return the value of $colname column
3818 function Fields($colname) {
3819 return $this->fields[$colname];
3823 * Defines the function to use for table fields case conversion
3824 * depending on ADODB_ASSOC_CASE
3825 * @return string strtolower/strtoupper or false if no conversion needed
3827 protected function AssocCaseConvertFunction($case = ADODB_ASSOC_CASE) {
3828 switch($case) {
3829 case ADODB_ASSOC_CASE_UPPER:
3830 return 'strtoupper';
3831 case ADODB_ASSOC_CASE_LOWER:
3832 return 'strtolower';
3833 case ADODB_ASSOC_CASE_NATIVE:
3834 default:
3835 return false;
3840 * Builds the bind array associating keys to recordset fields
3842 * @param int $upper Case for the array keys, defaults to uppercase
3843 * (see ADODB_ASSOC_CASE_xxx constants)
3845 function GetAssocKeys($upper = ADODB_ASSOC_CASE) {
3846 if ($this->bind) {
3847 return;
3849 $this->bind = array();
3851 // Define case conversion function for ASSOC fetch mode
3852 $fn_change_case = $this->AssocCaseConvertFunction($upper);
3854 // Build the bind array
3855 for ($i=0; $i < $this->_numOfFields; $i++) {
3856 $o = $this->FetchField($i);
3858 // Set the array's key
3859 if(is_numeric($o->name)) {
3860 // Just use the field ID
3861 $key = $i;
3863 elseif( $fn_change_case ) {
3864 // Convert the key's case
3865 $key = $fn_change_case($o->name);
3867 else {
3868 $key = $o->name;
3871 $this->bind[$key] = $i;
3876 * Use associative array to get fields array for databases that do not support
3877 * associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it
3879 * @param int $upper Case for the array keys, defaults to uppercase
3880 * (see ADODB_ASSOC_CASE_xxx constants)
3882 function GetRowAssoc($upper = ADODB_ASSOC_CASE) {
3883 $record = array();
3884 $this->GetAssocKeys($upper);
3886 foreach($this->bind as $k => $v) {
3887 if( array_key_exists( $v, $this->fields ) ) {
3888 $record[$k] = $this->fields[$v];
3889 } elseif( array_key_exists( $k, $this->fields ) ) {
3890 $record[$k] = $this->fields[$k];
3891 } else {
3892 # This should not happen... trigger error ?
3893 $record[$k] = null;
3896 return $record;
3900 * Clean up recordset
3902 * @return true or false
3904 function Close() {
3905 // free connection object - this seems to globally free the object
3906 // and not merely the reference, so don't do this...
3907 // $this->connection = false;
3908 if (!$this->_closed) {
3909 $this->_closed = true;
3910 return $this->_close();
3911 } else
3912 return true;
3916 * synonyms RecordCount and RowCount
3918 * @return the number of rows or -1 if this is not supported
3920 function RecordCount() {
3921 return $this->_numOfRows;
3926 * If we are using PageExecute(), this will return the maximum possible rows
3927 * that can be returned when paging a recordset.
3929 function MaxRecordCount() {
3930 return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();
3934 * synonyms RecordCount and RowCount
3936 * @return the number of rows or -1 if this is not supported
3938 function RowCount() {
3939 return $this->_numOfRows;
3944 * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
3946 * @return the number of records from a previous SELECT. All databases support this.
3948 * But aware possible problems in multiuser environments. For better speed the table
3949 * must be indexed by the condition. Heavy test this before deploying.
3951 function PO_RecordCount($table="", $condition="") {
3953 $lnumrows = $this->_numOfRows;
3954 // the database doesn't support native recordcount, so we do a workaround
3955 if ($lnumrows == -1 && $this->connection) {
3956 IF ($table) {
3957 if ($condition) {
3958 $condition = " WHERE " . $condition;
3960 $resultrows = $this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
3961 if ($resultrows) {
3962 $lnumrows = reset($resultrows->fields);
3966 return $lnumrows;
3971 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
3973 function CurrentRow() {
3974 return $this->_currentRow;
3978 * synonym for CurrentRow -- for ADO compat
3980 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
3982 function AbsolutePosition() {
3983 return $this->_currentRow;
3987 * @return the number of columns in the recordset. Some databases will set this to 0
3988 * if no records are returned, others will return the number of columns in the query.
3990 function FieldCount() {
3991 return $this->_numOfFields;
3996 * Get the ADOFieldObject of a specific column.
3998 * @param fieldoffset is the column position to access(0-based).
4000 * @return the ADOFieldObject for that column, or false.
4002 function FetchField($fieldoffset = -1) {
4003 // must be defined by child class
4005 return false;
4009 * Get the ADOFieldObjects of all columns in an array.
4012 function FieldTypesArray() {
4013 $arr = array();
4014 for ($i=0, $max=$this->_numOfFields; $i < $max; $i++)
4015 $arr[] = $this->FetchField($i);
4016 return $arr;
4020 * Return the fields array of the current row as an object for convenience.
4021 * The default case is lowercase field names.
4023 * @return the object with the properties set to the fields of the current row
4025 function FetchObj() {
4026 $o = $this->FetchObject(false);
4027 return $o;
4031 * Return the fields array of the current row as an object for convenience.
4032 * The default case is uppercase.
4034 * @param $isupper to set the object property names to uppercase
4036 * @return the object with the properties set to the fields of the current row
4038 function FetchObject($isupper=true) {
4039 if (empty($this->_obj)) {
4040 $this->_obj = new ADOFetchObj();
4041 $this->_names = array();
4042 for ($i=0; $i <$this->_numOfFields; $i++) {
4043 $f = $this->FetchField($i);
4044 $this->_names[] = $f->name;
4047 $i = 0;
4048 if (PHP_VERSION >= 5) {
4049 $o = clone($this->_obj);
4050 } else {
4051 $o = $this->_obj;
4054 for ($i=0; $i <$this->_numOfFields; $i++) {
4055 $name = $this->_names[$i];
4056 if ($isupper) {
4057 $n = strtoupper($name);
4058 } else {
4059 $n = $name;
4062 $o->$n = $this->Fields($name);
4064 return $o;
4068 * Return the fields array of the current row as an object for convenience.
4069 * The default is lower-case field names.
4071 * @return the object with the properties set to the fields of the current row,
4072 * or false if EOF
4074 * Fixed bug reported by tim@orotech.net
4076 function FetchNextObj() {
4077 $o = $this->FetchNextObject(false);
4078 return $o;
4083 * Return the fields array of the current row as an object for convenience.
4084 * The default is upper case field names.
4086 * @param $isupper to set the object property names to uppercase
4088 * @return the object with the properties set to the fields of the current row,
4089 * or false if EOF
4091 * Fixed bug reported by tim@orotech.net
4093 function FetchNextObject($isupper=true) {
4094 $o = false;
4095 if ($this->_numOfRows != 0 && !$this->EOF) {
4096 $o = $this->FetchObject($isupper);
4097 $this->_currentRow++;
4098 if ($this->_fetch()) {
4099 return $o;
4102 $this->EOF = true;
4103 return $o;
4107 * Get the metatype of the column. This is used for formatting. This is because
4108 * many databases use different names for the same type, so we transform the original
4109 * type to our standardised version which uses 1 character codes:
4111 * @param t is the type passed in. Normally is ADOFieldObject->type.
4112 * @param len is the maximum length of that field. This is because we treat character
4113 * fields bigger than a certain size as a 'B' (blob).
4114 * @param fieldobj is the field object returned by the database driver. Can hold
4115 * additional info (eg. primary_key for mysql).
4117 * @return the general type of the data:
4118 * C for character < 250 chars
4119 * X for teXt (>= 250 chars)
4120 * B for Binary
4121 * N for numeric or floating point
4122 * D for date
4123 * T for timestamp
4124 * L for logical/Boolean
4125 * I for integer
4126 * R for autoincrement counter/integer
4130 function MetaType($t,$len=-1,$fieldobj=false) {
4131 if (is_object($t)) {
4132 $fieldobj = $t;
4133 $t = $fieldobj->type;
4134 $len = $fieldobj->max_length;
4137 // changed in 2.32 to hashing instead of switch stmt for speed...
4138 static $typeMap = array(
4139 'VARCHAR' => 'C',
4140 'VARCHAR2' => 'C',
4141 'CHAR' => 'C',
4142 'C' => 'C',
4143 'STRING' => 'C',
4144 'NCHAR' => 'C',
4145 'NVARCHAR' => 'C',
4146 'VARYING' => 'C',
4147 'BPCHAR' => 'C',
4148 'CHARACTER' => 'C',
4149 'INTERVAL' => 'C', # Postgres
4150 'MACADDR' => 'C', # postgres
4151 'VAR_STRING' => 'C', # mysql
4153 'LONGCHAR' => 'X',
4154 'TEXT' => 'X',
4155 'NTEXT' => 'X',
4156 'M' => 'X',
4157 'X' => 'X',
4158 'CLOB' => 'X',
4159 'NCLOB' => 'X',
4160 'LVARCHAR' => 'X',
4162 'BLOB' => 'B',
4163 'IMAGE' => 'B',
4164 'BINARY' => 'B',
4165 'VARBINARY' => 'B',
4166 'LONGBINARY' => 'B',
4167 'B' => 'B',
4169 'YEAR' => 'D', // mysql
4170 'DATE' => 'D',
4171 'D' => 'D',
4173 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server
4175 'SMALLDATETIME' => 'T',
4176 'TIME' => 'T',
4177 'TIMESTAMP' => 'T',
4178 'DATETIME' => 'T',
4179 'DATETIME2' => 'T',
4180 'TIMESTAMPTZ' => 'T',
4181 'T' => 'T',
4182 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
4184 'BOOL' => 'L',
4185 'BOOLEAN' => 'L',
4186 'BIT' => 'L',
4187 'L' => 'L',
4189 'COUNTER' => 'R',
4190 'R' => 'R',
4191 'SERIAL' => 'R', // ifx
4192 'INT IDENTITY' => 'R',
4194 'INT' => 'I',
4195 'INT2' => 'I',
4196 'INT4' => 'I',
4197 'INT8' => 'I',
4198 'INTEGER' => 'I',
4199 'INTEGER UNSIGNED' => 'I',
4200 'SHORT' => 'I',
4201 'TINYINT' => 'I',
4202 'SMALLINT' => 'I',
4203 'I' => 'I',
4205 'LONG' => 'N', // interbase is numeric, oci8 is blob
4206 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
4207 'DECIMAL' => 'N',
4208 'DEC' => 'N',
4209 'REAL' => 'N',
4210 'DOUBLE' => 'N',
4211 'DOUBLE PRECISION' => 'N',
4212 'SMALLFLOAT' => 'N',
4213 'FLOAT' => 'N',
4214 'NUMBER' => 'N',
4215 'NUM' => 'N',
4216 'NUMERIC' => 'N',
4217 'MONEY' => 'N',
4219 ## informix 9.2
4220 'SQLINT' => 'I',
4221 'SQLSERIAL' => 'I',
4222 'SQLSMINT' => 'I',
4223 'SQLSMFLOAT' => 'N',
4224 'SQLFLOAT' => 'N',
4225 'SQLMONEY' => 'N',
4226 'SQLDECIMAL' => 'N',
4227 'SQLDATE' => 'D',
4228 'SQLVCHAR' => 'C',
4229 'SQLCHAR' => 'C',
4230 'SQLDTIME' => 'T',
4231 'SQLINTERVAL' => 'N',
4232 'SQLBYTES' => 'B',
4233 'SQLTEXT' => 'X',
4234 ## informix 10
4235 "SQLINT8" => 'I8',
4236 "SQLSERIAL8" => 'I8',
4237 "SQLNCHAR" => 'C',
4238 "SQLNVCHAR" => 'C',
4239 "SQLLVARCHAR" => 'X',
4240 "SQLBOOL" => 'L'
4243 $tmap = false;
4244 $t = strtoupper($t);
4245 $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N';
4246 switch ($tmap) {
4247 case 'C':
4248 // is the char field is too long, return as text field...
4249 if ($this->blobSize >= 0) {
4250 if ($len > $this->blobSize) {
4251 return 'X';
4253 } else if ($len > 250) {
4254 return 'X';
4256 return 'C';
4258 case 'I':
4259 if (!empty($fieldobj->primary_key)) {
4260 return 'R';
4262 return 'I';
4264 case false:
4265 return 'N';
4267 case 'B':
4268 if (isset($fieldobj->binary)) {
4269 return ($fieldobj->binary) ? 'B' : 'X';
4271 return 'B';
4273 case 'D':
4274 if (!empty($this->connection) && !empty($this->connection->datetime)) {
4275 return 'T';
4277 return 'D';
4279 default:
4280 if ($t == 'LONG' && $this->dataProvider == 'oci8') {
4281 return 'B';
4283 return $tmap;
4288 * Convert case of field names associative array, if needed
4289 * @return void
4291 protected function _updatefields()
4293 if( empty($this->fields)) {
4294 return;
4297 // Determine case conversion function
4298 $fn_change_case = $this->AssocCaseConvertFunction();
4299 if(!$fn_change_case) {
4300 // No conversion needed
4301 return;
4304 $arr = array();
4306 // Change the case
4307 foreach($this->fields as $k => $v) {
4308 if (!is_integer($k)) {
4309 $k = $fn_change_case($k);
4311 $arr[$k] = $v;
4313 $this->fields = $arr;
4316 function _close() {}
4319 * set/returns the current recordset page when paginating
4321 function AbsolutePage($page=-1) {
4322 if ($page != -1) {
4323 $this->_currentPage = $page;
4325 return $this->_currentPage;
4329 * set/returns the status of the atFirstPage flag when paginating
4331 function AtFirstPage($status=false) {
4332 if ($status != false) {
4333 $this->_atFirstPage = $status;
4335 return $this->_atFirstPage;
4338 function LastPageNo($page = false) {
4339 if ($page != false) {
4340 $this->_lastPageNo = $page;
4342 return $this->_lastPageNo;
4346 * set/returns the status of the atLastPage flag when paginating
4348 function AtLastPage($status=false) {
4349 if ($status != false) {
4350 $this->_atLastPage = $status;
4352 return $this->_atLastPage;
4355 } // end class ADORecordSet
4357 //==============================================================================================
4358 // CLASS ADORecordSet_array
4359 //==============================================================================================
4362 * This class encapsulates the concept of a recordset created in memory
4363 * as an array. This is useful for the creation of cached recordsets.
4365 * Note that the constructor is different from the standard ADORecordSet
4367 class ADORecordSet_array extends ADORecordSet
4369 var $databaseType = 'array';
4371 var $_array; // holds the 2-dimensional data array
4372 var $_types; // the array of types of each column (C B I L M)
4373 var $_colnames; // names of each column in array
4374 var $_skiprow1; // skip 1st row because it holds column names
4375 var $_fieldobjects; // holds array of field objects
4376 var $canSeek = true;
4377 var $affectedrows = false;
4378 var $insertid = false;
4379 var $sql = '';
4380 var $compat = false;
4383 * Constructor
4385 function __construct($fakeid=1) {
4386 global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;
4388 // fetch() on EOF does not delete $this->fields
4389 $this->compat = !empty($ADODB_COMPAT_FETCH);
4390 parent::__construct($fakeid); // fake queryID
4391 $this->fetchMode = $ADODB_FETCH_MODE;
4394 function _transpose($addfieldnames=true) {
4395 global $ADODB_INCLUDED_LIB;
4397 if (empty($ADODB_INCLUDED_LIB)) {
4398 include(ADODB_DIR.'/adodb-lib.inc.php');
4400 $hdr = true;
4402 $fobjs = $addfieldnames ? $this->_fieldobjects : false;
4403 adodb_transpose($this->_array, $newarr, $hdr, $fobjs);
4404 //adodb_pr($newarr);
4406 $this->_skiprow1 = false;
4407 $this->_array = $newarr;
4408 $this->_colnames = $hdr;
4410 adodb_probetypes($newarr,$this->_types);
4412 $this->_fieldobjects = array();
4414 foreach($hdr as $k => $name) {
4415 $f = new ADOFieldObject();
4416 $f->name = $name;
4417 $f->type = $this->_types[$k];
4418 $f->max_length = -1;
4419 $this->_fieldobjects[] = $f;
4421 $this->fields = reset($this->_array);
4423 $this->_initrs();
4428 * Setup the array.
4430 * @param array is a 2-dimensional array holding the data.
4431 * The first row should hold the column names
4432 * unless paramter $colnames is used.
4433 * @param typearr holds an array of types. These are the same types
4434 * used in MetaTypes (C,B,L,I,N).
4435 * @param [colnames] array of column names. If set, then the first row of
4436 * $array should not hold the column names.
4438 function InitArray($array,$typearr,$colnames=false) {
4439 $this->_array = $array;
4440 $this->_types = $typearr;
4441 if ($colnames) {
4442 $this->_skiprow1 = false;
4443 $this->_colnames = $colnames;
4444 } else {
4445 $this->_skiprow1 = true;
4446 $this->_colnames = $array[0];
4448 $this->Init();
4451 * Setup the Array and datatype file objects
4453 * @param array is a 2-dimensional array holding the data.
4454 * The first row should hold the column names
4455 * unless paramter $colnames is used.
4456 * @param fieldarr holds an array of ADOFieldObject's.
4458 function InitArrayFields(&$array,&$fieldarr) {
4459 $this->_array = $array;
4460 $this->_skiprow1= false;
4461 if ($fieldarr) {
4462 $this->_fieldobjects = $fieldarr;
4464 $this->Init();
4467 function GetArray($nRows=-1) {
4468 if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) {
4469 return $this->_array;
4470 } else {
4471 $arr = ADORecordSet::GetArray($nRows);
4472 return $arr;
4476 function _initrs() {
4477 $this->_numOfRows = sizeof($this->_array);
4478 if ($this->_skiprow1) {
4479 $this->_numOfRows -= 1;
4482 $this->_numOfFields = (isset($this->_fieldobjects))
4483 ? sizeof($this->_fieldobjects)
4484 : sizeof($this->_types);
4487 /* Use associative array to get fields array */
4488 function Fields($colname) {
4489 $mode = isset($this->adodbFetchMode) ? $this->adodbFetchMode : $this->fetchMode;
4491 if ($mode & ADODB_FETCH_ASSOC) {
4492 if (!isset($this->fields[$colname]) && !is_null($this->fields[$colname])) {
4493 $colname = strtolower($colname);
4495 return $this->fields[$colname];
4497 if (!$this->bind) {
4498 $this->bind = array();
4499 for ($i=0; $i < $this->_numOfFields; $i++) {
4500 $o = $this->FetchField($i);
4501 $this->bind[strtoupper($o->name)] = $i;
4504 return $this->fields[$this->bind[strtoupper($colname)]];
4507 function FetchField($fieldOffset = -1) {
4508 if (isset($this->_fieldobjects)) {
4509 return $this->_fieldobjects[$fieldOffset];
4511 $o = new ADOFieldObject();
4512 $o->name = $this->_colnames[$fieldOffset];
4513 $o->type = $this->_types[$fieldOffset];
4514 $o->max_length = -1; // length not known
4516 return $o;
4519 function _seek($row) {
4520 if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) {
4521 $this->_currentRow = $row;
4522 if ($this->_skiprow1) {
4523 $row += 1;
4525 $this->fields = $this->_array[$row];
4526 return true;
4528 return false;
4531 function MoveNext() {
4532 if (!$this->EOF) {
4533 $this->_currentRow++;
4535 $pos = $this->_currentRow;
4537 if ($this->_numOfRows <= $pos) {
4538 if (!$this->compat) {
4539 $this->fields = false;
4541 } else {
4542 if ($this->_skiprow1) {
4543 $pos += 1;
4545 $this->fields = $this->_array[$pos];
4546 return true;
4548 $this->EOF = true;
4551 return false;
4554 function _fetch() {
4555 $pos = $this->_currentRow;
4557 if ($this->_numOfRows <= $pos) {
4558 if (!$this->compat) {
4559 $this->fields = false;
4561 return false;
4563 if ($this->_skiprow1) {
4564 $pos += 1;
4566 $this->fields = $this->_array[$pos];
4567 return true;
4570 function _close() {
4571 return true;
4574 } // ADORecordSet_array
4576 //==============================================================================================
4577 // HELPER FUNCTIONS
4578 //==============================================================================================
4581 * Synonym for ADOLoadCode. Private function. Do not use.
4583 * @deprecated
4585 function ADOLoadDB($dbType) {
4586 return ADOLoadCode($dbType);
4590 * Load the code for a specific database driver. Private function. Do not use.
4592 function ADOLoadCode($dbType) {
4593 global $ADODB_LASTDB;
4595 if (!$dbType) {
4596 return false;
4598 $db = strtolower($dbType);
4599 switch ($db) {
4600 case 'ado':
4601 if (PHP_VERSION >= 5) {
4602 $db = 'ado5';
4604 $class = 'ado';
4605 break;
4607 case 'ifx':
4608 case 'maxsql':
4609 $class = $db = 'mysqlt';
4610 break;
4612 case 'pgsql':
4613 case 'postgres':
4614 $class = $db = 'postgres8';
4615 break;
4617 default:
4618 $class = $db; break;
4621 $file = ADODB_DIR."/drivers/adodb-".$db.".inc.php";
4622 @include_once($file);
4623 $ADODB_LASTDB = $class;
4624 if (class_exists("ADODB_" . $class)) {
4625 return $class;
4628 //ADOConnection::outp(adodb_pr(get_declared_classes(),true));
4629 if (!file_exists($file)) {
4630 ADOConnection::outp("Missing file: $file");
4631 } else {
4632 ADOConnection::outp("Syntax error in file: $file");
4634 return false;
4638 * synonym for ADONewConnection for people like me who cannot remember the correct name
4640 function NewADOConnection($db='') {
4641 $tmp = ADONewConnection($db);
4642 return $tmp;
4646 * Instantiate a new Connection class for a specific database driver.
4648 * @param [db] is the database Connection object to create. If undefined,
4649 * use the last database driver that was loaded by ADOLoadCode().
4651 * @return the freshly created instance of the Connection class.
4653 function ADONewConnection($db='') {
4654 global $ADODB_NEWCONNECTION, $ADODB_LASTDB;
4656 if (!defined('ADODB_ASSOC_CASE')) {
4657 define('ADODB_ASSOC_CASE', ADODB_ASSOC_CASE_NATIVE);
4659 $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false;
4660 if (($at = strpos($db,'://')) !== FALSE) {
4661 $origdsn = $db;
4662 $fakedsn = 'fake'.substr($origdsn,$at);
4663 if (($at2 = strpos($origdsn,'@/')) !== FALSE) {
4664 // special handling of oracle, which might not have host
4665 $fakedsn = str_replace('@/','@adodb-fakehost/',$fakedsn);
4668 if ((strpos($origdsn, 'sqlite')) !== FALSE && stripos($origdsn, '%2F') === FALSE) {
4669 // special handling for SQLite, it only might have the path to the database file.
4670 // If you try to connect to a SQLite database using a dsn
4671 // like 'sqlite:///path/to/database', the 'parse_url' php function
4672 // will throw you an exception with a message such as "unable to parse url"
4673 list($scheme, $path) = explode('://', $origdsn);
4674 $dsna['scheme'] = $scheme;
4675 if ($qmark = strpos($path,'?')) {
4676 $dsn['query'] = substr($path,$qmark+1);
4677 $path = substr($path,0,$qmark);
4679 $dsna['path'] = '/' . urlencode($path);
4680 } else
4681 $dsna = @parse_url($fakedsn);
4683 if (!$dsna) {
4684 return false;
4686 $dsna['scheme'] = substr($origdsn,0,$at);
4687 if ($at2 !== FALSE) {
4688 $dsna['host'] = '';
4691 if (strncmp($origdsn,'pdo',3) == 0) {
4692 $sch = explode('_',$dsna['scheme']);
4693 if (sizeof($sch)>1) {
4694 $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : '';
4695 if ($sch[1] == 'sqlite') {
4696 $dsna['host'] = rawurlencode($sch[1].':'.rawurldecode($dsna['host']));
4697 } else {
4698 $dsna['host'] = rawurlencode($sch[1].':host='.rawurldecode($dsna['host']));
4700 $dsna['scheme'] = 'pdo';
4704 $db = @$dsna['scheme'];
4705 if (!$db) {
4706 return false;
4708 $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : '';
4709 $dsna['user'] = isset($dsna['user']) ? rawurldecode($dsna['user']) : '';
4710 $dsna['pass'] = isset($dsna['pass']) ? rawurldecode($dsna['pass']) : '';
4711 $dsna['path'] = isset($dsna['path']) ? rawurldecode(substr($dsna['path'],1)) : ''; # strip off initial /
4713 if (isset($dsna['query'])) {
4714 $opt1 = explode('&',$dsna['query']);
4715 foreach($opt1 as $k => $v) {
4716 $arr = explode('=',$v);
4717 $opt[$arr[0]] = isset($arr[1]) ? rawurldecode($arr[1]) : 1;
4719 } else {
4720 $opt = array();
4724 * phptype: Database backend used in PHP (mysql, odbc etc.)
4725 * dbsyntax: Database used with regards to SQL syntax etc.
4726 * protocol: Communication protocol to use (tcp, unix etc.)
4727 * hostspec: Host specification (hostname[:port])
4728 * database: Database to use on the DBMS server
4729 * username: User name for login
4730 * password: Password for login
4732 if (!empty($ADODB_NEWCONNECTION)) {
4733 $obj = $ADODB_NEWCONNECTION($db);
4737 if(empty($obj)) {
4739 if (!isset($ADODB_LASTDB)) {
4740 $ADODB_LASTDB = '';
4742 if (empty($db)) {
4743 $db = $ADODB_LASTDB;
4745 if ($db != $ADODB_LASTDB) {
4746 $db = ADOLoadCode($db);
4749 if (!$db) {
4750 if (isset($origdsn)) {
4751 $db = $origdsn;
4753 if ($errorfn) {
4754 // raise an error
4755 $ignore = false;
4756 $errorfn('ADONewConnection', 'ADONewConnection', -998,
4757 "could not load the database driver for '$db'",
4758 $db,false,$ignore);
4759 } else {
4760 ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false);
4762 return false;
4765 $cls = 'ADODB_'.$db;
4766 if (!class_exists($cls)) {
4767 adodb_backtrace();
4768 return false;
4771 $obj = new $cls();
4774 # constructor should not fail
4775 if ($obj) {
4776 if ($errorfn) {
4777 $obj->raiseErrorFn = $errorfn;
4779 if (isset($dsna)) {
4780 if (isset($dsna['port'])) {
4781 $obj->port = $dsna['port'];
4783 foreach($opt as $k => $v) {
4784 switch(strtolower($k)) {
4785 case 'new':
4786 $nconnect = true; $persist = true; break;
4787 case 'persist':
4788 case 'persistent': $persist = $v; break;
4789 case 'debug': $obj->debug = (integer) $v; break;
4790 #ibase
4791 case 'role': $obj->role = $v; break;
4792 case 'dialect': $obj->dialect = (integer) $v; break;
4793 case 'charset': $obj->charset = $v; $obj->charSet=$v; break;
4794 case 'buffers': $obj->buffers = $v; break;
4795 case 'fetchmode': $obj->SetFetchMode($v); break;
4796 #ado
4797 case 'charpage': $obj->charPage = $v; break;
4798 #mysql, mysqli
4799 case 'clientflags': $obj->clientFlags = $v; break;
4800 #mysql, mysqli, postgres
4801 case 'port': $obj->port = $v; break;
4802 #mysqli
4803 case 'socket': $obj->socket = $v; break;
4804 #oci8
4805 case 'nls_date_format': $obj->NLS_DATE_FORMAT = $v; break;
4806 case 'cachesecs': $obj->cacheSecs = $v; break;
4807 case 'memcache':
4808 $varr = explode(':',$v);
4809 $vlen = sizeof($varr);
4810 if ($vlen == 0) {
4811 break;
4813 $obj->memCache = true;
4814 $obj->memCacheHost = explode(',',$varr[0]);
4815 if ($vlen == 1) {
4816 break;
4818 $obj->memCachePort = $varr[1];
4819 if ($vlen == 2) {
4820 break;
4822 $obj->memCacheCompress = $varr[2] ? true : false;
4823 break;
4826 if (empty($persist)) {
4827 $ok = $obj->Connect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4828 } else if (empty($nconnect)) {
4829 $ok = $obj->PConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4830 } else {
4831 $ok = $obj->NConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4834 if (!$ok) {
4835 return false;
4839 return $obj;
4844 // $perf == true means called by NewPerfMonitor(), otherwise for data dictionary
4845 function _adodb_getdriver($provider,$drivername,$perf=false) {
4846 switch ($provider) {
4847 case 'odbtp':
4848 if (strncmp('odbtp_',$drivername,6)==0) {
4849 return substr($drivername,6);
4851 case 'odbc' :
4852 if (strncmp('odbc_',$drivername,5)==0) {
4853 return substr($drivername,5);
4855 case 'ado' :
4856 if (strncmp('ado_',$drivername,4)==0) {
4857 return substr($drivername,4);
4859 case 'native':
4860 break;
4861 default:
4862 return $provider;
4865 switch($drivername) {
4866 case 'mysqlt':
4867 case 'mysqli':
4868 $drivername='mysql';
4869 break;
4870 case 'postgres7':
4871 case 'postgres8':
4872 $drivername = 'postgres';
4873 break;
4874 case 'firebird15':
4875 $drivername = 'firebird';
4876 break;
4877 case 'oracle':
4878 $drivername = 'oci8';
4879 break;
4880 case 'access':
4881 if ($perf) {
4882 $drivername = '';
4884 break;
4885 case 'db2' :
4886 case 'sapdb' :
4887 break;
4888 default:
4889 $drivername = 'generic';
4890 break;
4892 return $drivername;
4895 function NewPerfMonitor(&$conn) {
4896 $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType,true);
4897 if (!$drivername || $drivername == 'generic') {
4898 return false;
4900 include_once(ADODB_DIR.'/adodb-perf.inc.php');
4901 @include_once(ADODB_DIR."/perf/perf-$drivername.inc.php");
4902 $class = "Perf_$drivername";
4903 if (!class_exists($class)) {
4904 return false;
4906 $perf = new $class($conn);
4908 return $perf;
4911 function NewDataDictionary(&$conn,$drivername=false) {
4912 if (!$drivername) {
4913 $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType);
4916 include_once(ADODB_DIR.'/adodb-lib.inc.php');
4917 include_once(ADODB_DIR.'/adodb-datadict.inc.php');
4918 $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php";
4920 if (!file_exists($path)) {
4921 ADOConnection::outp("Dictionary driver '$path' not available");
4922 return false;
4924 include_once($path);
4925 $class = "ADODB2_$drivername";
4926 $dict = new $class();
4927 $dict->dataProvider = $conn->dataProvider;
4928 $dict->connection = $conn;
4929 $dict->upperName = strtoupper($drivername);
4930 $dict->quote = $conn->nameQuote;
4931 if (!empty($conn->_connectionID)) {
4932 $dict->serverInfo = $conn->ServerInfo();
4935 return $dict;
4941 Perform a print_r, with pre tags for better formatting.
4943 function adodb_pr($var,$as_string=false) {
4944 if ($as_string) {
4945 ob_start();
4948 if (isset($_SERVER['HTTP_USER_AGENT'])) {
4949 echo " <pre>\n";print_r($var);echo "</pre>\n";
4950 } else {
4951 print_r($var);
4954 if ($as_string) {
4955 $s = ob_get_contents();
4956 ob_end_clean();
4957 return $s;
4962 Perform a stack-crawl and pretty print it.
4964 @param printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then).
4965 @param levels Number of levels to display
4967 function adodb_backtrace($printOrArr=true,$levels=9999,$ishtml=null) {
4968 global $ADODB_INCLUDED_LIB;
4969 if (empty($ADODB_INCLUDED_LIB)) {
4970 include(ADODB_DIR.'/adodb-lib.inc.php');
4972 return _adodb_backtrace($printOrArr,$levels,0,$ishtml);