[!!!][TASK] Doctrine: Remove ext:dbal
[Packages/TYPO3.CMS.git] / typo3 / sysext / adodb / adodb / adodb.inc.php
1 <?php
2 /*
3 * Set tabs to 4 for best viewing.
4 *
5 * Latest version is available at http://adodb.sourceforge.net
6 *
7 * This is the main include file for ADOdb.
8 * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php
9 *
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/
12 */
13
14 /**
15 \mainpage
16
17 @version v5.20.3 01-Jan-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
20
21 Released under both BSD license and Lesser GPL library license. You can choose which license
22 you prefer.
23
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.
27
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.
32
33 Latest Download at http://adodb.sourceforge.net/
34
35 */
36
37 if (!defined('_ADODB_LAYER')) {
38 define('_ADODB_LAYER',1);
39
40 //==============================================================================================
41 // CONSTANT DEFINITIONS
42 //==============================================================================================
43
44
45 /**
46 * Set ADODB_DIR to the directory where this file resides...
47 * This constant was formerly called $ADODB_RootPath
48 */
49 if (!defined('ADODB_DIR')) {
50 define('ADODB_DIR',dirname(__FILE__));
51 }
52
53 //==============================================================================================
54 // GLOBAL VARIABLES
55 //==============================================================================================
56
57 GLOBAL
58 $ADODB_vers, // database version
59 $ADODB_COUNTRECS, // count number of records returned - slows down query
60 $ADODB_CACHE_DIR, // directory to cache recordsets
61 $ADODB_CACHE,
62 $ADODB_CACHE_CLASS,
63 $ADODB_EXTENSION, // ADODB extension installed
64 $ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF
65 $ADODB_FETCH_MODE, // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...
66 $ADODB_GETONE_EOF,
67 $ADODB_QUOTE_FIELDNAMES; // Allows you to force quotes (backticks) around field names in queries generated by getinsertsql and getupdatesql.
68
69 //==============================================================================================
70 // GLOBAL SETUP
71 //==============================================================================================
72
73 $ADODB_EXTENSION = defined('ADODB_EXTENSION');
74
75 // ********************************************************
76 // Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).
77 // Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi
78 //
79 // 0 = ignore empty fields. All empty fields in array are ignored.
80 // 1 = force null. All empty, php null and string 'null' fields are changed to sql NULL values.
81 // 2 = force empty. All empty, php null and string 'null' fields are changed to sql empty '' or 0 values.
82 // 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.
83
84 define('ADODB_FORCE_IGNORE',0);
85 define('ADODB_FORCE_NULL',1);
86 define('ADODB_FORCE_EMPTY',2);
87 define('ADODB_FORCE_VALUE',3);
88 // ********************************************************
89
90
91 if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) {
92
93 define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');
94
95 // allow [ ] @ ` " and . in table names
96 define('ADODB_TABLE_REGEX','([]0-9a-z_\:\"\`\.\@\[-]*)');
97
98 // prefetching used by oracle
99 if (!defined('ADODB_PREFETCH_ROWS')) {
100 define('ADODB_PREFETCH_ROWS',10);
101 }
102
103
104 /**
105 * Fetch mode
106 *
107 * Set global variable $ADODB_FETCH_MODE to one of these constants or use
108 * the SetFetchMode() method to control how recordset fields are returned
109 * when fetching data.
110 *
111 * - NUM: array()
112 * - ASSOC: array('id' => 456, 'name' => 'john')
113 * - BOTH: array(0 => 456, 'id' => 456, 1 => 'john', 'name' => 'john')
114 * - DEFAULT: driver-dependent
115 */
116 define('ADODB_FETCH_DEFAULT', 0);
117 define('ADODB_FETCH_NUM', 1);
118 define('ADODB_FETCH_ASSOC', 2);
119 define('ADODB_FETCH_BOTH', 3);
120
121 /**
122 * Associative array case constants
123 *
124 * By defining the ADODB_ASSOC_CASE constant to one of these values, it is
125 * possible to control the case of field names (associative array's keys)
126 * when operating in ADODB_FETCH_ASSOC fetch mode.
127 * - LOWER: $rs->fields['orderid']
128 * - UPPER: $rs->fields['ORDERID']
129 * - NATIVE: $rs->fields['OrderID'] (or whatever the RDBMS will return)
130 *
131 * The default is to use native case-names.
132 *
133 * NOTE: This functionality is not implemented everywhere, it currently
134 * works only with: mssql, odbc, oci8 and ibase derived drivers
135 */
136 define('ADODB_ASSOC_CASE_LOWER', 0);
137 define('ADODB_ASSOC_CASE_UPPER', 1);
138 define('ADODB_ASSOC_CASE_NATIVE', 2);
139
140
141 if (!defined('TIMESTAMP_FIRST_YEAR')) {
142 define('TIMESTAMP_FIRST_YEAR',100);
143 }
144
145 /**
146 * AutoExecute constants
147 * (moved from adodb-pear.inc.php since they are only used in here)
148 */
149 define('DB_AUTOQUERY_INSERT', 1);
150 define('DB_AUTOQUERY_UPDATE', 2);
151
152
153 // PHP's version scheme makes converting to numbers difficult - workaround
154 $_adodb_ver = (float) PHP_VERSION;
155 if ($_adodb_ver >= 5.2) {
156 define('ADODB_PHPVER',0x5200);
157 } else if ($_adodb_ver >= 5.0) {
158 define('ADODB_PHPVER',0x5000);
159 } else {
160 die("PHP5 or later required. You are running ".PHP_VERSION);
161 }
162 unset($_adodb_ver);
163 }
164
165
166 /**
167 Accepts $src and $dest arrays, replacing string $data
168 */
169 function ADODB_str_replace($src, $dest, $data) {
170 if (ADODB_PHPVER >= 0x4050) {
171 return str_replace($src,$dest,$data);
172 }
173
174 $s = reset($src);
175 $d = reset($dest);
176 while ($s !== false) {
177 $data = str_replace($s,$d,$data);
178 $s = next($src);
179 $d = next($dest);
180 }
181 return $data;
182 }
183
184 function ADODB_Setup() {
185 GLOBAL
186 $ADODB_vers, // database version
187 $ADODB_COUNTRECS, // count number of records returned - slows down query
188 $ADODB_CACHE_DIR, // directory to cache recordsets
189 $ADODB_FETCH_MODE,
190 $ADODB_CACHE,
191 $ADODB_CACHE_CLASS,
192 $ADODB_FORCE_TYPE,
193 $ADODB_GETONE_EOF,
194 $ADODB_QUOTE_FIELDNAMES;
195
196 if (empty($ADODB_CACHE_CLASS)) {
197 $ADODB_CACHE_CLASS = 'ADODB_Cache_File' ;
198 }
199 $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
200 $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE;
201 $ADODB_GETONE_EOF = null;
202
203 if (!isset($ADODB_CACHE_DIR)) {
204 $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp';
205 } else {
206 // do not accept url based paths, eg. http:/ or ftp:/
207 if (strpos($ADODB_CACHE_DIR,'://') !== false) {
208 die("Illegal path http:// or ftp://");
209 }
210 }
211
212
213 // Initialize random number generator for randomizing cache flushes
214 // -- note Since PHP 4.2.0, the seed becomes optional and defaults to a random value if omitted.
215 srand(((double)microtime())*1000000);
216
217 /**
218 * ADODB version as a string.
219 */
220 $ADODB_vers = 'v5.20.3 01-Jan-2016';
221
222 /**
223 * Determines whether recordset->RecordCount() is used.
224 * Set to false for highest performance -- RecordCount() will always return -1 then
225 * for databases that provide "virtual" recordcounts...
226 */
227 if (!isset($ADODB_COUNTRECS)) {
228 $ADODB_COUNTRECS = true;
229 }
230 }
231
232
233 //==============================================================================================
234 // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB
235 //==============================================================================================
236
237 ADODB_Setup();
238
239 //==============================================================================================
240 // CLASS ADOFieldObject
241 //==============================================================================================
242 /**
243 * Helper class for FetchFields -- holds info on a column
244 */
245 class ADOFieldObject {
246 var $name = '';
247 var $max_length=0;
248 var $type="";
249 /*
250 // additional fields by dannym... (danny_milo@yahoo.com)
251 var $not_null = false;
252 // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^
253 // so we can as well make not_null standard (leaving it at "false" does not harm anyways)
254
255 var $has_default = false; // this one I have done only in mysql and postgres for now ...
256 // others to come (dannym)
257 var $default_value; // default, if any, and supported. Check has_default first.
258 */
259 }
260
261
262 function _adodb_safedate($s) {
263 return str_replace(array("'", '\\'), '', $s);
264 }
265
266 // parse date string to prevent injection attack
267 // date string will have one quote at beginning e.g. '3434343'
268 function _adodb_safedateq($s) {
269 $len = strlen($s);
270 if ($s[0] !== "'") {
271 $s2 = "'".$s[0];
272 } else {
273 $s2 = "'";
274 }
275 for($i=1; $i<$len; $i++) {
276 $ch = $s[$i];
277 if ($ch === '\\') {
278 $s2 .= "'";
279 break;
280 } elseif ($ch === "'") {
281 $s2 .= $ch;
282 break;
283 }
284
285 $s2 .= $ch;
286 }
287
288 return strlen($s2) == 0 ? 'null' : $s2;
289 }
290
291
292 // for transaction handling
293
294 function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection) {
295 //print "Errorno ($fn errno=$errno m=$errmsg) ";
296 $thisConnection->_transOK = false;
297 if ($thisConnection->_oldRaiseFn) {
298 $fn = $thisConnection->_oldRaiseFn;
299 $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
300 }
301 }
302
303 //------------------
304 // class for caching
305 class ADODB_Cache_File {
306
307 var $createdir = true; // requires creation of temp dirs
308
309 function __construct() {
310 global $ADODB_INCLUDED_CSV;
311 if (empty($ADODB_INCLUDED_CSV)) {
312 include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
313 }
314 }
315
316 // write serialised recordset to cache item/file
317 function writecache($filename, $contents, $debug, $secs2cache) {
318 return adodb_write_file($filename, $contents,$debug);
319 }
320
321 // load serialised recordset and unserialise it
322 function &readcache($filename, &$err, $secs2cache, $rsClass) {
323 $rs = csv2rs($filename,$err,$secs2cache,$rsClass);
324 return $rs;
325 }
326
327 // flush all items in cache
328 function flushall($debug=false) {
329 global $ADODB_CACHE_DIR;
330
331 $rez = false;
332
333 if (strlen($ADODB_CACHE_DIR) > 1) {
334 $rez = $this->_dirFlush($ADODB_CACHE_DIR);
335 if ($debug) {
336 ADOConnection::outp( "flushall: $ADODB_CACHE_DIR<br><pre>\n". $rez."</pre>");
337 }
338 }
339 return $rez;
340 }
341
342 // flush one file in cache
343 function flushcache($f, $debug=false) {
344 if (!@unlink($f)) {
345 if ($debug) {
346 ADOConnection::outp( "flushcache: failed for $f");
347 }
348 }
349 }
350
351 function getdirname($hash) {
352 global $ADODB_CACHE_DIR;
353 if (!isset($this->notSafeMode)) {
354 $this->notSafeMode = !ini_get('safe_mode');
355 }
356 return ($this->notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($hash,0,2) : $ADODB_CACHE_DIR;
357 }
358
359 // create temp directories
360 function createdir($hash, $debug) {
361 global $ADODB_CACHE_PERMS;
362
363 $dir = $this->getdirname($hash);
364 if ($this->notSafeMode && !file_exists($dir)) {
365 $oldu = umask(0);
366 if (!@mkdir($dir, empty($ADODB_CACHE_PERMS) ? 0771 : $ADODB_CACHE_PERMS)) {
367 if(!is_dir($dir) && $debug) {
368 ADOConnection::outp("Cannot create $dir");
369 }
370 }
371 umask($oldu);
372 }
373
374 return $dir;
375 }
376
377 /**
378 * Private function to erase all of the files and subdirectories in a directory.
379 *
380 * Just specify the directory, and tell it if you want to delete the directory or just clear it out.
381 * Note: $kill_top_level is used internally in the function to flush subdirectories.
382 */
383 function _dirFlush($dir, $kill_top_level = false) {
384 if(!$dh = @opendir($dir)) return;
385
386 while (($obj = readdir($dh))) {
387 if($obj=='.' || $obj=='..') continue;
388 $f = $dir.'/'.$obj;
389
390 if (strpos($obj,'.cache')) {
391 @unlink($f);
392 }
393 if (is_dir($f)) {
394 $this->_dirFlush($f, true);
395 }
396 }
397 if ($kill_top_level === true) {
398 @rmdir($dir);
399 }
400 return true;
401 }
402 }
403
404 //==============================================================================================
405 // CLASS ADOConnection
406 //==============================================================================================
407
408 /**
409 * Connection object. For connecting to databases, and executing queries.
410 */
411 abstract class ADOConnection {
412 //
413 // PUBLIC VARS
414 //
415 var $dataProvider = 'native';
416 var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql
417 var $database = ''; /// Name of database to be used.
418 var $host = ''; /// The hostname of the database server
419 var $user = ''; /// The username which is used to connect to the database server.
420 var $password = ''; /// Password for the username. For security, we no longer store it.
421 var $debug = false; /// if set to true will output sql statements
422 var $maxblobsize = 262144; /// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxpro
423 var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase
424 var $substr = 'substr'; /// substring operator
425 var $length = 'length'; /// string length ofperator
426 var $random = 'rand()'; /// random function
427 var $upperCase = 'upper'; /// uppercase function
428 var $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the database
429 var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt.
430 var $true = '1'; /// string that represents TRUE for a database
431 var $false = '0'; /// string that represents FALSE for a database
432 var $replaceQuote = "\\'"; /// string to use to replace quotes
433 var $nameQuote = '"'; /// string to use to quote identifiers and names
434 var $charSet=false; /// character set to use - only for interbase, postgres and oci8
435 var $metaDatabasesSQL = '';
436 var $metaTablesSQL = '';
437 var $uniqueOrderBy = false; /// All order by columns have to be unique
438 var $emptyDate = '&nbsp;';
439 var $emptyTimeStamp = '&nbsp;';
440 var $lastInsID = false;
441 //--
442 var $hasInsertID = false; /// supports autoincrement ID?
443 var $hasAffectedRows = false; /// supports affected rows for update/delete?
444 var $hasTop = false; /// support mssql/access SELECT TOP 10 * FROM TABLE
445 var $hasLimit = false; /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10
446 var $readOnly = false; /// this is a readonly database - used by phpLens
447 var $hasMoveFirst = false; /// has ability to run MoveFirst(), scrolling backwards
448 var $hasGenID = false; /// can generate sequences using GenID();
449 var $hasTransactions = true; /// has transactions
450 //--
451 var $genID = 0; /// sequence id used by GenID();
452 var $raiseErrorFn = false; /// error function to call
453 var $isoDates = false; /// accepts dates in ISO format
454 var $cacheSecs = 3600; /// cache for 1 hour
455
456 // memcache
457 var $memCache = false; /// should we use memCache instead of caching in files
458 var $memCacheHost; /// memCache host
459 var $memCachePort = 11211; /// memCache port
460 var $memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib)
461
462 var $sysDate = false; /// name of function that returns the current date
463 var $sysTimeStamp = false; /// name of function that returns the current timestamp
464 var $sysUTimeStamp = false; // name of function that returns the current timestamp accurate to the microsecond or nearest fraction
465 var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets
466
467 var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' '
468 var $numCacheHits = 0;
469 var $numCacheMisses = 0;
470 var $pageExecuteCountRows = true;
471 var $uniqueSort = false; /// indicates that all fields in order by must be unique
472 var $leftOuter = false; /// operator to use for left outer join in WHERE clause
473 var $rightOuter = false; /// operator to use for right outer join in WHERE clause
474 var $ansiOuter = false; /// whether ansi outer join syntax supported
475 var $autoRollback = false; // autoRollback on PConnect().
476 var $poorAffectedRows = false; // affectedRows not working or unreliable
477
478 var $fnExecute = false;
479 var $fnCacheExecute = false;
480 var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char
481 var $rsPrefix = "ADORecordSet_";
482
483 var $autoCommit = true; /// do not modify this yourself - actually private
484 var $transOff = 0; /// temporarily disable transactions
485 var $transCnt = 0; /// count of nested transactions
486
487 var $fetchMode=false;
488
489 var $null2null = 'null'; // in autoexecute/getinsertsql/getupdatesql, this value will be converted to a null
490 var $bulkBind = false; // enable 2D Execute array
491 //
492 // PRIVATE VARS
493 //
494 var $_oldRaiseFn = false;
495 var $_transOK = null;
496 var $_connectionID = false; /// The returned link identifier whenever a successful database connection is made.
497 var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will
498 /// then returned by the errorMsg() function
499 var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8
500 var $_queryID = false; /// This variable keeps the last created result link identifier
501
502 var $_isPersistentConnection = false; /// A boolean variable to state whether its a persistent connection or normal connection. */
503 var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.
504 var $_evalAll = false;
505 var $_affected = false;
506 var $_logsql = false;
507 var $_transmode = ''; // transaction mode
508
509 /*
510 * Additional parameters that may be passed to drivers in the connect string
511 * Driver must be coded to accept the parameters
512 */
513 protected $connectionParameters = array();
514
515 /**
516 * Adds a parameter to the connection string.
517 *
518 * These parameters are added to the connection string when connecting,
519 * if the driver is coded to use it.
520 *
521 * @param string $parameter The name of the parameter to set
522 * @param string $value The value of the parameter
523 *
524 * @return null
525 *
526 * @example, for mssqlnative driver ('CharacterSet','UTF-8')
527 */
528 final public function setConnectionParameter($parameter,$value)
529 {
530
531 $this->connectionParameters[$parameter] = $value;
532
533 }
534
535 static function Version() {
536 global $ADODB_vers;
537
538 // Semantic Version number matching regex
539 $regex = '^[vV]?(\d+\.\d+\.\d+' // Version number (X.Y.Z) with optional 'V'
540 . '(?:-(?:' // Optional preprod version: a '-'
541 . 'dev|' // followed by 'dev'
542 . '(?:(?:alpha|beta|rc)(?:\.\d+))' // or a preprod suffix and version number
543 . '))?)(?:\s|$)'; // Whitespace or end of string
544
545 if (!preg_match("/$regex/", $ADODB_vers, $matches)) {
546 // This should normally not happen... Return whatever is between the start
547 // of the string and the first whitespace (or the end of the string).
548 self::outp("Invalid version number: '$ADODB_vers'", 'Version');
549 $regex = '^[vV]?(.*?)(?:\s|$)';
550 preg_match("/$regex/", $ADODB_vers, $matches);
551 }
552 return $matches[1];
553 }
554
555 /**
556 Get server version info...
557
558 @returns An array with 2 elements: $arr['string'] is the description string,
559 and $arr[version] is the version (also a string).
560 */
561 function ServerInfo() {
562 return array('description' => '', 'version' => '');
563 }
564
565 function IsConnected() {
566 return !empty($this->_connectionID);
567 }
568
569 function _findvers($str) {
570 if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) {
571 return $arr[1];
572 } else {
573 return '';
574 }
575 }
576
577 /**
578 * All error messages go through this bottleneck function.
579 * You can define your own handler by defining the function name in ADODB_OUTP.
580 */
581 static function outp($msg,$newline=true) {
582 global $ADODB_FLUSH,$ADODB_OUTP;
583
584 if (defined('ADODB_OUTP')) {
585 $fn = ADODB_OUTP;
586 $fn($msg,$newline);
587 return;
588 } else if (isset($ADODB_OUTP)) {
589 $fn = $ADODB_OUTP;
590 $fn($msg,$newline);
591 return;
592 }
593
594 if ($newline) {
595 $msg .= "<br>\n";
596 }
597
598 if (isset($_SERVER['HTTP_USER_AGENT']) || !$newline) {
599 echo $msg;
600 } else {
601 echo strip_tags($msg);
602 }
603
604
605 if (!empty($ADODB_FLUSH) && ob_get_length() !== false) {
606 flush(); // do not flush if output buffering enabled - useless - thx to Jesse Mullan
607 }
608
609 }
610
611 function Time() {
612 $rs = $this->_Execute("select $this->sysTimeStamp");
613 if ($rs && !$rs->EOF) {
614 return $this->UnixTimeStamp(reset($rs->fields));
615 }
616
617 return false;
618 }
619
620 /**
621 * Connect to database
622 *
623 * @param [argHostname] Host to connect to
624 * @param [argUsername] Userid to login
625 * @param [argPassword] Associated password
626 * @param [argDatabaseName] database
627 * @param [forceNew] force new connection
628 *
629 * @return true or false
630 */
631 function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) {
632 if ($argHostname != "") {
633 $this->host = $argHostname;
634 }
635 if ( strpos($this->host, ':') > 0 && isset($this->port) ) {
636 list($this->host, $this->port) = explode(":", $this->host, 2);
637 }
638 if ($argUsername != "") {
639 $this->user = $argUsername;
640 }
641 if ($argPassword != "") {
642 $this->password = 'not stored'; // not stored for security reasons
643 }
644 if ($argDatabaseName != "") {
645 $this->database = $argDatabaseName;
646 }
647
648 $this->_isPersistentConnection = false;
649
650 if ($forceNew) {
651 if ($rez=$this->_nconnect($this->host, $this->user, $argPassword, $this->database)) {
652 return true;
653 }
654 } else {
655 if ($rez=$this->_connect($this->host, $this->user, $argPassword, $this->database)) {
656 return true;
657 }
658 }
659 if (isset($rez)) {
660 $err = $this->ErrorMsg();
661 if (empty($err)) {
662 $err = "Connection error to server '$argHostname' with user '$argUsername'";
663 }
664 $ret = false;
665 } else {
666 $err = "Missing extension for ".$this->dataProvider;
667 $ret = 0;
668 }
669 if ($fn = $this->raiseErrorFn) {
670 $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
671 }
672
673 $this->_connectionID = false;
674 if ($this->debug) {
675 ADOConnection::outp( $this->host.': '.$err);
676 }
677 return $ret;
678 }
679
680 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) {
681 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
682 }
683
684
685 /**
686 * Always force a new connection to database - currently only works with oracle
687 *
688 * @param [argHostname] Host to connect to
689 * @param [argUsername] Userid to login
690 * @param [argPassword] Associated password
691 * @param [argDatabaseName] database
692 *
693 * @return true or false
694 */
695 function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {
696 return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
697 }
698
699 /**
700 * Establish persistent connect to database
701 *
702 * @param [argHostname] Host to connect to
703 * @param [argUsername] Userid to login
704 * @param [argPassword] Associated password
705 * @param [argDatabaseName] database
706 *
707 * @return return true or false
708 */
709 function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {
710
711 if (defined('ADODB_NEVER_PERSIST')) {
712 return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
713 }
714
715 if ($argHostname != "") {
716 $this->host = $argHostname;
717 }
718 if ( strpos($this->host, ':') > 0 && isset($this->port) ) {
719 list($this->host, $this->port) = explode(":", $this->host, 2);
720 }
721 if ($argUsername != "") {
722 $this->user = $argUsername;
723 }
724 if ($argPassword != "") {
725 $this->password = 'not stored';
726 }
727 if ($argDatabaseName != "") {
728 $this->database = $argDatabaseName;
729 }
730
731 $this->_isPersistentConnection = true;
732
733 if ($rez = $this->_pconnect($this->host, $this->user, $argPassword, $this->database)) {
734 return true;
735 }
736 if (isset($rez)) {
737 $err = $this->ErrorMsg();
738 if (empty($err)) {
739 $err = "Connection error to server '$argHostname' with user '$argUsername'";
740 }
741 $ret = false;
742 } else {
743 $err = "Missing extension for ".$this->dataProvider;
744 $ret = 0;
745 }
746 if ($fn = $this->raiseErrorFn) {
747 $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
748 }
749
750 $this->_connectionID = false;
751 if ($this->debug) {
752 ADOConnection::outp( $this->host.': '.$err);
753 }
754 return $ret;
755 }
756
757 function outp_throw($msg,$src='WARN',$sql='') {
758 if (defined('ADODB_ERROR_HANDLER') && ADODB_ERROR_HANDLER == 'adodb_throw') {
759 adodb_throw($this->databaseType,$src,-9999,$msg,$sql,false,$this);
760 return;
761 }
762 ADOConnection::outp($msg);
763 }
764
765 // create cache class. Code is backward compat with old memcache implementation
766 function _CreateCache() {
767 global $ADODB_CACHE, $ADODB_CACHE_CLASS;
768
769 if ($this->memCache) {
770 global $ADODB_INCLUDED_MEMCACHE;
771
772 if (empty($ADODB_INCLUDED_MEMCACHE)) {
773 include_once(ADODB_DIR.'/adodb-memcache.lib.inc.php');
774 }
775 $ADODB_CACHE = new ADODB_Cache_MemCache($this);
776 } else {
777 $ADODB_CACHE = new $ADODB_CACHE_CLASS($this);
778 }
779 }
780
781 // Format date column in sql string given an input format that understands Y M D
782 function SQLDate($fmt, $col=false) {
783 if (!$col) {
784 $col = $this->sysDate;
785 }
786 return $col; // child class implement
787 }
788
789 /**
790 * Should prepare the sql statement and return the stmt resource.
791 * For databases that do not support this, we return the $sql. To ensure
792 * compatibility with databases that do not support prepare:
793 *
794 * $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
795 * $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
796 * $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
797 *
798 * @param sql SQL to send to database
799 *
800 * @return return FALSE, or the prepared statement, or the original sql if
801 * if the database does not support prepare.
802 *
803 */
804 function Prepare($sql) {
805 return $sql;
806 }
807
808 /**
809 * Some databases, eg. mssql require a different function for preparing
810 * stored procedures. So we cannot use Prepare().
811 *
812 * Should prepare the stored procedure and return the stmt resource.
813 * For databases that do not support this, we return the $sql. To ensure
814 * compatibility with databases that do not support prepare:
815 *
816 * @param sql SQL to send to database
817 *
818 * @return return FALSE, or the prepared statement, or the original sql if
819 * if the database does not support prepare.
820 *
821 */
822 function PrepareSP($sql,$param=true) {
823 return $this->Prepare($sql,$param);
824 }
825
826 /**
827 * PEAR DB Compat
828 */
829 function Quote($s) {
830 return $this->qstr($s,false);
831 }
832
833 /**
834 * Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de>
835 */
836 function QMagic($s) {
837 return $this->qstr($s,get_magic_quotes_gpc());
838 }
839
840 function q(&$s) {
841 //if (!empty($this->qNull && $s == 'null') {
842 // return $s;
843 //}
844 $s = $this->qstr($s,false);
845 }
846
847 /**
848 * PEAR DB Compat - do not use internally.
849 */
850 function ErrorNative() {
851 return $this->ErrorNo();
852 }
853
854
855 /**
856 * PEAR DB Compat - do not use internally.
857 */
858 function nextId($seq_name) {
859 return $this->GenID($seq_name);
860 }
861
862 /**
863 * Lock a row, will escalate and lock the table if row locking not supported
864 * will normally free the lock at the end of the transaction
865 *
866 * @param $table name of table to lock
867 * @param $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
868 */
869 function RowLock($table,$where,$col='1 as adodbignore') {
870 return false;
871 }
872
873 function CommitLock($table) {
874 return $this->CommitTrans();
875 }
876
877 function RollbackLock($table) {
878 return $this->RollbackTrans();
879 }
880
881 /**
882 * PEAR DB Compat - do not use internally.
883 *
884 * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
885 * for easy porting :-)
886 *
887 * @param mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
888 * @returns The previous fetch mode
889 */
890 function SetFetchMode($mode) {
891 $old = $this->fetchMode;
892 $this->fetchMode = $mode;
893
894 if ($old === false) {
895 global $ADODB_FETCH_MODE;
896 return $ADODB_FETCH_MODE;
897 }
898 return $old;
899 }
900
901
902 /**
903 * PEAR DB Compat - do not use internally.
904 */
905 function Query($sql, $inputarr=false) {
906 $rs = $this->Execute($sql, $inputarr);
907 if (!$rs && defined('ADODB_PEAR')) {
908 return ADODB_PEAR_Error();
909 }
910 return $rs;
911 }
912
913
914 /**
915 * PEAR DB Compat - do not use internally
916 */
917 function LimitQuery($sql, $offset, $count, $params=false) {
918 $rs = $this->SelectLimit($sql, $count, $offset, $params);
919 if (!$rs && defined('ADODB_PEAR')) {
920 return ADODB_PEAR_Error();
921 }
922 return $rs;
923 }
924
925
926 /**
927 * PEAR DB Compat - do not use internally
928 */
929 function Disconnect() {
930 return $this->Close();
931 }
932
933 /**
934 * Returns a placeholder for query parameters
935 * e.g. $DB->Param('a') will return
936 * - '?' for most databases
937 * - ':a' for Oracle
938 * - '$1', '$2', etc. for PostgreSQL
939 * @param string $name parameter's name, false to force a reset of the
940 * number to 1 (for databases that require positioned
941 * params such as PostgreSQL; note that ADOdb will
942 * automatically reset this when executing a query )
943 * @param string $type (unused)
944 * @return string query parameter placeholder
945 */
946 function Param($name,$type='C') {
947 return '?';
948 }
949
950 /*
951 InParameter and OutParameter are self-documenting versions of Parameter().
952 */
953 function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {
954 return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
955 }
956
957 /*
958 */
959 function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {
960 return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);
961
962 }
963
964
965 /*
966 Usage in oracle
967 $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
968 $db->Parameter($stmt,$id,'myid');
969 $db->Parameter($stmt,$group,'group',64);
970 $db->Execute();
971
972 @param $stmt Statement returned by Prepare() or PrepareSP().
973 @param $var PHP variable to bind to
974 @param $name Name of stored procedure variable name to bind to.
975 @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
976 @param [$maxLen] Holds an maximum length of the variable.
977 @param [$type] The data type of $var. Legal values depend on driver.
978
979 */
980 function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) {
981 return false;
982 }
983
984
985 function IgnoreErrors($saveErrs=false) {
986 if (!$saveErrs) {
987 $saveErrs = array($this->raiseErrorFn,$this->_transOK);
988 $this->raiseErrorFn = false;
989 return $saveErrs;
990 } else {
991 $this->raiseErrorFn = $saveErrs[0];
992 $this->_transOK = $saveErrs[1];
993 }
994 }
995
996 /**
997 * Improved method of initiating a transaction. Used together with CompleteTrans().
998 * Advantages include:
999 *
1000 * a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.
1001 * Only the outermost block is treated as a transaction.<br>
1002 * b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>
1003 * c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block
1004 * are disabled, making it backward compatible.
1005 */
1006 function StartTrans($errfn = 'ADODB_TransMonitor') {
1007 if ($this->transOff > 0) {
1008 $this->transOff += 1;
1009 return true;
1010 }
1011
1012 $this->_oldRaiseFn = $this->raiseErrorFn;
1013 $this->raiseErrorFn = $errfn;
1014 $this->_transOK = true;
1015
1016 if ($this->debug && $this->transCnt > 0) {
1017 ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
1018 }
1019 $ok = $this->BeginTrans();
1020 $this->transOff = 1;
1021 return $ok;
1022 }
1023
1024
1025 /**
1026 Used together with StartTrans() to end a transaction. Monitors connection
1027 for sql errors, and will commit or rollback as appropriate.
1028
1029 @autoComplete if true, monitor sql errors and commit and rollback as appropriate,
1030 and if set to false force rollback even if no SQL error detected.
1031 @returns true on commit, false on rollback.
1032 */
1033 function CompleteTrans($autoComplete = true) {
1034 if ($this->transOff > 1) {
1035 $this->transOff -= 1;
1036 return true;
1037 }
1038 $this->raiseErrorFn = $this->_oldRaiseFn;
1039
1040 $this->transOff = 0;
1041 if ($this->_transOK && $autoComplete) {
1042 if (!$this->CommitTrans()) {
1043 $this->_transOK = false;
1044 if ($this->debug) {
1045 ADOConnection::outp("Smart Commit failed");
1046 }
1047 } else {
1048 if ($this->debug) {
1049 ADOConnection::outp("Smart Commit occurred");
1050 }
1051 }
1052 } else {
1053 $this->_transOK = false;
1054 $this->RollbackTrans();
1055 if ($this->debug) {
1056 ADOCOnnection::outp("Smart Rollback occurred");
1057 }
1058 }
1059
1060 return $this->_transOK;
1061 }
1062
1063 /*
1064 At the end of a StartTrans/CompleteTrans block, perform a rollback.
1065 */
1066 function FailTrans() {
1067 if ($this->debug)
1068 if ($this->transOff == 0) {
1069 ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
1070 } else {
1071 ADOConnection::outp("FailTrans was called");
1072 adodb_backtrace();
1073 }
1074 $this->_transOK = false;
1075 }
1076
1077 /**
1078 Check if transaction has failed, only for Smart Transactions.
1079 */
1080 function HasFailedTrans() {
1081 if ($this->transOff > 0) {
1082 return $this->_transOK == false;
1083 }
1084 return false;
1085 }
1086
1087 /**
1088 * Execute SQL
1089 *
1090 * @param sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
1091 * @param [inputarr] holds the input data to bind to. Null elements will be set to null.
1092 * @return RecordSet or false
1093 */
1094 function Execute($sql,$inputarr=false) {
1095 if ($this->fnExecute) {
1096 $fn = $this->fnExecute;
1097 $ret = $fn($this,$sql,$inputarr);
1098 if (isset($ret)) {
1099 return $ret;
1100 }
1101 }
1102 if ($inputarr !== false) {
1103 if (!is_array($inputarr)) {
1104 $inputarr = array($inputarr);
1105 }
1106
1107 $element0 = reset($inputarr);
1108 # is_object check because oci8 descriptors can be passed in
1109 $array_2d = $this->bulkBind && is_array($element0) && !is_object(reset($element0));
1110
1111 //remove extra memory copy of input -mikefedyk
1112 unset($element0);
1113
1114 if (!is_array($sql) && !$this->_bindInputArray) {
1115 // @TODO this would consider a '?' within a string as a parameter...
1116 $sqlarr = explode('?',$sql);
1117 $nparams = sizeof($sqlarr)-1;
1118
1119 // Make sure the number of parameters provided in the input
1120 // array matches what the query expects
1121 if ($nparams != count($inputarr)) {
1122 $this->outp_throw(
1123 "Input array has " . count($inputarr) .
1124 " params, does not match query: '" . htmlspecialchars($sql) . "'",
1125 'Execute'
1126 );
1127 return false;
1128 }
1129
1130 if (!$array_2d) {
1131 $inputarr = array($inputarr);
1132 }
1133
1134 foreach($inputarr as $arr) {
1135 $sql = ''; $i = 0;
1136 //Use each() instead of foreach to reduce memory usage -mikefedyk
1137 while(list(, $v) = each($arr)) {
1138 $sql .= $sqlarr[$i];
1139 // from Ron Baldwin <ron.baldwin#sourceprose.com>
1140 // Only quote string types
1141 $typ = gettype($v);
1142 if ($typ == 'string') {
1143 //New memory copy of input created here -mikefedyk
1144 $sql .= $this->qstr($v);
1145 } else if ($typ == 'double') {
1146 $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1
1147 } else if ($typ == 'boolean') {
1148 $sql .= $v ? $this->true : $this->false;
1149 } else if ($typ == 'object') {
1150 if (method_exists($v, '__toString')) {
1151 $sql .= $this->qstr($v->__toString());
1152 } else {
1153 $sql .= $this->qstr((string) $v);
1154 }
1155 } else if ($v === null) {
1156 $sql .= 'NULL';
1157 } else {
1158 $sql .= $v;
1159 }
1160 $i += 1;
1161
1162 if ($i == $nparams) {
1163 break;
1164 }
1165 } // while
1166 if (isset($sqlarr[$i])) {
1167 $sql .= $sqlarr[$i];
1168 if ($i+1 != sizeof($sqlarr)) {
1169 $this->outp_throw( "Input Array does not match ?: ".htmlspecialchars($sql),'Execute');
1170 }
1171 } else if ($i != sizeof($sqlarr)) {
1172 $this->outp_throw( "Input array does not match ?: ".htmlspecialchars($sql),'Execute');
1173 }
1174
1175 $ret = $this->_Execute($sql);
1176 if (!$ret) {
1177 return $ret;
1178 }
1179 }
1180 } else {
1181 if ($array_2d) {
1182 if (is_string($sql)) {
1183 $stmt = $this->Prepare($sql);
1184 } else {
1185 $stmt = $sql;
1186 }
1187
1188 foreach($inputarr as $arr) {
1189 $ret = $this->_Execute($stmt,$arr);
1190 if (!$ret) {
1191 return $ret;
1192 }
1193 }
1194 } else {
1195 $ret = $this->_Execute($sql,$inputarr);
1196 }
1197 }
1198 } else {
1199 $ret = $this->_Execute($sql,false);
1200 }
1201
1202 return $ret;
1203 }
1204
1205 function _Execute($sql,$inputarr=false) {
1206 // ExecuteCursor() may send non-string queries (such as arrays),
1207 // so we need to ignore those.
1208 if( is_string($sql) ) {
1209 // Strips keyword used to help generate SELECT COUNT(*) queries
1210 // from SQL if it exists.
1211 $sql = ADODB_str_replace( '_ADODB_COUNT', '', $sql );
1212 }
1213
1214 if ($this->debug) {
1215 global $ADODB_INCLUDED_LIB;
1216 if (empty($ADODB_INCLUDED_LIB)) {
1217 include(ADODB_DIR.'/adodb-lib.inc.php');
1218 }
1219 $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr);
1220 } else {
1221 $this->_queryID = @$this->_query($sql,$inputarr);
1222 }
1223
1224 // ************************
1225 // OK, query executed
1226 // ************************
1227
1228 // error handling if query fails
1229 if ($this->_queryID === false) {
1230 if ($this->debug == 99) {
1231 adodb_backtrace(true,5);
1232 }
1233 $fn = $this->raiseErrorFn;
1234 if ($fn) {
1235 $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
1236 }
1237 return false;
1238 }
1239
1240 // return simplified recordset for inserts/updates/deletes with lower overhead
1241 if ($this->_queryID === true) {
1242 $rsclass = $this->rsPrefix.'empty';
1243 $rs = (class_exists($rsclass)) ? new $rsclass(): new ADORecordSet_empty();
1244
1245 return $rs;
1246 }
1247
1248 // return real recordset from select statement
1249 $rsclass = $this->rsPrefix.$this->databaseType;
1250 $rs = new $rsclass($this->_queryID,$this->fetchMode);
1251 $rs->connection = $this; // Pablo suggestion
1252 $rs->Init();
1253 if (is_array($sql)) {
1254 $rs->sql = $sql[0];
1255 } else {
1256 $rs->sql = $sql;
1257 }
1258 if ($rs->_numOfRows <= 0) {
1259 global $ADODB_COUNTRECS;
1260 if ($ADODB_COUNTRECS) {
1261 if (!$rs->EOF) {
1262 $rs = $this->_rs2rs($rs,-1,-1,!is_array($sql));
1263 $rs->_queryID = $this->_queryID;
1264 } else
1265 $rs->_numOfRows = 0;
1266 }
1267 }
1268 return $rs;
1269 }
1270
1271 function CreateSequence($seqname='adodbseq',$startID=1) {
1272 if (empty($this->_genSeqSQL)) {
1273 return false;
1274 }
1275 return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
1276 }
1277
1278 function DropSequence($seqname='adodbseq') {
1279 if (empty($this->_dropSeqSQL)) {
1280 return false;
1281 }
1282 return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
1283 }
1284
1285 /**
1286 * Generates a sequence id and stores it in $this->genID;
1287 * GenID is only available if $this->hasGenID = true;
1288 *
1289 * @param seqname name of sequence to use
1290 * @param startID if sequence does not exist, start at this ID
1291 * @return 0 if not supported, otherwise a sequence id
1292 */
1293 function GenID($seqname='adodbseq',$startID=1) {
1294 if (!$this->hasGenID) {
1295 return 0; // formerly returns false pre 1.60
1296 }
1297
1298 $getnext = sprintf($this->_genIDSQL,$seqname);
1299
1300 $holdtransOK = $this->_transOK;
1301
1302 $save_handler = $this->raiseErrorFn;
1303 $this->raiseErrorFn = '';
1304 @($rs = $this->Execute($getnext));
1305 $this->raiseErrorFn = $save_handler;
1306
1307 if (!$rs) {
1308 $this->_transOK = $holdtransOK; //if the status was ok before reset
1309 $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
1310 $rs = $this->Execute($getnext);
1311 }
1312 if ($rs && !$rs->EOF) {
1313 $this->genID = reset($rs->fields);
1314 } else {
1315 $this->genID = 0; // false
1316 }
1317
1318 if ($rs) {
1319 $rs->Close();
1320 }
1321
1322 return $this->genID;
1323 }
1324
1325 /**
1326 * @param $table string name of the table, not needed by all databases (eg. mysql), default ''
1327 * @param $column string name of the column, not needed by all databases (eg. mysql), default ''
1328 * @return the last inserted ID. Not all databases support this.
1329 */
1330 function Insert_ID($table='',$column='') {
1331 if ($this->_logsql && $this->lastInsID) {
1332 return $this->lastInsID;
1333 }
1334 if ($this->hasInsertID) {
1335 return $this->_insertid($table,$column);
1336 }
1337 if ($this->debug) {
1338 ADOConnection::outp( '<p>Insert_ID error</p>');
1339 adodb_backtrace();
1340 }
1341 return false;
1342 }
1343
1344
1345 /**
1346 * Portable Insert ID. Pablo Roca <pabloroca#mvps.org>
1347 *
1348 * @return the last inserted ID. All databases support this. But aware possible
1349 * problems in multiuser environments. Heavy test this before deploying.
1350 */
1351 function PO_Insert_ID($table="", $id="") {
1352 if ($this->hasInsertID){
1353 return $this->Insert_ID($table,$id);
1354 } else {
1355 return $this->GetOne("SELECT MAX($id) FROM $table");
1356 }
1357 }
1358
1359 /**
1360 * @return # rows affected by UPDATE/DELETE
1361 */
1362 function Affected_Rows() {
1363 if ($this->hasAffectedRows) {
1364 if ($this->fnExecute === 'adodb_log_sql') {
1365 if ($this->_logsql && $this->_affected !== false) {
1366 return $this->_affected;
1367 }
1368 }
1369 $val = $this->_affectedrows();
1370 return ($val < 0) ? false : $val;
1371 }
1372
1373 if ($this->debug) {
1374 ADOConnection::outp( '<p>Affected_Rows error</p>',false);
1375 }
1376 return false;
1377 }
1378
1379
1380 /**
1381 * @return the last error message
1382 */
1383 function ErrorMsg() {
1384 if ($this->_errorMsg) {
1385 return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
1386 } else {
1387 return '';
1388 }
1389 }
1390
1391
1392 /**
1393 * @return the last error number. Normally 0 means no error.
1394 */
1395 function ErrorNo() {
1396 return ($this->_errorMsg) ? -1 : 0;
1397 }
1398
1399 function MetaError($err=false) {
1400 include_once(ADODB_DIR."/adodb-error.inc.php");
1401 if ($err === false) {
1402 $err = $this->ErrorNo();
1403 }
1404 return adodb_error($this->dataProvider,$this->databaseType,$err);
1405 }
1406
1407 function MetaErrorMsg($errno) {
1408 include_once(ADODB_DIR."/adodb-error.inc.php");
1409 return adodb_errormsg($errno);
1410 }
1411
1412 /**
1413 * @returns an array with the primary key columns in it.
1414 */
1415 function MetaPrimaryKeys($table, $owner=false) {
1416 // owner not used in base class - see oci8
1417 $p = array();
1418 $objs = $this->MetaColumns($table);
1419 if ($objs) {
1420 foreach($objs as $v) {
1421 if (!empty($v->primary_key)) {
1422 $p[] = $v->name;
1423 }
1424 }
1425 }
1426 if (sizeof($p)) {
1427 return $p;
1428 }
1429 if (function_exists('ADODB_VIEW_PRIMARYKEYS')) {
1430 return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);
1431 }
1432 return false;
1433 }
1434
1435 /**
1436 * @returns assoc array where keys are tables, and values are foreign keys
1437 */
1438 function MetaForeignKeys($table, $owner=false, $upper=false) {
1439 return false;
1440 }
1441 /**
1442 * Choose a database to connect to. Many databases do not support this.
1443 *
1444 * @param dbName is the name of the database to select
1445 * @return true or false
1446 */
1447 function SelectDB($dbName) {return false;}
1448
1449
1450 /**
1451 * Will select, getting rows from $offset (1-based), for $nrows.
1452 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1453 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1454 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1455 * eg.
1456 * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
1457 * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
1458 *
1459 * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
1460 * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
1461 *
1462 * @param sql
1463 * @param [offset] is the row to start calculations from (1-based)
1464 * @param [nrows] is the number of rows to get
1465 * @param [inputarr] array of bind variables
1466 * @param [secs2cache] is a private parameter only used by jlim
1467 * @return the recordset ($rs->databaseType == 'array')
1468 */
1469 function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) {
1470 if ($this->hasTop && $nrows > 0) {
1471 // suggested by Reinhard Balling. Access requires top after distinct
1472 // Informix requires first before distinct - F Riosa
1473 $ismssql = (strpos($this->databaseType,'mssql') !== false);
1474 if ($ismssql) {
1475 $isaccess = false;
1476 } else {
1477 $isaccess = (strpos($this->databaseType,'access') !== false);
1478 }
1479
1480 if ($offset <= 0) {
1481 // access includes ties in result
1482 if ($isaccess) {
1483 $sql = preg_replace(
1484 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1485
1486 if ($secs2cache != 0) {
1487 $ret = $this->CacheExecute($secs2cache, $sql,$inputarr);
1488 } else {
1489 $ret = $this->Execute($sql,$inputarr);
1490 }
1491 return $ret; // PHP5 fix
1492 } else if ($ismssql){
1493 $sql = preg_replace(
1494 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1495 } else {
1496 $sql = preg_replace(
1497 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1498 }
1499 } else {
1500 $nn = $nrows + $offset;
1501 if ($isaccess || $ismssql) {
1502 $sql = preg_replace(
1503 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1504 } else {
1505 $sql = preg_replace(
1506 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1507 }
1508 }
1509 }
1510
1511 // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows
1512 // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.
1513 global $ADODB_COUNTRECS;
1514
1515 $savec = $ADODB_COUNTRECS;
1516 $ADODB_COUNTRECS = false;
1517
1518
1519 if ($secs2cache != 0) {
1520 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1521 } else {
1522 $rs = $this->Execute($sql,$inputarr);
1523 }
1524
1525 $ADODB_COUNTRECS = $savec;
1526 if ($rs && !$rs->EOF) {
1527 $rs = $this->_rs2rs($rs,$nrows,$offset);
1528 }
1529 //print_r($rs);
1530 return $rs;
1531 }
1532
1533 /**
1534 * Create serializable recordset. Breaks rs link to connection.
1535 *
1536 * @param rs the recordset to serialize
1537 */
1538 function SerializableRS(&$rs) {
1539 $rs2 = $this->_rs2rs($rs);
1540 $ignore = false;
1541 $rs2->connection = $ignore;
1542
1543 return $rs2;
1544 }
1545
1546 /**
1547 * Convert database recordset to an array recordset
1548 * input recordset's cursor should be at beginning, and
1549 * old $rs will be closed.
1550 *
1551 * @param rs the recordset to copy
1552 * @param [nrows] number of rows to retrieve (optional)
1553 * @param [offset] offset by number of rows (optional)
1554 * @return the new recordset
1555 */
1556 function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true) {
1557 if (! $rs) {
1558 return false;
1559 }
1560 $dbtype = $rs->databaseType;
1561 if (!$dbtype) {
1562 $rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?
1563 return $rs;
1564 }
1565 if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {
1566 $rs->MoveFirst();
1567 $rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?
1568 return $rs;
1569 }
1570 $flds = array();
1571 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
1572 $flds[] = $rs->FetchField($i);
1573 }
1574
1575 $arr = $rs->GetArrayLimit($nrows,$offset);
1576 //print_r($arr);
1577 if ($close) {
1578 $rs->Close();
1579 }
1580
1581 $arrayClass = $this->arrayClass;
1582
1583 $rs2 = new $arrayClass();
1584 $rs2->connection = $this;
1585 $rs2->sql = $rs->sql;
1586 $rs2->dataProvider = $this->dataProvider;
1587 $rs2->InitArrayFields($arr,$flds);
1588 $rs2->fetchMode = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
1589 return $rs2;
1590 }
1591
1592 /*
1593 * Return all rows. Compat with PEAR DB
1594 */
1595 function GetAll($sql, $inputarr=false) {
1596 $arr = $this->GetArray($sql,$inputarr);
1597 return $arr;
1598 }
1599
1600 function GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false) {
1601 $rs = $this->Execute($sql, $inputarr);
1602 if (!$rs) {
1603 return false;
1604 }
1605 $arr = $rs->GetAssoc($force_array,$first2cols);
1606 return $arr;
1607 }
1608
1609 function CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false) {
1610 if (!is_numeric($secs2cache)) {
1611 $first2cols = $force_array;
1612 $force_array = $inputarr;
1613 }
1614 $rs = $this->CacheExecute($secs2cache, $sql, $inputarr);
1615 if (!$rs) {
1616 return false;
1617 }
1618 $arr = $rs->GetAssoc($force_array,$first2cols);
1619 return $arr;
1620 }
1621
1622 /**
1623 * Return first element of first row of sql statement. Recordset is disposed
1624 * for you.
1625 *
1626 * @param sql SQL statement
1627 * @param [inputarr] input bind array
1628 */
1629 function GetOne($sql,$inputarr=false) {
1630 global $ADODB_COUNTRECS,$ADODB_GETONE_EOF;
1631
1632 $crecs = $ADODB_COUNTRECS;
1633 $ADODB_COUNTRECS = false;
1634
1635 $ret = false;
1636 $rs = $this->Execute($sql,$inputarr);
1637 if ($rs) {
1638 if ($rs->EOF) {
1639 $ret = $ADODB_GETONE_EOF;
1640 } else {
1641 $ret = reset($rs->fields);
1642 }
1643
1644 $rs->Close();
1645 }
1646 $ADODB_COUNTRECS = $crecs;
1647 return $ret;
1648 }
1649
1650 // $where should include 'WHERE fld=value'
1651 function GetMedian($table, $field,$where = '') {
1652 $total = $this->GetOne("select count(*) from $table $where");
1653 if (!$total) {
1654 return false;
1655 }
1656
1657 $midrow = (integer) ($total/2);
1658 $rs = $this->SelectLimit("select $field from $table $where order by 1",1,$midrow);
1659 if ($rs && !$rs->EOF) {
1660 return reset($rs->fields);
1661 }
1662 return false;
1663 }
1664
1665
1666 function CacheGetOne($secs2cache,$sql=false,$inputarr=false) {
1667 global $ADODB_GETONE_EOF;
1668
1669 $ret = false;
1670 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1671 if ($rs) {
1672 if ($rs->EOF) {
1673 $ret = $ADODB_GETONE_EOF;
1674 } else {
1675 $ret = reset($rs->fields);
1676 }
1677 $rs->Close();
1678 }
1679
1680 return $ret;
1681 }
1682
1683 function GetCol($sql, $inputarr = false, $trim = false) {
1684
1685 $rs = $this->Execute($sql, $inputarr);
1686 if ($rs) {
1687 $rv = array();
1688 if ($trim) {
1689 while (!$rs->EOF) {
1690 $rv[] = trim(reset($rs->fields));
1691 $rs->MoveNext();
1692 }
1693 } else {
1694 while (!$rs->EOF) {
1695 $rv[] = reset($rs->fields);
1696 $rs->MoveNext();
1697 }
1698 }
1699 $rs->Close();
1700 } else {
1701 $rv = false;
1702 }
1703 return $rv;
1704 }
1705
1706 function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false) {
1707 $rs = $this->CacheExecute($secs, $sql, $inputarr);
1708 if ($rs) {
1709 $rv = array();
1710 if ($trim) {
1711 while (!$rs->EOF) {
1712 $rv[] = trim(reset($rs->fields));
1713 $rs->MoveNext();
1714 }
1715 } else {
1716 while (!$rs->EOF) {
1717 $rv[] = reset($rs->fields);
1718 $rs->MoveNext();
1719 }
1720 }
1721 $rs->Close();
1722 } else
1723 $rv = false;
1724
1725 return $rv;
1726 }
1727
1728 function Transpose(&$rs,$addfieldnames=true) {
1729 $rs2 = $this->_rs2rs($rs);
1730 if (!$rs2) {
1731 return false;
1732 }
1733
1734 $rs2->_transpose($addfieldnames);
1735 return $rs2;
1736 }
1737
1738 /*
1739 Calculate the offset of a date for a particular database and generate
1740 appropriate SQL. Useful for calculating future/past dates and storing
1741 in a database.
1742
1743 If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
1744 */
1745 function OffsetDate($dayFraction,$date=false) {
1746 if (!$date) {
1747 $date = $this->sysDate;
1748 }
1749 return '('.$date.'+'.$dayFraction.')';
1750 }
1751
1752
1753 /**
1754 *
1755 * @param sql SQL statement
1756 * @param [inputarr] input bind array
1757 */
1758 function GetArray($sql,$inputarr=false) {
1759 global $ADODB_COUNTRECS;
1760
1761 $savec = $ADODB_COUNTRECS;
1762 $ADODB_COUNTRECS = false;
1763 $rs = $this->Execute($sql,$inputarr);
1764 $ADODB_COUNTRECS = $savec;
1765 if (!$rs)
1766 if (defined('ADODB_PEAR')) {
1767 $cls = ADODB_PEAR_Error();
1768 return $cls;
1769 } else {
1770 return false;
1771 }
1772 $arr = $rs->GetArray();
1773 $rs->Close();
1774 return $arr;
1775 }
1776
1777 function CacheGetAll($secs2cache,$sql=false,$inputarr=false) {
1778 $arr = $this->CacheGetArray($secs2cache,$sql,$inputarr);
1779 return $arr;
1780 }
1781
1782 function CacheGetArray($secs2cache,$sql=false,$inputarr=false) {
1783 global $ADODB_COUNTRECS;
1784
1785 $savec = $ADODB_COUNTRECS;
1786 $ADODB_COUNTRECS = false;
1787 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1788 $ADODB_COUNTRECS = $savec;
1789
1790 if (!$rs)
1791 if (defined('ADODB_PEAR')) {
1792 $cls = ADODB_PEAR_Error();
1793 return $cls;
1794 } else {
1795 return false;
1796 }
1797 $arr = $rs->GetArray();
1798 $rs->Close();
1799 return $arr;
1800 }
1801
1802 function GetRandRow($sql, $arr= false) {
1803 $rezarr = $this->GetAll($sql, $arr);
1804 $sz = sizeof($rezarr);
1805 return $rezarr[abs(rand()) % $sz];
1806 }
1807
1808 /**
1809 * Return one row of sql statement. Recordset is disposed for you.
1810 * Note that SelectLimit should not be called.
1811 *
1812 * @param sql SQL statement
1813 * @param [inputarr] input bind array
1814 */
1815 function GetRow($sql,$inputarr=false) {
1816 global $ADODB_COUNTRECS;
1817
1818 $crecs = $ADODB_COUNTRECS;
1819 $ADODB_COUNTRECS = false;
1820
1821 $rs = $this->Execute($sql,$inputarr);
1822
1823 $ADODB_COUNTRECS = $crecs;
1824 if ($rs) {
1825 if (!$rs->EOF) {
1826 $arr = $rs->fields;
1827 } else {
1828 $arr = array();
1829 }
1830 $rs->Close();
1831 return $arr;
1832 }
1833
1834 return false;
1835 }
1836
1837 function CacheGetRow($secs2cache,$sql=false,$inputarr=false) {
1838 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
1839 if ($rs) {
1840 if (!$rs->EOF) {
1841 $arr = $rs->fields;
1842 } else {
1843 $arr = array();
1844 }
1845
1846 $rs->Close();
1847 return $arr;
1848 }
1849 return false;
1850 }
1851
1852 /**
1853 * Insert or replace a single record. Note: this is not the same as MySQL's replace.
1854 * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
1855 * Also note that no table locking is done currently, so it is possible that the
1856 * record be inserted twice by two programs...
1857 *
1858 * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
1859 *
1860 * $table table name
1861 * $fieldArray associative array of data (you must quote strings yourself).
1862 * $keyCol the primary key field name or if compound key, array of field names
1863 * autoQuote set to true to use a hueristic to quote strings. Works with nulls and numbers
1864 * but does not work with dates nor SQL functions.
1865 * has_autoinc the primary key is an auto-inc field, so skip in insert.
1866 *
1867 * Currently blob replace not supported
1868 *
1869 * returns 0 = fail, 1 = update, 2 = insert
1870 */
1871
1872 function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false) {
1873 global $ADODB_INCLUDED_LIB;
1874 if (empty($ADODB_INCLUDED_LIB)) {
1875 include(ADODB_DIR.'/adodb-lib.inc.php');
1876 }
1877
1878 return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);
1879 }
1880
1881
1882 /**
1883 * Will select, getting rows from $offset (1-based), for $nrows.
1884 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1885 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1886 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1887 * eg.
1888 * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
1889 * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
1890 *
1891 * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
1892 *
1893 * @param [secs2cache] seconds to cache data, set to 0 to force query. This is optional
1894 * @param sql
1895 * @param [offset] is the row to start calculations from (1-based)
1896 * @param [nrows] is the number of rows to get
1897 * @param [inputarr] array of bind variables
1898 * @return the recordset ($rs->databaseType == 'array')
1899 */
1900 function CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false) {
1901 if (!is_numeric($secs2cache)) {
1902 if ($sql === false) {
1903 $sql = -1;
1904 }
1905 if ($offset == -1) {
1906 $offset = false;
1907 }
1908 // sql, nrows, offset,inputarr
1909 $rs = $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs);
1910 } else {
1911 if ($sql === false) {
1912 $this->outp_throw("Warning: \$sql missing from CacheSelectLimit()",'CacheSelectLimit');
1913 }
1914 $rs = $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
1915 }
1916 return $rs;
1917 }
1918
1919 /**
1920 * Flush cached recordsets that match a particular $sql statement.
1921 * If $sql == false, then we purge all files in the cache.
1922 */
1923 function CacheFlush($sql=false,$inputarr=false) {
1924 global $ADODB_CACHE_DIR, $ADODB_CACHE;
1925
1926 # Create cache if it does not exist
1927 if (empty($ADODB_CACHE)) {
1928 $this->_CreateCache();
1929 }
1930
1931 if (!$sql) {
1932 $ADODB_CACHE->flushall($this->debug);
1933 return;
1934 }
1935
1936 $f = $this->_gencachename($sql.serialize($inputarr),false);
1937 return $ADODB_CACHE->flushcache($f, $this->debug);
1938 }
1939
1940
1941 /**
1942 * Private function to generate filename for caching.
1943 * Filename is generated based on:
1944 *
1945 * - sql statement
1946 * - database type (oci8, ibase, ifx, etc)
1947 * - database name
1948 * - userid
1949 * - setFetchMode (adodb 4.23)
1950 *
1951 * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
1952 * Assuming that we can have 50,000 files per directory with good performance,
1953 * then we can scale to 12.8 million unique cached recordsets. Wow!
1954 */
1955 function _gencachename($sql,$createdir) {
1956 global $ADODB_CACHE, $ADODB_CACHE_DIR;
1957
1958 if ($this->fetchMode === false) {
1959 global $ADODB_FETCH_MODE;
1960 $mode = $ADODB_FETCH_MODE;
1961 } else {
1962 $mode = $this->fetchMode;
1963 }
1964 $m = md5($sql.$this->databaseType.$this->database.$this->user.$mode);
1965 if (!$ADODB_CACHE->createdir) {
1966 return $m;
1967 }
1968 if (!$createdir) {
1969 $dir = $ADODB_CACHE->getdirname($m);
1970 } else {
1971 $dir = $ADODB_CACHE->createdir($m, $this->debug);
1972 }
1973
1974 return $dir.'/adodb_'.$m.'.cache';
1975 }
1976
1977
1978 /**
1979 * Execute SQL, caching recordsets.
1980 *
1981 * @param [secs2cache] seconds to cache data, set to 0 to force query.
1982 * This is an optional parameter.
1983 * @param sql SQL statement to execute
1984 * @param [inputarr] holds the input data to bind to
1985 * @return RecordSet or false
1986 */
1987 function CacheExecute($secs2cache,$sql=false,$inputarr=false) {
1988 global $ADODB_CACHE;
1989
1990 if (empty($ADODB_CACHE)) {
1991 $this->_CreateCache();
1992 }
1993
1994 if (!is_numeric($secs2cache)) {
1995 $inputarr = $sql;
1996 $sql = $secs2cache;
1997 $secs2cache = $this->cacheSecs;
1998 }
1999
2000 if (is_array($sql)) {
2001 $sqlparam = $sql;
2002 $sql = $sql[0];
2003 } else
2004 $sqlparam = $sql;
2005
2006
2007 $md5file = $this->_gencachename($sql.serialize($inputarr),true);
2008 $err = '';
2009
2010 if ($secs2cache > 0){
2011 $rs = $ADODB_CACHE->readcache($md5file,$err,$secs2cache,$this->arrayClass);
2012 $this->numCacheHits += 1;
2013 } else {
2014 $err='Timeout 1';
2015 $rs = false;
2016 $this->numCacheMisses += 1;
2017 }
2018
2019 if (!$rs) {
2020 // no cached rs found
2021 if ($this->debug) {
2022 if (get_magic_quotes_runtime() && !$this->memCache) {
2023 ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
2024 }
2025 if ($this->debug !== -1) {
2026 ADOConnection::outp( " $md5file cache failure: $err (this is a notice and not an error)");
2027 }
2028 }
2029
2030 $rs = $this->Execute($sqlparam,$inputarr);
2031
2032 if ($rs) {
2033 $eof = $rs->EOF;
2034 $rs = $this->_rs2rs($rs); // read entire recordset into memory immediately
2035 $rs->timeCreated = time(); // used by caching
2036 $txt = _rs2serialize($rs,false,$sql); // serialize
2037
2038 $ok = $ADODB_CACHE->writecache($md5file,$txt,$this->debug, $secs2cache);
2039 if (!$ok) {
2040 if ($ok === false) {
2041 $em = 'Cache write error';
2042 $en = -32000;
2043
2044 if ($fn = $this->raiseErrorFn) {
2045 $fn($this->databaseType,'CacheExecute', $en, $em, $md5file,$sql,$this);
2046 }
2047 } else {
2048 $em = 'Cache file locked warning';
2049 $en = -32001;
2050 // do not call error handling for just a warning
2051 }
2052
2053 if ($this->debug) {
2054 ADOConnection::outp( " ".$em);
2055 }
2056 }
2057 if ($rs->EOF && !$eof) {
2058 $rs->MoveFirst();
2059 //$rs = csv2rs($md5file,$err);
2060 $rs->connection = $this; // Pablo suggestion
2061 }
2062
2063 } else if (!$this->memCache) {
2064 $ADODB_CACHE->flushcache($md5file);
2065 }
2066 } else {
2067 $this->_errorMsg = '';
2068 $this->_errorCode = 0;
2069
2070 if ($this->fnCacheExecute) {
2071 $fn = $this->fnCacheExecute;
2072 $fn($this, $secs2cache, $sql, $inputarr);
2073 }
2074 // ok, set cached object found
2075 $rs->connection = $this; // Pablo suggestion
2076 if ($this->debug){
2077 if ($this->debug == 99) {
2078 adodb_backtrace();
2079 }
2080 $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
2081 $ttl = $rs->timeCreated + $secs2cache - time();
2082 $s = is_array($sql) ? $sql[0] : $sql;
2083 if ($inBrowser) {
2084 $s = '<i>'.htmlspecialchars($s).'</i>';
2085 }
2086
2087 ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
2088 }
2089 }
2090 return $rs;
2091 }
2092
2093
2094 /*
2095 Similar to PEAR DB's autoExecute(), except that
2096 $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
2097 If $mode == 'UPDATE', then $where is compulsory as a safety measure.
2098
2099 $forceUpdate means that even if the data has not changed, perform update.
2100 */
2101 function AutoExecute($table, $fields_values, $mode = 'INSERT', $where = false, $forceUpdate = true, $magicq = false) {
2102 if ($where === false && ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) ) {
2103 $this->outp_throw('AutoExecute: Illegal mode=UPDATE with empty WHERE clause', 'AutoExecute');
2104 return false;
2105 }
2106
2107 $sql = "SELECT * FROM $table";
2108 $rs = $this->SelectLimit($sql, 1);
2109 if (!$rs) {
2110 return false; // table does not exist
2111 }
2112
2113 $rs->tableName = $table;
2114 if ($where !== false) {
2115 $sql .= " WHERE $where";
2116 }
2117 $rs->sql = $sql;
2118
2119 switch($mode) {
2120 case 'UPDATE':
2121 case DB_AUTOQUERY_UPDATE:
2122 $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq);
2123 break;
2124 case 'INSERT':
2125 case DB_AUTOQUERY_INSERT:
2126 $sql = $this->GetInsertSQL($rs, $fields_values, $magicq);
2127 break;
2128 default:
2129 $this->outp_throw("AutoExecute: Unknown mode=$mode", 'AutoExecute');
2130 return false;
2131 }
2132 return $sql && $this->Execute($sql);
2133 }
2134
2135
2136 /**
2137 * Generates an Update Query based on an existing recordset.
2138 * $arrFields is an associative array of fields with the value
2139 * that should be assigned.
2140 *
2141 * Note: This function should only be used on a recordset
2142 * that is run against a single table and sql should only
2143 * be a simple select stmt with no groupby/orderby/limit
2144 *
2145 * "Jonathan Younger" <jyounger@unilab.com>
2146 */
2147 function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null) {
2148 global $ADODB_INCLUDED_LIB;
2149
2150 // ********************************************************
2151 // This is here to maintain compatibility
2152 // with older adodb versions. Sets force type to force nulls if $forcenulls is set.
2153 if (!isset($force)) {
2154 global $ADODB_FORCE_TYPE;
2155 $force = $ADODB_FORCE_TYPE;
2156 }
2157 // ********************************************************
2158
2159 if (empty($ADODB_INCLUDED_LIB)) {
2160 include(ADODB_DIR.'/adodb-lib.inc.php');
2161 }
2162 return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
2163 }
2164
2165 /**
2166 * Generates an Insert Query based on an existing recordset.
2167 * $arrFields is an associative array of fields with the value
2168 * that should be assigned.
2169 *
2170 * Note: This function should only be used on a recordset
2171 * that is run against a single table.
2172 */
2173 function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null) {
2174 global $ADODB_INCLUDED_LIB;
2175 if (!isset($force)) {
2176 global $ADODB_FORCE_TYPE;
2177 $force = $ADODB_FORCE_TYPE;
2178 }
2179 if (empty($ADODB_INCLUDED_LIB)) {
2180 include(ADODB_DIR.'/adodb-lib.inc.php');
2181 }
2182 return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
2183 }
2184
2185
2186 /**
2187 * Update a blob column, given a where clause. There are more sophisticated
2188 * blob handling functions that we could have implemented, but all require
2189 * a very complex API. Instead we have chosen something that is extremely
2190 * simple to understand and use.
2191 *
2192 * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
2193 *
2194 * Usage to update a $blobvalue which has a primary key blob_id=1 into a
2195 * field blobtable.blobcolumn:
2196 *
2197 * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
2198 *
2199 * Insert example:
2200 *
2201 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
2202 * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
2203 */
2204 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') {
2205 return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
2206 }
2207
2208 /**
2209 * Usage:
2210 * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
2211 *
2212 * $blobtype supports 'BLOB' and 'CLOB'
2213 *
2214 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
2215 * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
2216 */
2217 function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') {
2218 $fd = fopen($path,'rb');
2219 if ($fd === false) {
2220 return false;
2221 }
2222 $val = fread($fd,filesize($path));
2223 fclose($fd);
2224 return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
2225 }
2226
2227 function BlobDecode($blob) {
2228 return $blob;
2229 }
2230
2231 function BlobEncode($blob) {
2232 return $blob;
2233 }
2234
2235 function GetCharSet() {
2236 return $this->charSet;
2237 }
2238
2239 function SetCharSet($charset) {
2240 $this->charSet = $charset;
2241 return true;
2242 }
2243
2244 function IfNull( $field, $ifNull ) {
2245 return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
2246 }
2247
2248 function LogSQL($enable=true) {
2249 include_once(ADODB_DIR.'/adodb-perf.inc.php');
2250
2251 if ($enable) {
2252 $this->fnExecute = 'adodb_log_sql';
2253 } else {
2254 $this->fnExecute = false;
2255 }
2256
2257 $old = $this->_logsql;
2258 $this->_logsql = $enable;
2259 if ($enable && !$old) {
2260 $this->_affected = false;
2261 }
2262 return $old;
2263 }
2264
2265 /**
2266 * Usage:
2267 * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
2268 *
2269 * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
2270 * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
2271 */
2272 function UpdateClob($table,$column,$val,$where) {
2273 return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
2274 }
2275
2276 // not the fastest implementation - quick and dirty - jlim
2277 // for best performance, use the actual $rs->MetaType().
2278 function MetaType($t,$len=-1,$fieldobj=false) {
2279
2280 if (empty($this->_metars)) {
2281 $rsclass = $this->rsPrefix.$this->databaseType;
2282 $this->_metars = new $rsclass(false,$this->fetchMode);
2283 $this->_metars->connection = $this;
2284 }
2285 return $this->_metars->MetaType($t,$len,$fieldobj);
2286 }
2287
2288
2289 /**
2290 * Change the SQL connection locale to a specified locale.
2291 * This is used to get the date formats written depending on the client locale.
2292 */
2293 function SetDateLocale($locale = 'En') {
2294 $this->locale = $locale;
2295 switch (strtoupper($locale))
2296 {
2297 case 'EN':
2298 $this->fmtDate="'Y-m-d'";
2299 $this->fmtTimeStamp = "'Y-m-d H:i:s'";
2300 break;
2301
2302 case 'US':
2303 $this->fmtDate = "'m-d-Y'";
2304 $this->fmtTimeStamp = "'m-d-Y H:i:s'";
2305 break;
2306
2307 case 'PT_BR':
2308 case 'NL':
2309 case 'FR':
2310 case 'RO':
2311 case 'IT':
2312 $this->fmtDate="'d-m-Y'";
2313 $this->fmtTimeStamp = "'d-m-Y H:i:s'";
2314 break;
2315
2316 case 'GE':
2317 $this->fmtDate="'d.m.Y'";
2318 $this->fmtTimeStamp = "'d.m.Y H:i:s'";
2319 break;
2320
2321 default:
2322 $this->fmtDate="'Y-m-d'";
2323 $this->fmtTimeStamp = "'Y-m-d H:i:s'";
2324 break;
2325 }
2326 }
2327
2328 /**
2329 * GetActiveRecordsClass Performs an 'ALL' query
2330 *
2331 * @param mixed $class This string represents the class of the current active record
2332 * @param mixed $table Table used by the active record object
2333 * @param mixed $whereOrderBy Where, order, by clauses
2334 * @param mixed $bindarr
2335 * @param mixed $primkeyArr
2336 * @param array $extra Query extras: limit, offset...
2337 * @param mixed $relations Associative array: table's foreign name, "hasMany", "belongsTo"
2338 * @access public
2339 * @return void
2340 */
2341 function GetActiveRecordsClass(
2342 $class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false,
2343 $extra=array(),
2344 $relations=array())
2345 {
2346 global $_ADODB_ACTIVE_DBS;
2347 ## reduce overhead of adodb.inc.php -- moved to adodb-active-record.inc.php
2348 ## if adodb-active-recordx is loaded -- should be no issue as they will probably use Find()
2349 if (!isset($_ADODB_ACTIVE_DBS)) {
2350 include_once(ADODB_DIR.'/adodb-active-record.inc.php');
2351 }
2352 return adodb_GetActiveRecordsClass($this, $class, $table, $whereOrderBy, $bindarr, $primkeyArr, $extra, $relations);
2353 }
2354
2355 function GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false) {
2356 $arr = $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr);
2357 return $arr;
2358 }
2359
2360 /**
2361 * Close Connection
2362 */
2363 function Close() {
2364 $rez = $this->_close();
2365 $this->_connectionID = false;
2366 return $rez;
2367 }
2368
2369 /**
2370 * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
2371 *
2372 * @return true if succeeded or false if database does not support transactions
2373 */
2374 function BeginTrans() {
2375 if ($this->debug) {
2376 ADOConnection::outp("BeginTrans: Transactions not supported for this driver");
2377 }
2378 return false;
2379 }
2380
2381 /* set transaction mode */
2382 function SetTransactionMode( $transaction_mode ) {
2383 $transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider);
2384 $this->_transmode = $transaction_mode;
2385 }
2386 /*
2387 http://msdn2.microsoft.com/en-US/ms173763.aspx
2388 http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html
2389 http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html
2390 http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm
2391 */
2392 function MetaTransaction($mode,$db) {
2393 $mode = strtoupper($mode);
2394 $mode = str_replace('ISOLATION LEVEL ','',$mode);
2395
2396 switch($mode) {
2397
2398 case 'READ UNCOMMITTED':
2399 switch($db) {
2400 case 'oci8':
2401 case 'oracle':
2402 return 'ISOLATION LEVEL READ COMMITTED';
2403 default:
2404 return 'ISOLATION LEVEL READ UNCOMMITTED';
2405 }
2406 break;
2407
2408 case 'READ COMMITTED':
2409 return 'ISOLATION LEVEL READ COMMITTED';
2410 break;
2411
2412 case 'REPEATABLE READ':
2413 switch($db) {
2414 case 'oci8':
2415 case 'oracle':
2416 return 'ISOLATION LEVEL SERIALIZABLE';
2417 default:
2418 return 'ISOLATION LEVEL REPEATABLE READ';
2419 }
2420 break;
2421
2422 case 'SERIALIZABLE':
2423 return 'ISOLATION LEVEL SERIALIZABLE';
2424 break;
2425
2426 default:
2427 return $mode;
2428 }
2429 }
2430
2431 /**
2432 * If database does not support transactions, always return true as data always commited
2433 *
2434 * @param $ok set to false to rollback transaction, true to commit
2435 *
2436 * @return true/false.
2437 */
2438 function CommitTrans($ok=true) {
2439 return true;
2440 }
2441
2442
2443 /**
2444 * If database does not support transactions, rollbacks always fail, so return false
2445 *
2446 * @return true/false.
2447 */
2448 function RollbackTrans() {
2449 return false;
2450 }
2451
2452
2453 /**
2454 * return the databases that the driver can connect to.
2455 * Some databases will return an empty array.
2456 *
2457 * @return an array of database names.
2458 */
2459 function MetaDatabases() {
2460 global $ADODB_FETCH_MODE;
2461
2462 if ($this->metaDatabasesSQL) {
2463 $save = $ADODB_FETCH_MODE;
2464 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2465
2466 if ($this->fetchMode !== false) {
2467 $savem = $this->SetFetchMode(false);
2468 }
2469
2470 $arr = $this->GetCol($this->metaDatabasesSQL);
2471 if (isset($savem)) {
2472 $this->SetFetchMode($savem);
2473 }
2474 $ADODB_FETCH_MODE = $save;
2475
2476 return $arr;
2477 }
2478
2479 return false;
2480 }
2481
2482 /**
2483 * List procedures or functions in an array.
2484 * @param procedureNamePattern a procedure name pattern; must match the procedure name as it is stored in the database
2485 * @param catalog a catalog name; must match the catalog name as it is stored in the database;
2486 * @param schemaPattern a schema name pattern;
2487 *
2488 * @return array of procedures on current database.
2489 *
2490 * Array(
2491 * [name_of_procedure] => Array(
2492 * [type] => PROCEDURE or FUNCTION
2493 * [catalog] => Catalog_name
2494 * [schema] => Schema_name
2495 * [remarks] => explanatory comment on the procedure
2496 * )
2497 * )
2498 */
2499 function MetaProcedures($procedureNamePattern = null, $catalog = null, $schemaPattern = null) {
2500 return false;
2501 }
2502
2503
2504 /**
2505 * @param ttype can either be 'VIEW' or 'TABLE' or false.
2506 * If false, both views and tables are returned.
2507 * "VIEW" returns only views
2508 * "TABLE" returns only tables
2509 * @param showSchema returns the schema/user with the table name, eg. USER.TABLE
2510 * @param mask is the input mask - only supported by oci8 and postgresql
2511 *
2512 * @return array of tables for current database.
2513 */
2514 function MetaTables($ttype=false,$showSchema=false,$mask=false) {
2515 global $ADODB_FETCH_MODE;
2516
2517 if ($mask) {
2518 return false;
2519 }
2520 if ($this->metaTablesSQL) {
2521 $save = $ADODB_FETCH_MODE;
2522 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2523
2524 if ($this->fetchMode !== false) {
2525 $savem = $this->SetFetchMode(false);
2526 }
2527
2528 $rs = $this->Execute($this->metaTablesSQL);
2529 if (isset($savem)) {
2530 $this->SetFetchMode($savem);
2531 }
2532 $ADODB_FETCH_MODE = $save;
2533
2534 if ($rs === false) {
2535 return false;
2536 }
2537 $arr = $rs->GetArray();
2538 $arr2 = array();
2539
2540 if ($hast = ($ttype && isset($arr[0][1]))) {
2541 $showt = strncmp($ttype,'T',1);
2542 }
2543
2544 for ($i=0; $i < sizeof($arr); $i++) {
2545 if ($hast) {
2546 if ($showt == 0) {
2547 if (strncmp($arr[$i][1],'T',1) == 0) {
2548 $arr2[] = trim($arr[$i][0]);
2549 }
2550 } else {
2551 if (strncmp($arr[$i][1],'V',1) == 0) {
2552 $arr2[] = trim($arr[$i][0]);
2553 }
2554 }
2555 } else
2556 $arr2[] = trim($arr[$i][0]);
2557 }
2558 $rs->Close();
2559 return $arr2;
2560 }
2561 return false;
2562 }
2563
2564
2565 function _findschema(&$table,&$schema) {
2566 if (!$schema && ($at = strpos($table,'.')) !== false) {
2567 $schema = substr($table,0,$at);
2568 $table = substr($table,$at+1);
2569 }
2570 }
2571
2572 /**
2573 * List columns in a database as an array of ADOFieldObjects.
2574 * See top of file for definition of object.
2575 *
2576 * @param $table table name to query
2577 * @param $normalize makes table name case-insensitive (required by some databases)
2578 * @schema is optional database schema to use - not supported by all databases.
2579 *
2580 * @return array of ADOFieldObjects for current table.
2581 */
2582 function MetaColumns($table,$normalize=true) {
2583 global $ADODB_FETCH_MODE;
2584
2585 if (!empty($this->metaColumnsSQL)) {
2586 $schema = false;
2587 $this->_findschema($table,$schema);
2588
2589 $save = $ADODB_FETCH_MODE;
2590 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2591 if ($this->fetchMode !== false) {
2592 $savem = $this->SetFetchMode(false);
2593 }
2594 $rs = $this->Execute(sprintf($this->metaColumnsSQL,($normalize)?strtoupper($table):$table));
2595 if (isset($savem)) {
2596 $this->SetFetchMode($savem);
2597 }
2598 $ADODB_FETCH_MODE = $save;
2599 if ($rs === false || $rs->EOF) {
2600 return false;
2601 }
2602
2603 $retarr = array();
2604 while (!$rs->EOF) { //print_r($rs->fields);
2605 $fld = new ADOFieldObject();
2606 $fld->name = $rs->fields[0];
2607 $fld->type = $rs->fields[1];
2608 if (isset($rs->fields[3]) && $rs->fields[3]) {
2609 if ($rs->fields[3]>0) {
2610 $fld->max_length = $rs->fields[3];
2611 }
2612 $fld->scale = $rs->fields[4];
2613 if ($fld->scale>0) {
2614 $fld->max_length += 1;
2615 }
2616 } else {
2617 $fld->max_length = $rs->fields[2];
2618 }
2619
2620 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) {
2621 $retarr[] = $fld;
2622 } else {
2623 $retarr[strtoupper($fld->name)] = $fld;
2624 }
2625 $rs->MoveNext();
2626 }
2627 $rs->Close();
2628 return $retarr;
2629 }
2630 return false;
2631 }
2632
2633 /**
2634 * List indexes on a table as an array.
2635 * @param table table name to query
2636 * @param primary true to only show primary keys. Not actually used for most databases
2637 *
2638 * @return array of indexes on current table. Each element represents an index, and is itself an associative array.
2639 *
2640 * Array(
2641 * [name_of_index] => Array(
2642 * [unique] => true or false
2643 * [columns] => Array(
2644 * [0] => firstname
2645 * [1] => lastname
2646 * )
2647 * )
2648 * )
2649 */
2650 function MetaIndexes($table, $primary = false, $owner = false) {
2651 return false;
2652 }
2653
2654 /**
2655 * List columns names in a table as an array.
2656 * @param table table name to query
2657 *
2658 * @return array of column names for current table.
2659 */
2660 function MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */) {
2661 $objarr = $this->MetaColumns($table);
2662 if (!is_array($objarr)) {
2663 return false;
2664 }
2665 $arr = array();
2666 if ($numIndexes) {
2667 $i = 0;
2668 if ($useattnum) {
2669 foreach($objarr as $v)
2670 $arr[$v->attnum] = $v->name;
2671
2672 } else
2673 foreach($objarr as $v) $arr[$i++] = $v->name;
2674 } else
2675 foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name;
2676
2677 return $arr;
2678 }
2679
2680 /**
2681 * Different SQL databases used different methods to combine strings together.
2682 * This function provides a wrapper.
2683 *
2684 * param s variable number of string parameters
2685 *
2686 * Usage: $db->Concat($str1,$str2);
2687 *
2688 * @return concatenated string
2689 */
2690 function Concat() {
2691 $arr = func_get_args();
2692 return implode($this->concat_operator, $arr);
2693 }
2694
2695
2696 /**
2697 * Converts a date "d" to a string that the database can understand.
2698 *
2699 * @param d a date in Unix date time format.
2700 *
2701 * @return date string in database date format
2702 */
2703 function DBDate($d, $isfld=false) {
2704 if (empty($d) && $d !== 0) {
2705 return 'null';
2706 }
2707 if ($isfld) {
2708 return $d;
2709 }
2710 if (is_object($d)) {
2711 return $d->format($this->fmtDate);
2712 }
2713
2714 if (is_string($d) && !is_numeric($d)) {
2715 if ($d === 'null') {
2716 return $d;
2717 }
2718 if (strncmp($d,"'",1) === 0) {
2719 $d = _adodb_safedateq($d);
2720 return $d;
2721 }
2722 if ($this->isoDates) {
2723 return "'$d'";
2724 }
2725 $d = ADOConnection::UnixDate($d);
2726 }
2727
2728 return adodb_date($this->fmtDate,$d);
2729 }
2730
2731 function BindDate($d) {
2732 $d = $this->DBDate($d);
2733 if (strncmp($d,"'",1)) {
2734 return $d;
2735 }
2736
2737 return substr($d,1,strlen($d)-2);
2738 }
2739
2740 function BindTimeStamp($d) {
2741 $d = $this->DBTimeStamp($d);
2742 if (strncmp($d,"'",1)) {
2743 return $d;
2744 }
2745
2746 return substr($d,1,strlen($d)-2);
2747 }
2748
2749
2750 /**
2751 * Converts a timestamp "ts" to a string that the database can understand.
2752 *
2753 * @param ts a timestamp in Unix date time format.
2754 *
2755 * @return timestamp string in database timestamp format
2756 */
2757 function DBTimeStamp($ts,$isfld=false) {
2758 if (empty($ts) && $ts !== 0) {
2759 return 'null';
2760 }
2761 if ($isfld) {
2762 return $ts;
2763 }
2764 if (is_object($ts)) {
2765 return $ts->format($this->fmtTimeStamp);
2766 }
2767
2768 # strlen(14) allows YYYYMMDDHHMMSS format
2769 if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) {
2770 return adodb_date($this->fmtTimeStamp,$ts);
2771 }
2772
2773 if ($ts === 'null') {
2774 return $ts;
2775 }
2776 if ($this->isoDates && strlen($ts) !== 14) {
2777 $ts = _adodb_safedate($ts);
2778 return "'$ts'";
2779 }
2780 $ts = ADOConnection::UnixTimeStamp($ts);
2781 return adodb_date($this->fmtTimeStamp,$ts);
2782 }
2783
2784 /**
2785 * Also in ADORecordSet.
2786 * @param $v is a date string in YYYY-MM-DD format
2787 *
2788 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2789 */
2790 static function UnixDate($v) {
2791 if (is_object($v)) {
2792 // odbtp support
2793 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2794 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2795 }
2796
2797 if (is_numeric($v) && strlen($v) !== 8) {
2798 return $v;
2799 }
2800 if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", $v, $rr)) {
2801 return false;
2802 }
2803
2804 if ($rr[1] <= TIMESTAMP_FIRST_YEAR) {
2805 return 0;
2806 }
2807
2808 // h-m-s-MM-DD-YY
2809 return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2810 }
2811
2812
2813 /**
2814 * Also in ADORecordSet.
2815 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
2816 *
2817 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2818 */
2819 static function UnixTimeStamp($v) {
2820 if (is_object($v)) {
2821 // odbtp support
2822 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2823 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2824 }
2825
2826 if (!preg_match(
2827 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
2828 ($v), $rr)) return false;
2829
2830 if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) {
2831 return 0;
2832 }
2833
2834 // h-m-s-MM-DD-YY
2835 if (!isset($rr[5])) {
2836 return adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2837 }
2838 return @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
2839 }
2840
2841 /**
2842 * Also in ADORecordSet.
2843 *
2844 * Format database date based on user defined format.
2845 *
2846 * @param v is the character date in YYYY-MM-DD format, returned by database
2847 * @param fmt is the format to apply to it, using date()
2848 *
2849 * @return a date formated as user desires
2850 */
2851 function UserDate($v,$fmt='Y-m-d',$gmt=false) {
2852 $tt = $this->UnixDate($v);
2853
2854 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2855 if (($tt === false || $tt == -1) && $v != false) {
2856 return $v;
2857 } else if ($tt == 0) {
2858 return $this->emptyDate;
2859 } else if ($tt == -1) {
2860 // pre-TIMESTAMP_FIRST_YEAR
2861 }
2862
2863 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2864
2865 }
2866
2867 /**
2868 *
2869 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
2870 * @param fmt is the format to apply to it, using date()
2871 *
2872 * @return a timestamp formated as user desires
2873 */
2874 function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false) {
2875 if (!isset($v)) {
2876 return $this->emptyTimeStamp;
2877 }
2878 # strlen(14) allows YYYYMMDDHHMMSS format
2879 if (is_numeric($v) && strlen($v)<14) {
2880 return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v);
2881 }
2882 $tt = $this->UnixTimeStamp($v);
2883 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2884 if (($tt === false || $tt == -1) && $v != false) {
2885 return $v;
2886 }
2887 if ($tt == 0) {
2888 return $this->emptyTimeStamp;
2889 }
2890 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2891 }
2892
2893 function escape($s,$magic_quotes=false) {
2894 return $this->addq($s,$magic_quotes);
2895 }
2896
2897 /**
2898 * Quotes a string, without prefixing nor appending quotes.
2899 */
2900 function addq($s,$magic_quotes=false) {
2901 if (!$magic_quotes) {
2902 if ($this->replaceQuote[0] == '\\') {
2903 // only since php 4.0.5
2904 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2905 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2906 }
2907 return str_replace("'",$this->replaceQuote,$s);
2908 }
2909
2910 // undo magic quotes for "
2911 $s = str_replace('\\"','"',$s);
2912
2913 if ($this->replaceQuote == "\\'" || ini_get('magic_quotes_sybase')) {
2914 // ' already quoted, no need to change anything
2915 return $s;
2916 } else {
2917 // change \' to '' for sybase/mssql
2918 $s = str_replace('\\\\','\\',$s);
2919 return str_replace("\\'",$this->replaceQuote,$s);
2920 }
2921 }
2922
2923 /**
2924 * Correctly quotes a string so that all strings are escaped. We prefix and append
2925 * to the string single-quotes.
2926 * An example is $db->qstr("Don't bother",magic_quotes_runtime());
2927 *
2928 * @param s the string to quote
2929 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
2930 * This undoes the stupidity of magic quotes for GPC.
2931 *
2932 * @return quoted string to be sent back to database
2933 */
2934 function qstr($s,$magic_quotes=false) {
2935 if (!$magic_quotes) {
2936 if ($this->replaceQuote[0] == '\\'){
2937 // only since php 4.0.5
2938 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2939 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2940 }
2941 return "'".str_replace("'",$this->replaceQuote,$s)."'";
2942 }
2943
2944 // undo magic quotes for "
2945 $s = str_replace('\\"','"',$s);
2946
2947 if ($this->replaceQuote == "\\'" || ini_get('magic_quotes_sybase')) {
2948 // ' already quoted, no need to change anything
2949 return "'$s'";
2950 } else {
2951 // change \' to '' for sybase/mssql
2952 $s = str_replace('\\\\','\\',$s);
2953 return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
2954 }
2955 }
2956
2957
2958 /**
2959 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2960 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2961 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2962 *
2963 * See docs-adodb.htm#ex8 for an example of usage.
2964 *
2965 * @param sql
2966 * @param nrows is the number of rows per page to get
2967 * @param page is the page number to get (1-based)
2968 * @param [inputarr] array of bind variables
2969 * @param [secs2cache] is a private parameter only used by jlim
2970 * @return the recordset ($rs->databaseType == 'array')
2971 *
2972 * NOTE: phpLens uses a different algorithm and does not use PageExecute().
2973 *
2974 */
2975 function PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0) {
2976 global $ADODB_INCLUDED_LIB;
2977 if (empty($ADODB_INCLUDED_LIB)) {
2978 include(ADODB_DIR.'/adodb-lib.inc.php');
2979 }
2980 if ($this->pageExecuteCountRows) {
2981 $rs = _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2982 } else {
2983 $rs = _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2984 }
2985 return $rs;
2986 }
2987
2988
2989 /**
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.
2993 *
2994 * @param secs2cache seconds to cache data, set to 0 to force query
2995 * @param sql
2996 * @param nrows is the number of rows per page to get
2997 * @param page is the page number to get (1-based)
2998 * @param [inputarr] array of bind variables
2999 * @return the recordset ($rs->databaseType == 'array')
3000 */
3001 function CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false) {
3002 /*switch($this->dataProvider) {
3003 case 'postgres':
3004 case 'mysql':
3005 break;
3006 default: $secs2cache = 0; break;
3007 }*/
3008 $rs = $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
3009 return $rs;
3010 }
3011
3012 } // end class ADOConnection
3013
3014
3015
3016 //==============================================================================================
3017 // CLASS ADOFetchObj
3018 //==============================================================================================
3019
3020 /**
3021 * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
3022 */
3023 class ADOFetchObj {
3024 };
3025
3026 //==============================================================================================
3027 // CLASS ADORecordSet_empty
3028 //==============================================================================================
3029
3030 class ADODB_Iterator_empty implements Iterator {
3031
3032 private $rs;
3033
3034 function __construct($rs) {
3035 $this->rs = $rs;
3036 }
3037
3038 function rewind() {}
3039
3040 function valid() {
3041 return !$this->rs->EOF;
3042 }
3043
3044 function key() {
3045 return false;
3046 }
3047
3048 function current() {
3049 return false;
3050 }
3051
3052 function next() {}
3053
3054 function __call($func, $params) {
3055 return call_user_func_array(array($this->rs, $func), $params);
3056 }
3057
3058 function hasMore() {
3059 return false;
3060 }
3061
3062 }
3063
3064
3065 /**
3066 * Lightweight recordset when there are no records to be returned
3067 */
3068 class ADORecordSet_empty implements IteratorAggregate
3069 {
3070 var $dataProvider = 'empty';
3071 var $databaseType = false;
3072 var $EOF = true;
3073 var $_numOfRows = 0;
3074 var $fields = false;
3075 var $connection = false;
3076
3077 function RowCount() {
3078 return 0;
3079 }
3080
3081 function RecordCount() {
3082 return 0;
3083 }
3084
3085 function PO_RecordCount() {
3086 return 0;
3087 }
3088
3089 function Close() {
3090 return true;
3091 }
3092
3093 function FetchRow() {
3094 return false;
3095 }
3096
3097 function FieldCount() {
3098 return 0;
3099 }
3100
3101 function Init() {}
3102
3103 function getIterator() {
3104 return new ADODB_Iterator_empty($this);
3105 }
3106
3107 function GetAssoc() {
3108 return array();
3109 }
3110
3111 function GetArray() {
3112 return array();
3113 }
3114
3115 function GetAll() {
3116 return array();
3117 }
3118
3119 function GetArrayLimit() {
3120 return array();
3121 }
3122
3123 function GetRows() {
3124 return array();
3125 }
3126
3127 function GetRowAssoc() {
3128 return array();
3129 }
3130
3131 function MaxRecordCount() {
3132 return 0;
3133 }
3134
3135 function NumRows() {
3136 return 0;
3137 }
3138
3139 function NumCols() {
3140 return 0;
3141 }
3142 }
3143
3144 //==============================================================================================
3145 // DATE AND TIME FUNCTIONS
3146 //==============================================================================================
3147 if (!defined('ADODB_DATE_VERSION')) {
3148 include(ADODB_DIR.'/adodb-time.inc.php');
3149 }
3150
3151 //==============================================================================================
3152 // CLASS ADORecordSet
3153 //==============================================================================================
3154
3155 class ADODB_Iterator implements Iterator {
3156
3157 private $rs;
3158
3159 function __construct($rs) {
3160 $this->rs = $rs;
3161 }
3162
3163 function rewind() {
3164 $this->rs->MoveFirst();
3165 }
3166
3167 function valid() {
3168 return !$this->rs->EOF;
3169 }
3170
3171 function key() {
3172 return $this->rs->_currentRow;
3173 }
3174
3175 function current() {
3176 return $this->rs->fields;
3177 }
3178
3179 function next() {
3180 $this->rs->MoveNext();
3181 }
3182
3183 function __call($func, $params) {
3184 return call_user_func_array(array($this->rs, $func), $params);
3185 }
3186
3187 function hasMore() {
3188 return !$this->rs->EOF;
3189 }
3190
3191 }
3192
3193
3194 /**
3195 * RecordSet class that represents the dataset returned by the database.
3196 * To keep memory overhead low, this class holds only the current row in memory.
3197 * No prefetching of data is done, so the RecordCount() can return -1 ( which
3198 * means recordcount not known).
3199 */
3200 class ADORecordSet implements IteratorAggregate {
3201
3202 /**
3203 * public variables
3204 */
3205 var $dataProvider = "native";
3206 var $fields = false; /// holds the current row data
3207 var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob
3208 /// in other words, we use a text area for editing.
3209 var $canSeek = false; /// indicates that seek is supported
3210 var $sql; /// sql text
3211 var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object.
3212
3213 var $emptyTimeStamp = '&nbsp;'; /// what to display when $time==0
3214 var $emptyDate = '&nbsp;'; /// what to display when $time==0
3215 var $debug = false;
3216 var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsets
3217
3218 var $bind = false; /// used by Fields() to hold array - should be private?
3219 var $fetchMode; /// default fetch mode
3220 var $connection = false; /// the parent connection
3221
3222 /**
3223 * private variables
3224 */
3225 var $_numOfRows = -1; /** number of rows, or -1 */
3226 var $_numOfFields = -1; /** number of fields in recordset */
3227 var $_queryID = -1; /** This variable keeps the result link identifier. */
3228 var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */
3229 var $_closed = false; /** has recordset been closed */
3230 var $_inited = false; /** Init() should only be called once */
3231 var $_obj; /** Used by FetchObj */
3232 var $_names; /** Used by FetchObj */
3233
3234 var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */
3235 var $_atFirstPage = false; /** Added by Iván Oliva to implement recordset pagination */
3236 var $_atLastPage = false; /** Added by Iván Oliva to implement recordset pagination */
3237 var $_lastPageNo = -1;
3238 var $_maxRecordCount = 0;
3239 var $datetime = false;
3240
3241 /**
3242 * Constructor
3243 *
3244 * @param queryID this is the queryID returned by ADOConnection->_query()
3245 *
3246 */
3247 function __construct($queryID) {
3248 $this->_queryID = $queryID;
3249 }
3250
3251 function __destruct() {
3252 $this->Close();
3253 }
3254
3255 function getIterator() {
3256 return new ADODB_Iterator($this);
3257 }
3258
3259 /* this is experimental - i don't really know what to return... */
3260 function __toString() {
3261 include_once(ADODB_DIR.'/toexport.inc.php');
3262 return _adodb_export($this,',',',',false,true);
3263 }
3264
3265 function Init() {
3266 if ($this->_inited) {
3267 return;
3268 }
3269 $this->_inited = true;
3270 if ($this->_queryID) {
3271 @$this->_initrs();
3272 } else {
3273 $this->_numOfRows = 0;
3274 $this->_numOfFields = 0;
3275 }
3276 if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
3277 $this->_currentRow = 0;
3278 if ($this->EOF = ($this->_fetch() === false)) {
3279 $this->_numOfRows = 0; // _numOfRows could be -1
3280 }
3281 } else {
3282 $this->EOF = true;
3283 }
3284 }
3285
3286
3287 /**
3288 * Generate a SELECT tag string from a recordset, and return the string.
3289 * If the recordset has 2 cols, we treat the 1st col as the containing
3290 * the text to display to the user, and 2nd col as the return value. Default
3291 * strings are compared with the FIRST column.
3292 *
3293 * @param name name of SELECT tag
3294 * @param [defstr] the value to hilite. Use an array for multiple hilites for listbox.
3295 * @param [blank1stItem] true to leave the 1st item in list empty
3296 * @param [multiple] true for listbox, false for popup
3297 * @param [size] #rows to show for listbox. not used by popup
3298 * @param [selectAttr] additional attributes to defined for SELECT tag.
3299 * useful for holding javascript onChange='...' handlers.
3300 & @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with
3301 * column 0 (1st col) if this is true. This is not documented.
3302 *
3303 * @return HTML
3304 *
3305 * changes by glen.davies@cce.ac.nz to support multiple hilited items
3306 */
3307 function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
3308 $size=0, $selectAttr='',$compareFields0=true)
3309 {
3310 global</