Merge branch 'MDL-60115-Book-cancel-button-redirect-bug-33' of https://github.com...
[moodle.git] / lib / adodb / adodb.inc.php
blob4967f6ae67a50878187ddee018954dd4790f9e06
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.7 20-Sep-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.7 20-Sep-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 //Use each() instead of foreach to reduce memory usage -mikefedyk
1168 while(list(, $v) = each($arr)) {
1169 $sql .= $sqlarr[$i];
1170 // from Ron Baldwin <ron.baldwin#sourceprose.com>
1171 // Only quote string types
1172 $typ = gettype($v);
1173 if ($typ == 'string') {
1174 //New memory copy of input created here -mikefedyk
1175 $sql .= $this->qstr($v);
1176 } else if ($typ == 'double') {
1177 $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1
1178 } else if ($typ == 'boolean') {
1179 $sql .= $v ? $this->true : $this->false;
1180 } else if ($typ == 'object') {
1181 if (method_exists($v, '__toString')) {
1182 $sql .= $this->qstr($v->__toString());
1183 } else {
1184 $sql .= $this->qstr((string) $v);
1186 } else if ($v === null) {
1187 $sql .= 'NULL';
1188 } else {
1189 $sql .= $v;
1191 $i += 1;
1193 if ($i == $nparams) {
1194 break;
1196 } // while
1197 if (isset($sqlarr[$i])) {
1198 $sql .= $sqlarr[$i];
1199 if ($i+1 != sizeof($sqlarr)) {
1200 $this->outp_throw( "Input Array does not match ?: ".htmlspecialchars($sql),'Execute');
1202 } else if ($i != sizeof($sqlarr)) {
1203 $this->outp_throw( "Input array does not match ?: ".htmlspecialchars($sql),'Execute');
1206 $ret = $this->_Execute($sql);
1207 if (!$ret) {
1208 return $ret;
1211 } else {
1212 if ($array_2d) {
1213 if (is_string($sql)) {
1214 $stmt = $this->Prepare($sql);
1215 } else {
1216 $stmt = $sql;
1219 foreach($inputarr as $arr) {
1220 $ret = $this->_Execute($stmt,$arr);
1221 if (!$ret) {
1222 return $ret;
1225 } else {
1226 $ret = $this->_Execute($sql,$inputarr);
1229 } else {
1230 $ret = $this->_Execute($sql,false);
1233 return $ret;
1236 function _Execute($sql,$inputarr=false) {
1237 // ExecuteCursor() may send non-string queries (such as arrays),
1238 // so we need to ignore those.
1239 if( is_string($sql) ) {
1240 // Strips keyword used to help generate SELECT COUNT(*) queries
1241 // from SQL if it exists.
1242 $sql = ADODB_str_replace( '_ADODB_COUNT', '', $sql );
1245 if ($this->debug) {
1246 global $ADODB_INCLUDED_LIB;
1247 if (empty($ADODB_INCLUDED_LIB)) {
1248 include(ADODB_DIR.'/adodb-lib.inc.php');
1250 $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr);
1251 } else {
1252 $this->_queryID = @$this->_query($sql,$inputarr);
1255 // ************************
1256 // OK, query executed
1257 // ************************
1259 // error handling if query fails
1260 if ($this->_queryID === false) {
1261 if ($this->debug == 99) {
1262 adodb_backtrace(true,5);
1264 $fn = $this->raiseErrorFn;
1265 if ($fn) {
1266 $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
1268 return false;
1271 // return simplified recordset for inserts/updates/deletes with lower overhead
1272 if ($this->_queryID === true) {
1273 $rsclass = $this->rsPrefix.'empty';
1274 $rs = (class_exists($rsclass)) ? new $rsclass(): new ADORecordSet_empty();
1276 return $rs;
1279 // return real recordset from select statement
1280 $rsclass = $this->rsPrefix.$this->databaseType;
1281 $rs = new $rsclass($this->_queryID,$this->fetchMode);
1282 $rs->connection = $this; // Pablo suggestion
1283 $rs->Init();
1284 if (is_array($sql)) {
1285 $rs->sql = $sql[0];
1286 } else {
1287 $rs->sql = $sql;
1289 if ($rs->_numOfRows <= 0) {
1290 global $ADODB_COUNTRECS;
1291 if ($ADODB_COUNTRECS) {
1292 if (!$rs->EOF) {
1293 $rs = $this->_rs2rs($rs,-1,-1,!is_array($sql));
1294 $rs->_queryID = $this->_queryID;
1295 } else
1296 $rs->_numOfRows = 0;
1299 return $rs;
1302 function CreateSequence($seqname='adodbseq',$startID=1) {
1303 if (empty($this->_genSeqSQL)) {
1304 return false;
1306 return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
1309 function DropSequence($seqname='adodbseq') {
1310 if (empty($this->_dropSeqSQL)) {
1311 return false;
1313 return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
1317 * Generates a sequence id and stores it in $this->genID;
1318 * GenID is only available if $this->hasGenID = true;
1320 * @param seqname name of sequence to use
1321 * @param startID if sequence does not exist, start at this ID
1322 * @return 0 if not supported, otherwise a sequence id
1324 function GenID($seqname='adodbseq',$startID=1) {
1325 if (!$this->hasGenID) {
1326 return 0; // formerly returns false pre 1.60
1329 $getnext = sprintf($this->_genIDSQL,$seqname);
1331 $holdtransOK = $this->_transOK;
1333 $save_handler = $this->raiseErrorFn;
1334 $this->raiseErrorFn = '';
1335 @($rs = $this->Execute($getnext));
1336 $this->raiseErrorFn = $save_handler;
1338 if (!$rs) {
1339 $this->_transOK = $holdtransOK; //if the status was ok before reset
1340 $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
1341 $rs = $this->Execute($getnext);
1343 if ($rs && !$rs->EOF) {
1344 $this->genID = reset($rs->fields);
1345 } else {
1346 $this->genID = 0; // false
1349 if ($rs) {
1350 $rs->Close();
1353 return $this->genID;
1357 * @param $table string name of the table, not needed by all databases (eg. mysql), default ''
1358 * @param $column string name of the column, not needed by all databases (eg. mysql), default ''
1359 * @return the last inserted ID. Not all databases support this.
1361 function Insert_ID($table='',$column='') {
1362 if ($this->_logsql && $this->lastInsID) {
1363 return $this->lastInsID;
1365 if ($this->hasInsertID) {
1366 return $this->_insertid($table,$column);
1368 if ($this->debug) {
1369 ADOConnection::outp( '<p>Insert_ID error</p>');
1370 adodb_backtrace();
1372 return false;
1377 * Portable Insert ID. Pablo Roca <pabloroca#mvps.org>
1379 * @return the last inserted ID. All databases support this. But aware possible
1380 * problems in multiuser environments. Heavy test this before deploying.
1382 function PO_Insert_ID($table="", $id="") {
1383 if ($this->hasInsertID){
1384 return $this->Insert_ID($table,$id);
1385 } else {
1386 return $this->GetOne("SELECT MAX($id) FROM $table");
1391 * @return # rows affected by UPDATE/DELETE
1393 function Affected_Rows() {
1394 if ($this->hasAffectedRows) {
1395 if ($this->fnExecute === 'adodb_log_sql') {
1396 if ($this->_logsql && $this->_affected !== false) {
1397 return $this->_affected;
1400 $val = $this->_affectedrows();
1401 return ($val < 0) ? false : $val;
1404 if ($this->debug) {
1405 ADOConnection::outp( '<p>Affected_Rows error</p>',false);
1407 return false;
1412 * @return the last error message
1414 function ErrorMsg() {
1415 if ($this->_errorMsg) {
1416 return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
1417 } else {
1418 return '';
1424 * @return the last error number. Normally 0 means no error.
1426 function ErrorNo() {
1427 return ($this->_errorMsg) ? -1 : 0;
1430 function MetaError($err=false) {
1431 include_once(ADODB_DIR."/adodb-error.inc.php");
1432 if ($err === false) {
1433 $err = $this->ErrorNo();
1435 return adodb_error($this->dataProvider,$this->databaseType,$err);
1438 function MetaErrorMsg($errno) {
1439 include_once(ADODB_DIR."/adodb-error.inc.php");
1440 return adodb_errormsg($errno);
1444 * @returns an array with the primary key columns in it.
1446 function MetaPrimaryKeys($table, $owner=false) {
1447 // owner not used in base class - see oci8
1448 $p = array();
1449 $objs = $this->MetaColumns($table);
1450 if ($objs) {
1451 foreach($objs as $v) {
1452 if (!empty($v->primary_key)) {
1453 $p[] = $v->name;
1457 if (sizeof($p)) {
1458 return $p;
1460 if (function_exists('ADODB_VIEW_PRIMARYKEYS')) {
1461 return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);
1463 return false;
1467 * @returns assoc array where keys are tables, and values are foreign keys
1469 function MetaForeignKeys($table, $owner=false, $upper=false) {
1470 return false;
1473 * Choose a database to connect to. Many databases do not support this.
1475 * @param dbName is the name of the database to select
1476 * @return true or false
1478 function SelectDB($dbName) {return false;}
1482 * Will select, getting rows from $offset (1-based), for $nrows.
1483 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1484 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1485 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1486 * eg.
1487 * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
1488 * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
1490 * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
1491 * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
1493 * @param sql
1494 * @param [offset] is the row to start calculations from (1-based)
1495 * @param [nrows] is the number of rows to get
1496 * @param [inputarr] array of bind variables
1497 * @param [secs2cache] is a private parameter only used by jlim
1498 * @return the recordset ($rs->databaseType == 'array')
1500 function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) {
1501 if ($this->hasTop && $nrows > 0) {
1502 // suggested by Reinhard Balling. Access requires top after distinct
1503 // Informix requires first before distinct - F Riosa
1504 $ismssql = (strpos($this->databaseType,'mssql') !== false);
1505 if ($ismssql) {
1506 $isaccess = false;
1507 } else {
1508 $isaccess = (strpos($this->databaseType,'access') !== false);
1511 if ($offset <= 0) {
1512 // access includes ties in result
1513 if ($isaccess) {
1514 $sql = preg_replace(
1515 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1517 if ($secs2cache != 0) {
1518 $ret = $this->CacheExecute($secs2cache, $sql,$inputarr);
1519 } else {
1520 $ret = $this->Execute($sql,$inputarr);
1522 return $ret; // PHP5 fix
1523 } else if ($ismssql){
1524 $sql = preg_replace(
1525 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1526 } else {
1527 $sql = preg_replace(
1528 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1530 } else {
1531 $nn = $nrows + $offset;
1532 if ($isaccess || $ismssql) {
1533 $sql = preg_replace(
1534 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1535 } else {
1536 $sql = preg_replace(
1537 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1542 // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows
1543 // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.
1544 global $ADODB_COUNTRECS;
1546 $savec = $ADODB_COUNTRECS;
1547 $ADODB_COUNTRECS = false;
1550 if ($secs2cache != 0) {
1551 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1552 } else {
1553 $rs = $this->Execute($sql,$inputarr);
1556 $ADODB_COUNTRECS = $savec;
1557 if ($rs && !$rs->EOF) {
1558 $rs = $this->_rs2rs($rs,$nrows,$offset);
1560 //print_r($rs);
1561 return $rs;
1565 * Create serializable recordset. Breaks rs link to connection.
1567 * @param rs the recordset to serialize
1569 function SerializableRS(&$rs) {
1570 $rs2 = $this->_rs2rs($rs);
1571 $ignore = false;
1572 $rs2->connection = $ignore;
1574 return $rs2;
1578 * Convert database recordset to an array recordset
1579 * input recordset's cursor should be at beginning, and
1580 * old $rs will be closed.
1582 * @param rs the recordset to copy
1583 * @param [nrows] number of rows to retrieve (optional)
1584 * @param [offset] offset by number of rows (optional)
1585 * @return the new recordset
1587 function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true) {
1588 if (! $rs) {
1589 return false;
1591 $dbtype = $rs->databaseType;
1592 if (!$dbtype) {
1593 $rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?
1594 return $rs;
1596 if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {
1597 $rs->MoveFirst();
1598 $rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?
1599 return $rs;
1601 $flds = array();
1602 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
1603 $flds[] = $rs->FetchField($i);
1606 $arr = $rs->GetArrayLimit($nrows,$offset);
1607 //print_r($arr);
1608 if ($close) {
1609 $rs->Close();
1612 $arrayClass = $this->arrayClass;
1614 $rs2 = new $arrayClass();
1615 $rs2->connection = $this;
1616 $rs2->sql = $rs->sql;
1617 $rs2->dataProvider = $this->dataProvider;
1618 $rs2->InitArrayFields($arr,$flds);
1619 $rs2->fetchMode = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
1620 return $rs2;
1624 * Return all rows. Compat with PEAR DB
1626 function GetAll($sql, $inputarr=false) {
1627 $arr = $this->GetArray($sql,$inputarr);
1628 return $arr;
1631 function GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false) {
1632 $rs = $this->Execute($sql, $inputarr);
1633 if (!$rs) {
1634 return false;
1636 $arr = $rs->GetAssoc($force_array,$first2cols);
1637 return $arr;
1640 function CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false) {
1641 if (!is_numeric($secs2cache)) {
1642 $first2cols = $force_array;
1643 $force_array = $inputarr;
1645 $rs = $this->CacheExecute($secs2cache, $sql, $inputarr);
1646 if (!$rs) {
1647 return false;
1649 $arr = $rs->GetAssoc($force_array,$first2cols);
1650 return $arr;
1654 * Return first element of first row of sql statement. Recordset is disposed
1655 * for you.
1657 * @param sql SQL statement
1658 * @param [inputarr] input bind array
1660 function GetOne($sql,$inputarr=false) {
1661 global $ADODB_COUNTRECS,$ADODB_GETONE_EOF;
1663 $crecs = $ADODB_COUNTRECS;
1664 $ADODB_COUNTRECS = false;
1666 $ret = false;
1667 $rs = $this->Execute($sql,$inputarr);
1668 if ($rs) {
1669 if ($rs->EOF) {
1670 $ret = $ADODB_GETONE_EOF;
1671 } else {
1672 $ret = reset($rs->fields);
1675 $rs->Close();
1677 $ADODB_COUNTRECS = $crecs;
1678 return $ret;
1681 // $where should include 'WHERE fld=value'
1682 function GetMedian($table, $field,$where = '') {
1683 $total = $this->GetOne("select count(*) from $table $where");
1684 if (!$total) {
1685 return false;
1688 $midrow = (integer) ($total/2);
1689 $rs = $this->SelectLimit("select $field from $table $where order by 1",1,$midrow);
1690 if ($rs && !$rs->EOF) {
1691 return reset($rs->fields);
1693 return false;
1697 function CacheGetOne($secs2cache,$sql=false,$inputarr=false) {
1698 global $ADODB_GETONE_EOF;
1700 $ret = false;
1701 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1702 if ($rs) {
1703 if ($rs->EOF) {
1704 $ret = $ADODB_GETONE_EOF;
1705 } else {
1706 $ret = reset($rs->fields);
1708 $rs->Close();
1711 return $ret;
1714 function GetCol($sql, $inputarr = false, $trim = false) {
1716 $rs = $this->Execute($sql, $inputarr);
1717 if ($rs) {
1718 $rv = array();
1719 if ($trim) {
1720 while (!$rs->EOF) {
1721 $rv[] = trim(reset($rs->fields));
1722 $rs->MoveNext();
1724 } else {
1725 while (!$rs->EOF) {
1726 $rv[] = reset($rs->fields);
1727 $rs->MoveNext();
1730 $rs->Close();
1731 } else {
1732 $rv = false;
1734 return $rv;
1737 function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false) {
1738 $rs = $this->CacheExecute($secs, $sql, $inputarr);
1739 if ($rs) {
1740 $rv = array();
1741 if ($trim) {
1742 while (!$rs->EOF) {
1743 $rv[] = trim(reset($rs->fields));
1744 $rs->MoveNext();
1746 } else {
1747 while (!$rs->EOF) {
1748 $rv[] = reset($rs->fields);
1749 $rs->MoveNext();
1752 $rs->Close();
1753 } else
1754 $rv = false;
1756 return $rv;
1759 function Transpose(&$rs,$addfieldnames=true) {
1760 $rs2 = $this->_rs2rs($rs);
1761 if (!$rs2) {
1762 return false;
1765 $rs2->_transpose($addfieldnames);
1766 return $rs2;
1770 Calculate the offset of a date for a particular database and generate
1771 appropriate SQL. Useful for calculating future/past dates and storing
1772 in a database.
1774 If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
1776 function OffsetDate($dayFraction,$date=false) {
1777 if (!$date) {
1778 $date = $this->sysDate;
1780 return '('.$date.'+'.$dayFraction.')';
1786 * @param sql SQL statement
1787 * @param [inputarr] input bind array
1789 function GetArray($sql,$inputarr=false) {
1790 global $ADODB_COUNTRECS;
1792 $savec = $ADODB_COUNTRECS;
1793 $ADODB_COUNTRECS = false;
1794 $rs = $this->Execute($sql,$inputarr);
1795 $ADODB_COUNTRECS = $savec;
1796 if (!$rs)
1797 if (defined('ADODB_PEAR')) {
1798 $cls = ADODB_PEAR_Error();
1799 return $cls;
1800 } else {
1801 return false;
1803 $arr = $rs->GetArray();
1804 $rs->Close();
1805 return $arr;
1808 function CacheGetAll($secs2cache,$sql=false,$inputarr=false) {
1809 $arr = $this->CacheGetArray($secs2cache,$sql,$inputarr);
1810 return $arr;
1813 function CacheGetArray($secs2cache,$sql=false,$inputarr=false) {
1814 global $ADODB_COUNTRECS;
1816 $savec = $ADODB_COUNTRECS;
1817 $ADODB_COUNTRECS = false;
1818 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1819 $ADODB_COUNTRECS = $savec;
1821 if (!$rs)
1822 if (defined('ADODB_PEAR')) {
1823 $cls = ADODB_PEAR_Error();
1824 return $cls;
1825 } else {
1826 return false;
1828 $arr = $rs->GetArray();
1829 $rs->Close();
1830 return $arr;
1833 function GetRandRow($sql, $arr= false) {
1834 $rezarr = $this->GetAll($sql, $arr);
1835 $sz = sizeof($rezarr);
1836 return $rezarr[abs(rand()) % $sz];
1840 * Return one row of sql statement. Recordset is disposed for you.
1841 * Note that SelectLimit should not be called.
1843 * @param sql SQL statement
1844 * @param [inputarr] input bind array
1846 function GetRow($sql,$inputarr=false) {
1847 global $ADODB_COUNTRECS;
1849 $crecs = $ADODB_COUNTRECS;
1850 $ADODB_COUNTRECS = false;
1852 $rs = $this->Execute($sql,$inputarr);
1854 $ADODB_COUNTRECS = $crecs;
1855 if ($rs) {
1856 if (!$rs->EOF) {
1857 $arr = $rs->fields;
1858 } else {
1859 $arr = array();
1861 $rs->Close();
1862 return $arr;
1865 return false;
1868 function CacheGetRow($secs2cache,$sql=false,$inputarr=false) {
1869 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1870 if ($rs) {
1871 if (!$rs->EOF) {
1872 $arr = $rs->fields;
1873 } else {
1874 $arr = array();
1877 $rs->Close();
1878 return $arr;
1880 return false;
1884 * Insert or replace a single record. Note: this is not the same as MySQL's replace.
1885 * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
1886 * Also note that no table locking is done currently, so it is possible that the
1887 * record be inserted twice by two programs...
1889 * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
1891 * $table table name
1892 * $fieldArray associative array of data (you must quote strings yourself).
1893 * $keyCol the primary key field name or if compound key, array of field names
1894 * autoQuote set to true to use a hueristic to quote strings. Works with nulls and numbers
1895 * but does not work with dates nor SQL functions.
1896 * has_autoinc the primary key is an auto-inc field, so skip in insert.
1898 * Currently blob replace not supported
1900 * returns 0 = fail, 1 = update, 2 = insert
1903 function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false) {
1904 global $ADODB_INCLUDED_LIB;
1905 if (empty($ADODB_INCLUDED_LIB)) {
1906 include(ADODB_DIR.'/adodb-lib.inc.php');
1909 return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);
1914 * Will select, getting rows from $offset (1-based), for $nrows.
1915 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1916 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1917 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1918 * eg.
1919 * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
1920 * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
1922 * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
1924 * @param [secs2cache] seconds to cache data, set to 0 to force query. This is optional
1925 * @param sql
1926 * @param [offset] is the row to start calculations from (1-based)
1927 * @param [nrows] is the number of rows to get
1928 * @param [inputarr] array of bind variables
1929 * @return the recordset ($rs->databaseType == 'array')
1931 function CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false) {
1932 if (!is_numeric($secs2cache)) {
1933 if ($sql === false) {
1934 $sql = -1;
1936 if ($offset == -1) {
1937 $offset = false;
1939 // sql, nrows, offset,inputarr
1940 $rs = $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs);
1941 } else {
1942 if ($sql === false) {
1943 $this->outp_throw("Warning: \$sql missing from CacheSelectLimit()",'CacheSelectLimit');
1945 $rs = $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
1947 return $rs;
1951 * Flush cached recordsets that match a particular $sql statement.
1952 * If $sql == false, then we purge all files in the cache.
1954 function CacheFlush($sql=false,$inputarr=false) {
1955 global $ADODB_CACHE_DIR, $ADODB_CACHE;
1957 # Create cache if it does not exist
1958 if (empty($ADODB_CACHE)) {
1959 $this->_CreateCache();
1962 if (!$sql) {
1963 $ADODB_CACHE->flushall($this->debug);
1964 return;
1967 $f = $this->_gencachename($sql.serialize($inputarr),false);
1968 return $ADODB_CACHE->flushcache($f, $this->debug);
1973 * Private function to generate filename for caching.
1974 * Filename is generated based on:
1976 * - sql statement
1977 * - database type (oci8, ibase, ifx, etc)
1978 * - database name
1979 * - userid
1980 * - setFetchMode (adodb 4.23)
1982 * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
1983 * Assuming that we can have 50,000 files per directory with good performance,
1984 * then we can scale to 12.8 million unique cached recordsets. Wow!
1986 function _gencachename($sql,$createdir) {
1987 global $ADODB_CACHE, $ADODB_CACHE_DIR;
1989 if ($this->fetchMode === false) {
1990 global $ADODB_FETCH_MODE;
1991 $mode = $ADODB_FETCH_MODE;
1992 } else {
1993 $mode = $this->fetchMode;
1995 $m = md5($sql.$this->databaseType.$this->database.$this->user.$mode);
1996 if (!$ADODB_CACHE->createdir) {
1997 return $m;
1999 if (!$createdir) {
2000 $dir = $ADODB_CACHE->getdirname($m);
2001 } else {
2002 $dir = $ADODB_CACHE->createdir($m, $this->debug);
2005 return $dir.'/adodb_'.$m.'.cache';
2010 * Execute SQL, caching recordsets.
2012 * @param [secs2cache] seconds to cache data, set to 0 to force query.
2013 * This is an optional parameter.
2014 * @param sql SQL statement to execute
2015 * @param [inputarr] holds the input data to bind to
2016 * @return RecordSet or false
2018 function CacheExecute($secs2cache,$sql=false,$inputarr=false) {
2019 global $ADODB_CACHE;
2021 if (empty($ADODB_CACHE)) {
2022 $this->_CreateCache();
2025 if (!is_numeric($secs2cache)) {
2026 $inputarr = $sql;
2027 $sql = $secs2cache;
2028 $secs2cache = $this->cacheSecs;
2031 if (is_array($sql)) {
2032 $sqlparam = $sql;
2033 $sql = $sql[0];
2034 } else
2035 $sqlparam = $sql;
2038 $md5file = $this->_gencachename($sql.serialize($inputarr),true);
2039 $err = '';
2041 if ($secs2cache > 0){
2042 $rs = $ADODB_CACHE->readcache($md5file,$err,$secs2cache,$this->arrayClass);
2043 $this->numCacheHits += 1;
2044 } else {
2045 $err='Timeout 1';
2046 $rs = false;
2047 $this->numCacheMisses += 1;
2050 if (!$rs) {
2051 // no cached rs found
2052 if ($this->debug) {
2053 if (get_magic_quotes_runtime() && !$this->memCache) {
2054 ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
2056 if ($this->debug !== -1) {
2057 ADOConnection::outp( " $md5file cache failure: $err (this is a notice and not an error)");
2061 $rs = $this->Execute($sqlparam,$inputarr);
2063 if ($rs) {
2064 $eof = $rs->EOF;
2065 $rs = $this->_rs2rs($rs); // read entire recordset into memory immediately
2066 $rs->timeCreated = time(); // used by caching
2067 $txt = _rs2serialize($rs,false,$sql); // serialize
2069 $ok = $ADODB_CACHE->writecache($md5file,$txt,$this->debug, $secs2cache);
2070 if (!$ok) {
2071 if ($ok === false) {
2072 $em = 'Cache write error';
2073 $en = -32000;
2075 if ($fn = $this->raiseErrorFn) {
2076 $fn($this->databaseType,'CacheExecute', $en, $em, $md5file,$sql,$this);
2078 } else {
2079 $em = 'Cache file locked warning';
2080 $en = -32001;
2081 // do not call error handling for just a warning
2084 if ($this->debug) {
2085 ADOConnection::outp( " ".$em);
2088 if ($rs->EOF && !$eof) {
2089 $rs->MoveFirst();
2090 //$rs = csv2rs($md5file,$err);
2091 $rs->connection = $this; // Pablo suggestion
2094 } else if (!$this->memCache) {
2095 $ADODB_CACHE->flushcache($md5file);
2097 } else {
2098 $this->_errorMsg = '';
2099 $this->_errorCode = 0;
2101 if ($this->fnCacheExecute) {
2102 $fn = $this->fnCacheExecute;
2103 $fn($this, $secs2cache, $sql, $inputarr);
2105 // ok, set cached object found
2106 $rs->connection = $this; // Pablo suggestion
2107 if ($this->debug){
2108 if ($this->debug == 99) {
2109 adodb_backtrace();
2111 $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
2112 $ttl = $rs->timeCreated + $secs2cache - time();
2113 $s = is_array($sql) ? $sql[0] : $sql;
2114 if ($inBrowser) {
2115 $s = '<i>'.htmlspecialchars($s).'</i>';
2118 ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
2121 return $rs;
2126 Similar to PEAR DB's autoExecute(), except that
2127 $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
2128 If $mode == 'UPDATE', then $where is compulsory as a safety measure.
2130 $forceUpdate means that even if the data has not changed, perform update.
2132 function AutoExecute($table, $fields_values, $mode = 'INSERT', $where = false, $forceUpdate = true, $magicq = false) {
2133 if ($where === false && ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) ) {
2134 $this->outp_throw('AutoExecute: Illegal mode=UPDATE with empty WHERE clause', 'AutoExecute');
2135 return false;
2138 $sql = "SELECT * FROM $table";
2139 $rs = $this->SelectLimit($sql, 1);
2140 if (!$rs) {
2141 return false; // table does not exist
2144 $rs->tableName = $table;
2145 if ($where !== false) {
2146 $sql .= " WHERE $where";
2148 $rs->sql = $sql;
2150 switch($mode) {
2151 case 'UPDATE':
2152 case DB_AUTOQUERY_UPDATE:
2153 $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq);
2154 break;
2155 case 'INSERT':
2156 case DB_AUTOQUERY_INSERT:
2157 $sql = $this->GetInsertSQL($rs, $fields_values, $magicq);
2158 break;
2159 default:
2160 $this->outp_throw("AutoExecute: Unknown mode=$mode", 'AutoExecute');
2161 return false;
2163 return $sql && $this->Execute($sql);
2168 * Generates an Update Query based on an existing recordset.
2169 * $arrFields is an associative array of fields with the value
2170 * that should be assigned.
2172 * Note: This function should only be used on a recordset
2173 * that is run against a single table and sql should only
2174 * be a simple select stmt with no groupby/orderby/limit
2176 * "Jonathan Younger" <jyounger@unilab.com>
2178 function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null) {
2179 global $ADODB_INCLUDED_LIB;
2181 // ********************************************************
2182 // This is here to maintain compatibility
2183 // with older adodb versions. Sets force type to force nulls if $forcenulls is set.
2184 if (!isset($force)) {
2185 global $ADODB_FORCE_TYPE;
2186 $force = $ADODB_FORCE_TYPE;
2188 // ********************************************************
2190 if (empty($ADODB_INCLUDED_LIB)) {
2191 include(ADODB_DIR.'/adodb-lib.inc.php');
2193 return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
2197 * Generates an Insert Query based on an existing recordset.
2198 * $arrFields is an associative array of fields with the value
2199 * that should be assigned.
2201 * Note: This function should only be used on a recordset
2202 * that is run against a single table.
2204 function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null) {
2205 global $ADODB_INCLUDED_LIB;
2206 if (!isset($force)) {
2207 global $ADODB_FORCE_TYPE;
2208 $force = $ADODB_FORCE_TYPE;
2210 if (empty($ADODB_INCLUDED_LIB)) {
2211 include(ADODB_DIR.'/adodb-lib.inc.php');
2213 return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
2218 * Update a blob column, given a where clause. There are more sophisticated
2219 * blob handling functions that we could have implemented, but all require
2220 * a very complex API. Instead we have chosen something that is extremely
2221 * simple to understand and use.
2223 * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
2225 * Usage to update a $blobvalue which has a primary key blob_id=1 into a
2226 * field blobtable.blobcolumn:
2228 * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
2230 * Insert example:
2232 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
2233 * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
2235 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') {
2236 return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
2240 * Usage:
2241 * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
2243 * $blobtype supports 'BLOB' and 'CLOB'
2245 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
2246 * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
2248 function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') {
2249 $fd = fopen($path,'rb');
2250 if ($fd === false) {
2251 return false;
2253 $val = fread($fd,filesize($path));
2254 fclose($fd);
2255 return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
2258 function BlobDecode($blob) {
2259 return $blob;
2262 function BlobEncode($blob) {
2263 return $blob;
2266 function GetCharSet() {
2267 return $this->charSet;
2270 function SetCharSet($charset) {
2271 $this->charSet = $charset;
2272 return true;
2275 function IfNull( $field, $ifNull ) {
2276 return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
2279 function LogSQL($enable=true) {
2280 include_once(ADODB_DIR.'/adodb-perf.inc.php');
2282 if ($enable) {
2283 $this->fnExecute = 'adodb_log_sql';
2284 } else {
2285 $this->fnExecute = false;
2288 $old = $this->_logsql;
2289 $this->_logsql = $enable;
2290 if ($enable && !$old) {
2291 $this->_affected = false;
2293 return $old;
2297 * Usage:
2298 * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
2300 * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
2301 * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
2303 function UpdateClob($table,$column,$val,$where) {
2304 return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
2307 // not the fastest implementation - quick and dirty - jlim
2308 // for best performance, use the actual $rs->MetaType().
2309 function MetaType($t,$len=-1,$fieldobj=false) {
2311 if (empty($this->_metars)) {
2312 $rsclass = $this->rsPrefix.$this->databaseType;
2313 $this->_metars = new $rsclass(false,$this->fetchMode);
2314 $this->_metars->connection = $this;
2316 return $this->_metars->MetaType($t,$len,$fieldobj);
2321 * Change the SQL connection locale to a specified locale.
2322 * This is used to get the date formats written depending on the client locale.
2324 function SetDateLocale($locale = 'En') {
2325 $this->locale = $locale;
2326 switch (strtoupper($locale))
2328 case 'EN':
2329 $this->fmtDate="'Y-m-d'";
2330 $this->fmtTimeStamp = "'Y-m-d H:i:s'";
2331 break;
2333 case 'US':
2334 $this->fmtDate = "'m-d-Y'";
2335 $this->fmtTimeStamp = "'m-d-Y H:i:s'";
2336 break;
2338 case 'PT_BR':
2339 case 'NL':
2340 case 'FR':
2341 case 'RO':
2342 case 'IT':
2343 $this->fmtDate="'d-m-Y'";
2344 $this->fmtTimeStamp = "'d-m-Y H:i:s'";
2345 break;
2347 case 'GE':
2348 $this->fmtDate="'d.m.Y'";
2349 $this->fmtTimeStamp = "'d.m.Y H:i:s'";
2350 break;
2352 default:
2353 $this->fmtDate="'Y-m-d'";
2354 $this->fmtTimeStamp = "'Y-m-d H:i:s'";
2355 break;
2360 * GetActiveRecordsClass Performs an 'ALL' query
2362 * @param mixed $class This string represents the class of the current active record
2363 * @param mixed $table Table used by the active record object
2364 * @param mixed $whereOrderBy Where, order, by clauses
2365 * @param mixed $bindarr
2366 * @param mixed $primkeyArr
2367 * @param array $extra Query extras: limit, offset...
2368 * @param mixed $relations Associative array: table's foreign name, "hasMany", "belongsTo"
2369 * @access public
2370 * @return void
2372 function GetActiveRecordsClass(
2373 $class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false,
2374 $extra=array(),
2375 $relations=array())
2377 global $_ADODB_ACTIVE_DBS;
2378 ## reduce overhead of adodb.inc.php -- moved to adodb-active-record.inc.php
2379 ## if adodb-active-recordx is loaded -- should be no issue as they will probably use Find()
2380 if (!isset($_ADODB_ACTIVE_DBS)) {
2381 include_once(ADODB_DIR.'/adodb-active-record.inc.php');
2383 return adodb_GetActiveRecordsClass($this, $class, $table, $whereOrderBy, $bindarr, $primkeyArr, $extra, $relations);
2386 function GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false) {
2387 $arr = $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr);
2388 return $arr;
2392 * Close Connection
2394 function Close() {
2395 $rez = $this->_close();
2396 $this->_connectionID = false;
2397 return $rez;
2401 * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
2403 * @return true if succeeded or false if database does not support transactions
2405 function BeginTrans() {
2406 if ($this->debug) {
2407 ADOConnection::outp("BeginTrans: Transactions not supported for this driver");
2409 return false;
2412 /* set transaction mode */
2413 function SetTransactionMode( $transaction_mode ) {
2414 $transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider);
2415 $this->_transmode = $transaction_mode;
2418 http://msdn2.microsoft.com/en-US/ms173763.aspx
2419 http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html
2420 http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html
2421 http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm
2423 function MetaTransaction($mode,$db) {
2424 $mode = strtoupper($mode);
2425 $mode = str_replace('ISOLATION LEVEL ','',$mode);
2427 switch($mode) {
2429 case 'READ UNCOMMITTED':
2430 switch($db) {
2431 case 'oci8':
2432 case 'oracle':
2433 return 'ISOLATION LEVEL READ COMMITTED';
2434 default:
2435 return 'ISOLATION LEVEL READ UNCOMMITTED';
2437 break;
2439 case 'READ COMMITTED':
2440 return 'ISOLATION LEVEL READ COMMITTED';
2441 break;
2443 case 'REPEATABLE READ':
2444 switch($db) {
2445 case 'oci8':
2446 case 'oracle':
2447 return 'ISOLATION LEVEL SERIALIZABLE';
2448 default:
2449 return 'ISOLATION LEVEL REPEATABLE READ';
2451 break;
2453 case 'SERIALIZABLE':
2454 return 'ISOLATION LEVEL SERIALIZABLE';
2455 break;
2457 default:
2458 return $mode;
2463 * If database does not support transactions, always return true as data always commited
2465 * @param $ok set to false to rollback transaction, true to commit
2467 * @return true/false.
2469 function CommitTrans($ok=true) {
2470 return true;
2475 * If database does not support transactions, rollbacks always fail, so return false
2477 * @return true/false.
2479 function RollbackTrans() {
2480 return false;
2485 * return the databases that the driver can connect to.
2486 * Some databases will return an empty array.
2488 * @return an array of database names.
2490 function MetaDatabases() {
2491 global $ADODB_FETCH_MODE;
2493 if ($this->metaDatabasesSQL) {
2494 $save = $ADODB_FETCH_MODE;
2495 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2497 if ($this->fetchMode !== false) {
2498 $savem = $this->SetFetchMode(false);
2501 $arr = $this->GetCol($this->metaDatabasesSQL);
2502 if (isset($savem)) {
2503 $this->SetFetchMode($savem);
2505 $ADODB_FETCH_MODE = $save;
2507 return $arr;
2510 return false;
2514 * List procedures or functions in an array.
2515 * @param procedureNamePattern a procedure name pattern; must match the procedure name as it is stored in the database
2516 * @param catalog a catalog name; must match the catalog name as it is stored in the database;
2517 * @param schemaPattern a schema name pattern;
2519 * @return array of procedures on current database.
2521 * Array(
2522 * [name_of_procedure] => Array(
2523 * [type] => PROCEDURE or FUNCTION
2524 * [catalog] => Catalog_name
2525 * [schema] => Schema_name
2526 * [remarks] => explanatory comment on the procedure
2530 function MetaProcedures($procedureNamePattern = null, $catalog = null, $schemaPattern = null) {
2531 return false;
2536 * @param ttype can either be 'VIEW' or 'TABLE' or false.
2537 * If false, both views and tables are returned.
2538 * "VIEW" returns only views
2539 * "TABLE" returns only tables
2540 * @param showSchema returns the schema/user with the table name, eg. USER.TABLE
2541 * @param mask is the input mask - only supported by oci8 and postgresql
2543 * @return array of tables for current database.
2545 function MetaTables($ttype=false,$showSchema=false,$mask=false) {
2546 global $ADODB_FETCH_MODE;
2548 if ($mask) {
2549 return false;
2551 if ($this->metaTablesSQL) {
2552 $save = $ADODB_FETCH_MODE;
2553 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2555 if ($this->fetchMode !== false) {
2556 $savem = $this->SetFetchMode(false);
2559 $rs = $this->Execute($this->metaTablesSQL);
2560 if (isset($savem)) {
2561 $this->SetFetchMode($savem);
2563 $ADODB_FETCH_MODE = $save;
2565 if ($rs === false) {
2566 return false;
2568 $arr = $rs->GetArray();
2569 $arr2 = array();
2571 if ($hast = ($ttype && isset($arr[0][1]))) {
2572 $showt = strncmp($ttype,'T',1);
2575 for ($i=0; $i < sizeof($arr); $i++) {
2576 if ($hast) {
2577 if ($showt == 0) {
2578 if (strncmp($arr[$i][1],'T',1) == 0) {
2579 $arr2[] = trim($arr[$i][0]);
2581 } else {
2582 if (strncmp($arr[$i][1],'V',1) == 0) {
2583 $arr2[] = trim($arr[$i][0]);
2586 } else
2587 $arr2[] = trim($arr[$i][0]);
2589 $rs->Close();
2590 return $arr2;
2592 return false;
2596 function _findschema(&$table,&$schema) {
2597 if (!$schema && ($at = strpos($table,'.')) !== false) {
2598 $schema = substr($table,0,$at);
2599 $table = substr($table,$at+1);
2604 * List columns in a database as an array of ADOFieldObjects.
2605 * See top of file for definition of object.
2607 * @param $table table name to query
2608 * @param $normalize makes table name case-insensitive (required by some databases)
2609 * @schema is optional database schema to use - not supported by all databases.
2611 * @return array of ADOFieldObjects for current table.
2613 function MetaColumns($table,$normalize=true) {
2614 global $ADODB_FETCH_MODE;
2616 if (!empty($this->metaColumnsSQL)) {
2617 $schema = false;
2618 $this->_findschema($table,$schema);
2620 $save = $ADODB_FETCH_MODE;
2621 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2622 if ($this->fetchMode !== false) {
2623 $savem = $this->SetFetchMode(false);
2625 $rs = $this->Execute(sprintf($this->metaColumnsSQL,($normalize)?strtoupper($table):$table));
2626 if (isset($savem)) {
2627 $this->SetFetchMode($savem);
2629 $ADODB_FETCH_MODE = $save;
2630 if ($rs === false || $rs->EOF) {
2631 return false;
2634 $retarr = array();
2635 while (!$rs->EOF) { //print_r($rs->fields);
2636 $fld = new ADOFieldObject();
2637 $fld->name = $rs->fields[0];
2638 $fld->type = $rs->fields[1];
2639 if (isset($rs->fields[3]) && $rs->fields[3]) {
2640 if ($rs->fields[3]>0) {
2641 $fld->max_length = $rs->fields[3];
2643 $fld->scale = $rs->fields[4];
2644 if ($fld->scale>0) {
2645 $fld->max_length += 1;
2647 } else {
2648 $fld->max_length = $rs->fields[2];
2651 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) {
2652 $retarr[] = $fld;
2653 } else {
2654 $retarr[strtoupper($fld->name)] = $fld;
2656 $rs->MoveNext();
2658 $rs->Close();
2659 return $retarr;
2661 return false;
2665 * List indexes on a table as an array.
2666 * @param table table name to query
2667 * @param primary true to only show primary keys. Not actually used for most databases
2669 * @return array of indexes on current table. Each element represents an index, and is itself an associative array.
2671 * Array(
2672 * [name_of_index] => Array(
2673 * [unique] => true or false
2674 * [columns] => Array(
2675 * [0] => firstname
2676 * [1] => lastname
2681 function MetaIndexes($table, $primary = false, $owner = false) {
2682 return false;
2686 * List columns names in a table as an array.
2687 * @param table table name to query
2689 * @return array of column names for current table.
2691 function MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */) {
2692 $objarr = $this->MetaColumns($table);
2693 if (!is_array($objarr)) {
2694 return false;
2696 $arr = array();
2697 if ($numIndexes) {
2698 $i = 0;
2699 if ($useattnum) {
2700 foreach($objarr as $v)
2701 $arr[$v->attnum] = $v->name;
2703 } else
2704 foreach($objarr as $v) $arr[$i++] = $v->name;
2705 } else
2706 foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name;
2708 return $arr;
2712 * Different SQL databases used different methods to combine strings together.
2713 * This function provides a wrapper.
2715 * param s variable number of string parameters
2717 * Usage: $db->Concat($str1,$str2);
2719 * @return concatenated string
2721 function Concat() {
2722 $arr = func_get_args();
2723 return implode($this->concat_operator, $arr);
2728 * Converts a date "d" to a string that the database can understand.
2730 * @param d a date in Unix date time format.
2732 * @return date string in database date format
2734 function DBDate($d, $isfld=false) {
2735 if (empty($d) && $d !== 0) {
2736 return 'null';
2738 if ($isfld) {
2739 return $d;
2741 if (is_object($d)) {
2742 return $d->format($this->fmtDate);
2745 if (is_string($d) && !is_numeric($d)) {
2746 if ($d === 'null') {
2747 return $d;
2749 if (strncmp($d,"'",1) === 0) {
2750 $d = _adodb_safedateq($d);
2751 return $d;
2753 if ($this->isoDates) {
2754 return "'$d'";
2756 $d = ADOConnection::UnixDate($d);
2759 return adodb_date($this->fmtDate,$d);
2762 function BindDate($d) {
2763 $d = $this->DBDate($d);
2764 if (strncmp($d,"'",1)) {
2765 return $d;
2768 return substr($d,1,strlen($d)-2);
2771 function BindTimeStamp($d) {
2772 $d = $this->DBTimeStamp($d);
2773 if (strncmp($d,"'",1)) {
2774 return $d;
2777 return substr($d,1,strlen($d)-2);
2782 * Converts a timestamp "ts" to a string that the database can understand.
2784 * @param ts a timestamp in Unix date time format.
2786 * @return timestamp string in database timestamp format
2788 function DBTimeStamp($ts,$isfld=false) {
2789 if (empty($ts) && $ts !== 0) {
2790 return 'null';
2792 if ($isfld) {
2793 return $ts;
2795 if (is_object($ts)) {
2796 return $ts->format($this->fmtTimeStamp);
2799 # strlen(14) allows YYYYMMDDHHMMSS format
2800 if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) {
2801 return adodb_date($this->fmtTimeStamp,$ts);
2804 if ($ts === 'null') {
2805 return $ts;
2807 if ($this->isoDates && strlen($ts) !== 14) {
2808 $ts = _adodb_safedate($ts);
2809 return "'$ts'";
2811 $ts = ADOConnection::UnixTimeStamp($ts);
2812 return adodb_date($this->fmtTimeStamp,$ts);
2816 * Also in ADORecordSet.
2817 * @param $v is a date string in YYYY-MM-DD format
2819 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2821 static function UnixDate($v) {
2822 if (is_object($v)) {
2823 // odbtp support
2824 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2825 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2828 if (is_numeric($v) && strlen($v) !== 8) {
2829 return $v;
2831 if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", $v, $rr)) {
2832 return false;
2835 if ($rr[1] <= TIMESTAMP_FIRST_YEAR) {
2836 return 0;
2839 // h-m-s-MM-DD-YY
2840 return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2845 * Also in ADORecordSet.
2846 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
2848 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2850 static function UnixTimeStamp($v) {
2851 if (is_object($v)) {
2852 // odbtp support
2853 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2854 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2857 if (!preg_match(
2858 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
2859 ($v), $rr)) return false;
2861 if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) {
2862 return 0;
2865 // h-m-s-MM-DD-YY
2866 if (!isset($rr[5])) {
2867 return adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2869 return @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
2873 * Also in ADORecordSet.
2875 * Format database date based on user defined format.
2877 * @param v is the character date in YYYY-MM-DD format, returned by database
2878 * @param fmt is the format to apply to it, using date()
2880 * @return a date formated as user desires
2882 function UserDate($v,$fmt='Y-m-d',$gmt=false) {
2883 $tt = $this->UnixDate($v);
2885 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2886 if (($tt === false || $tt == -1) && $v != false) {
2887 return $v;
2888 } else if ($tt == 0) {
2889 return $this->emptyDate;
2890 } else if ($tt == -1) {
2891 // pre-TIMESTAMP_FIRST_YEAR
2894 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2900 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
2901 * @param fmt is the format to apply to it, using date()
2903 * @return a timestamp formated as user desires
2905 function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false) {
2906 if (!isset($v)) {
2907 return $this->emptyTimeStamp;
2909 # strlen(14) allows YYYYMMDDHHMMSS format
2910 if (is_numeric($v) && strlen($v)<14) {
2911 return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v);
2913 $tt = $this->UnixTimeStamp($v);
2914 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2915 if (($tt === false || $tt == -1) && $v != false) {
2916 return $v;
2918 if ($tt == 0) {
2919 return $this->emptyTimeStamp;
2921 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2924 function escape($s,$magic_quotes=false) {
2925 return $this->addq($s,$magic_quotes);
2929 * Quotes a string, without prefixing nor appending quotes.
2931 function addq($s,$magic_quotes=false) {
2932 if (!$magic_quotes) {
2933 if ($this->replaceQuote[0] == '\\') {
2934 // only since php 4.0.5
2935 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2936 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2938 return str_replace("'",$this->replaceQuote,$s);
2941 // undo magic quotes for "
2942 $s = str_replace('\\"','"',$s);
2944 if ($this->replaceQuote == "\\'" || ini_get('magic_quotes_sybase')) {
2945 // ' already quoted, no need to change anything
2946 return $s;
2947 } else {
2948 // change \' to '' for sybase/mssql
2949 $s = str_replace('\\\\','\\',$s);
2950 return str_replace("\\'",$this->replaceQuote,$s);
2955 * Correctly quotes a string so that all strings are escaped. We prefix and append
2956 * to the string single-quotes.
2957 * An example is $db->qstr("Don't bother",magic_quotes_runtime());
2959 * @param s the string to quote
2960 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
2961 * This undoes the stupidity of magic quotes for GPC.
2963 * @return quoted string to be sent back to database
2965 function qstr($s,$magic_quotes=false) {
2966 if (!$magic_quotes) {
2967 if ($this->replaceQuote[0] == '\\'){
2968 // only since php 4.0.5
2969 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2970 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2972 return "'".str_replace("'",$this->replaceQuote,$s)."'";
2975 // undo magic quotes for "
2976 $s = str_replace('\\"','"',$s);
2978 if ($this->replaceQuote == "\\'" || ini_get('magic_quotes_sybase')) {
2979 // ' already quoted, no need to change anything
2980 return "'$s'";
2981 } else {
2982 // change \' to '' for sybase/mssql
2983 $s = str_replace('\\\\','\\',$s);
2984 return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
2990 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2991 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2992 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2994 * See docs-adodb.htm#ex8 for an example of usage.
2996 * @param sql
2997 * @param nrows is the number of rows per page to get
2998 * @param page is the page number to get (1-based)
2999 * @param [inputarr] array of bind variables
3000 * @param [secs2cache] is a private parameter only used by jlim
3001 * @return the recordset ($rs->databaseType == 'array')
3003 * NOTE: phpLens uses a different algorithm and does not use PageExecute().
3006 function PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0) {
3007 global $ADODB_INCLUDED_LIB;
3008 if (empty($ADODB_INCLUDED_LIB)) {
3009 include(ADODB_DIR.'/adodb-lib.inc.php');
3011 if ($this->pageExecuteCountRows) {
3012 $rs = _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
3013 } else {
3014 $rs = _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache);
3016 return $rs;
3021 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
3022 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
3023 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
3025 * @param secs2cache seconds to cache data, set to 0 to force query
3026 * @param sql
3027 * @param nrows is the number of rows per page to get
3028 * @param page is the page number to get (1-based)
3029 * @param [inputarr] array of bind variables
3030 * @return the recordset ($rs->databaseType == 'array')
3032 function CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false) {
3033 /*switch($this->dataProvider) {
3034 case 'postgres':
3035 case 'mysql':
3036 break;
3037 default: $secs2cache = 0; break;
3039 $rs = $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
3040 return $rs;
3043 } // end class ADOConnection
3047 //==============================================================================================
3048 // CLASS ADOFetchObj
3049 //==============================================================================================
3052 * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
3054 class ADOFetchObj {
3057 //==============================================================================================
3058 // CLASS ADORecordSet_empty
3059 //==============================================================================================
3061 class ADODB_Iterator_empty implements Iterator {
3063 private $rs;
3065 function __construct($rs) {
3066 $this->rs = $rs;
3069 function rewind() {}
3071 function valid() {
3072 return !$this->rs->EOF;
3075 function key() {
3076 return false;
3079 function current() {
3080 return false;
3083 function next() {}
3085 function __call($func, $params) {
3086 return call_user_func_array(array($this->rs, $func), $params);
3089 function hasMore() {
3090 return false;
3097 * Lightweight recordset when there are no records to be returned
3099 class ADORecordSet_empty implements IteratorAggregate
3101 var $dataProvider = 'empty';
3102 var $databaseType = false;
3103 var $EOF = true;
3104 var $_numOfRows = 0;
3105 var $fields = false;
3106 var $connection = false;
3108 function RowCount() {
3109 return 0;
3112 function RecordCount() {
3113 return 0;
3116 function PO_RecordCount() {
3117 return 0;
3120 function Close() {
3121 return true;
3124 function FetchRow() {
3125 return false;
3128 function FieldCount() {
3129 return 0;
3132 function Init() {}
3134 function getIterator() {
3135 return new ADODB_Iterator_empty($this);
3138 function GetAssoc() {
3139 return array();
3142 function GetArray() {
3143 return array();
3146 function GetAll() {
3147 return array();
3150 function GetArrayLimit() {
3151 return array();
3154 function GetRows() {
3155 return array();
3158 function GetRowAssoc() {
3159 return array();
3162 function MaxRecordCount() {
3163 return 0;
3166 function NumRows() {
3167 return 0;
3170 function NumCols() {
3171 return 0;
3175 //==============================================================================================
3176 // DATE AND TIME FUNCTIONS
3177 //==============================================================================================
3178 if (!defined('ADODB_DATE_VERSION')) {
3179 include(ADODB_DIR.'/adodb-time.inc.php');
3182 //==============================================================================================
3183 // CLASS ADORecordSet
3184 //==============================================================================================
3186 class ADODB_Iterator implements Iterator {
3188 private $rs;
3190 function __construct($rs) {
3191 $this->rs = $rs;
3194 function rewind() {
3195 $this->rs->MoveFirst();
3198 function valid() {
3199 return !$this->rs->EOF;
3202 function key() {
3203 return $this->rs->_currentRow;
3206 function current() {
3207 return $this->rs->fields;
3210 function next() {
3211 $this->rs->MoveNext();
3214 function __call($func, $params) {
3215 return call_user_func_array(array($this->rs, $func), $params);
3218 function hasMore() {
3219 return !$this->rs->EOF;
3226 * RecordSet class that represents the dataset returned by the database.
3227 * To keep memory overhead low, this class holds only the current row in memory.
3228 * No prefetching of data is done, so the RecordCount() can return -1 ( which
3229 * means recordcount not known).
3231 class ADORecordSet implements IteratorAggregate {
3234 * public variables
3236 var $dataProvider = "native";
3237 var $fields = false; /// holds the current row data
3238 var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob
3239 /// in other words, we use a text area for editing.
3240 var $canSeek = false; /// indicates that seek is supported
3241 var $sql; /// sql text
3242 var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object.
3244 var $emptyTimeStamp = '&nbsp;'; /// what to display when $time==0
3245 var $emptyDate = '&nbsp;'; /// what to display when $time==0
3246 var $debug = false;
3247 var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsets
3249 var $bind = false; /// used by Fields() to hold array - should be private?
3250 var $fetchMode; /// default fetch mode
3251 var $connection = false; /// the parent connection
3254 * private variables
3256 var $_numOfRows = -1; /** number of rows, or -1 */
3257 var $_numOfFields = -1; /** number of fields in recordset */
3258 var $_queryID = -1; /** This variable keeps the result link identifier. */
3259 var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */
3260 var $_closed = false; /** has recordset been closed */
3261 var $_inited = false; /** Init() should only be called once */
3262 var $_obj; /** Used by FetchObj */
3263 var $_names; /** Used by FetchObj */
3265 var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */
3266 var $_atFirstPage = false; /** Added by Iván Oliva to implement recordset pagination */
3267 var $_atLastPage = false; /** Added by Iván Oliva to implement recordset pagination */
3268 var $_lastPageNo = -1;
3269 var $_maxRecordCount = 0;
3270 var $datetime = false;
3273 * Constructor
3275 * @param queryID this is the queryID returned by ADOConnection->_query()
3278 function __construct($queryID) {
3279 $this->_queryID = $queryID;
3282 function __destruct() {
3283 @$this->Close();
3286 function getIterator() {
3287 return new ADODB_Iterator($this);
3290 /* this is experimental - i don't really know what to return... */
3291 function __toString() {
3292 include_once(ADODB_DIR.'/toexport.inc.php');
3293 return _adodb_export($this,',',',',false,true);
3296 function Init() {
3297 if ($this->_inited) {
3298 return;
3300 $this->_inited = true;
3301 if ($this->_queryID) {
3302 @$this->_initrs();
3303 } else {
3304 $this->_numOfRows = 0;
3305 $this->_numOfFields = 0;
3307 if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
3308 $this->_currentRow = 0;
3309 if ($this->EOF = ($this->_fetch() === false)) {
3310 $this->_numOfRows = 0; // _numOfRows could be -1
3312 } else {
3313 $this->EOF = true;
3319 * Generate a SELECT tag string from a recordset, and return the string.
3320 * If the recordset has 2 cols, we treat the 1st col as the containing
3321 * the text to display to the user, and 2nd col as the return value. Default
3322 * strings are compared with the FIRST column.
3324 * @param name name of SELECT tag
3325 * @param [defstr] the value to hilite. Use an array for multiple hilites for listbox.
3326 * @param [blank1stItem] true to leave the 1st item in list empty
3327 * @param [multiple] true for listbox, false for popup
3328 * @param [size] #rows to show for listbox. not used by popup
3329 * @param [selectAttr] additional attributes to defined for SELECT tag.
3330 * useful for holding javascript onChange='...' handlers.
3331 & @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with
3332 * column 0 (1st col) if this is true. This is not documented.
3334 * @return HTML
3336 * changes by glen.davies@cce.ac.nz to support multiple hilited items
3338 function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
3339 $size=0, $selectAttr='',$compareFields0=true)
3341 global $ADODB_INCLUDED_LIB;
3342 if (empty($ADODB_INCLUDED_LIB)) {
3343 include(ADODB_DIR.'/adodb-lib.inc.php');
3345 return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
3346 $size, $selectAttr,$compareFields0);
3352 * Generate a SELECT tag string from a recordset, and return the string.
3353 * If the recordset has 2 cols, we treat the 1st col as the containing
3354 * the text to display to the user, and 2nd col as the return value. Default
3355 * strings are compared with the SECOND column.
3358 function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='') {
3359 return $this->GetMenu($name,$defstr,$blank1stItem,$multiple,
3360 $size, $selectAttr,false);
3364 Grouped Menu
3366 function GetMenu3($name,$defstr='',$blank1stItem=true,$multiple=false,
3367 $size=0, $selectAttr='')
3369 global $ADODB_INCLUDED_LIB;
3370 if (empty($ADODB_INCLUDED_LIB)) {
3371 include(ADODB_DIR.'/adodb-lib.inc.php');
3373 return _adodb_getmenu_gp($this, $name,$defstr,$blank1stItem,$multiple,
3374 $size, $selectAttr,false);
3378 * return recordset as a 2-dimensional array.
3380 * @param [nRows] is the number of rows to return. -1 means every row.
3382 * @return an array indexed by the rows (0-based) from the recordset
3384 function GetArray($nRows = -1) {
3385 global $ADODB_EXTENSION; if ($ADODB_EXTENSION) {
3386 $results = adodb_getall($this,$nRows);
3387 return $results;
3389 $results = array();
3390 $cnt = 0;
3391 while (!$this->EOF && $nRows != $cnt) {
3392 $results[] = $this->fields;
3393 $this->MoveNext();
3394 $cnt++;
3396 return $results;
3399 function GetAll($nRows = -1) {
3400 $arr = $this->GetArray($nRows);
3401 return $arr;
3405 * Some databases allow multiple recordsets to be returned. This function
3406 * will return true if there is a next recordset, or false if no more.
3408 function NextRecordSet() {
3409 return false;
3413 * return recordset as a 2-dimensional array.
3414 * Helper function for ADOConnection->SelectLimit()
3416 * @param offset is the row to start calculations from (1-based)
3417 * @param [nrows] is the number of rows to return
3419 * @return an array indexed by the rows (0-based) from the recordset
3421 function GetArrayLimit($nrows,$offset=-1) {
3422 if ($offset <= 0) {
3423 $arr = $this->GetArray($nrows);
3424 return $arr;
3427 $this->Move($offset);
3429 $results = array();
3430 $cnt = 0;
3431 while (!$this->EOF && $nrows != $cnt) {
3432 $results[$cnt++] = $this->fields;
3433 $this->MoveNext();
3436 return $results;
3441 * Synonym for GetArray() for compatibility with ADO.
3443 * @param [nRows] is the number of rows to return. -1 means every row.
3445 * @return an array indexed by the rows (0-based) from the recordset
3447 function GetRows($nRows = -1) {
3448 $arr = $this->GetArray($nRows);
3449 return $arr;
3453 * return whole recordset as a 2-dimensional associative array if there are more than 2 columns.
3454 * The first column is treated as the key and is not included in the array.
3455 * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless
3456 * $force_array == true.
3458 * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional
3459 * array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,
3460 * read the source.
3462 * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and
3463 * instead of returning array[col0] => array(remaining cols), return array[col0] => col1
3465 * @return an associative array indexed by the first column of the array,
3466 * or false if the data has less than 2 cols.
3468 function GetAssoc($force_array = false, $first2cols = false) {
3469 global $ADODB_EXTENSION;
3471 $cols = $this->_numOfFields;
3472 if ($cols < 2) {
3473 return false;
3476 // Empty recordset
3477 if (!$this->fields) {
3478 return array();
3481 // Determine whether the array is associative or 0-based numeric
3482 $numIndex = array_keys($this->fields) == range(0, count($this->fields) - 1);
3484 $results = array();
3486 if (!$first2cols && ($cols > 2 || $force_array)) {
3487 if ($ADODB_EXTENSION) {
3488 if ($numIndex) {
3489 while (!$this->EOF) {
3490 $results[trim($this->fields[0])] = array_slice($this->fields, 1);
3491 adodb_movenext($this);
3493 } else {
3494 while (!$this->EOF) {
3495 // Fix for array_slice re-numbering numeric associative keys
3496 $keys = array_slice(array_keys($this->fields), 1);
3497 $sliced_array = array();
3499 foreach($keys as $key) {
3500 $sliced_array[$key] = $this->fields[$key];
3503 $results[trim(reset($this->fields))] = $sliced_array;
3504 adodb_movenext($this);
3507 } else {
3508 if ($numIndex) {
3509 while (!$this->EOF) {
3510 $results[trim($this->fields[0])] = array_slice($this->fields, 1);
3511 $this->MoveNext();
3513 } else {
3514 while (!$this->EOF) {
3515 // Fix for array_slice re-numbering numeric associative keys
3516 $keys = array_slice(array_keys($this->fields), 1);
3517 $sliced_array = array();
3519 foreach($keys as $key) {
3520 $sliced_array[$key] = $this->fields[$key];
3523 $results[trim(reset($this->fields))] = $sliced_array;
3524 $this->MoveNext();
3528 } else {
3529 if ($ADODB_EXTENSION) {
3530 // return scalar values
3531 if ($numIndex) {
3532 while (!$this->EOF) {
3533 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3534 $results[trim(($this->fields[0]))] = $this->fields[1];
3535 adodb_movenext($this);
3537 } else {
3538 while (!$this->EOF) {
3539 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3540 $v1 = trim(reset($this->fields));
3541 $v2 = ''.next($this->fields);
3542 $results[$v1] = $v2;
3543 adodb_movenext($this);
3546 } else {
3547 if ($numIndex) {
3548 while (!$this->EOF) {
3549 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3550 $results[trim(($this->fields[0]))] = $this->fields[1];
3551 $this->MoveNext();
3553 } else {
3554 while (!$this->EOF) {
3555 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3556 $v1 = trim(reset($this->fields));
3557 $v2 = ''.next($this->fields);
3558 $results[$v1] = $v2;
3559 $this->MoveNext();
3565 $ref = $results; # workaround accelerator incompat with PHP 4.4 :(
3566 return $ref;
3572 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
3573 * @param fmt is the format to apply to it, using date()
3575 * @return a timestamp formated as user desires
3577 function UserTimeStamp($v,$fmt='Y-m-d H:i:s') {
3578 if (is_numeric($v) && strlen($v)<14) {
3579 return adodb_date($fmt,$v);
3581 $tt = $this->UnixTimeStamp($v);
3582 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
3583 if (($tt === false || $tt == -1) && $v != false) {
3584 return $v;
3586 if ($tt === 0) {
3587 return $this->emptyTimeStamp;
3589 return adodb_date($fmt,$tt);
3594 * @param v is the character date in YYYY-MM-DD format, returned by database
3595 * @param fmt is the format to apply to it, using date()
3597 * @return a date formated as user desires
3599 function UserDate($v,$fmt='Y-m-d') {
3600 $tt = $this->UnixDate($v);
3601 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
3602 if (($tt === false || $tt == -1) && $v != false) {
3603 return $v;
3604 } else if ($tt == 0) {
3605 return $this->emptyDate;
3606 } else if ($tt == -1) {
3607 // pre-TIMESTAMP_FIRST_YEAR
3609 return adodb_date($fmt,$tt);
3614 * @param $v is a date string in YYYY-MM-DD format
3616 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
3618 static function UnixDate($v) {
3619 return ADOConnection::UnixDate($v);
3624 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
3626 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
3628 static function UnixTimeStamp($v) {
3629 return ADOConnection::UnixTimeStamp($v);
3634 * PEAR DB Compat - do not use internally
3636 function Free() {
3637 return $this->Close();
3642 * PEAR DB compat, number of rows
3644 function NumRows() {
3645 return $this->_numOfRows;
3650 * PEAR DB compat, number of cols
3652 function NumCols() {
3653 return $this->_numOfFields;
3657 * Fetch a row, returning false if no more rows.
3658 * This is PEAR DB compat mode.
3660 * @return false or array containing the current record
3662 function FetchRow() {
3663 if ($this->EOF) {
3664 return false;
3666 $arr = $this->fields;
3667 $this->_currentRow++;
3668 if (!$this->_fetch()) {
3669 $this->EOF = true;
3671 return $arr;
3676 * Fetch a row, returning PEAR_Error if no more rows.
3677 * This is PEAR DB compat mode.
3679 * @return DB_OK or error object
3681 function FetchInto(&$arr) {
3682 if ($this->EOF) {
3683 return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false;
3685 $arr = $this->fields;
3686 $this->MoveNext();
3687 return 1; // DB_OK
3692 * Move to the first row in the recordset. Many databases do NOT support this.
3694 * @return true or false
3696 function MoveFirst() {
3697 if ($this->_currentRow == 0) {
3698 return true;
3700 return $this->Move(0);
3705 * Move to the last row in the recordset.
3707 * @return true or false
3709 function MoveLast() {
3710 if ($this->_numOfRows >= 0) {
3711 return $this->Move($this->_numOfRows-1);
3713 if ($this->EOF) {
3714 return false;
3716 while (!$this->EOF) {
3717 $f = $this->fields;
3718 $this->MoveNext();
3720 $this->fields = $f;
3721 $this->EOF = false;
3722 return true;
3727 * Move to next record in the recordset.
3729 * @return true if there still rows available, or false if there are no more rows (EOF).
3731 function MoveNext() {
3732 if (!$this->EOF) {
3733 $this->_currentRow++;
3734 if ($this->_fetch()) {
3735 return true;
3738 $this->EOF = true;
3739 /* -- tested error handling when scrolling cursor -- seems useless.
3740 $conn = $this->connection;
3741 if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
3742 $fn = $conn->raiseErrorFn;
3743 $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
3746 return false;
3751 * Random access to a specific row in the recordset. Some databases do not support
3752 * access to previous rows in the databases (no scrolling backwards).
3754 * @param rowNumber is the row to move to (0-based)
3756 * @return true if there still rows available, or false if there are no more rows (EOF).
3758 function Move($rowNumber = 0) {
3759 $this->EOF = false;
3760 if ($rowNumber == $this->_currentRow) {
3761 return true;
3763 if ($rowNumber >= $this->_numOfRows) {
3764 if ($this->_numOfRows != -1) {
3765 $rowNumber = $this->_numOfRows-2;
3769 if ($rowNumber < 0) {
3770 $this->EOF = true;
3771 return false;
3774 if ($this->canSeek) {
3775 if ($this->_seek($rowNumber)) {
3776 $this->_currentRow = $rowNumber;
3777 if ($this->_fetch()) {
3778 return true;
3780 } else {
3781 $this->EOF = true;
3782 return false;
3784 } else {
3785 if ($rowNumber < $this->_currentRow) {
3786 return false;
3788 global $ADODB_EXTENSION;
3789 if ($ADODB_EXTENSION) {
3790 while (!$this->EOF && $this->_currentRow < $rowNumber) {
3791 adodb_movenext($this);
3793 } else {
3794 while (! $this->EOF && $this->_currentRow < $rowNumber) {
3795 $this->_currentRow++;
3797 if (!$this->_fetch()) {
3798 $this->EOF = true;
3802 return !($this->EOF);
3805 $this->fields = false;
3806 $this->EOF = true;
3807 return false;
3812 * Get the value of a field in the current row by column name.
3813 * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
3815 * @param colname is the field to access
3817 * @return the value of $colname column
3819 function Fields($colname) {
3820 return $this->fields[$colname];
3824 * Defines the function to use for table fields case conversion
3825 * depending on ADODB_ASSOC_CASE
3826 * @return string strtolower/strtoupper or false if no conversion needed
3828 protected function AssocCaseConvertFunction($case = ADODB_ASSOC_CASE) {
3829 switch($case) {
3830 case ADODB_ASSOC_CASE_UPPER:
3831 return 'strtoupper';
3832 case ADODB_ASSOC_CASE_LOWER:
3833 return 'strtolower';
3834 case ADODB_ASSOC_CASE_NATIVE:
3835 default:
3836 return false;
3841 * Builds the bind array associating keys to recordset fields
3843 * @param int $upper Case for the array keys, defaults to uppercase
3844 * (see ADODB_ASSOC_CASE_xxx constants)
3846 function GetAssocKeys($upper = ADODB_ASSOC_CASE) {
3847 if ($this->bind) {
3848 return;
3850 $this->bind = array();
3852 // Define case conversion function for ASSOC fetch mode
3853 $fn_change_case = $this->AssocCaseConvertFunction($upper);
3855 // Build the bind array
3856 for ($i=0; $i < $this->_numOfFields; $i++) {
3857 $o = $this->FetchField($i);
3859 // Set the array's key
3860 if(is_numeric($o->name)) {
3861 // Just use the field ID
3862 $key = $i;
3864 elseif( $fn_change_case ) {
3865 // Convert the key's case
3866 $key = $fn_change_case($o->name);
3868 else {
3869 $key = $o->name;
3872 $this->bind[$key] = $i;
3877 * Use associative array to get fields array for databases that do not support
3878 * associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it
3880 * @param int $upper Case for the array keys, defaults to uppercase
3881 * (see ADODB_ASSOC_CASE_xxx constants)
3883 function GetRowAssoc($upper = ADODB_ASSOC_CASE) {
3884 $record = array();
3885 $this->GetAssocKeys($upper);
3887 foreach($this->bind as $k => $v) {
3888 if( array_key_exists( $v, $this->fields ) ) {
3889 $record[$k] = $this->fields[$v];
3890 } elseif( array_key_exists( $k, $this->fields ) ) {
3891 $record[$k] = $this->fields[$k];
3892 } else {
3893 # This should not happen... trigger error ?
3894 $record[$k] = null;
3897 return $record;
3901 * Clean up recordset
3903 * @return true or false
3905 function Close() {
3906 // free connection object - this seems to globally free the object
3907 // and not merely the reference, so don't do this...
3908 // $this->connection = false;
3909 if (!$this->_closed) {
3910 $this->_closed = true;
3911 return $this->_close();
3912 } else
3913 return true;
3917 * synonyms RecordCount and RowCount
3919 * @return the number of rows or -1 if this is not supported
3921 function RecordCount() {
3922 return $this->_numOfRows;
3927 * If we are using PageExecute(), this will return the maximum possible rows
3928 * that can be returned when paging a recordset.
3930 function MaxRecordCount() {
3931 return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();
3935 * synonyms RecordCount and RowCount
3937 * @return the number of rows or -1 if this is not supported
3939 function RowCount() {
3940 return $this->_numOfRows;
3945 * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
3947 * @return the number of records from a previous SELECT. All databases support this.
3949 * But aware possible problems in multiuser environments. For better speed the table
3950 * must be indexed by the condition. Heavy test this before deploying.
3952 function PO_RecordCount($table="", $condition="") {
3954 $lnumrows = $this->_numOfRows;
3955 // the database doesn't support native recordcount, so we do a workaround
3956 if ($lnumrows == -1 && $this->connection) {
3957 IF ($table) {
3958 if ($condition) {
3959 $condition = " WHERE " . $condition;
3961 $resultrows = $this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
3962 if ($resultrows) {
3963 $lnumrows = reset($resultrows->fields);
3967 return $lnumrows;
3972 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
3974 function CurrentRow() {
3975 return $this->_currentRow;
3979 * synonym for CurrentRow -- for ADO compat
3981 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
3983 function AbsolutePosition() {
3984 return $this->_currentRow;
3988 * @return the number of columns in the recordset. Some databases will set this to 0
3989 * if no records are returned, others will return the number of columns in the query.
3991 function FieldCount() {
3992 return $this->_numOfFields;
3997 * Get the ADOFieldObject of a specific column.
3999 * @param fieldoffset is the column position to access(0-based).
4001 * @return the ADOFieldObject for that column, or false.
4003 function FetchField($fieldoffset = -1) {
4004 // must be defined by child class
4006 return false;
4010 * Get the ADOFieldObjects of all columns in an array.
4013 function FieldTypesArray() {
4014 $arr = array();
4015 for ($i=0, $max=$this->_numOfFields; $i < $max; $i++)
4016 $arr[] = $this->FetchField($i);
4017 return $arr;
4021 * Return the fields array of the current row as an object for convenience.
4022 * The default case is lowercase field names.
4024 * @return the object with the properties set to the fields of the current row
4026 function FetchObj() {
4027 $o = $this->FetchObject(false);
4028 return $o;
4032 * Return the fields array of the current row as an object for convenience.
4033 * The default case is uppercase.
4035 * @param $isupper to set the object property names to uppercase
4037 * @return the object with the properties set to the fields of the current row
4039 function FetchObject($isupper=true) {
4040 if (empty($this->_obj)) {
4041 $this->_obj = new ADOFetchObj();
4042 $this->_names = array();
4043 for ($i=0; $i <$this->_numOfFields; $i++) {
4044 $f = $this->FetchField($i);
4045 $this->_names[] = $f->name;
4048 $i = 0;
4049 if (PHP_VERSION >= 5) {
4050 $o = clone($this->_obj);
4051 } else {
4052 $o = $this->_obj;
4055 for ($i=0; $i <$this->_numOfFields; $i++) {
4056 $name = $this->_names[$i];
4057 if ($isupper) {
4058 $n = strtoupper($name);
4059 } else {
4060 $n = $name;
4063 $o->$n = $this->Fields($name);
4065 return $o;
4069 * Return the fields array of the current row as an object for convenience.
4070 * The default is lower-case field names.
4072 * @return the object with the properties set to the fields of the current row,
4073 * or false if EOF
4075 * Fixed bug reported by tim@orotech.net
4077 function FetchNextObj() {
4078 $o = $this->FetchNextObject(false);
4079 return $o;
4084 * Return the fields array of the current row as an object for convenience.
4085 * The default is upper case field names.
4087 * @param $isupper to set the object property names to uppercase
4089 * @return the object with the properties set to the fields of the current row,
4090 * or false if EOF
4092 * Fixed bug reported by tim@orotech.net
4094 function FetchNextObject($isupper=true) {
4095 $o = false;
4096 if ($this->_numOfRows != 0 && !$this->EOF) {
4097 $o = $this->FetchObject($isupper);
4098 $this->_currentRow++;
4099 if ($this->_fetch()) {
4100 return $o;
4103 $this->EOF = true;
4104 return $o;
4108 * Get the metatype of the column. This is used for formatting. This is because
4109 * many databases use different names for the same type, so we transform the original
4110 * type to our standardised version which uses 1 character codes:
4112 * @param t is the type passed in. Normally is ADOFieldObject->type.
4113 * @param len is the maximum length of that field. This is because we treat character
4114 * fields bigger than a certain size as a 'B' (blob).
4115 * @param fieldobj is the field object returned by the database driver. Can hold
4116 * additional info (eg. primary_key for mysql).
4118 * @return the general type of the data:
4119 * C for character < 250 chars
4120 * X for teXt (>= 250 chars)
4121 * B for Binary
4122 * N for numeric or floating point
4123 * D for date
4124 * T for timestamp
4125 * L for logical/Boolean
4126 * I for integer
4127 * R for autoincrement counter/integer
4131 function MetaType($t,$len=-1,$fieldobj=false) {
4132 if (is_object($t)) {
4133 $fieldobj = $t;
4134 $t = $fieldobj->type;
4135 $len = $fieldobj->max_length;
4138 // changed in 2.32 to hashing instead of switch stmt for speed...
4139 static $typeMap = array(
4140 'VARCHAR' => 'C',
4141 'VARCHAR2' => 'C',
4142 'CHAR' => 'C',
4143 'C' => 'C',
4144 'STRING' => 'C',
4145 'NCHAR' => 'C',
4146 'NVARCHAR' => 'C',
4147 'VARYING' => 'C',
4148 'BPCHAR' => 'C',
4149 'CHARACTER' => 'C',
4150 'INTERVAL' => 'C', # Postgres
4151 'MACADDR' => 'C', # postgres
4152 'VAR_STRING' => 'C', # mysql
4154 'LONGCHAR' => 'X',
4155 'TEXT' => 'X',
4156 'NTEXT' => 'X',
4157 'M' => 'X',
4158 'X' => 'X',
4159 'CLOB' => 'X',
4160 'NCLOB' => 'X',
4161 'LVARCHAR' => 'X',
4163 'BLOB' => 'B',
4164 'IMAGE' => 'B',
4165 'BINARY' => 'B',
4166 'VARBINARY' => 'B',
4167 'LONGBINARY' => 'B',
4168 'B' => 'B',
4170 'YEAR' => 'D', // mysql
4171 'DATE' => 'D',
4172 'D' => 'D',
4174 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server
4176 'SMALLDATETIME' => 'T',
4177 'TIME' => 'T',
4178 'TIMESTAMP' => 'T',
4179 'DATETIME' => 'T',
4180 'DATETIME2' => 'T',
4181 'TIMESTAMPTZ' => 'T',
4182 'T' => 'T',
4183 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
4185 'BOOL' => 'L',
4186 'BOOLEAN' => 'L',
4187 'BIT' => 'L',
4188 'L' => 'L',
4190 'COUNTER' => 'R',
4191 'R' => 'R',
4192 'SERIAL' => 'R', // ifx
4193 'INT IDENTITY' => 'R',
4195 'INT' => 'I',
4196 'INT2' => 'I',
4197 'INT4' => 'I',
4198 'INT8' => 'I',
4199 'INTEGER' => 'I',
4200 'INTEGER UNSIGNED' => 'I',
4201 'SHORT' => 'I',
4202 'TINYINT' => 'I',
4203 'SMALLINT' => 'I',
4204 'I' => 'I',
4206 'LONG' => 'N', // interbase is numeric, oci8 is blob
4207 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
4208 'DECIMAL' => 'N',
4209 'DEC' => 'N',
4210 'REAL' => 'N',
4211 'DOUBLE' => 'N',
4212 'DOUBLE PRECISION' => 'N',
4213 'SMALLFLOAT' => 'N',
4214 'FLOAT' => 'N',
4215 'NUMBER' => 'N',
4216 'NUM' => 'N',
4217 'NUMERIC' => 'N',
4218 'MONEY' => 'N',
4220 ## informix 9.2
4221 'SQLINT' => 'I',
4222 'SQLSERIAL' => 'I',
4223 'SQLSMINT' => 'I',
4224 'SQLSMFLOAT' => 'N',
4225 'SQLFLOAT' => 'N',
4226 'SQLMONEY' => 'N',
4227 'SQLDECIMAL' => 'N',
4228 'SQLDATE' => 'D',
4229 'SQLVCHAR' => 'C',
4230 'SQLCHAR' => 'C',
4231 'SQLDTIME' => 'T',
4232 'SQLINTERVAL' => 'N',
4233 'SQLBYTES' => 'B',
4234 'SQLTEXT' => 'X',
4235 ## informix 10
4236 "SQLINT8" => 'I8',
4237 "SQLSERIAL8" => 'I8',
4238 "SQLNCHAR" => 'C',
4239 "SQLNVCHAR" => 'C',
4240 "SQLLVARCHAR" => 'X',
4241 "SQLBOOL" => 'L'
4244 $tmap = false;
4245 $t = strtoupper($t);
4246 $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N';
4247 switch ($tmap) {
4248 case 'C':
4249 // is the char field is too long, return as text field...
4250 if ($this->blobSize >= 0) {
4251 if ($len > $this->blobSize) {
4252 return 'X';
4254 } else if ($len > 250) {
4255 return 'X';
4257 return 'C';
4259 case 'I':
4260 if (!empty($fieldobj->primary_key)) {
4261 return 'R';
4263 return 'I';
4265 case false:
4266 return 'N';
4268 case 'B':
4269 if (isset($fieldobj->binary)) {
4270 return ($fieldobj->binary) ? 'B' : 'X';
4272 return 'B';
4274 case 'D':
4275 if (!empty($this->connection) && !empty($this->connection->datetime)) {
4276 return 'T';
4278 return 'D';
4280 default:
4281 if ($t == 'LONG' && $this->dataProvider == 'oci8') {
4282 return 'B';
4284 return $tmap;
4289 * Convert case of field names associative array, if needed
4290 * @return void
4292 protected function _updatefields()
4294 if( empty($this->fields)) {
4295 return;
4298 // Determine case conversion function
4299 $fn_change_case = $this->AssocCaseConvertFunction();
4300 if(!$fn_change_case) {
4301 // No conversion needed
4302 return;
4305 $arr = array();
4307 // Change the case
4308 foreach($this->fields as $k => $v) {
4309 if (!is_integer($k)) {
4310 $k = $fn_change_case($k);
4312 $arr[$k] = $v;
4314 $this->fields = $arr;
4317 function _close() {}
4320 * set/returns the current recordset page when paginating
4322 function AbsolutePage($page=-1) {
4323 if ($page != -1) {
4324 $this->_currentPage = $page;
4326 return $this->_currentPage;
4330 * set/returns the status of the atFirstPage flag when paginating
4332 function AtFirstPage($status=false) {
4333 if ($status != false) {
4334 $this->_atFirstPage = $status;
4336 return $this->_atFirstPage;
4339 function LastPageNo($page = false) {
4340 if ($page != false) {
4341 $this->_lastPageNo = $page;
4343 return $this->_lastPageNo;
4347 * set/returns the status of the atLastPage flag when paginating
4349 function AtLastPage($status=false) {
4350 if ($status != false) {
4351 $this->_atLastPage = $status;
4353 return $this->_atLastPage;
4356 } // end class ADORecordSet
4358 //==============================================================================================
4359 // CLASS ADORecordSet_array
4360 //==============================================================================================
4363 * This class encapsulates the concept of a recordset created in memory
4364 * as an array. This is useful for the creation of cached recordsets.
4366 * Note that the constructor is different from the standard ADORecordSet
4368 class ADORecordSet_array extends ADORecordSet
4370 var $databaseType = 'array';
4372 var $_array; // holds the 2-dimensional data array
4373 var $_types; // the array of types of each column (C B I L M)
4374 var $_colnames; // names of each column in array
4375 var $_skiprow1; // skip 1st row because it holds column names
4376 var $_fieldobjects; // holds array of field objects
4377 var $canSeek = true;
4378 var $affectedrows = false;
4379 var $insertid = false;
4380 var $sql = '';
4381 var $compat = false;
4384 * Constructor
4386 function __construct($fakeid=1) {
4387 global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;
4389 // fetch() on EOF does not delete $this->fields
4390 $this->compat = !empty($ADODB_COMPAT_FETCH);
4391 parent::__construct($fakeid); // fake queryID
4392 $this->fetchMode = $ADODB_FETCH_MODE;
4395 function _transpose($addfieldnames=true) {
4396 global $ADODB_INCLUDED_LIB;
4398 if (empty($ADODB_INCLUDED_LIB)) {
4399 include(ADODB_DIR.'/adodb-lib.inc.php');
4401 $hdr = true;
4403 $fobjs = $addfieldnames ? $this->_fieldobjects : false;
4404 adodb_transpose($this->_array, $newarr, $hdr, $fobjs);
4405 //adodb_pr($newarr);
4407 $this->_skiprow1 = false;
4408 $this->_array = $newarr;
4409 $this->_colnames = $hdr;
4411 adodb_probetypes($newarr,$this->_types);
4413 $this->_fieldobjects = array();
4415 foreach($hdr as $k => $name) {
4416 $f = new ADOFieldObject();
4417 $f->name = $name;
4418 $f->type = $this->_types[$k];
4419 $f->max_length = -1;
4420 $this->_fieldobjects[] = $f;
4422 $this->fields = reset($this->_array);
4424 $this->_initrs();
4429 * Setup the array.
4431 * @param array is a 2-dimensional array holding the data.
4432 * The first row should hold the column names
4433 * unless paramter $colnames is used.
4434 * @param typearr holds an array of types. These are the same types
4435 * used in MetaTypes (C,B,L,I,N).
4436 * @param [colnames] array of column names. If set, then the first row of
4437 * $array should not hold the column names.
4439 function InitArray($array,$typearr,$colnames=false) {
4440 $this->_array = $array;
4441 $this->_types = $typearr;
4442 if ($colnames) {
4443 $this->_skiprow1 = false;
4444 $this->_colnames = $colnames;
4445 } else {
4446 $this->_skiprow1 = true;
4447 $this->_colnames = $array[0];
4449 $this->Init();
4452 * Setup the Array and datatype file objects
4454 * @param array is a 2-dimensional array holding the data.
4455 * The first row should hold the column names
4456 * unless paramter $colnames is used.
4457 * @param fieldarr holds an array of ADOFieldObject's.
4459 function InitArrayFields(&$array,&$fieldarr) {
4460 $this->_array = $array;
4461 $this->_skiprow1= false;
4462 if ($fieldarr) {
4463 $this->_fieldobjects = $fieldarr;
4465 $this->Init();
4468 function GetArray($nRows=-1) {
4469 if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) {
4470 return $this->_array;
4471 } else {
4472 $arr = ADORecordSet::GetArray($nRows);
4473 return $arr;
4477 function _initrs() {
4478 $this->_numOfRows = sizeof($this->_array);
4479 if ($this->_skiprow1) {
4480 $this->_numOfRows -= 1;
4483 $this->_numOfFields = (isset($this->_fieldobjects))
4484 ? sizeof($this->_fieldobjects)
4485 : sizeof($this->_types);
4488 /* Use associative array to get fields array */
4489 function Fields($colname) {
4490 $mode = isset($this->adodbFetchMode) ? $this->adodbFetchMode : $this->fetchMode;
4492 if ($mode & ADODB_FETCH_ASSOC) {
4493 if (!isset($this->fields[$colname]) && !is_null($this->fields[$colname])) {
4494 $colname = strtolower($colname);
4496 return $this->fields[$colname];
4498 if (!$this->bind) {
4499 $this->bind = array();
4500 for ($i=0; $i < $this->_numOfFields; $i++) {
4501 $o = $this->FetchField($i);
4502 $this->bind[strtoupper($o->name)] = $i;
4505 return $this->fields[$this->bind[strtoupper($colname)]];
4508 function FetchField($fieldOffset = -1) {
4509 if (isset($this->_fieldobjects)) {
4510 return $this->_fieldobjects[$fieldOffset];
4512 $o = new ADOFieldObject();
4513 $o->name = $this->_colnames[$fieldOffset];
4514 $o->type = $this->_types[$fieldOffset];
4515 $o->max_length = -1; // length not known
4517 return $o;
4520 function _seek($row) {
4521 if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) {
4522 $this->_currentRow = $row;
4523 if ($this->_skiprow1) {
4524 $row += 1;
4526 $this->fields = $this->_array[$row];
4527 return true;
4529 return false;
4532 function MoveNext() {
4533 if (!$this->EOF) {
4534 $this->_currentRow++;
4536 $pos = $this->_currentRow;
4538 if ($this->_numOfRows <= $pos) {
4539 if (!$this->compat) {
4540 $this->fields = false;
4542 } else {
4543 if ($this->_skiprow1) {
4544 $pos += 1;
4546 $this->fields = $this->_array[$pos];
4547 return true;
4549 $this->EOF = true;
4552 return false;
4555 function _fetch() {
4556 $pos = $this->_currentRow;
4558 if ($this->_numOfRows <= $pos) {
4559 if (!$this->compat) {
4560 $this->fields = false;
4562 return false;
4564 if ($this->_skiprow1) {
4565 $pos += 1;
4567 $this->fields = $this->_array[$pos];
4568 return true;
4571 function _close() {
4572 return true;
4575 } // ADORecordSet_array
4577 //==============================================================================================
4578 // HELPER FUNCTIONS
4579 //==============================================================================================
4582 * Synonym for ADOLoadCode. Private function. Do not use.
4584 * @deprecated
4586 function ADOLoadDB($dbType) {
4587 return ADOLoadCode($dbType);
4591 * Load the code for a specific database driver. Private function. Do not use.
4593 function ADOLoadCode($dbType) {
4594 global $ADODB_LASTDB;
4596 if (!$dbType) {
4597 return false;
4599 $db = strtolower($dbType);
4600 switch ($db) {
4601 case 'ado':
4602 if (PHP_VERSION >= 5) {
4603 $db = 'ado5';
4605 $class = 'ado';
4606 break;
4608 case 'ifx':
4609 case 'maxsql':
4610 $class = $db = 'mysqlt';
4611 break;
4613 case 'pgsql':
4614 case 'postgres':
4615 $class = $db = 'postgres8';
4616 break;
4618 default:
4619 $class = $db; break;
4622 $file = ADODB_DIR."/drivers/adodb-".$db.".inc.php";
4623 @include_once($file);
4624 $ADODB_LASTDB = $class;
4625 if (class_exists("ADODB_" . $class)) {
4626 return $class;
4629 //ADOConnection::outp(adodb_pr(get_declared_classes(),true));
4630 if (!file_exists($file)) {
4631 ADOConnection::outp("Missing file: $file");
4632 } else {
4633 ADOConnection::outp("Syntax error in file: $file");
4635 return false;
4639 * synonym for ADONewConnection for people like me who cannot remember the correct name
4641 function NewADOConnection($db='') {
4642 $tmp = ADONewConnection($db);
4643 return $tmp;
4647 * Instantiate a new Connection class for a specific database driver.
4649 * @param [db] is the database Connection object to create. If undefined,
4650 * use the last database driver that was loaded by ADOLoadCode().
4652 * @return the freshly created instance of the Connection class.
4654 function ADONewConnection($db='') {
4655 global $ADODB_NEWCONNECTION, $ADODB_LASTDB;
4657 if (!defined('ADODB_ASSOC_CASE')) {
4658 define('ADODB_ASSOC_CASE', ADODB_ASSOC_CASE_NATIVE);
4660 $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false;
4661 if (($at = strpos($db,'://')) !== FALSE) {
4662 $origdsn = $db;
4663 $fakedsn = 'fake'.substr($origdsn,$at);
4664 if (($at2 = strpos($origdsn,'@/')) !== FALSE) {
4665 // special handling of oracle, which might not have host
4666 $fakedsn = str_replace('@/','@adodb-fakehost/',$fakedsn);
4669 if ((strpos($origdsn, 'sqlite')) !== FALSE && stripos($origdsn, '%2F') === FALSE) {
4670 // special handling for SQLite, it only might have the path to the database file.
4671 // If you try to connect to a SQLite database using a dsn
4672 // like 'sqlite:///path/to/database', the 'parse_url' php function
4673 // will throw you an exception with a message such as "unable to parse url"
4674 list($scheme, $path) = explode('://', $origdsn);
4675 $dsna['scheme'] = $scheme;
4676 if ($qmark = strpos($path,'?')) {
4677 $dsn['query'] = substr($path,$qmark+1);
4678 $path = substr($path,0,$qmark);
4680 $dsna['path'] = '/' . urlencode($path);
4681 } else
4682 $dsna = @parse_url($fakedsn);
4684 if (!$dsna) {
4685 return false;
4687 $dsna['scheme'] = substr($origdsn,0,$at);
4688 if ($at2 !== FALSE) {
4689 $dsna['host'] = '';
4692 if (strncmp($origdsn,'pdo',3) == 0) {
4693 $sch = explode('_',$dsna['scheme']);
4694 if (sizeof($sch)>1) {
4695 $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : '';
4696 if ($sch[1] == 'sqlite') {
4697 $dsna['host'] = rawurlencode($sch[1].':'.rawurldecode($dsna['host']));
4698 } else {
4699 $dsna['host'] = rawurlencode($sch[1].':host='.rawurldecode($dsna['host']));
4701 $dsna['scheme'] = 'pdo';
4705 $db = @$dsna['scheme'];
4706 if (!$db) {
4707 return false;
4709 $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : '';
4710 $dsna['user'] = isset($dsna['user']) ? rawurldecode($dsna['user']) : '';
4711 $dsna['pass'] = isset($dsna['pass']) ? rawurldecode($dsna['pass']) : '';
4712 $dsna['path'] = isset($dsna['path']) ? rawurldecode(substr($dsna['path'],1)) : ''; # strip off initial /
4714 if (isset($dsna['query'])) {
4715 $opt1 = explode('&',$dsna['query']);
4716 foreach($opt1 as $k => $v) {
4717 $arr = explode('=',$v);
4718 $opt[$arr[0]] = isset($arr[1]) ? rawurldecode($arr[1]) : 1;
4720 } else {
4721 $opt = array();
4725 * phptype: Database backend used in PHP (mysql, odbc etc.)
4726 * dbsyntax: Database used with regards to SQL syntax etc.
4727 * protocol: Communication protocol to use (tcp, unix etc.)
4728 * hostspec: Host specification (hostname[:port])
4729 * database: Database to use on the DBMS server
4730 * username: User name for login
4731 * password: Password for login
4733 if (!empty($ADODB_NEWCONNECTION)) {
4734 $obj = $ADODB_NEWCONNECTION($db);
4738 if(empty($obj)) {
4740 if (!isset($ADODB_LASTDB)) {
4741 $ADODB_LASTDB = '';
4743 if (empty($db)) {
4744 $db = $ADODB_LASTDB;
4746 if ($db != $ADODB_LASTDB) {
4747 $db = ADOLoadCode($db);
4750 if (!$db) {
4751 if (isset($origdsn)) {
4752 $db = $origdsn;
4754 if ($errorfn) {
4755 // raise an error
4756 $ignore = false;
4757 $errorfn('ADONewConnection', 'ADONewConnection', -998,
4758 "could not load the database driver for '$db'",
4759 $db,false,$ignore);
4760 } else {
4761 ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false);
4763 return false;
4766 $cls = 'ADODB_'.$db;
4767 if (!class_exists($cls)) {
4768 adodb_backtrace();
4769 return false;
4772 $obj = new $cls();
4775 # constructor should not fail
4776 if ($obj) {
4777 if ($errorfn) {
4778 $obj->raiseErrorFn = $errorfn;
4780 if (isset($dsna)) {
4781 if (isset($dsna['port'])) {
4782 $obj->port = $dsna['port'];
4784 foreach($opt as $k => $v) {
4785 switch(strtolower($k)) {
4786 case 'new':
4787 $nconnect = true; $persist = true; break;
4788 case 'persist':
4789 case 'persistent': $persist = $v; break;
4790 case 'debug': $obj->debug = (integer) $v; break;
4791 #ibase
4792 case 'role': $obj->role = $v; break;
4793 case 'dialect': $obj->dialect = (integer) $v; break;
4794 case 'charset': $obj->charset = $v; $obj->charSet=$v; break;
4795 case 'buffers': $obj->buffers = $v; break;
4796 case 'fetchmode': $obj->SetFetchMode($v); break;
4797 #ado
4798 case 'charpage': $obj->charPage = $v; break;
4799 #mysql, mysqli
4800 case 'clientflags': $obj->clientFlags = $v; break;
4801 #mysql, mysqli, postgres
4802 case 'port': $obj->port = $v; break;
4803 #mysqli
4804 case 'socket': $obj->socket = $v; break;
4805 #oci8
4806 case 'nls_date_format': $obj->NLS_DATE_FORMAT = $v; break;
4807 case 'cachesecs': $obj->cacheSecs = $v; break;
4808 case 'memcache':
4809 $varr = explode(':',$v);
4810 $vlen = sizeof($varr);
4811 if ($vlen == 0) {
4812 break;
4814 $obj->memCache = true;
4815 $obj->memCacheHost = explode(',',$varr[0]);
4816 if ($vlen == 1) {
4817 break;
4819 $obj->memCachePort = $varr[1];
4820 if ($vlen == 2) {
4821 break;
4823 $obj->memCacheCompress = $varr[2] ? true : false;
4824 break;
4827 if (empty($persist)) {
4828 $ok = $obj->Connect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4829 } else if (empty($nconnect)) {
4830 $ok = $obj->PConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4831 } else {
4832 $ok = $obj->NConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4835 if (!$ok) {
4836 return false;
4840 return $obj;
4845 // $perf == true means called by NewPerfMonitor(), otherwise for data dictionary
4846 function _adodb_getdriver($provider,$drivername,$perf=false) {
4847 switch ($provider) {
4848 case 'odbtp':
4849 if (strncmp('odbtp_',$drivername,6)==0) {
4850 return substr($drivername,6);
4852 case 'odbc' :
4853 if (strncmp('odbc_',$drivername,5)==0) {
4854 return substr($drivername,5);
4856 case 'ado' :
4857 if (strncmp('ado_',$drivername,4)==0) {
4858 return substr($drivername,4);
4860 case 'native':
4861 break;
4862 default:
4863 return $provider;
4866 switch($drivername) {
4867 case 'mysqlt':
4868 case 'mysqli':
4869 $drivername='mysql';
4870 break;
4871 case 'postgres7':
4872 case 'postgres8':
4873 $drivername = 'postgres';
4874 break;
4875 case 'firebird15':
4876 $drivername = 'firebird';
4877 break;
4878 case 'oracle':
4879 $drivername = 'oci8';
4880 break;
4881 case 'access':
4882 if ($perf) {
4883 $drivername = '';
4885 break;
4886 case 'db2' :
4887 case 'sapdb' :
4888 break;
4889 default:
4890 $drivername = 'generic';
4891 break;
4893 return $drivername;
4896 function NewPerfMonitor(&$conn) {
4897 $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType,true);
4898 if (!$drivername || $drivername == 'generic') {
4899 return false;
4901 include_once(ADODB_DIR.'/adodb-perf.inc.php');
4902 @include_once(ADODB_DIR."/perf/perf-$drivername.inc.php");
4903 $class = "Perf_$drivername";
4904 if (!class_exists($class)) {
4905 return false;
4907 $perf = new $class($conn);
4909 return $perf;
4912 function NewDataDictionary(&$conn,$drivername=false) {
4913 if (!$drivername) {
4914 $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType);
4917 include_once(ADODB_DIR.'/adodb-lib.inc.php');
4918 include_once(ADODB_DIR.'/adodb-datadict.inc.php');
4919 $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php";
4921 if (!file_exists($path)) {
4922 ADOConnection::outp("Dictionary driver '$path' not available");
4923 return false;
4925 include_once($path);
4926 $class = "ADODB2_$drivername";
4927 $dict = new $class();
4928 $dict->dataProvider = $conn->dataProvider;
4929 $dict->connection = $conn;
4930 $dict->upperName = strtoupper($drivername);
4931 $dict->quote = $conn->nameQuote;
4932 if (!empty($conn->_connectionID)) {
4933 $dict->serverInfo = $conn->ServerInfo();
4936 return $dict;
4942 Perform a print_r, with pre tags for better formatting.
4944 function adodb_pr($var,$as_string=false) {
4945 if ($as_string) {
4946 ob_start();
4949 if (isset($_SERVER['HTTP_USER_AGENT'])) {
4950 echo " <pre>\n";print_r($var);echo "</pre>\n";
4951 } else {
4952 print_r($var);
4955 if ($as_string) {
4956 $s = ob_get_contents();
4957 ob_end_clean();
4958 return $s;
4963 Perform a stack-crawl and pretty print it.
4965 @param printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then).
4966 @param levels Number of levels to display
4968 function adodb_backtrace($printOrArr=true,$levels=9999,$ishtml=null) {
4969 global $ADODB_INCLUDED_LIB;
4970 if (empty($ADODB_INCLUDED_LIB)) {
4971 include(ADODB_DIR.'/adodb-lib.inc.php');
4973 return _adodb_backtrace($printOrArr,$levels,0,$ishtml);