Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
1 <?php 2 /* 3 * Set tabs to 4 for best viewing. 4 * 5 * Latest version is available at http://adodb.org/ 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.16 12-Jan-2020 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 34 if (!defined('_ADODB_LAYER')) { 35 define('_ADODB_LAYER',1); 36 37 // The ADOdb extension is no longer maintained and effectively unsupported 38 // since v5.04. The library will not function properly if it is present. 39 if(defined('ADODB_EXTENSION')) { 40 $msg = "Unsupported ADOdb Extension (v" . ADODB_EXTENSION . ") detected! " 41 . "Disable it to use ADOdb"; 42 43 $errorfn = defined('ADODB_ERROR_HANDLER') ? ADODB_ERROR_HANDLER : false; 44 if ($errorfn) { 45 $conn = false; 46 $errorfn('ADOdb', basename(__FILE__), -9999, $msg, null, null, $conn); 47 } else { 48 die($msg . PHP_EOL); 49 } 50 } 51 52 //============================================================================================== 53 // CONSTANT DEFINITIONS 54 //============================================================================================== 55 56 57 /** 58 * Set ADODB_DIR to the directory where this file resides... 59 * This constant was formerly called $ADODB_RootPath 60 */ 61 if (!defined('ADODB_DIR')) { 62 define('ADODB_DIR',dirname(__FILE__)); 63 } 64 65 //============================================================================================== 66 // GLOBAL VARIABLES 67 //============================================================================================== 68 69 GLOBAL 70 $ADODB_vers, // database version 71 $ADODB_COUNTRECS, // count number of records returned - slows down query 72 $ADODB_CACHE_DIR, // directory to cache recordsets 73 $ADODB_CACHE, 74 $ADODB_CACHE_CLASS, 75 $ADODB_EXTENSION, // ADODB extension installed 76 $ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF 77 $ADODB_FETCH_MODE, // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default... 78 $ADODB_GETONE_EOF, 79 $ADODB_QUOTE_FIELDNAMES; // Allows you to force quotes (backticks) around field names in queries generated by getinsertsql and getupdatesql. 80 81 //============================================================================================== 82 // GLOBAL SETUP 83 //============================================================================================== 84 85 $ADODB_EXTENSION = defined('ADODB_EXTENSION'); 86 87 // ******************************************************** 88 // Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3). 89 // Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi 90 // 91 // 0 = ignore empty fields. All empty fields in array are ignored. 92 // 1 = force null. All empty, php null and string 'null' fields are changed to sql NULL values. 93 // 2 = force empty. All empty, php null and string 'null' fields are changed to sql empty '' or 0 values. 94 // 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. 95 96 define('ADODB_FORCE_IGNORE',0); 97 define('ADODB_FORCE_NULL',1); 98 define('ADODB_FORCE_EMPTY',2); 99 define('ADODB_FORCE_VALUE',3); 100 // ******************************************************** 101 102 103 if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) { 104 105 define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>'); 106 107 // allow [ ] @ ` " and . in table names 108 define('ADODB_TABLE_REGEX','([]0-9a-z_\:\"\`\.\@\[-]*)'); 109 110 // prefetching used by oracle 111 if (!defined('ADODB_PREFETCH_ROWS')) { 112 define('ADODB_PREFETCH_ROWS',10); 113 } 114 115 116 /** 117 * Fetch mode 118 * 119 * Set global variable $ADODB_FETCH_MODE to one of these constants or use 120 * the SetFetchMode() method to control how recordset fields are returned 121 * when fetching data. 122 * 123 * - NUM: array() 124 * - ASSOC: array('id' => 456, 'name' => 'john') 125 * - BOTH: array(0 => 456, 'id' => 456, 1 => 'john', 'name' => 'john') 126 * - DEFAULT: driver-dependent 127 */ 128 define('ADODB_FETCH_DEFAULT', 0); 129 define('ADODB_FETCH_NUM', 1); 130 define('ADODB_FETCH_ASSOC', 2); 131 define('ADODB_FETCH_BOTH', 3); 132 133 /** 134 * Associative array case constants 135 * 136 * By defining the ADODB_ASSOC_CASE constant to one of these values, it is 137 * possible to control the case of field names (associative array's keys) 138 * when operating in ADODB_FETCH_ASSOC fetch mode. 139 * - LOWER: $rs->fields['orderid'] 140 * - UPPER: $rs->fields['ORDERID'] 141 * - NATIVE: $rs->fields['OrderID'] (or whatever the RDBMS will return) 142 * 143 * The default is to use native case-names. 144 * 145 * NOTE: This functionality is not implemented everywhere, it currently 146 * works only with: mssql, odbc, oci8 and ibase derived drivers 147 */ 148 define('ADODB_ASSOC_CASE_LOWER', 0); 149 define('ADODB_ASSOC_CASE_UPPER', 1); 150 define('ADODB_ASSOC_CASE_NATIVE', 2); 151 152 153 if (!defined('TIMESTAMP_FIRST_YEAR')) { 154 define('TIMESTAMP_FIRST_YEAR',100); 155 } 156 157 /** 158 * AutoExecute constants 159 * (moved from adodb-pear.inc.php since they are only used in here) 160 */ 161 define('DB_AUTOQUERY_INSERT', 1); 162 define('DB_AUTOQUERY_UPDATE', 2); 163 164 165 // PHP's version scheme makes converting to numbers difficult - workaround 166 $_adodb_ver = (float) PHP_VERSION; 167 if ($_adodb_ver >= 5.2) { 168 define('ADODB_PHPVER',0x5200); 169 } else if ($_adodb_ver >= 5.0) { 170 define('ADODB_PHPVER',0x5000); 171 } else { 172 die("PHP5 or later required. You are running ".PHP_VERSION); 173 } 174 unset($_adodb_ver); 175 } 176 177 178 /** 179 Accepts $src and $dest arrays, replacing string $data 180 */ 181 function ADODB_str_replace($src, $dest, $data) { 182 if (ADODB_PHPVER >= 0x4050) { 183 return str_replace($src,$dest,$data); 184 } 185 186 $s = reset($src); 187 $d = reset($dest); 188 while ($s !== false) { 189 $data = str_replace($s,$d,$data); 190 $s = next($src); 191 $d = next($dest); 192 } 193 return $data; 194 } 195 196 function ADODB_Setup() { 197 GLOBAL 198 $ADODB_vers, // database version 199 $ADODB_COUNTRECS, // count number of records returned - slows down query 200 $ADODB_CACHE_DIR, // directory to cache recordsets 201 $ADODB_FETCH_MODE, 202 $ADODB_CACHE, 203 $ADODB_CACHE_CLASS, 204 $ADODB_FORCE_TYPE, 205 $ADODB_GETONE_EOF, 206 $ADODB_QUOTE_FIELDNAMES; 207 208 if (empty($ADODB_CACHE_CLASS)) { 209 $ADODB_CACHE_CLASS = 'ADODB_Cache_File' ; 210 } 211 $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT; 212 $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE; 213 $ADODB_GETONE_EOF = null; 214 215 if (!isset($ADODB_CACHE_DIR)) { 216 $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp'; 217 } else { 218 // do not accept url based paths, eg. http:/ or ftp:/ 219 if (strpos($ADODB_CACHE_DIR,'://') !== false) { 220 die("Illegal path http:// or ftp://"); 221 } 222 } 223 224 /** 225 * ADODB version as a string. 226 */ 227 $ADODB_vers = 'v5.20.16 12-Jan-2020'; 228 229 /** 230 * Determines whether recordset->RecordCount() is used. 231 * Set to false for highest performance -- RecordCount() will always return -1 then 232 * for databases that provide "virtual" recordcounts... 233 */ 234 if (!isset($ADODB_COUNTRECS)) { 235 $ADODB_COUNTRECS = true; 236 } 237 } 238 239 240 //============================================================================================== 241 // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB 242 //============================================================================================== 243 244 ADODB_Setup(); 245 246 //============================================================================================== 247 // CLASS ADOFieldObject 248 //============================================================================================== 249 /** 250 * Helper class for FetchFields -- holds info on a column 251 */ 252 class ADOFieldObject { 253 var $name = ''; 254 var $max_length=0; 255 var $type=""; 256 /* 257 // additional fields by dannym... (danny_milo@yahoo.com) 258 var $not_null = false; 259 // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^ 260 // so we can as well make not_null standard (leaving it at "false" does not harm anyways) 261 262 var $has_default = false; // this one I have done only in mysql and postgres for now ... 263 // others to come (dannym) 264 var $default_value; // default, if any, and supported. Check has_default first. 265 */ 266 } 267 268 269 function _adodb_safedate($s) { 270 return str_replace(array("'", '\\'), '', $s); 271 } 272 273 // parse date string to prevent injection attack 274 // date string will have one quote at beginning e.g. '3434343' 275 function _adodb_safedateq($s) { 276 $len = strlen($s); 277 if ($s[0] !== "'") { 278 $s2 = "'".$s[0]; 279 } else { 280 $s2 = "'"; 281 } 282 for($i=1; $i<$len; $i++) { 283 $ch = $s[$i]; 284 if ($ch === '\\') { 285 $s2 .= "'"; 286 break; 287 } elseif ($ch === "'") { 288 $s2 .= $ch; 289 break; 290 } 291 292 $s2 .= $ch; 293 } 294 295 return strlen($s2) == 0 ? 'null' : $s2; 296 } 297 298 299 // for transaction handling 300 301 function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection) { 302 //print "Errorno ($fn errno=$errno m=$errmsg) "; 303 $thisConnection->_transOK = false; 304 if ($thisConnection->_oldRaiseFn) { 305 $fn = $thisConnection->_oldRaiseFn; 306 $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection); 307 } 308 } 309 310 //------------------ 311 // class for caching 312 class ADODB_Cache_File { 313 314 var $createdir = true; // requires creation of temp dirs 315 316 function __construct() { 317 global $ADODB_INCLUDED_CSV; 318 if (empty($ADODB_INCLUDED_CSV)) { 319 include_once (ADODB_DIR.'/adodb-csvlib.inc.php'); 320 } 321 } 322 323 // write serialised recordset to cache item/file 324 function writecache($filename, $contents, $debug, $secs2cache) { 325 return adodb_write_file($filename, $contents,$debug); 326 } 327 328 // load serialised recordset and unserialise it 329 function &readcache($filename, &$err, $secs2cache, $rsClass) { 330 $rs = csv2rs($filename,$err,$secs2cache,$rsClass); 331 return $rs; 332 } 333 334 // flush all items in cache 335 function flushall($debug=false) { 336 global $ADODB_CACHE_DIR; 337 338 $rez = false; 339 340 if (strlen($ADODB_CACHE_DIR) > 1) { 341 $rez = $this->_dirFlush($ADODB_CACHE_DIR); 342 if ($debug) { 343 ADOConnection::outp( "flushall: $ADODB_CACHE_DIR<br><pre>\n". $rez."</pre>"); 344 } 345 } 346 return $rez; 347 } 348 349 // flush one file in cache 350 function flushcache($f, $debug=false) { 351 if (!@unlink($f)) { 352 if ($debug) { 353 ADOConnection::outp( "flushcache: failed for $f"); 354 } 355 } 356 } 357 358 function getdirname($hash) { 359 global $ADODB_CACHE_DIR; 360 if (!isset($this->notSafeMode)) { 361 $this->notSafeMode = !ini_get('safe_mode'); 362 } 363 return ($this->notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($hash,0,2) : $ADODB_CACHE_DIR; 364 } 365 366 // create temp directories 367 function createdir($hash, $debug) { 368 global $ADODB_CACHE_PERMS; 369 370 $dir = $this->getdirname($hash); 371 if ($this->notSafeMode && !file_exists($dir)) { 372 $oldu = umask(0); 373 if (!@mkdir($dir, empty($ADODB_CACHE_PERMS) ? 0771 : $ADODB_CACHE_PERMS)) { 374 if(!is_dir($dir) && $debug) { 375 ADOConnection::outp("Cannot create $dir"); 376 } 377 } 378 umask($oldu); 379 } 380 381 return $dir; 382 } 383 384 /** 385 * Private function to erase all of the files and subdirectories in a directory. 386 * 387 * Just specify the directory, and tell it if you want to delete the directory or just clear it out. 388 * Note: $kill_top_level is used internally in the function to flush subdirectories. 389 */ 390 function _dirFlush($dir, $kill_top_level = false) { 391 if(!$dh = @opendir($dir)) return; 392 393 while (($obj = readdir($dh))) { 394 if($obj=='.' || $obj=='..') continue; 395 $f = $dir.'/'.$obj; 396 397 if (strpos($obj,'.cache')) { 398 @unlink($f); 399 } 400 if (is_dir($f)) { 401 $this->_dirFlush($f, true); 402 } 403 } 404 if ($kill_top_level === true) { 405 @rmdir($dir); 406 } 407 return true; 408 } 409 } 410 411 //============================================================================================== 412 // CLASS ADOConnection 413 //============================================================================================== 414 415 /** 416 * Connection object. For connecting to databases, and executing queries. 417 */ 418 abstract class ADOConnection { 419 // 420 // PUBLIC VARS 421 // 422 var $dataProvider = 'native'; 423 var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql 424 var $database = ''; /// Name of database to be used. 425 var $host = ''; /// The hostname of the database server 426 var $port = ''; /// The port of the database server 427 var $user = ''; /// The username which is used to connect to the database server. 428 var $password = ''; /// Password for the username. For security, we no longer store it. 429 var $debug = false; /// if set to true will output sql statements 430 var $maxblobsize = 262144; /// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxpro 431 var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase 432 var $substr = 'substr'; /// substring operator 433 var $length = 'length'; /// string length ofperator 434 var $random = 'rand()'; /// random function 435 var $upperCase = 'upper'; /// uppercase function 436 var $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the database 437 var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt. 438 var $true = '1'; /// string that represents TRUE for a database 439 var $false = '0'; /// string that represents FALSE for a database 440 var $replaceQuote = "\\'"; /// string to use to replace quotes 441 var $nameQuote = '"'; /// string to use to quote identifiers and names 442 var $charSet=false; /// character set to use - only for interbase, postgres and oci8 443 var $metaDatabasesSQL = ''; 444 var $metaTablesSQL = ''; 445 var $uniqueOrderBy = false; /// All order by columns have to be unique 446 var $emptyDate = ' '; 447 var $emptyTimeStamp = ' '; 448 var $lastInsID = false; 449 //-- 450 var $hasInsertID = false; /// supports autoincrement ID? 451 var $hasAffectedRows = false; /// supports affected rows for update/delete? 452 var $hasTop = false; /// support mssql/access SELECT TOP 10 * FROM TABLE 453 var $hasLimit = false; /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10 454 var $readOnly = false; /// this is a readonly database - used by phpLens 455 var $hasMoveFirst = false; /// has ability to run MoveFirst(), scrolling backwards 456 var $hasGenID = false; /// can generate sequences using GenID(); 457 var $hasTransactions = true; /// has transactions 458 //-- 459 var $genID = 0; /// sequence id used by GenID(); 460 var $raiseErrorFn = false; /// error function to call 461 var $isoDates = false; /// accepts dates in ISO format 462 var $cacheSecs = 3600; /// cache for 1 hour 463 464 // memcache 465 var $memCache = false; /// should we use memCache instead of caching in files 466 var $memCacheHost; /// memCache host 467 var $memCachePort = 11211; /// memCache port 468 var $memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib) 469 470 var $sysDate = false; /// name of function that returns the current date 471 var $sysTimeStamp = false; /// name of function that returns the current timestamp 472 var $sysUTimeStamp = false; // name of function that returns the current timestamp accurate to the microsecond or nearest fraction 473 var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets 474 475 var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' ' 476 var $numCacheHits = 0; 477 var $numCacheMisses = 0; 478 var $pageExecuteCountRows = true; 479 var $uniqueSort = false; /// indicates that all fields in order by must be unique 480 var $leftOuter = false; /// operator to use for left outer join in WHERE clause 481 var $rightOuter = false; /// operator to use for right outer join in WHERE clause 482 var $ansiOuter = false; /// whether ansi outer join syntax supported 483 var $autoRollback = false; // autoRollback on PConnect(). 484 var $poorAffectedRows = false; // affectedRows not working or unreliable 485 486 var $fnExecute = false; 487 var $fnCacheExecute = false; 488 var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char 489 var $rsPrefix = "ADORecordSet_"; 490 491 var $autoCommit = true; /// do not modify this yourself - actually private 492 var $transOff = 0; /// temporarily disable transactions 493 var $transCnt = 0; /// count of nested transactions 494 495 var $fetchMode=false; 496 497 var $null2null = 'null'; // in autoexecute/getinsertsql/getupdatesql, this value will be converted to a null 498 var $bulkBind = false; // enable 2D Execute array 499 // 500 // PRIVATE VARS 501 // 502 var $_oldRaiseFn = false; 503 var $_transOK = null; 504 var $_connectionID = false; /// The returned link identifier whenever a successful database connection is made. 505 var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will 506 /// then returned by the errorMsg() function 507 var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8 508 var $_queryID = false; /// This variable keeps the last created result link identifier 509 510 var $_isPersistentConnection = false; /// A boolean variable to state whether its a persistent connection or normal connection. */ 511 var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters. 512 var $_evalAll = false; 513 var $_affected = false; 514 var $_logsql = false; 515 var $_transmode = ''; // transaction mode 516 517 /* 518 * Additional parameters that may be passed to drivers in the connect string 519 * Driver must be coded to accept the parameters 520 */ 521 protected $connectionParameters = array(); 522 523 /** 524 * Adds a parameter to the connection string. 525 * 526 * These parameters are added to the connection string when connecting, 527 * if the driver is coded to use it. 528 * 529 * @param string $parameter The name of the parameter to set 530 * @param string $value The value of the parameter 531 * 532 * @return null 533 * 534 * @example, for mssqlnative driver ('CharacterSet','UTF-8') 535 */ 536 final public function setConnectionParameter($parameter,$value) 537 { 538 539 $this->connectionParameters[$parameter] = $value; 540 541 } 542 543 static function Version() { 544 global $ADODB_vers; 545 546 // Semantic Version number matching regex 547 $regex = '^[vV]?(\d+\.\d+\.\d+' // Version number (X.Y.Z) with optional 'V' 548 . '(?:-(?:' // Optional preprod version: a '-' 549 . 'dev|' // followed by 'dev' 550 . '(?:(?:alpha|beta|rc)(?:\.\d+))' // or a preprod suffix and version number 551 . '))?)(?:\s|$)'; // Whitespace or end of string 552 553 if (!preg_match("/$regex/", $ADODB_vers, $matches)) { 554 // This should normally not happen... Return whatever is between the start 555 // of the string and the first whitespace (or the end of the string). 556 self::outp("Invalid version number: '$ADODB_vers'", 'Version'); 557 $regex = '^[vV]?(.*?)(?:\s|$)'; 558 preg_match("/$regex/", $ADODB_vers, $matches); 559 } 560 return $matches[1]; 561 } 562 563 /** 564 Get server version info... 565 566 @returns An array with 2 elements: $arr['string'] is the description string, 567 and $arr[version] is the version (also a string). 568 */ 569 function ServerInfo() { 570 return array('description' => '', 'version' => ''); 571 } 572 573 function IsConnected() { 574 return !empty($this->_connectionID); 575 } 576 577 function _findvers($str) { 578 if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) { 579 return $arr[1]; 580 } else { 581 return ''; 582 } 583 } 584 585 /** 586 * All error messages go through this bottleneck function. 587 * You can define your own handler by defining the function name in ADODB_OUTP. 588 */ 589 static function outp($msg,$newline=true) { 590 global $ADODB_FLUSH,$ADODB_OUTP; 591 592 if (defined('ADODB_OUTP')) { 593 $fn = ADODB_OUTP; 594 $fn($msg,$newline); 595 return; 596 } else if (isset($ADODB_OUTP)) { 597 $fn = $ADODB_OUTP; 598 $fn($msg,$newline); 599 return; 600 } 601 602 if ($newline) { 603 $msg .= "<br>\n"; 604 } 605 606 if (isset($_SERVER['HTTP_USER_AGENT']) || !$newline) { 607 echo $msg; 608 } else { 609 echo strip_tags($msg); 610 } 611 612 613 if (!empty($ADODB_FLUSH) && ob_get_length() !== false) { 614 flush(); // do not flush if output buffering enabled - useless - thx to Jesse Mullan 615 } 616 617 } 618 619 function Time() { 620 $rs = $this->_Execute("select $this->sysTimeStamp"); 621 if ($rs && !$rs->EOF) { 622 return $this->UnixTimeStamp(reset($rs->fields)); 623 } 624 625 return false; 626 } 627 628 /** 629 * Parses the hostname to extract the port. 630 * Overwrites $this->host and $this->port, only if a port is specified. 631 * The Hostname can be fully or partially qualified, 632 * ie: "db.mydomain.com:5432" or "ldaps://ldap.mydomain.com:636" 633 * Any specified scheme such as ldap:// or ldaps:// is maintained. 634 */ 635 protected function parseHostNameAndPort() { 636 $parsed_url = parse_url($this->host); 637 if (is_array($parsed_url) && isset($parsed_url['host']) && isset($parsed_url['port'])) { 638 if ( isset($parsed_url['scheme']) ) { 639 // If scheme is specified (ie: ldap:// or ldaps://, make sure we retain that. 640 $this->host = $parsed_url['scheme'] . "://" . $parsed_url['host']; 641 } else { 642 $this->host = $parsed_url['host']; 643 } 644 $this->port = $parsed_url['port']; 645 } 646 } 647 648 /** 649 * Connect to database 650 * 651 * @param [argHostname] Host to connect to 652 * @param [argUsername] Userid to login 653 * @param [argPassword] Associated password 654 * @param [argDatabaseName] database 655 * @param [forceNew] force new connection 656 * 657 * @return true or false 658 */ 659 function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) { 660 if ($argHostname != "") { 661 $this->host = $argHostname; 662 } 663 // Overwrites $this->host and $this->port if a port is specified. 664 $this->parseHostNameAndPort(); 665 666 if ($argUsername != "") { 667 $this->user = $argUsername; 668 } 669 if ($argPassword != "") { 670 $this->password = 'not stored'; // not stored for security reasons 671 } 672 if ($argDatabaseName != "") { 673 $this->database = $argDatabaseName; 674 } 675 676 $this->_isPersistentConnection = false; 677 678 if ($forceNew) { 679 if ($rez=$this->_nconnect($this->host, $this->user, $argPassword, $this->database)) { 680 return true; 681 } 682 } else { 683 if ($rez=$this->_connect($this->host, $this->user, $argPassword, $this->database)) { 684 return true; 685 } 686 } 687 if (isset($rez)) { 688 $err = $this->ErrorMsg(); 689 $errno = $this->ErrorNo(); 690 if (empty($err)) { 691 $err = "Connection error to server '$argHostname' with user '$argUsername'"; 692 } 693 } else { 694 $err = "Missing extension for ".$this->dataProvider; 695 $errno = 0; 696 } 697 if ($fn = $this->raiseErrorFn) { 698 $fn($this->databaseType, 'CONNECT', $errno, $err, $this->host, $this->database, $this); 699 } 700 701 $this->_connectionID = false; 702 if ($this->debug) { 703 ADOConnection::outp( $this->host.': '.$err); 704 } 705 return false; 706 } 707 708 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) { 709 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName); 710 } 711 712 713 /** 714 * Always force a new connection to database - currently only works with oracle 715 * 716 * @param [argHostname] Host to connect to 717 * @param [argUsername] Userid to login 718 * @param [argPassword] Associated password 719 * @param [argDatabaseName] database 720 * 721 * @return true or false 722 */ 723 function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") { 724 return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true); 725 } 726 727 /** 728 * Establish persistent connect to database 729 * 730 * @param [argHostname] Host to connect to 731 * @param [argUsername] Userid to login 732 * @param [argPassword] Associated password 733 * @param [argDatabaseName] database 734 * 735 * @return return true or false 736 */ 737 function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") { 738 739 if (defined('ADODB_NEVER_PERSIST')) { 740 return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName); 741 } 742 743 if ($argHostname != "") { 744 $this->host = $argHostname; 745 } 746 // Overwrites $this->host and $this->port if a port is specified. 747 $this->parseHostNameAndPort(); 748 749 if ($argUsername != "") { 750 $this->user = $argUsername; 751 } 752 if ($argPassword != "") { 753 $this->password = 'not stored'; 754 } 755 if ($argDatabaseName != "") { 756 $this->database = $argDatabaseName; 757 } 758 759 $this->_isPersistentConnection = true; 760 761 if ($rez = $this->_pconnect($this->host, $this->user, $argPassword, $this->database)) { 762 return true; 763 } 764 if (isset($rez)) { 765 $err = $this->ErrorMsg(); 766 if (empty($err)) { 767 $err = "Connection error to server '$argHostname' with user '$argUsername'"; 768 } 769 $ret = false; 770 } else { 771 $err = "Missing extension for ".$this->dataProvider; 772 $ret = 0; 773 } 774 if ($fn = $this->raiseErrorFn) { 775 $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this); 776 } 777 778 $this->_connectionID = false; 779 if ($this->debug) { 780 ADOConnection::outp( $this->host.': '.$err); 781 } 782 return $ret; 783 } 784 785 function outp_throw($msg,$src='WARN',$sql='') { 786 if (defined('ADODB_ERROR_HANDLER') && ADODB_ERROR_HANDLER == 'adodb_throw') { 787 adodb_throw($this->databaseType,$src,-9999,$msg,$sql,false,$this); 788 return; 789 } 790 ADOConnection::outp($msg); 791 } 792 793 // create cache class. Code is backward compat with old memcache implementation 794 function _CreateCache() { 795 global $ADODB_CACHE, $ADODB_CACHE_CLASS; 796 797 if ($this->memCache) { 798 global $ADODB_INCLUDED_MEMCACHE; 799 800 if (empty($ADODB_INCLUDED_MEMCACHE)) { 801 include_once (ADODB_DIR.'/adodb-memcache.lib.inc.php'); 802 } 803 $ADODB_CACHE = new ADODB_Cache_MemCache($this); 804 } else { 805 $ADODB_CACHE = new $ADODB_CACHE_CLASS($this); 806 } 807 } 808 809 // Format date column in sql string given an input format that understands Y M D 810 function SQLDate($fmt, $col=false) { 811 if (!$col) { 812 $col = $this->sysDate; 813 } 814 return $col; // child class implement 815 } 816 817 /** 818 * Should prepare the sql statement and return the stmt resource. 819 * For databases that do not support this, we return the $sql. To ensure 820 * compatibility with databases that do not support prepare: 821 * 822 * $stmt = $db->Prepare("insert into table (id, name) values (?,?)"); 823 * $db->Execute($stmt,array(1,'Jill')) or die('insert failed'); 824 * $db->Execute($stmt,array(2,'Joe')) or die('insert failed'); 825 * 826 * @param sql SQL to send to database 827 * 828 * @return return FALSE, or the prepared statement, or the original sql if 829 * if the database does not support prepare. 830 * 831 */ 832 function Prepare($sql) { 833 return $sql; 834 } 835 836 /** 837 * Some databases, eg. mssql require a different function for preparing 838 * stored procedures. So we cannot use Prepare(). 839 * 840 * Should prepare the stored procedure and return the stmt resource. 841 * For databases that do not support this, we return the $sql. To ensure 842 * compatibility with databases that do not support prepare: 843 * 844 * @param sql SQL to send to database 845 * 846 * @return return FALSE, or the prepared statement, or the original sql if 847 * if the database does not support prepare. 848 * 849 */ 850 function PrepareSP($sql,$param=true) { 851 return $this->Prepare($sql,$param); 852 } 853 854 /** 855 * PEAR DB Compat 856 */ 857 function Quote($s) { 858 return $this->qstr($s,false); 859 } 860 861 /** 862 * Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de> 863 */ 864 function QMagic($s) { 865 return $this->qstr($s,get_magic_quotes_gpc()); 866 } 867 868 function q(&$s) { 869 //if (!empty($this->qNull && $s == 'null') { 870 // return $s; 871 //} 872 $s = $this->qstr($s,false); 873 } 874 875 /** 876 * PEAR DB Compat - do not use internally. 877 */ 878 function ErrorNative() { 879 return $this->ErrorNo(); 880 } 881 882 883 /** 884 * PEAR DB Compat - do not use internally. 885 */ 886 function nextId($seq_name) { 887 return $this->GenID($seq_name); 888 } 889 890 /** 891 * Lock a row, will escalate and lock the table if row locking not supported 892 * will normally free the lock at the end of the transaction 893 * 894 * @param $table name of table to lock 895 * @param $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock 896 */ 897 function RowLock($table,$where,$col='1 as adodbignore') { 898 return false; 899 } 900 901 function CommitLock($table) { 902 return $this->CommitTrans(); 903 } 904 905 function RollbackLock($table) { 906 return $this->RollbackTrans(); 907 } 908 909 /** 910 * PEAR DB Compat - do not use internally. 911 * 912 * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical 913 * for easy porting :-) 914 * 915 * @param mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM 916 * @returns The previous fetch mode 917 */ 918 function SetFetchMode($mode) { 919 $old = $this->fetchMode; 920 $this->fetchMode = $mode; 921 922 if ($old === false) { 923 global $ADODB_FETCH_MODE; 924 return $ADODB_FETCH_MODE; 925 } 926 return $old; 927 } 928 929 930 /** 931 * PEAR DB Compat - do not use internally. 932 */ 933 function Query($sql, $inputarr=false) { 934 $rs = $this->Execute($sql, $inputarr); 935 if (!$rs && defined('ADODB_PEAR')) { 936 return ADODB_PEAR_Error(); 937 } 938 return $rs; 939 } 940 941 942 /** 943 * PEAR DB Compat - do not use internally 944 */ 945 function LimitQuery($sql, $offset, $count, $params=false) { 946 $rs = $this->SelectLimit($sql, $count, $offset, $params); 947 if (!$rs && defined('ADODB_PEAR')) { 948 return ADODB_PEAR_Error(); 949 } 950 return $rs; 951 } 952 953 954 /** 955 * PEAR DB Compat - do not use internally 956 */ 957 function Disconnect() { 958 return $this->Close(); 959 } 960 961 /** 962 * Returns a placeholder for query parameters 963 * e.g. $DB->Param('a') will return 964 * - '?' for most databases 965 * - ':a' for Oracle 966 * - '$1', '$2', etc. for PostgreSQL 967 * @param string $name parameter's name, false to force a reset of the 968 * number to 1 (for databases that require positioned 969 * params such as PostgreSQL; note that ADOdb will 970 * automatically reset this when executing a query ) 971 * @param string $type (unused) 972 * @return string query parameter placeholder 973 */ 974 function Param($name,$type='C') { 975 return '?'; 976 } 977 978 /* 979 InParameter and OutParameter are self-documenting versions of Parameter(). 980 */ 981 function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) { 982 return $this->Parameter($stmt,$var,$name,false,$maxLen,$type); 983 } 984 985 /* 986 */ 987 function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) { 988 return $this->Parameter($stmt,$var,$name,true,$maxLen,$type); 989 990 } 991 992 993 /* 994 Usage in oracle 995 $stmt = $db->Prepare('select * from table where id =:myid and group=:group'); 996 $db->Parameter($stmt,$id,'myid'); 997 $db->Parameter($stmt,$group,'group',64); 998 $db->Execute(); 999 1000 @param $stmt Statement returned by Prepare() or PrepareSP(). 1001 @param $var PHP variable to bind to 1002 @param $name Name of stored procedure variable name to bind to. 1003 @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8. 1004 @param [$maxLen] Holds an maximum length of the variable. 1005 @param [$type] The data type of $var. Legal values depend on driver. 1006 1007 */ 1008 function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) { 1009 return false; 1010 } 1011 1012 1013 function IgnoreErrors($saveErrs=false) { 1014 if (!$saveErrs) { 1015 $saveErrs = array($this->raiseErrorFn,$this->_transOK); 1016 $this->raiseErrorFn = false; 1017 return $saveErrs; 1018 } else { 1019 $this->raiseErrorFn = $saveErrs[0]; 1020 $this->_transOK = $saveErrs[1]; 1021 } 1022 } 1023 1024 /** 1025 * Improved method of initiating a transaction. Used together with CompleteTrans(). 1026 * Advantages include: 1027 * 1028 * a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans. 1029 * Only the outermost block is treated as a transaction.<br> 1030 * b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br> 1031 * c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block 1032 * are disabled, making it backward compatible. 1033 */ 1034 function StartTrans($errfn = 'ADODB_TransMonitor') { 1035 if ($this->transOff > 0) { 1036 $this->transOff += 1; 1037 return true; 1038 } 1039 1040 $this->_oldRaiseFn = $this->raiseErrorFn; 1041 $this->raiseErrorFn = $errfn; 1042 $this->_transOK = true; 1043 1044 if ($this->debug && $this->transCnt > 0) { 1045 ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans"); 1046 } 1047 $ok = $this->BeginTrans(); 1048 $this->transOff = 1; 1049 return $ok; 1050 } 1051 1052 1053 /** 1054 Used together with StartTrans() to end a transaction. Monitors connection 1055 for sql errors, and will commit or rollback as appropriate. 1056 1057 @autoComplete if true, monitor sql errors and commit and rollback as appropriate, 1058 and if set to false force rollback even if no SQL error detected. 1059 @returns true on commit, false on rollback. 1060 */ 1061 function CompleteTrans($autoComplete = true) { 1062 if ($this->transOff > 1) { 1063 $this->transOff -= 1; 1064 return true; 1065 } 1066 $this->raiseErrorFn = $this->_oldRaiseFn; 1067 1068 $this->transOff = 0; 1069 if ($this->_transOK && $autoComplete) { 1070 if (!$this->CommitTrans()) { 1071 $this->_transOK = false; 1072 if ($this->debug) { 1073 ADOConnection::outp("Smart Commit failed"); 1074 } 1075 } else { 1076 if ($this->debug) { 1077 ADOConnection::outp("Smart Commit occurred"); 1078 } 1079 } 1080 } else { 1081 $this->_transOK = false; 1082 $this->RollbackTrans(); 1083 if ($this->debug) { 1084 ADOCOnnection::outp("Smart Rollback occurred"); 1085 } 1086 } 1087 1088 return $this->_transOK; 1089 } 1090 1091 /* 1092 At the end of a StartTrans/CompleteTrans block, perform a rollback. 1093 */ 1094 function FailTrans() { 1095 if ($this->debug) 1096 if ($this->transOff == 0) { 1097 ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans"); 1098 } else { 1099 ADOConnection::outp("FailTrans was called"); 1100 adodb_backtrace(); 1101 } 1102 $this->_transOK = false; 1103 } 1104 1105 /** 1106 Check if transaction has failed, only for Smart Transactions. 1107 */ 1108 function HasFailedTrans() { 1109 if ($this->transOff > 0) { 1110 return $this->_transOK == false; 1111 } 1112 return false; 1113 } 1114 1115 /** 1116 * Execute SQL 1117 * 1118 * @param sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text) 1119 * @param [inputarr] holds the input data to bind to. Null elements will be set to null. 1120 * @return RecordSet or false 1121 */ 1122 function Execute($sql,$inputarr=false) { 1123 if ($this->fnExecute) { 1124 $fn = $this->fnExecute; 1125 $ret = $fn($this,$sql,$inputarr); 1126 if (isset($ret)) { 1127 return $ret; 1128 } 1129 } 1130 if ($inputarr !== false) { 1131 if (!is_array($inputarr)) { 1132 $inputarr = array($inputarr); 1133 } 1134 1135 $element0 = reset($inputarr); 1136 # is_object check because oci8 descriptors can be passed in 1137 $array_2d = $this->bulkBind && is_array($element0) && !is_object(reset($element0)); 1138 1139 //remove extra memory copy of input -mikefedyk 1140 unset($element0); 1141 1142 if (!is_array($sql) && !$this->_bindInputArray) { 1143 // @TODO this would consider a '?' within a string as a parameter... 1144 $sqlarr = explode('?',$sql); 1145 $nparams = sizeof($sqlarr)-1; 1146 1147 if (!$array_2d) { 1148 // When not Bind Bulk - convert to array of arguments list 1149 $inputarr = array($inputarr); 1150 } else { 1151 // Bulk bind - Make sure all list of params have the same number of elements 1152 $countElements = array_map('count', $inputarr); 1153 if (1 != count(array_unique($countElements))) { 1154 $this->outp_throw( 1155 "[bulk execute] Input array has different number of params [" . print_r($countElements, true) . "].", 1156 'Execute' 1157 ); 1158 return false; 1159 } 1160 unset($countElements); 1161 } 1162 // Make sure the number of parameters provided in the input 1163 // array matches what the query expects 1164 $element0 = reset($inputarr); 1165 if ($nparams != count($element0)) { 1166 $this->outp_throw( 1167 "Input array has " . count($element0) . 1168 " params, does not match query: '" . htmlspecialchars($sql) . "'", 1169 'Execute' 1170 ); 1171 return false; 1172 } 1173 1174 // clean memory 1175 unset($element0); 1176 1177 foreach($inputarr as $arr) { 1178 $sql = ''; $i = 0; 1179 foreach ($arr as $v) { 1180 $sql .= $sqlarr[$i]; 1181 // from Ron Baldwin <ron.baldwin#sourceprose.com> 1182 // Only quote string types 1183 $typ = gettype($v); 1184 if ($typ == 'string') { 1185 //New memory copy of input created here -mikefedyk 1186 $sql .= $this->qstr($v); 1187 } else if ($typ == 'double') { 1188 $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1 1189 } else if ($typ == 'boolean') { 1190 $sql .= $v ? $this->true : $this->false; 1191 } else if ($typ == 'object') { 1192 if (method_exists($v, '__toString')) { 1193 $sql .= $this->qstr($v->__toString()); 1194 } else { 1195 $sql .= $this->qstr((string) $v); 1196 } 1197 } else if ($v === null) { 1198 $sql .= 'NULL'; 1199 } else { 1200 $sql .= $v; 1201 } 1202 $i += 1; 1203 1204 if ($i == $nparams) { 1205 break; 1206 } 1207 } // while 1208 if (isset($sqlarr[$i])) { 1209 $sql .= $sqlarr[$i]; 1210 if ($i+1 != sizeof($sqlarr)) { 1211 $this->outp_throw( "Input Array does not match ?: ".htmlspecialchars($sql),'Execute'); 1212 } 1213 } else if ($i != sizeof($sqlarr)) { 1214 $this->outp_throw( "Input array does not match ?: ".htmlspecialchars($sql),'Execute'); 1215 } 1216 1217 $ret = $this->_Execute($sql); 1218 if (!$ret) { 1219 return $ret; 1220 } 1221 } 1222 } else { 1223 if ($array_2d) { 1224 if (is_string($sql)) { 1225 $stmt = $this->Prepare($sql); 1226 } else { 1227 $stmt = $sql; 1228 } 1229 1230 foreach($inputarr as $arr) { 1231 $ret = $this->_Execute($stmt,$arr); 1232 if (!$ret) { 1233 return $ret; 1234 } 1235 } 1236 } else { 1237 $ret = $this->_Execute($sql,$inputarr); 1238 } 1239 } 1240 } else { 1241 $ret = $this->_Execute($sql,false); 1242 } 1243 1244 return $ret; 1245 } 1246 1247 function _Execute($sql,$inputarr=false) { 1248 // ExecuteCursor() may send non-string queries (such as arrays), 1249 // so we need to ignore those. 1250 if( is_string($sql) ) { 1251 // Strips keyword used to help generate SELECT COUNT(*) queries 1252 // from SQL if it exists. 1253 $sql = ADODB_str_replace( '_ADODB_COUNT', '', $sql ); 1254 } 1255 1256 if ($this->debug) { 1257 global $ADODB_INCLUDED_LIB; 1258 if (empty($ADODB_INCLUDED_LIB)) { 1259 include (ADODB_DIR.'/adodb-lib.inc.php'); 1260 } 1261 $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr); 1262 } else { 1263 $this->_queryID = @$this->_query($sql,$inputarr); 1264 } 1265 1266 // ************************ 1267 // OK, query executed 1268 // ************************ 1269 1270 // error handling if query fails 1271 if ($this->_queryID === false) { 1272 if ($this->debug == 99) { 1273 adodb_backtrace(true,5); 1274 } 1275 $fn = $this->raiseErrorFn; 1276 if ($fn) { 1277 $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this); 1278 } 1279 return false; 1280 } 1281 1282 // return simplified recordset for inserts/updates/deletes with lower overhead 1283 if ($this->_queryID === true) { 1284 $rsclass = $this->rsPrefix.'empty'; 1285 $rs = (class_exists($rsclass)) ? new $rsclass(): new ADORecordSet_empty(); 1286 1287 return $rs; 1288 } 1289 1290 // return real recordset from select statement 1291 $rsclass = $this->rsPrefix.$this->databaseType; 1292 $rs = new $rsclass($this->_queryID,$this->fetchMode); 1293 $rs->connection = $this; // Pablo suggestion 1294 $rs->Init(); 1295 if (is_array($sql)) { 1296 $rs->sql = $sql[0]; 1297 } else { 1298 $rs->sql = $sql; 1299 } 1300 if ($rs->_numOfRows <= 0) { 1301 global $ADODB_COUNTRECS; 1302 if ($ADODB_COUNTRECS) { 1303 if (!$rs->EOF) { 1304 $rs = $this->_rs2rs($rs,-1,-1,!is_array($sql)); 1305 $rs->_queryID = $this->_queryID; 1306 } else 1307 $rs->_numOfRows = 0; 1308 } 1309 } 1310 return $rs; 1311 } 1312 1313 function CreateSequence($seqname='adodbseq',$startID=1) { 1314 if (empty($this->_genSeqSQL)) { 1315 return false; 1316 } 1317 return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID)); 1318 } 1319 1320 function DropSequence($seqname='adodbseq') { 1321 if (empty($this->_dropSeqSQL)) { 1322 return false; 1323 } 1324 return $this->Execute(sprintf($this->_dropSeqSQL,$seqname)); 1325 } 1326 1327 /** 1328 * Generates a sequence id and stores it in $this->genID; 1329 * GenID is only available if $this->hasGenID = true; 1330 * 1331 * @param seqname name of sequence to use 1332 * @param startID if sequence does not exist, start at this ID 1333 * @return 0 if not supported, otherwise a sequence id 1334 */ 1335 function GenID($seqname='adodbseq',$startID=1) { 1336 if (!$this->hasGenID) { 1337 return 0; // formerly returns false pre 1.60 1338 } 1339 1340 $getnext = sprintf($this->_genIDSQL,$seqname); 1341 1342 $holdtransOK = $this->_transOK; 1343 1344 $save_handler = $this->raiseErrorFn; 1345 $this->raiseErrorFn = ''; 1346 @($rs = $this->Execute($getnext)); 1347 $this->raiseErrorFn = $save_handler; 1348 1349 if (!$rs) { 1350 $this->_transOK = $holdtransOK; //if the status was ok before reset 1351 $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID)); 1352 $rs = $this->Execute($getnext); 1353 } 1354 if ($rs && !$rs->EOF) { 1355 $this->genID = reset($rs->fields); 1356 } else { 1357 $this->genID = 0; // false 1358 } 1359 1360 if ($rs) { 1361 $rs->Close(); 1362 } 1363 1364 return $this->genID; 1365 } 1366 1367 /** 1368 * @param $table string name of the table, not needed by all databases (eg. mysql), default '' 1369 * @param $column string name of the column, not needed by all databases (eg. mysql), default '' 1370 * @return the last inserted ID. Not all databases support this. 1371 */ 1372 function Insert_ID($table='',$column='') { 1373 if ($this->_logsql && $this->lastInsID) { 1374 return $this->lastInsID; 1375 } 1376 if ($this->hasInsertID) { 1377 return $this->_insertid($table,$column); 1378 } 1379 if ($this->debug) { 1380 ADOConnection::outp( '<p>Insert_ID error</p>'); 1381 adodb_backtrace(); 1382 } 1383 return false; 1384 } 1385 1386 1387 /** 1388 * Portable Insert ID. Pablo Roca <pabloroca#mvps.org> 1389 * 1390 * @return the last inserted ID. All databases support this. But aware possible 1391 * problems in multiuser environments. Heavy test this before deploying. 1392 */ 1393 function PO_Insert_ID($table="", $id="") { 1394 if ($this->hasInsertID){ 1395 return $this->Insert_ID($table,$id); 1396 } else { 1397 return $this->GetOne("SELECT MAX($id) FROM $table"); 1398 } 1399 } 1400 1401 /** 1402 * @return # rows affected by UPDATE/DELETE 1403 */ 1404 function Affected_Rows() { 1405 if ($this->hasAffectedRows) { 1406 if ($this->fnExecute === 'adodb_log_sql') { 1407 if ($this->_logsql && $this->_affected !== false) { 1408 return $this->_affected; 1409 } 1410 } 1411 $val = $this->_affectedrows(); 1412 return ($val < 0) ? false : $val; 1413 } 1414 1415 if ($this->debug) { 1416 ADOConnection::outp( '<p>Affected_Rows error</p>',false); 1417 } 1418 return false; 1419 } 1420 1421 1422 /** 1423 * @return the last error message 1424 */ 1425 function ErrorMsg() { 1426 if ($this->_errorMsg) { 1427 return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg; 1428 } else { 1429 return ''; 1430 } 1431 } 1432 1433 1434 /** 1435 * @return the last error number. Normally 0 means no error. 1436 */ 1437 function ErrorNo() { 1438 return ($this->_errorMsg) ? -1 : 0; 1439 } 1440 1441 function MetaError($err=false) { 1442 include_once (ADODB_DIR."/adodb-error.inc.php"); 1443 if ($err === false) { 1444 $err = $this->ErrorNo(); 1445 } 1446 return adodb_error($this->dataProvider,$this->databaseType,$err); 1447 } 1448 1449 function MetaErrorMsg($errno) { 1450 include_once (ADODB_DIR."/adodb-error.inc.php"); 1451 return adodb_errormsg($errno); 1452 } 1453 1454 /** 1455 * @returns an array with the primary key columns in it. 1456 */ 1457 function MetaPrimaryKeys($table, $owner=false) { 1458 // owner not used in base class - see oci8 1459 $p = array(); 1460 $objs = $this->MetaColumns($table); 1461 if ($objs) { 1462 foreach($objs as $v) { 1463 if (!empty($v->primary_key)) { 1464 $p[] = $v->name; 1465 } 1466 } 1467 } 1468 if (sizeof($p)) { 1469 return $p; 1470 } 1471 if (function_exists('ADODB_VIEW_PRIMARYKEYS')) { 1472 return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner); 1473 } 1474 return false; 1475 } 1476 1477 /** 1478 * @returns assoc array where keys are tables, and values are foreign keys 1479 */ 1480 function MetaForeignKeys($table, $owner=false, $upper=false) { 1481 return false; 1482 } 1483 /** 1484 * Choose a database to connect to. Many databases do not support this. 1485 * 1486 * @param dbName is the name of the database to select 1487 * @return true or false 1488 */ 1489 function SelectDB($dbName) {return false;} 1490 1491 1492 /** 1493 * Will select, getting rows from $offset (1-based), for $nrows. 1494 * This simulates the MySQL "select * from table limit $offset,$nrows" , and 1495 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that 1496 * MySQL and PostgreSQL parameter ordering is the opposite of the other. 1497 * eg. 1498 * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based) 1499 * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based) 1500 * 1501 * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set) 1502 * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set 1503 * 1504 * @param sql 1505 * @param [offset] is the row to start calculations from (1-based) 1506 * @param [nrows] is the number of rows to get 1507 * @param [inputarr] array of bind variables 1508 * @param [secs2cache] is a private parameter only used by jlim 1509 * @return the recordset ($rs->databaseType == 'array') 1510 */ 1511 function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) { 1512 $nrows = (int)$nrows; 1513 $offset = (int)$offset; 1514 1515 if ($this->hasTop && $nrows > 0) { 1516 // suggested by Reinhard Balling. Access requires top after distinct 1517 // Informix requires first before distinct - F Riosa 1518 $ismssql = (strpos($this->databaseType,'mssql') !== false); 1519 if ($ismssql) { 1520 $isaccess = false; 1521 } else { 1522 $isaccess = (strpos($this->databaseType,'access') !== false); 1523 } 1524 1525 if ($offset <= 0) { 1526 // access includes ties in result 1527 if ($isaccess) { 1528 $sql = preg_replace( 1529 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql); 1530 1531 if ($secs2cache != 0) { 1532 $ret = $this->CacheExecute($secs2cache, $sql,$inputarr); 1533 } else { 1534 $ret = $this->Execute($sql,$inputarr); 1535 } 1536 return $ret; // PHP5 fix 1537 } else if ($ismssql){ 1538 $sql = preg_replace( 1539 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql); 1540 } else { 1541 $sql = preg_replace( 1542 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql); 1543 } 1544 } else { 1545 $nn = $nrows + $offset; 1546 if ($isaccess || $ismssql) { 1547 $sql = preg_replace( 1548 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql); 1549 } else { 1550 $sql = preg_replace( 1551 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql); 1552 } 1553 } 1554 } 1555 1556 // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows 1557 // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS. 1558 global $ADODB_COUNTRECS; 1559 1560 $savec = $ADODB_COUNTRECS; 1561 $ADODB_COUNTRECS = false; 1562 1563 1564 if ($secs2cache != 0) { 1565 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr); 1566 } else { 1567 $rs = $this->Execute($sql,$inputarr); 1568 } 1569 1570 $ADODB_COUNTRECS = $savec; 1571 if ($rs && !$rs->EOF) { 1572 $rs = $this->_rs2rs($rs,$nrows,$offset); 1573 } 1574 //print_r($rs); 1575 return $rs; 1576 } 1577 1578 /** 1579 * Create serializable recordset. Breaks rs link to connection. 1580 * 1581 * @param rs the recordset to serialize 1582 */ 1583 function SerializableRS(&$rs) { 1584 $rs2 = $this->_rs2rs($rs); 1585 $ignore = false; 1586 $rs2->connection = $ignore; 1587 1588 return $rs2; 1589 } 1590 1591 /** 1592 * Convert database recordset to an array recordset 1593 * input recordset's cursor should be at beginning, and 1594 * old $rs will be closed. 1595 * 1596 * @param rs the recordset to copy 1597 * @param [nrows] number of rows to retrieve (optional) 1598 * @param [offset] offset by number of rows (optional) 1599 * @return the new recordset 1600 */ 1601 function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true) { 1602 if (! $rs) { 1603 return false; 1604 } 1605 $dbtype = $rs->databaseType; 1606 if (!$dbtype) { 1607 $rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ? 1608 return $rs; 1609 } 1610 if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) { 1611 $rs->MoveFirst(); 1612 $rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ? 1613 return $rs; 1614 } 1615 $flds = array(); 1616 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) { 1617 $flds[] = $rs->FetchField($i); 1618 } 1619 1620 $arr = $rs->GetArrayLimit($nrows,$offset); 1621 //print_r($arr); 1622 if ($close) { 1623 $rs->Close(); 1624 } 1625 1626 $arrayClass = $this->arrayClass; 1627 1628 $rs2 = new $arrayClass(); 1629 $rs2->connection = $this; 1630 $rs2->sql = $rs->sql; 1631 $rs2->dataProvider = $this->dataProvider; 1632 $rs2->InitArrayFields($arr,$flds); 1633 $rs2->fetchMode = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode; 1634 return $rs2; 1635 } 1636 1637 /* 1638 * Return all rows. Compat with PEAR DB 1639 */ 1640 function GetAll($sql, $inputarr=false) { 1641 $arr = $this->GetArray($sql,$inputarr); 1642 return $arr; 1643 } 1644 1645 function GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false) { 1646 $rs = $this->Execute($sql, $inputarr); 1647 if (!$rs) { 1648 return false; 1649 } 1650 $arr = $rs->GetAssoc($force_array,$first2cols); 1651 return $arr; 1652 } 1653 1654 function CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false) { 1655 if (!is_numeric($secs2cache)) { 1656 $first2cols = $force_array; 1657 $force_array = $inputarr; 1658 } 1659 $rs = $this->CacheExecute($secs2cache, $sql, $inputarr); 1660 if (!$rs) { 1661 return false; 1662 } 1663 $arr = $rs->GetAssoc($force_array,$first2cols); 1664 return $arr; 1665 } 1666 1667 /** 1668 * Return first element of first row of sql statement. Recordset is disposed 1669 * for you. 1670 * 1671 * @param sql SQL statement 1672 * @param [inputarr] input bind array 1673 */ 1674 function GetOne($sql,$inputarr=false) { 1675 global $ADODB_COUNTRECS,$ADODB_GETONE_EOF; 1676 1677 $crecs = $ADODB_COUNTRECS; 1678 $ADODB_COUNTRECS = false; 1679 1680 $ret = false; 1681 $rs = $this->Execute($sql,$inputarr); 1682 if ($rs) { 1683 if ($rs->EOF) { 1684 $ret = $ADODB_GETONE_EOF; 1685 } else { 1686 $ret = reset($rs->fields); 1687 } 1688 1689 $rs->Close(); 1690 } 1691 $ADODB_COUNTRECS = $crecs; 1692 return $ret; 1693 } 1694 1695 // $where should include 'WHERE fld=value' 1696 function GetMedian($table, $field,$where = '') { 1697 $total = $this->GetOne("select count(*) from $table $where"); 1698 if (!$total) { 1699 return false; 1700 } 1701 1702 $midrow = (integer) ($total/2); 1703 $rs = $this->SelectLimit("select $field from $table $where order by 1",1,$midrow); 1704 if ($rs && !$rs->EOF) { 1705 return reset($rs->fields); 1706 } 1707 return false; 1708 } 1709 1710 1711 function CacheGetOne($secs2cache,$sql=false,$inputarr=false) { 1712 global $ADODB_GETONE_EOF; 1713 1714 $ret = false; 1715 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr); 1716 if ($rs) { 1717 if ($rs->EOF) { 1718 $ret = $ADODB_GETONE_EOF; 1719 } else { 1720 $ret = reset($rs->fields); 1721 } 1722 $rs->Close(); 1723 } 1724 1725 return $ret; 1726 } 1727 1728 function GetCol($sql, $inputarr = false, $trim = false) { 1729 1730 $rs = $this->Execute($sql, $inputarr); 1731 if ($rs) { 1732 $rv = array(); 1733 if ($trim) { 1734 while (!$rs->EOF) { 1735 $rv[] = trim(reset($rs->fields)); 1736 $rs->MoveNext(); 1737 } 1738 } else { 1739 while (!$rs->EOF) { 1740 $rv[] = reset($rs->fields); 1741 $rs->MoveNext(); 1742 } 1743 } 1744 $rs->Close(); 1745 } else { 1746 $rv = false; 1747 } 1748 return $rv; 1749 } 1750 1751 function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false) { 1752 $rs = $this->CacheExecute($secs, $sql, $inputarr); 1753 if ($rs) { 1754 $rv = array(); 1755 if ($trim) { 1756 while (!$rs->EOF) { 1757 $rv[] = trim(reset($rs->fields)); 1758 $rs->MoveNext(); 1759 } 1760 } else { 1761 while (!$rs->EOF) { 1762 $rv[] = reset($rs->fields); 1763 $rs->MoveNext(); 1764 } 1765 } 1766 $rs->Close(); 1767 } else 1768 $rv = false; 1769 1770 return $rv; 1771 } 1772 1773 function Transpose(&$rs,$addfieldnames=true) { 1774 $rs2 = $this->_rs2rs($rs); 1775 if (!$rs2) { 1776 return false; 1777 } 1778 1779 $rs2->_transpose($addfieldnames); 1780 return $rs2; 1781 } 1782 1783 /* 1784 Calculate the offset of a date for a particular database and generate 1785 appropriate SQL. Useful for calculating future/past dates and storing 1786 in a database. 1787 1788 If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour. 1789 */ 1790 function OffsetDate($dayFraction,$date=false) { 1791 if (!$date) { 1792 $date = $this->sysDate; 1793 } 1794 return '('.$date.'+'.$dayFraction.')'; 1795 } 1796 1797 1798 /** 1799 * 1800 * @param sql SQL statement 1801 * @param [inputarr] input bind array 1802 */ 1803 function GetArray($sql,$inputarr=false) { 1804 global $ADODB_COUNTRECS; 1805 1806 $savec = $ADODB_COUNTRECS; 1807 $ADODB_COUNTRECS = false; 1808 $rs = $this->Execute($sql,$inputarr); 1809 $ADODB_COUNTRECS = $savec; 1810 if (!$rs) 1811 if (defined('ADODB_PEAR')) { 1812 $cls = ADODB_PEAR_Error(); 1813 return $cls; 1814 } else { 1815 return false; 1816 } 1817 $arr = $rs->GetArray(); 1818 $rs->Close(); 1819 return $arr; 1820 } 1821 1822 function CacheGetAll($secs2cache,$sql=false,$inputarr=false) { 1823 $arr = $this->CacheGetArray($secs2cache,$sql,$inputarr); 1824 return $arr; 1825 } 1826 1827 function CacheGetArray($secs2cache,$sql=false,$inputarr=false) { 1828 global $ADODB_COUNTRECS; 1829 1830 $savec = $ADODB_COUNTRECS; 1831 $ADODB_COUNTRECS = false; 1832 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr); 1833 $ADODB_COUNTRECS = $savec; 1834 1835 if (!$rs) 1836 if (defined('ADODB_PEAR')) { 1837 $cls = ADODB_PEAR_Error(); 1838 return $cls; 1839 } else { 1840 return false; 1841 } 1842 $arr = $rs->GetArray(); 1843 $rs->Close(); 1844 return $arr; 1845 } 1846 1847 function GetRandRow($sql, $arr= false) { 1848 $rezarr = $this->GetAll($sql, $arr); 1849 $sz = sizeof($rezarr); 1850 return $rezarr[abs(rand()) % $sz]; 1851 } 1852 1853 /** 1854 * Return one row of sql statement. Recordset is disposed for you. 1855 * Note that SelectLimit should not be called. 1856 * 1857 * @param sql SQL statement 1858 * @param [inputarr] input bind array 1859 */ 1860 function GetRow($sql,$inputarr=false) { 1861 global $ADODB_COUNTRECS; 1862 1863 $crecs = $ADODB_COUNTRECS; 1864 $ADODB_COUNTRECS = false; 1865 1866 $rs = $this->Execute($sql,$inputarr); 1867 1868 $ADODB_COUNTRECS = $crecs; 1869 if ($rs) { 1870 if (!$rs->EOF) { 1871 $arr = $rs->fields; 1872 } else { 1873 $arr = array(); 1874 } 1875 $rs->Close(); 1876 return $arr; 1877 } 1878 1879 return false; 1880 } 1881 1882 function CacheGetRow($secs2cache,$sql=false,$inputarr=false) { 1883 $rs = $this->CacheExecute($secs2cache,$sql,$inputarr); 1884 if ($rs) { 1885 if (!$rs->EOF) { 1886 $arr = $rs->fields; 1887 } else { 1888 $arr = array(); 1889 } 1890 1891 $rs->Close(); 1892 return $arr; 1893 } 1894 return false; 1895 } 1896 1897 /** 1898 * Insert or replace a single record. Note: this is not the same as MySQL's replace. 1899 * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL. 1900 * Also note that no table locking is done currently, so it is possible that the 1901 * record be inserted twice by two programs... 1902 * 1903 * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname'); 1904 * 1905 * $table table name 1906 * $fieldArray associative array of data (you must quote strings yourself). 1907 * $keyCol the primary key field name or if compound key, array of field names 1908 * autoQuote set to true to use a hueristic to quote strings. Works with nulls and numbers 1909 * but does not work with dates nor SQL functions. 1910 * has_autoinc the primary key is an auto-inc field, so skip in insert. 1911 * 1912 * Currently blob replace not supported 1913 * 1914 * returns 0 = fail, 1 = update, 2 = insert 1915 */ 1916 1917 function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false) { 1918 global $ADODB_INCLUDED_LIB; 1919 if (empty($ADODB_INCLUDED_LIB)) { 1920 include (ADODB_DIR.'/adodb-lib.inc.php'); 1921 } 1922 1923 return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc); 1924 } 1925 1926 1927 /** 1928 * Will select, getting rows from $offset (1-based), for $nrows. 1929 * This simulates the MySQL "select * from table limit $offset,$nrows" , and 1930 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that 1931 * MySQL and PostgreSQL parameter ordering is the opposite of the other. 1932 * eg. 1933 * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based) 1934 * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based) 1935 * 1936 * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set 1937 * 1938 * @param [secs2cache] seconds to cache data, set to 0 to force query. This is optional 1939 * @param sql 1940 * @param [offset] is the row to start calculations from (1-based) 1941 * @param [nrows] is the number of rows to get 1942 * @param [inputarr] array of bind variables 1943 * @return the recordset ($rs->databaseType == 'array') 1944 */ 1945 function CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false) { 1946 if (!is_numeric($secs2cache)) { 1947 if ($sql === false) { 1948 $sql = -1; 1949 } 1950 if ($offset == -1) { 1951 $offset = false; 1952 } 1953 // sql, nrows, offset,inputarr 1954 $rs = $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs); 1955 } else { 1956 if ($sql === false) { 1957 $this->outp_throw("Warning: \$sql missing from CacheSelectLimit()",'CacheSelectLimit'); 1958 } 1959 $rs = $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); 1960 } 1961 return $rs; 1962 } 1963 1964 /** 1965 * Flush cached recordsets that match a particular $sql statement. 1966 * If $sql == false, then we purge all files in the cache. 1967 */ 1968 function CacheFlush($sql=false,$inputarr=false) { 1969 global $ADODB_CACHE_DIR, $ADODB_CACHE; 1970 1971 # Create cache if it does not exist 1972 if (empty($ADODB_CACHE)) { 1973 $this->_CreateCache(); 1974 } 1975 1976 if (!$sql) { 1977 $ADODB_CACHE->flushall($this->debug); 1978 return; 1979 } 1980 1981 $f = $this->_gencachename($sql.serialize($inputarr),false); 1982 return $ADODB_CACHE->flushcache($f, $this->debug); 1983 } 1984 1985 1986 /** 1987 * Private function to generate filename for caching. 1988 * Filename is generated based on: 1989 * 1990 * - sql statement 1991 * - database type (oci8, ibase, ifx, etc) 1992 * - database name 1993 * - userid 1994 * - setFetchMode (adodb 4.23) 1995 * 1996 * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR). 1997 * Assuming that we can have 50,000 files per directory with good performance, 1998 * then we can scale to 12.8 million unique cached recordsets. Wow! 1999 */ 2000 function _gencachename($sql,$createdir) { 2001 global $ADODB_CACHE, $ADODB_CACHE_DIR; 2002 2003 if ($this->fetchMode === false) { 2004 global $ADODB_FETCH_MODE; 2005 $mode = $ADODB_FETCH_MODE; 2006 } else { 2007 $mode = $this->fetchMode; 2008 } 2009 $m = md5($sql.$this->databaseType.$this->database.$this->user.$mode); 2010 if (!$ADODB_CACHE->createdir) { 2011 return $m; 2012 } 2013 if (!$createdir) { 2014 $dir = $ADODB_CACHE->getdirname($m); 2015 } else { 2016 $dir = $ADODB_CACHE->createdir($m, $this->debug); 2017 } 2018 2019 return $dir.'/adodb_'.$m.'.cache'; 2020 } 2021 2022 2023 /** 2024 * Execute SQL, caching recordsets. 2025 * 2026 * @param [secs2cache] seconds to cache data, set to 0 to force query. 2027 * This is an optional parameter. 2028 * @param sql SQL statement to execute 2029 * @param [inputarr] holds the input data to bind to 2030 * @return RecordSet or false 2031 */ 2032 function CacheExecute($secs2cache,$sql=false,$inputarr=false) { 2033 global $ADODB_CACHE; 2034 2035 if (empty($ADODB_CACHE)) { 2036 $this->_CreateCache(); 2037 } 2038 2039 if (!is_numeric($secs2cache)) { 2040 $inputarr = $sql; 2041 $sql = $secs2cache; 2042 $secs2cache = $this->cacheSecs; 2043 } 2044 2045 if (is_array($sql)) { 2046 $sqlparam = $sql; 2047 $sql = $sql[0]; 2048 } else 2049 $sqlparam = $sql; 2050 2051 2052 $md5file = $this->_gencachename($sql.serialize($inputarr),true); 2053 $err = ''; 2054 2055 if ($secs2cache > 0){ 2056 $rs = $ADODB_CACHE->readcache($md5file,$err,$secs2cache,$this->arrayClass); 2057 $this->numCacheHits += 1; 2058 } else { 2059 $err='Timeout 1'; 2060 $rs = false; 2061 $this->numCacheMisses += 1; 2062 } 2063 2064 if (!$rs) { 2065 // no cached rs found 2066 if ($this->debug) { 2067 if (get_magic_quotes_runtime() && !$this->memCache) { 2068 ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :("); 2069 } 2070 if ($this->debug !== -1) { 2071 ADOConnection::outp( " $md5file cache failure: $err (this is a notice and not an error)"); 2072 } 2073 } 2074 2075 $rs = $this->Execute($sqlparam,$inputarr); 2076 2077 if ($rs) { 2078 $eof = $rs->EOF; 2079 $rs = $this->_rs2rs($rs); // read entire recordset into memory immediately 2080 $rs->timeCreated = time(); // used by caching 2081 $txt = _rs2serialize($rs,false,$sql); // serialize 2082 2083 $ok = $ADODB_CACHE->writecache($md5file,$txt,$this->debug, $secs2cache); 2084 if (!$ok) { 2085 if ($ok === false) { 2086 $em = 'Cache write error'; 2087 $en = -32000; 2088 2089 if ($fn = $this->raiseErrorFn) { 2090 $fn($this->databaseType,'CacheExecute', $en, $em, $md5file,$sql,$this); 2091 } 2092 } else { 2093 $em = 'Cache file locked warning'; 2094 $en = -32001; 2095 // do not call error handling for just a warning 2096 } 2097 2098 if ($this->debug) { 2099 ADOConnection::outp( " ".$em); 2100 } 2101 } 2102 if ($rs->EOF && !$eof) { 2103 $rs->MoveFirst(); 2104 //$rs = csv2rs($md5file,$err); 2105 $rs->connection = $this; // Pablo suggestion 2106 } 2107 2108 } else if (!$this->memCache) { 2109 $ADODB_CACHE->flushcache($md5file); 2110 } 2111 } else { 2112 $this->_errorMsg = ''; 2113 $this->_errorCode = 0; 2114 2115 if ($this->fnCacheExecute) { 2116 $fn = $this->fnCacheExecute; 2117 $fn($this, $secs2cache, $sql, $inputarr); 2118 } 2119 // ok, set cached object found 2120 $rs->connection = $this; // Pablo suggestion 2121 if ($this->debug){ 2122 if ($this->debug == 99) { 2123 adodb_backtrace(); 2124 } 2125 $inBrowser = isset($_SERVER['HTTP_USER_AGENT']); 2126 $ttl = $rs->timeCreated + $secs2cache - time(); 2127 $s = is_array($sql) ? $sql[0] : $sql; 2128 if ($inBrowser) { 2129 $s = '<i>'.htmlspecialchars($s).'</i>'; 2130 } 2131 2132 ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]"); 2133 } 2134 } 2135 return $rs; 2136 } 2137 2138 2139 /* 2140 Similar to PEAR DB's autoExecute(), except that 2141 $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE 2142 If $mode == 'UPDATE', then $where is compulsory as a safety measure. 2143 2144 $forceUpdate means that even if the data has not changed, perform update. 2145 */ 2146 function AutoExecute($table, $fields_values, $mode = 'INSERT', $where = false, $forceUpdate = true, $magicq = false) { 2147 if ($where === false && ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) ) { 2148 $this->outp_throw('AutoExecute: Illegal mode=UPDATE with empty WHERE clause', 'AutoExecute'); 2149 return false; 2150 } 2151 2152 $sql = "SELECT * FROM $table"; 2153 $rs = $this->SelectLimit($sql, 1); 2154 if (!$rs) { 2155 return false; // table does not exist 2156 } 2157 2158 $rs->tableName = $table; 2159 if ($where !== false) { 2160 $sql .= " WHERE $where"; 2161 } 2162 $rs->sql = $sql; 2163 2164 switch($mode) { 2165 case 'UPDATE': 2166 case DB_AUTOQUERY_UPDATE: 2167 $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq); 2168 break; 2169 case 'INSERT': 2170 case DB_AUTOQUERY_INSERT: 2171 $sql = $this->GetInsertSQL($rs, $fields_values, $magicq); 2172 break; 2173 default: 2174 $this->outp_throw("AutoExecute: Unknown mode=$mode", 'AutoExecute'); 2175 return false; 2176 } 2177 return $sql && $this->Execute($sql); 2178 } 2179 2180 2181 /** 2182 * Generates an Update Query based on an existing recordset. 2183 * $arrFields is an associative array of fields with the value 2184 * that should be assigned. 2185 * 2186 * Note: This function should only be used on a recordset 2187 * that is run against a single table and sql should only 2188 * be a simple select stmt with no groupby/orderby/limit 2189 * 2190 * "Jonathan Younger" <jyounger@unilab.com> 2191 */ 2192 function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null) { 2193 global $ADODB_INCLUDED_LIB; 2194 2195 // ******************************************************** 2196 // This is here to maintain compatibility 2197 // with older adodb versions. Sets force type to force nulls if $forcenulls is set. 2198 if (!isset($force)) { 2199 global $ADODB_FORCE_TYPE; 2200 $force = $ADODB_FORCE_TYPE; 2201 } 2202 // ******************************************************** 2203 2204 if (empty($ADODB_INCLUDED_LIB)) { 2205 include (ADODB_DIR.'/adodb-lib.inc.php'); 2206 } 2207 return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force); 2208 } 2209 2210 /** 2211 * Generates an Insert Query based on an existing recordset. 2212 * $arrFields is an associative array of fields with the value 2213 * that should be assigned. 2214 * 2215 * Note: This function should only be used on a recordset 2216 * that is run against a single table. 2217 */ 2218 function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null) { 2219 global $ADODB_INCLUDED_LIB; 2220 if (!isset($force)) { 2221 global $ADODB_FORCE_TYPE; 2222 $force = $ADODB_FORCE_TYPE; 2223 } 2224 if (empty($ADODB_INCLUDED_LIB)) { 2225 include (ADODB_DIR.'/adodb-lib.inc.php'); 2226 } 2227 return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force); 2228 } 2229 2230 2231 /** 2232 * Update a blob column, given a where clause. There are more sophisticated 2233 * blob handling functions that we could have implemented, but all require 2234 * a very complex API. Instead we have chosen something that is extremely 2235 * simple to understand and use. 2236 * 2237 * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course. 2238 * 2239 * Usage to update a $blobvalue which has a primary key blob_id=1 into a 2240 * field blobtable.blobcolumn: 2241 * 2242 * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1'); 2243 * 2244 * Insert example: 2245 * 2246 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); 2247 * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1'); 2248 */ 2249 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') { 2250 return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false; 2251 } 2252 2253 /** 2254 * Usage: 2255 * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1'); 2256 * 2257 * $blobtype supports 'BLOB' and 'CLOB' 2258 * 2259 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); 2260 * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1'); 2261 */ 2262 function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') { 2263 $fd = fopen($path,'rb'); 2264 if ($fd === false) { 2265 return false; 2266 } 2267 $val = fread($fd,filesize($path)); 2268 fclose($fd); 2269 return $this->UpdateBlob($table,$column,$val,$where,$blobtype); 2270 } 2271 2272 function BlobDecode($blob) { 2273 return $blob; 2274 } 2275 2276 function BlobEncode($blob) { 2277 return $blob; 2278 } 2279 2280 function GetCharSet() { 2281 return $this->charSet; 2282 } 2283 2284 function SetCharSet($charset) { 2285 $this->charSet = $charset; 2286 return true; 2287 } 2288 2289 function IfNull( $field, $ifNull ) { 2290 return " CASE WHEN $field is null THEN $ifNull ELSE $field END "; 2291 } 2292 2293 function LogSQL($enable=true) { 2294 include_once (ADODB_DIR.'/adodb-perf.inc.php'); 2295 2296 if ($enable) { 2297 $this->fnExecute = 'adodb_log_sql'; 2298 } else { 2299 $this->fnExecute = false; 2300 } 2301 2302 $old = $this->_logsql; 2303 $this->_logsql = $enable; 2304 if ($enable && !$old) { 2305 $this->_affected = false; 2306 } 2307 return $old; 2308 } 2309 2310 /** 2311 * Usage: 2312 * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB'); 2313 * 2314 * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)'); 2315 * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1'); 2316 */ 2317 function UpdateClob($table,$column,$val,$where) { 2318 return $this->UpdateBlob($table,$column,$val,$where,'CLOB'); 2319 } 2320 2321 // not the fastest implementation - quick and dirty - jlim 2322 // for best performance, use the actual $rs->MetaType(). 2323 function MetaType($t,$len=-1,$fieldobj=false) { 2324 2325 if (empty($this->_metars)) { 2326 $rsclass = $this->rsPrefix.$this->databaseType; 2327 $this->_metars = new $rsclass(false,$this->fetchMode); 2328 $this->_metars->connection = $this; 2329 } 2330 return $this->_metars->MetaType($t,$len,$fieldobj); 2331 } 2332 2333 2334 /** 2335 * Change the SQL connection locale to a specified locale. 2336 * This is used to get the date formats written depending on the client locale. 2337 */ 2338 function SetDateLocale($locale = 'En') { 2339 $this->locale = $locale; 2340 switch (strtoupper($locale)) 2341 { 2342 case 'EN': 2343 $this->fmtDate="'Y-m-d'"; 2344 $this->fmtTimeStamp = "'Y-m-d H:i:s'"; 2345 break; 2346 2347 case 'US': 2348 $this->fmtDate = "'m-d-Y'"; 2349 $this->fmtTimeStamp = "'m-d-Y H:i:s'"; 2350 break; 2351 2352 case 'PT_BR': 2353 case 'NL': 2354 case 'FR': 2355 case 'RO': 2356 case 'IT': 2357 $this->fmtDate="'d-m-Y'"; 2358 $this->fmtTimeStamp = "'d-m-Y H:i:s'"; 2359 break; 2360 2361 case 'GE': 2362 $this->fmtDate="'d.m.Y'"; 2363 $this->fmtTimeStamp = "'d.m.Y H:i:s'"; 2364 break; 2365 2366 default: 2367 $this->fmtDate="'Y-m-d'"; 2368 $this->fmtTimeStamp = "'Y-m-d H:i:s'"; 2369 break; 2370 } 2371 } 2372 2373 /** 2374 * GetActiveRecordsClass Performs an 'ALL' query 2375 * 2376 * @param mixed $class This string represents the class of the current active record 2377 * @param mixed $table Table used by the active record object 2378 * @param mixed $whereOrderBy Where, order, by clauses 2379 * @param mixed $bindarr 2380 * @param mixed $primkeyArr 2381 * @param array $extra Query extras: limit, offset... 2382 * @param mixed $relations Associative array: table's foreign name, "hasMany", "belongsTo" 2383 * @access public 2384 * @return void 2385 */ 2386 function GetActiveRecordsClass( 2387 $class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false, 2388 $extra=array(), 2389 $relations=array()) 2390 { 2391 global $_ADODB_ACTIVE_DBS; 2392 ## reduce overhead of adodb.inc.php -- moved to adodb-active-record.inc.php 2393 ## if adodb-active-recordx is loaded -- should be no issue as they will probably use Find() 2394 if (!isset($_ADODB_ACTIVE_DBS)) { 2395 include_once (ADODB_DIR.'/adodb-active-record.inc.php'); 2396 } 2397 return adodb_GetActiveRecordsClass($this, $class, $table, $whereOrderBy, $bindarr, $primkeyArr, $extra, $relations); 2398 } 2399 2400 function GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false) { 2401 $arr = $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr); 2402 return $arr; 2403 } 2404 2405 /** 2406 * Close Connection 2407 */ 2408 function Close() { 2409 $rez = $this->_close(); 2410 $this->_queryID = false; 2411 $this->_connectionID = false; 2412 return $rez; 2413 } 2414 2415 /** 2416 * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans(). 2417 * 2418 * @return true if succeeded or false if database does not support transactions 2419 */ 2420 function BeginTrans() { 2421 if ($this->debug) { 2422 ADOConnection::outp("BeginTrans: Transactions not supported for this driver"); 2423 } 2424 return false; 2425 } 2426 2427 /* set transaction mode */ 2428 function SetTransactionMode( $transaction_mode ) { 2429 $transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider); 2430 $this->_transmode = $transaction_mode; 2431 } 2432 /* 2433 http://msdn2.microsoft.com/en-US/ms173763.aspx 2434 http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html 2435 http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html 2436 http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm 2437 */ 2438 function MetaTransaction($mode,$db) { 2439 $mode = strtoupper($mode); 2440 $mode = str_replace('ISOLATION LEVEL ','',$mode); 2441 2442 switch($mode) { 2443 2444 case 'READ UNCOMMITTED': 2445 switch($db) { 2446 case 'oci8': 2447 case 'oracle': 2448 return 'ISOLATION LEVEL READ COMMITTED'; 2449 default: 2450 return 'ISOLATION LEVEL READ UNCOMMITTED'; 2451 } 2452 break; 2453 2454 case 'READ COMMITTED': 2455 return 'ISOLATION LEVEL READ COMMITTED'; 2456 break; 2457 2458 case 'REPEATABLE READ': 2459 switch($db) { 2460 case 'oci8': 2461 case 'oracle': 2462 return 'ISOLATION LEVEL SERIALIZABLE'; 2463 default: 2464 return 'ISOLATION LEVEL REPEATABLE READ'; 2465 } 2466 break; 2467 2468 case 'SERIALIZABLE': 2469 return 'ISOLATION LEVEL SERIALIZABLE'; 2470 break; 2471 2472 default: 2473 return $mode; 2474 } 2475 } 2476 2477 /** 2478 * If database does not support transactions, always return true as data always commited 2479 * 2480 * @param $ok set to false to rollback transaction, true to commit 2481 * 2482 * @return true/false. 2483 */ 2484 function CommitTrans($ok=true) { 2485 return true; 2486 } 2487 2488 2489 /** 2490 * If database does not support transactions, rollbacks always fail, so return false 2491 * 2492 * @return true/false. 2493 */ 2494 function RollbackTrans() { 2495 return false; 2496 } 2497 2498 2499 /** 2500 * return the databases that the driver can connect to. 2501 * Some databases will return an empty array. 2502 * 2503 * @return an array of database names. 2504 */ 2505 function MetaDatabases() { 2506 global $ADODB_FETCH_MODE; 2507 2508 if ($this->metaDatabasesSQL) { 2509 $save = $ADODB_FETCH_MODE; 2510 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 2511 2512 if ($this->fetchMode !== false) { 2513 $savem = $this->SetFetchMode(false); 2514 } 2515 2516 $arr = $this->GetCol($this->metaDatabasesSQL); 2517 if (isset($savem)) { 2518 $this->SetFetchMode($savem); 2519 } 2520 $ADODB_FETCH_MODE = $save; 2521 2522 return $arr; 2523 } 2524 2525 return false; 2526 } 2527 2528 /** 2529 * List procedures or functions in an array. 2530 * @param procedureNamePattern a procedure name pattern; must match the procedure name as it is stored in the database 2531 * @param catalog a catalog name; must match the catalog name as it is stored in the database; 2532 * @param schemaPattern a schema name pattern; 2533 * 2534 * @return array of procedures on current database. 2535 * 2536 * Array( 2537 * [name_of_procedure] => Array( 2538 * [type] => PROCEDURE or FUNCTION 2539 * [catalog] => Catalog_name 2540 * [schema] => Schema_name 2541 * [remarks] => explanatory comment on the procedure 2542 * ) 2543 * ) 2544 */ 2545 function MetaProcedures($procedureNamePattern = null, $catalog = null, $schemaPattern = null) { 2546 return false; 2547 } 2548 2549 2550 /** 2551 * @param ttype can either be 'VIEW' or 'TABLE' or false. 2552 * If false, both views and tables are returned. 2553 * "VIEW" returns only views 2554 * "TABLE" returns only tables 2555 * @param showSchema returns the schema/user with the table name, eg. USER.TABLE 2556 * @param mask is the input mask - only supported by oci8 and postgresql 2557 * 2558 * @return array of tables for current database. 2559 */ 2560 function MetaTables($ttype=false,$showSchema=false,$mask=false) { 2561 global $ADODB_FETCH_MODE; 2562 2563 if ($mask) { 2564 return false; 2565 } 2566 if ($this->metaTablesSQL) { 2567 $save = $ADODB_FETCH_MODE; 2568 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 2569 2570 if ($this->fetchMode !== false) { 2571 $savem = $this->SetFetchMode(false); 2572 } 2573 2574 $rs = $this->Execute($this->metaTablesSQL); 2575 if (isset($savem)) { 2576 $this->SetFetchMode($savem); 2577 } 2578 $ADODB_FETCH_MODE = $save; 2579 2580 if ($rs === false) { 2581 return false; 2582 } 2583 $arr = $rs->GetArray(); 2584 $arr2 = array(); 2585 2586 if ($hast = ($ttype && isset($arr[0][1]))) { 2587 $showt = strncmp($ttype,'T',1); 2588 } 2589 2590 for ($i=0; $i < sizeof($arr); $i++) { 2591 if ($hast) { 2592 if ($showt == 0) { 2593 if (strncmp($arr[$i][1],'T',1) == 0) { 2594 $arr2[] = trim($arr[$i][0]); 2595 } 2596 } else { 2597 if (strncmp($arr[$i][1],'V',1) == 0) { 2598 $arr2[] = trim($arr[$i][0]); 2599 } 2600 } 2601 } else 2602 $arr2[] = trim($arr[$i][0]); 2603 } 2604 $rs->Close(); 2605 return $arr2; 2606 } 2607 return false; 2608 } 2609 2610 2611 function _findschema(&$table,&$schema) { 2612 if (!$schema && ($at = strpos($table,'.')) !== false) { 2613 $schema = substr($table,0,$at); 2614 $table = substr($table,$at+1); 2615 } 2616 } 2617 2618 /** 2619 * List columns in a database as an array of ADOFieldObjects. 2620 * See top of file for definition of object. 2621 * 2622 * @param $table table name to query 2623 * @param $normalize makes table name case-insensitive (required by some databases) 2624 * @schema is optional database schema to use - not supported by all databases. 2625 * 2626 * @return array of ADOFieldObjects for current table. 2627 */ 2628 function MetaColumns($table,$normalize=true) { 2629 global $ADODB_FETCH_MODE; 2630 2631 if (!empty($this->metaColumnsSQL)) { 2632 $schema = false; 2633 $this->_findschema($table,$schema); 2634 2635 $save = $ADODB_FETCH_MODE; 2636 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 2637 if ($this->fetchMode !== false) { 2638 $savem = $this->SetFetchMode(false); 2639 } 2640 $rs = $this->Execute(sprintf($this->metaColumnsSQL,($normalize)?strtoupper($table):$table)); 2641 if (isset($savem)) { 2642 $this->SetFetchMode($savem); 2643 } 2644 $ADODB_FETCH_MODE = $save; 2645 if ($rs === false || $rs->EOF) { 2646 return false; 2647 } 2648 2649 $retarr = array(); 2650 while (!$rs->EOF) { //print_r($rs->fields); 2651 $fld = new ADOFieldObject(); 2652 $fld->name = $rs->fields[0]; 2653 $fld->type = $rs->fields[1]; 2654 if (isset($rs->fields[3]) && $rs->fields[3]) { 2655 if ($rs->fields[3]>0) { 2656 $fld->max_length = $rs->fields[3]; 2657 } 2658 $fld->scale = $rs->fields[4]; 2659 if ($fld->scale>0) { 2660 $fld->max_length += 1; 2661 } 2662 } else { 2663 $fld->max_length = $rs->fields[2]; 2664 } 2665 2666 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) { 2667 $retarr[] = $fld; 2668 } else { 2669 $retarr[strtoupper($fld->name)] = $fld; 2670 } 2671 $rs->MoveNext(); 2672 } 2673 $rs->Close(); 2674 return $retarr; 2675 } 2676 return false; 2677 } 2678 2679 /** 2680 * List indexes on a table as an array. 2681 * @param table table name to query 2682 * @param primary true to only show primary keys. Not actually used for most databases 2683 * 2684 * @return array of indexes on current table. Each element represents an index, and is itself an associative array. 2685 * 2686 * Array( 2687 * [name_of_index] => Array( 2688 * [unique] => true or false 2689 * [columns] => Array( 2690 * [0] => firstname 2691 * [1] => lastname 2692 * ) 2693 * ) 2694 * ) 2695 */ 2696 function MetaIndexes($table, $primary = false, $owner = false) { 2697 return false; 2698 } 2699 2700 /** 2701 * List columns names in a table as an array. 2702 * @param table table name to query 2703 * 2704 * @return array of column names for current table. 2705 */ 2706 function MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */) { 2707 $objarr = $this->MetaColumns($table); 2708 if (!is_array($objarr)) { 2709 return false; 2710 } 2711 $arr = array(); 2712 if ($numIndexes) { 2713 $i = 0; 2714 if ($useattnum) { 2715 foreach($objarr as $v) 2716 $arr[$v->attnum] = $v->name; 2717 2718 } else 2719 foreach($objarr as $v) $arr[$i++] = $v->name; 2720 } else 2721 foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name; 2722 2723 return $arr; 2724 } 2725 2726 /** 2727 * Different SQL databases used different methods to combine strings together. 2728 * This function provides a wrapper. 2729 * 2730 * param s variable number of string parameters 2731 * 2732 * Usage: $db->Concat($str1,$str2); 2733 * 2734 * @return concatenated string 2735 */ 2736 function Concat() { 2737 $arr = func_get_args(); 2738 return implode($this->concat_operator, $arr); 2739 } 2740 2741 2742 /** 2743 * Converts a date "d" to a string that the database can understand. 2744 * 2745 * @param d a date in Unix date time format. 2746 * 2747 * @return date string in database date format 2748 */ 2749 function DBDate($d, $isfld=false) { 2750 if (empty($d) && $d !== 0) { 2751 return 'null'; 2752 } 2753 if ($isfld) { 2754 return $d; 2755 } 2756 if (is_object($d)) { 2757 return $d->format($this->fmtDate); 2758 } 2759 2760 if (is_string($d) && !is_numeric($d)) { 2761 if ($d === 'null') { 2762 return $d; 2763 } 2764 if (strncmp($d,"'",1) === 0) { 2765 $d = _adodb_safedateq($d); 2766 return $d; 2767 } 2768 if ($this->isoDates) { 2769 return "'$d'"; 2770 } 2771 $d = ADOConnection::UnixDate($d); 2772 } 2773 2774 return adodb_date($this->fmtDate,$d); 2775 } 2776 2777 function BindDate($d) { 2778 $d = $this->DBDate($d); 2779 if (strncmp($d,"'",1)) { 2780 return $d; 2781 } 2782 2783 return substr($d,1,strlen($d)-2); 2784 } 2785 2786 function BindTimeStamp($d) { 2787 $d = $this->DBTimeStamp($d); 2788 if (strncmp($d,"'",1)) { 2789 return $d; 2790 } 2791 2792 return substr($d,1,strlen($d)-2); 2793 } 2794 2795 2796 /** 2797 * Converts a timestamp "ts" to a string that the database can understand. 2798 * 2799 * @param ts a timestamp in Unix date time format. 2800 * 2801 * @return timestamp string in database timestamp format 2802 */ 2803 function DBTimeStamp($ts,$isfld=false) { 2804 if (empty($ts) && $ts !== 0) { 2805 return 'null'; 2806 } 2807 if ($isfld) { 2808 return $ts; 2809 } 2810 if (is_object($ts)) { 2811 return $ts->format($this->fmtTimeStamp); 2812 } 2813 2814 # strlen(14) allows YYYYMMDDHHMMSS format 2815 if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) { 2816 return adodb_date($this->fmtTimeStamp,$ts); 2817 } 2818 2819 if ($ts === 'null') { 2820 return $ts; 2821 } 2822 if ($this->isoDates && strlen($ts) !== 14) { 2823 $ts = _adodb_safedate($ts); 2824 return "'$ts'"; 2825 } 2826 $ts = ADOConnection::UnixTimeStamp($ts); 2827 return adodb_date($this->fmtTimeStamp,$ts); 2828 } 2829 2830 /** 2831 * Also in ADORecordSet. 2832 * @param $v is a date string in YYYY-MM-DD format 2833 * 2834 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format 2835 */ 2836 static function UnixDate($v) { 2837 if (is_object($v)) { 2838 // odbtp support 2839 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) 2840 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year); 2841 } 2842 2843 if (is_numeric($v) && strlen($v) !== 8) { 2844 return $v; 2845 } 2846 if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", $v, $rr)) { 2847 return false; 2848 } 2849 2850 if ($rr[1] <= TIMESTAMP_FIRST_YEAR) { 2851 return 0; 2852 } 2853 2854 // h-m-s-MM-DD-YY 2855 return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]); 2856 } 2857 2858 2859 /** 2860 * Also in ADORecordSet. 2861 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format 2862 * 2863 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format 2864 */ 2865 static function UnixTimeStamp($v) { 2866 if (is_object($v)) { 2867 // odbtp support 2868 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) 2869 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year); 2870 } 2871 2872 if (!preg_match( 2873 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 2874 ($v), $rr)) return false; 2875 2876 if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) { 2877 return 0; 2878 } 2879 2880 // h-m-s-MM-DD-YY 2881 if (!isset($rr[5])) { 2882 return adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]); 2883 } 2884 return @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]); 2885 } 2886 2887 /** 2888 * Also in ADORecordSet. 2889 * 2890 * Format database date based on user defined format. 2891 * 2892 * @param v is the character date in YYYY-MM-DD format, returned by database 2893 * @param fmt is the format to apply to it, using date() 2894 * 2895 * @return a date formated as user desires 2896 */ 2897 function UserDate($v,$fmt='Y-m-d',$gmt=false) { 2898 $tt = $this->UnixDate($v); 2899 2900 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR 2901 if (($tt === false || $tt == -1) && $v != false) { 2902 return $v; 2903 } else if ($tt == 0) { 2904 return $this->emptyDate; 2905 } else if ($tt == -1) { 2906 // pre-TIMESTAMP_FIRST_YEAR 2907 } 2908 2909 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt); 2910 2911 } 2912 2913 /** 2914 * 2915 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format 2916 * @param fmt is the format to apply to it, using date() 2917 * 2918 * @return a timestamp formated as user desires 2919 */ 2920 function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false) { 2921 if (!isset($v)) { 2922 return $this->emptyTimeStamp; 2923 } 2924 # strlen(14) allows YYYYMMDDHHMMSS format 2925 if (is_numeric($v) && strlen($v)<14) { 2926 return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v); 2927 } 2928 $tt = $this->UnixTimeStamp($v); 2929 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR 2930 if (($tt === false || $tt == -1) && $v != false) { 2931 return $v; 2932 } 2933 if ($tt == 0) { 2934 return $this->emptyTimeStamp; 2935 } 2936 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt); 2937 } 2938 2939 function escape($s,$magic_quotes=false) { 2940 return $this->addq($s,$magic_quotes); 2941 } 2942 2943 /** 2944 * Quotes a string, without prefixing nor appending quotes. 2945 */ 2946 function addq($s,$magic_quotes=false) { 2947 if (!$magic_quotes) { 2948 if ($this->replaceQuote[0] == '\\') { 2949 // only since php 4.0.5 2950 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); 2951 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s)); 2952 } 2953 return str_replace("'",$this->replaceQuote,$s); 2954 } 2955 2956 // undo magic quotes for " 2957 $s = str_replace('\\"','"',$s); 2958 2959 if ($this->replaceQuote == "\\'" || ini_get('magic_quotes_sybase')) { 2960 // ' already quoted, no need to change anything 2961 return $s; 2962 } else { 2963 // change \' to '' for sybase/mssql 2964 $s = str_replace('\\\\','\\',$s); 2965 return str_replace("\\'",$this->replaceQuote,$s); 2966 } 2967 } 2968 2969 /** 2970 * Correctly quotes a string so that all strings are escaped. We prefix and append 2971 * to the string single-quotes. 2972 * An example is $db->qstr("Don't bother",magic_quotes_runtime()); 2973 * 2974 * @param s the string to quote 2975 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc(). 2976 * This undoes the stupidity of magic quotes for GPC. 2977 * 2978 * @return quoted string to be sent back to database 2979 */ 2980 function qstr($s,$magic_quotes=false) { 2981 if (!$magic_quotes) { 2982 if ($this->replaceQuote[0] == '\\'){ 2983 // only since php 4.0.5 2984 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); 2985 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s)); 2986 } 2987 return "'".str_replace("'",$this->replaceQuote,$s)."'"; 2988 } 2989 2990 // undo magic quotes for " 2991 $s = str_replace('\\"','"',$s); 2992 2993 if ($this->replaceQuote == "\\'" || ini_get('magic_quotes_sybase')) { 2994 // ' already quoted, no need to change anything 2995 return "'$s'"; 2996 } else { 2997 // change \' to '' for sybase/mssql 2998 $s = str_replace('\\\\','\\',$s); 2999 return "'".str_replace("\\'",$this->replaceQuote,$s)."'"; 3000 } 3001 } 3002 3003 3004 /** 3005 * Will select the supplied $page number from a recordset, given that it is paginated in pages of 3006 * $nrows rows per page. It also saves two boolean values saying if the given page is the first 3007 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination. 3008 * 3009 * See docs-adodb.htm#ex8 for an example of usage. 3010 * 3011 * @param sql 3012 * @param nrows is the number of rows per page to get 3013 * @param page is the page number to get (1-based) 3014 * @param [inputarr] array of bind variables 3015 * @param [secs2cache] is a private parameter only used by jlim 3016 * @return the recordset ($rs->databaseType == 'array') 3017 * 3018 * NOTE: phpLens uses a different algorithm and does not use PageExecute(). 3019 * 3020 */ 3021 function PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0) { 3022 global $ADODB_INCLUDED_LIB; 3023 if (empty($ADODB_INCLUDED_LIB)) { 3024 include (ADODB_DIR.'/adodb-lib.inc.php'); 3025 } 3026 if ($this->pageExecuteCountRows) { 3027 $rs = _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache); 3028 } else { 3029 $rs = _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache); 3030 } 3031 return $rs; 3032 } 3033 3034 3035 /** 3036 * Will select the supplied $page number from a recordset, given that it is paginated in pages of 3037 * $nrows rows per page. It also saves two boolean values saying if the given page is the first 3038 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination. 3039 * 3040 * @param secs2cache seconds to cache data, set to 0 to force query 3041 * @param sql 3042 * @param nrows is the number of rows per page to get 3043 * @param page is the page number to get (1-based) 3044 * @param [inputarr] array of bind variables 3045 * @return the recordset ($rs->databaseType == 'array') 3046 */ 3047 function CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false) { 3048 /*switch($this->dataProvider) { 3049 case 'postgres': 3050 case 'mysql': 3051 break; 3052 default: $secs2cache = 0; break; 3053 }*/ 3054 $rs = $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache); 3055 return $rs; 3056 } 3057 3058 /** 3059 * Get the last error recorded by PHP and clear the message. 3060 * 3061 * By clearing the message, it becomes possible to detect whether a new error 3062 * has occurred, even when it is the same error as before being repeated. 3063 * 3064 * @return array|null Array if an error has previously occurred. Null otherwise. 3065 */ 3066 protected function resetLastError() { 3067 $error = error_get_last(); 3068 3069 if (is_array($error)) { 3070 $error['message'] = ''; 3071 } 3072 3073 return $error; 3074 } 3075 3076 /** 3077 * Compare a previously stored error message with the last error recorded by PHP 3078 * to determine whether a new error has occured. 3079 * 3080 * @param array|null $old Optional. Previously stored return value of error_get_last(). 3081 * 3082 * @return string The error message if a new error has occured 3083 * or an empty string if no (new) errors have occured.. 3084 */ 3085 protected function getChangedErrorMsg($old = null) { 3086 $new = error_get_last(); 3087 3088 if (is_null($new)) { 3089 // No error has occured yet at all. 3090 return ''; 3091 } 3092 3093 if (is_null($old)) { 3094 // First error recorded. 3095 return $new['message']; 3096 } 3097 3098 $changed = false; 3099 foreach($new as $key => $value) { 3100 if ($new[$key] !== $old[$key]) { 3101 $changed = true; 3102 break; 3103 } 3104 } 3105 3106 if ($changed === true) { 3107 return $new['message']; 3108 } 3109 3110 return ''; 3111 } 3112 3113 } // end class ADOConnection 3114 3115 3116 3117 //============================================================================================== 3118 // CLASS ADOFetchObj 3119 //============================================================================================== 3120 3121 /** 3122 * Internal placeholder for record objects. Used by ADORecordSet->FetchObj(). 3123 */ 3124 class ADOFetchObj { 3125 }; 3126 3127 //============================================================================================== 3128 // CLASS ADORecordSet_empty 3129 //============================================================================================== 3130 3131 class ADODB_Iterator_empty implements Iterator { 3132 3133 private $rs; 3134 3135 function __construct($rs) { 3136 $this->rs = $rs; 3137 } 3138 3139 function rewind() {} 3140 3141 function valid() { 3142 return !$this->rs->EOF; 3143 } 3144 3145 function key() { 3146 return false; 3147 } 3148 3149 function current() { 3150 return false; 3151 } 3152 3153 function next() {} 3154 3155 function __call($func, $params) { 3156 return call_user_func_array(array($this->rs, $func), $params); 3157 } 3158 3159 function hasMore() { 3160 return false; 3161 } 3162 3163 } 3164 3165 3166 /** 3167 * Lightweight recordset when there are no records to be returned 3168 */ 3169 class ADORecordSet_empty implements IteratorAggregate 3170 { 3171 var $dataProvider = 'empty'; 3172 var $databaseType = false; 3173 var $EOF = true; 3174 var $_numOfRows = 0; 3175 var $fields = false; 3176 var $connection = false; 3177 3178 function RowCount() { 3179 return 0; 3180 } 3181 3182 function RecordCount() { 3183 return 0; 3184 } 3185 3186 function PO_RecordCount() { 3187 return 0; 3188 } 3189 3190 function Close() { 3191 return true; 3192 } 3193 3194 function FetchRow() { 3195 return false; 3196 } 3197 3198 function FieldCount() { 3199 return 0; 3200 } 3201 3202 function Init() {} 3203 3204 function getIterator() { 3205 return new ADODB_Iterator_empty($this); 3206 } 3207 3208 function GetAssoc() { 3209 return array(); 3210 } 3211 3212 function GetArray() { 3213 return array(); 3214 } 3215 3216 function GetAll() { 3217 return array(); 3218 } 3219 3220 function GetArrayLimit() { 3221 return array(); 3222 } 3223 3224 function GetRows() { 3225 return array(); 3226 } 3227 3228 function GetRowAssoc() { 3229 return array(); 3230 } 3231 3232 function MaxRecordCount() { 3233 return 0; 3234 } 3235 3236 function NumRows() { 3237 return 0; 3238 } 3239 3240 function NumCols() { 3241 return 0; 3242 } 3243 } 3244 3245 //============================================================================================== 3246 // DATE AND TIME FUNCTIONS 3247 //============================================================================================== 3248 if (!defined('ADODB_DATE_VERSION')) { 3249 include (ADODB_DIR.'/adodb-time.inc.php'); 3250 } 3251 3252 //============================================================================================== 3253 // CLASS ADORecordSet 3254 //============================================================================================== 3255 3256 class ADODB_Iterator implements Iterator { 3257 3258 private $rs; 3259 3260 function __construct($rs) { 3261 $this->rs = $rs; 3262 } 3263 3264 function rewind() { 3265 $this->rs->MoveFirst(); 3266 } 3267 3268 function valid() { 3269 return !$this->rs->EOF; 3270 } 3271 3272 function key() { 3273 return $this->rs->_currentRow; 3274 } 3275 3276 function current() { 3277 return $this->rs->fields; 3278 } 3279 3280 function next() { 3281 $this->rs->MoveNext(); 3282 } 3283 3284 function __call($func, $params) { 3285 return call_user_func_array(array($this->rs, $func), $params); 3286 } 3287 3288 function hasMore() { 3289 return !$this->rs->EOF; 3290 } 3291 3292 } 3293 3294 3295 /** 3296 * RecordSet class that represents the dataset returned by the database. 3297 * To keep memory overhead low, this class holds only the current row in memory. 3298 * No prefetching of data is done, so the RecordCount() can return -1 ( which 3299 * means recordcount not known). 3300 */ 3301 class ADORecordSet implements IteratorAggregate { 3302 3303 /** 3304 * public variables 3305 */ 3306 var $dataProvider = "native"; 3307 var $fields = false; /// holds the current row data 3308 var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob 3309 /// in other words, we use a text area for editing. 3310 var $canSeek = false; /// indicates that seek is supported 3311 var $sql; /// sql text 3312 var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object. 3313 3314 var $emptyTimeStamp = ' '; /// what to display when $time==0 3315 var $emptyDate = ' '; /// what to display when $time==0 3316 var $debug = false; 3317 var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsets 3318 3319 var $bind = false; /// used by Fields() to hold array - should be private? 3320 var $fetchMode; /// default fetch mode 3321 var $connection = false; /// the parent connection 3322 3323 /** 3324 * private variables 3325 */ 3326 var $_numOfRows = -1; /** number of rows, or -1 */ 3327 var $_numOfFields = -1; /** number of fields in recordset */ 3328 var $_queryID = -1; /** This variable keeps the result link identifier. */ 3329 var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */ 3330 var $_closed = false; /** has recordset been closed */ 3331 var $_inited = false; /** Init() should only be called once */ 3332 var $_obj; /** Used by FetchObj */ 3333 var $_names; /** Used by FetchObj */ 3334 3335 var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */ 3336 var $_atFirstPage = false; /** Added by Iván Oliva to implement recordset pagination */ 3337 var $_atLastPage = false; /** Added by Iván Oliva to implement recordset pagination */ 3338 var $_lastPageNo = -1; 3339 var $_maxRecordCount = 0; 3340 var $datetime = false; 3341 3342 /** 3343 * Constructor 3344 * 3345 * @param queryID this is the queryID returned by ADOConnection->_query() 3346 * 3347 */ 3348 function __construct($queryID) { 3349 $this->_queryID = $queryID; 3350 } 3351 3352 function __destruct() { 3353 $this->Close(); 3354 } 3355 3356 function getIterator() { 3357 return new ADODB_Iterator($this); 3358 } 3359 3360 /* this is experimental - i don't really know what to return... */ 3361 function __toString() { 3362 include_once (ADODB_DIR.'/toexport.inc.php'); 3363 return _adodb_export($this,',',',',false,true); 3364 } 3365 3366 function Init() { 3367 if ($this->_inited) { 3368 return; 3369 } 3370 $this->_inited = true; 3371 if ($this->_queryID) { 3372 @$this->_initrs(); 3373 } else { 3374 $this->_numOfRows = 0; 3375 $this->_numOfFields = 0; 3376 } 3377 if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) { 3378 $this->_currentRow = 0; 3379 if ($this->EOF = ($this->_fetch() === false)) { 3380 $this->_numOfRows = 0; // _numOfRows could be -1 3381 } 3382 } else { 3383 $this->EOF = true; 3384 } 3385 } 3386 3387 3388 /** 3389 * Generate a SELECT tag from a recordset, and return the HTML markup. 3390 * 3391 * If the recordset has 2 columns, we treat the first one as the text to 3392 * display to the user, and the second as the return value. Extra columns 3393 * are discarded. 3394 * 3395 * @param string $name Name of SELECT tag 3396 * @param string|array $defstr The value to highlight. Use an array for multiple highlight values. 3397 * @param bool|string $blank1stItem True to create an empty item (default), False not to add one; 3398 * 'string' to set its label and 'value:string' to assign a value to it. 3399 * @param bool $multiple True for multi-select list 3400 * @param int $size Number of rows to show (applies to multi-select box only) 3401 * @param string $selectAttr Additional attributes to defined for SELECT tag, 3402 * useful for holding javascript onChange='...' handlers, CSS class, etc. 3403 * @param bool $compareFirstCol When true (default), $defstr is compared against the value (column 2), 3404 * while false will compare against the description (column 1). 3405 * 3406 * @return string HTML 3407 */ 3408 function getMenu($name, $defstr = '', $blank1stItem = true, $multiple = false, 3409 $size = 0, $selectAttr = '', $compareFirstCol = true) 3410 { 3411 global $ADODB_INCLUDED_LIB; 3412 if (empty($ADODB_INCLUDED_LIB)) { 3413 include (ADODB_DIR.'/adodb-lib.inc.php'); 3414 } 3415 return _adodb_getmenu($this, $name, $defstr, $blank1stItem, $multiple, 3416 $size, $selectAttr, $compareFirstCol); 3417 } 3418 3419 /** 3420 * Generate a SELECT tag with groups from a recordset, and return the HTML markup. 3421 * 3422 * The recordset must have 3 columns and be ordered by the 3rd column. The 3423 * first column contains the text to display to the user, the second is the 3424 * return value and the third is the option group. Extra columns are discarded. 3425 * Default strings are compared with the SECOND column. 3426 * 3427 * @param string $name Name of SELECT tag 3428 * @param string|array $defstr The value to highlight. Use an array for multiple highlight values. 3429 * @param bool|string $blank1stItem True to create an empty item (default), False not to add one; 3430 * 'string' to set its label and 'value:string' to assign a value to it. 3431 * @param bool $multiple True for multi-select list 3432 * @param int $size Number of rows to show (applies to multi-select box only) 3433 * @param string $selectAttr Additional attributes to defined for SELECT tag, 3434 * useful for holding javascript onChange='...' handlers, CSS class, etc. 3435 * @param bool $compareFirstCol When true (default), $defstr is compared against the value (column 2), 3436 * while false will compare against the description (column 1). 3437 * 3438 * @return string HTML 3439 */ 3440 function getMenuGrouped($name, $defstr = '', $blank1stItem = true, $multiple = false, 3441 $size = 0, $selectAttr = '', $compareFirstCol = true) 3442 { 3443 global $ADODB_INCLUDED_LIB; 3444 if (empty($ADODB_INCLUDED_LIB)) { 3445 include (ADODB_DIR.'/adodb-lib.inc.php'); 3446 } 3447 return _adodb_getmenu_gp($this, $name, $defstr, $blank1stItem, $multiple, 3448 $size, $selectAttr, $compareFirstCol); 3449 } 3450 3451 /** 3452 * Generate a SELECT tag from a recordset, and return the HTML markup. 3453 * 3454 * Same as GetMenu(), except that default strings are compared with the 3455 * FIRST column (the description). 3456 * 3457 * @param string $name Name of SELECT tag 3458 * @param string|array $defstr The value to highlight. Use an array for multiple highlight values. 3459 * @param bool|string $blank1stItem True to create an empty item (default), False not to add one; 3460 * 'string' to set its label and 'value:string' to assign a value to it. 3461 * @param bool $multiple True for multi-select list 3462 * @param int $size Number of rows to show (applies to multi-select box only) 3463 * @param string $selectAttr Additional attributes to defined for SELECT tag, 3464 * useful for holding javascript onChange='...' handlers, CSS class, etc. 3465 * 3466 * @return string HTML 3467 * 3468 * @deprecated 5.21.0 Use getMenu() with $compareFirstCol = false instead. 3469 */ 3470 function getMenu2($name, $defstr = '', $blank1stItem = true, $multiple = false, 3471 $size = 0, $selectAttr = '') 3472 { 3473 return $this->getMenu($name, $defstr, $blank1stItem, $multiple, 3474 $size, $selectAttr,false); 3475 } 3476 3477 /** 3478 * Generate a SELECT tag with groups from a recordset, and return the HTML markup. 3479 * 3480 * Same as GetMenuGrouped(), except that default strings are compared with the 3481 * FIRST column (the description). 3482 * 3483 * @param string $name Name of SELECT tag 3484 * @param string|array $defstr The value to highlight. Use an array for multiple highlight values. 3485 * @param bool|string $blank1stItem True to create an empty item (default), False not to add one; 3486 * 'string' to set its label and 'value:string' to assign a value to it. 3487 * @param bool $multiple True for multi-select list 3488 * @param int $size Number of rows to show (applies to multi-select box only) 3489 * @param string $selectAttr Additional attributes to defined for SELECT tag, 3490 * useful for holding javascript onChange='...' handlers, CSS class, etc. 3491 * 3492 * @return string HTML 3493 * 3494 * @deprecated 5.21.0 Use getMenuGrouped() with $compareFirstCol = false instead. 3495 */ 3496 function getMenu3($name, $defstr = '', $blank1stItem = true, $multiple = false, 3497 $size = 0, $selectAttr = '') 3498 { 3499 return $this->getMenuGrouped($name, $defstr, $blank1stItem, $multiple, 3500 $size, $selectAttr, false); 3501 } 3502 3503 /** 3504 * return recordset as a 2-dimensional array. 3505 * 3506 * @param [nRows] is the number of rows to return. -1 means every row. 3507 * 3508 * @return an array indexed by the rows (0-based) from the recordset 3509 */ 3510 function GetArray($nRows = -1) { 3511 global $ADODB_EXTENSION; if ($ADODB_EXTENSION) { 3512 $results = adodb_getall($this,$nRows); 3513 return $results; 3514 } 3515 $results = array(); 3516 $cnt = 0; 3517 while (!$this->EOF && $nRows != $cnt) { 3518 $results[] = $this->fields; 3519 $this->MoveNext(); 3520 $cnt++; 3521 } 3522 return $results; 3523 } 3524 3525 function GetAll($nRows = -1) { 3526 $arr = $this->GetArray($nRows); 3527 return $arr; 3528 } 3529 3530 /* 3531 * Some databases allow multiple recordsets to be returned. This function 3532 * will return true if there is a next recordset, or false if no more. 3533 */ 3534 function NextRecordSet() { 3535 return false; 3536 } 3537 3538 /** 3539 * return recordset as a 2-dimensional array. 3540 * Helper function for ADOConnection->SelectLimit() 3541 * 3542 * @param offset is the row to start calculations from (1-based) 3543 * @param [nrows] is the number of rows to return 3544 * 3545 * @return an array indexed by the rows (0-based) from the recordset 3546 */ 3547 function GetArrayLimit($nrows,$offset=-1) { 3548 if ($offset <= 0) { 3549 $arr = $this->GetArray($nrows); 3550 return $arr; 3551 } 3552 3553 $this->Move($offset); 3554 3555 $results = array(); 3556 $cnt = 0; 3557 while (!$this->EOF && $nrows != $cnt) { 3558 $results[$cnt++] = $this->fields; 3559 $this->MoveNext(); 3560 } 3561 3562 return $results; 3563 } 3564 3565 3566 /** 3567 * Synonym for GetArray() for compatibility with ADO. 3568 * 3569 * @param [nRows] is the number of rows to return. -1 means every row. 3570 * 3571 * @return an array indexed by the rows (0-based) from the recordset 3572 */ 3573 function GetRows($nRows = -1) { 3574 $arr = $this->GetArray($nRows); 3575 return $arr; 3576 } 3577 3578 /** 3579 * return whole recordset as a 2-dimensional associative array if there are more than 2 columns. 3580 * The first column is treated as the key and is not included in the array. 3581 * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless 3582 * $force_array == true. 3583 * 3584 * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional 3585 * array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing, 3586 * read the source. 3587 * 3588 * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and 3589 * instead of returning array[col0] => array(remaining cols), return array[col0] => col1 3590 * 3591 * @return an associative array indexed by the first column of the array, 3592 * or false if the data has less than 2 cols. 3593 */ 3594 function GetAssoc($force_array = false, $first2cols = false) { 3595 global $ADODB_EXTENSION; 3596 3597 $cols = $this->_numOfFields; 3598 if ($cols < 2) { 3599 return false; 3600 } 3601 3602 // Empty recordset 3603 if (!$this->fields) { 3604 return array(); 3605 } 3606 3607 // Determine whether the array is associative or 0-based numeric 3608 $numIndex = array_keys($this->fields) == range(0, count($this->fields) - 1); 3609 3610 $results = array(); 3611 3612 if (!$first2cols && ($cols > 2 || $force_array)) { 3613 if ($ADODB_EXTENSION) { 3614 if ($numIndex) { 3615 while (!$this->EOF) { 3616 $results[trim($this->fields[0])] = array_slice($this->fields, 1); 3617 adodb_movenext($this); 3618 } 3619 } else { 3620 while (!$this->EOF) { 3621 // Fix for array_slice re-numbering numeric associative keys 3622 $keys = array_slice(array_keys($this->fields), 1); 3623 $sliced_array = array(); 3624 3625 foreach($keys as $key) { 3626 $sliced_array[$key] = $this->fields[$key]; 3627 } 3628 3629 $results[trim(reset($this->fields))] = $sliced_array; 3630 adodb_movenext($this); 3631 } 3632 } 3633 } else { 3634 if ($numIndex) { 3635 while (!$this->EOF) { 3636 $results[trim($this->fields[0])] = array_slice($this->fields, 1); 3637 $this->MoveNext(); 3638 } 3639 } else { 3640 while (!$this->EOF) { 3641 // Fix for array_slice re-numbering numeric associative keys 3642 $keys = array_slice(array_keys($this->fields), 1); 3643 $sliced_array = array(); 3644 3645 foreach($keys as $key) { 3646 $sliced_array[$key] = $this->fields[$key]; 3647 } 3648 3649 $results[trim(reset($this->fields))] = $sliced_array; 3650 $this->MoveNext(); 3651 } 3652 } 3653 } 3654 } else { 3655 if ($ADODB_EXTENSION) { 3656 // return scalar values 3657 if ($numIndex) { 3658 while (!$this->EOF) { 3659 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string 3660 $results[trim(($this->fields[0]))] = $this->fields[1]; 3661 adodb_movenext($this); 3662 } 3663 } else { 3664 while (!$this->EOF) { 3665 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string 3666 $v1 = trim(reset($this->fields)); 3667 $v2 = ''.next($this->fields); 3668 $results[$v1] = $v2; 3669 adodb_movenext($this); 3670 } 3671 } 3672 } else { 3673 if ($numIndex) { 3674 while (!$this->EOF) { 3675 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string 3676 $results[trim(($this->fields[0]))] = $this->fields[1]; 3677 $this->MoveNext(); 3678 } 3679 } else { 3680 while (!$this->EOF) { 3681 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string 3682 $v1 = trim(reset($this->fields)); 3683 $v2 = ''.next($this->fields); 3684 $results[$v1] = $v2; 3685 $this->MoveNext(); 3686 } 3687 } 3688 } 3689 } 3690 3691 $ref = $results; # workaround accelerator incompat with PHP 4.4 :( 3692 return $ref; 3693 } 3694 3695 3696 /** 3697 * 3698 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format 3699 * @param fmt is the format to apply to it, using date() 3700 * 3701 * @return a timestamp formated as user desires 3702 */ 3703 function UserTimeStamp($v,$fmt='Y-m-d H:i:s') { 3704 if (is_numeric($v) && strlen($v)<14) { 3705 return adodb_date($fmt,$v); 3706 } 3707 $tt = $this->UnixTimeStamp($v); 3708 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR 3709 if (($tt === false || $tt == -1) && $v != false) { 3710 return $v; 3711 } 3712 if ($tt === 0) { 3713 return $this->emptyTimeStamp; 3714 } 3715 return adodb_date($fmt,$tt); 3716 } 3717 3718 3719 /** 3720 * @param v is the character date in YYYY-MM-DD format, returned by database 3721 * @param fmt is the format to apply to it, using date() 3722 * 3723 * @return a date formated as user desires 3724 */ 3725 function UserDate($v,$fmt='Y-m-d') { 3726 $tt = $this->UnixDate($v); 3727 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR 3728 if (($tt === false || $tt == -1) && $v != false) { 3729 return $v; 3730 } else if ($tt == 0) { 3731 return $this->emptyDate; 3732 } else if ($tt == -1) { 3733 // pre-TIMESTAMP_FIRST_YEAR 3734 } 3735 return adodb_date($fmt,$tt); 3736 } 3737 3738 3739 /** 3740 * @param $v is a date string in YYYY-MM-DD format 3741 * 3742 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format 3743 */ 3744 static function UnixDate($v) { 3745 return ADOConnection::UnixDate($v); 3746 } 3747 3748 3749 /** 3750 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format 3751 * 3752 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format 3753 */ 3754 static function UnixTimeStamp($v) { 3755 return ADOConnection::UnixTimeStamp($v); 3756 } 3757 3758 3759 /** 3760 * PEAR DB Compat - do not use internally 3761 */ 3762 function Free() { 3763 return $this->Close(); 3764 } 3765 3766 3767 /** 3768 * PEAR DB compat, number of rows 3769 */ 3770 function NumRows() { 3771 return $this->_numOfRows; 3772 } 3773 3774 3775 /** 3776 * PEAR DB compat, number of cols 3777 */ 3778 function NumCols() { 3779 return $this->_numOfFields; 3780 } 3781 3782 /** 3783 * Fetch a row, returning false if no more rows. 3784 * This is PEAR DB compat mode. 3785 * 3786 * @return false or array containing the current record 3787 */ 3788 function FetchRow() { 3789 if ($this->EOF) { 3790 return false; 3791 } 3792 $arr = $this->fields; 3793 $this->_currentRow++; 3794 if (!$this->_fetch()) { 3795 $this->EOF = true; 3796 } 3797 return $arr; 3798 } 3799 3800 3801 /** 3802 * Fetch a row, returning PEAR_Error if no more rows. 3803 * This is PEAR DB compat mode. 3804 * 3805 * @return DB_OK or error object 3806 */ 3807 function FetchInto(&$arr) { 3808 if ($this->EOF) { 3809 return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false; 3810 } 3811 $arr = $this->fields; 3812 $this->MoveNext(); 3813 return 1; // DB_OK 3814 } 3815 3816 3817 /** 3818 * Move to the first row in the recordset. Many databases do NOT support this. 3819 * 3820 * @return true or false 3821 */ 3822 function MoveFirst() { 3823 if ($this->_currentRow == 0) { 3824 return true; 3825 } 3826 return $this->Move(0); 3827 } 3828 3829 3830 /** 3831 * Move to the last row in the recordset. 3832 * 3833 * @return true or false 3834 */ 3835 function MoveLast() { 3836 if ($this->_numOfRows >= 0) { 3837 return $this->Move($this->_numOfRows-1); 3838 } 3839 if ($this->EOF) { 3840 return false; 3841 } 3842 while (!$this->EOF) { 3843 $f = $this->fields; 3844 $this->MoveNext(); 3845 } 3846 $this->fields = $f; 3847 $this->EOF = false; 3848 return true; 3849 } 3850 3851 3852 /** 3853 * Move to next record in the recordset. 3854 * 3855 * @return true if there still rows available, or false if there are no more rows (EOF). 3856 */ 3857 function MoveNext() { 3858 if (!$this->EOF) { 3859 $this->_currentRow++; 3860 if ($this->_fetch()) { 3861 return true; 3862 } 3863 } 3864 $this->EOF = true; 3865 /* -- tested error handling when scrolling cursor -- seems useless. 3866 $conn = $this->connection; 3867 if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) { 3868 $fn = $conn->raiseErrorFn; 3869 $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database); 3870 } 3871 */ 3872 return false; 3873 } 3874 3875 3876 /** 3877 * Random access to a specific row in the recordset. Some databases do not support 3878 * access to previous rows in the databases (no scrolling backwards). 3879 * 3880 * @param rowNumber is the row to move to (0-based) 3881 * 3882 * @return true if there still rows available, or false if there are no more rows (EOF). 3883 */ 3884 function Move($rowNumber = 0) { 3885 $this->EOF = false; 3886 if ($rowNumber == $this->_currentRow) { 3887 return true; 3888 } 3889 if ($rowNumber >= $this->_numOfRows) { 3890 if ($this->_numOfRows != -1) { 3891 $rowNumber = $this->_numOfRows-2; 3892 } 3893 } 3894 3895 if ($rowNumber < 0) { 3896 $this->EOF = true; 3897 return false; 3898 } 3899 3900 if ($this->canSeek) { 3901 if ($this->_seek($rowNumber)) { 3902 $this->_currentRow = $rowNumber; 3903 if ($this->_fetch()) { 3904 return true; 3905 } 3906 } else { 3907 $this->EOF = true; 3908 return false; 3909 } 3910 } else { 3911 if ($rowNumber < $this->_currentRow) { 3912 return false; 3913 } 3914 global $ADODB_EXTENSION; 3915 if ($ADODB_EXTENSION) { 3916 while (!$this->EOF && $this->_currentRow < $rowNumber) { 3917 adodb_movenext($this); 3918 } 3919 } else { 3920 while (! $this->EOF && $this->_currentRow < $rowNumber) { 3921 $this->_currentRow++; 3922 3923 if (!$this->_fetch()) { 3924 $this->EOF = true; 3925 } 3926 } 3927 } 3928 return !($this->EOF); 3929 } 3930 3931 $this->fields = false; 3932 $this->EOF = true; 3933 return false; 3934 } 3935 3936 3937 /** 3938 * Get the value of a field in the current row by column name. 3939 * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM. 3940 * 3941 * @param colname is the field to access 3942 * 3943 * @return the value of $colname column 3944 */ 3945 function Fields($colname) { 3946 return $this->fields[$colname]; 3947 } 3948 3949 /** 3950 * Defines the function to use for table fields case conversion 3951 * depending on ADODB_ASSOC_CASE 3952 * @return string strtolower/strtoupper or false if no conversion needed 3953 */ 3954 protected function AssocCaseConvertFunction($case = ADODB_ASSOC_CASE) { 3955 switch($case) { 3956 case ADODB_ASSOC_CASE_UPPER: 3957 return 'strtoupper'; 3958 case ADODB_ASSOC_CASE_LOWER: 3959 return 'strtolower'; 3960 case ADODB_ASSOC_CASE_NATIVE: 3961 default: 3962 return false; 3963 } 3964 } 3965 3966 /** 3967 * Builds the bind array associating keys to recordset fields 3968 * 3969 * @param int $upper Case for the array keys, defaults to uppercase 3970 * (see ADODB_ASSOC_CASE_xxx constants) 3971 */ 3972 function GetAssocKeys($upper = ADODB_ASSOC_CASE) { 3973 if ($this->bind) { 3974 return; 3975 } 3976 $this->bind = array(); 3977 3978 // Define case conversion function for ASSOC fetch mode 3979 $fn_change_case = $this->AssocCaseConvertFunction($upper); 3980 3981 // Build the bind array 3982 for ($i=0; $i < $this->_numOfFields; $i++) { 3983 $o = $this->FetchField($i); 3984 3985 // Set the array's key 3986 if(is_numeric($o->name)) { 3987 // Just use the field ID 3988 $key = $i; 3989 } 3990 elseif( $fn_change_case ) { 3991 // Convert the key's case 3992 $key = $fn_change_case($o->name); 3993 } 3994 else { 3995 $key = $o->name; 3996 } 3997 3998 $this->bind[$key] = $i; 3999 } 4000 } 4001 4002 /** 4003 * Use associative array to get fields array for databases that do not support 4004 * associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it 4005 * 4006 * @param int $upper Case for the array keys, defaults to uppercase 4007 * (see ADODB_ASSOC_CASE_xxx constants) 4008 */ 4009 function GetRowAssoc($upper = ADODB_ASSOC_CASE) { 4010 $record = array(); 4011 $this->GetAssocKeys($upper); 4012 4013 foreach($this->bind as $k => $v) { 4014 if( array_key_exists( $v, $this->fields ) ) { 4015 $record[$k] = $this->fields[$v]; 4016 } elseif( array_key_exists( $k, $this->fields ) ) { 4017 $record[$k] = $this->fields[$k]; 4018 } else { 4019 # This should not happen... trigger error ? 4020 $record[$k] = null; 4021 } 4022 } 4023 return $record; 4024 } 4025 4026 /** 4027 * Clean up recordset 4028 * 4029 * @return true or false 4030 */ 4031 function Close() { 4032 // free connection object - this seems to globally free the object 4033 // and not merely the reference, so don't do this... 4034 // $this->connection = false; 4035 if (!$this->_closed) { 4036 $this->_closed = true; 4037 return $this->_close(); 4038 } else 4039 return true; 4040 } 4041 4042 /** 4043 * synonyms RecordCount and RowCount 4044 * 4045 * @return the number of rows or -1 if this is not supported 4046 */ 4047 function RecordCount() { 4048 return $this->_numOfRows; 4049 } 4050 4051 4052 /* 4053 * If we are using PageExecute(), this will return the maximum possible rows 4054 * that can be returned when paging a recordset. 4055 */ 4056 function MaxRecordCount() { 4057 return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount(); 4058 } 4059 4060 /** 4061 * synonyms RecordCount and RowCount 4062 * 4063 * @return the number of rows or -1 if this is not supported 4064 */ 4065 function RowCount() { 4066 return $this->_numOfRows; 4067 } 4068 4069 4070 /** 4071 * Portable RecordCount. Pablo Roca <pabloroca@mvps.org> 4072 * 4073 * @return the number of records from a previous SELECT. All databases support this. 4074 * 4075 * But aware possible problems in multiuser environments. For better speed the table 4076 * must be indexed by the condition. Heavy test this before deploying. 4077 */ 4078 function PO_RecordCount($table="", $condition="") { 4079 4080 $lnumrows = $this->_numOfRows; 4081 // the database doesn't support native recordcount, so we do a workaround 4082 if ($lnumrows == -1 && $this->connection) { 4083 IF ($table) { 4084 if ($condition) { 4085 $condition = " WHERE " . $condition; 4086 } 4087 $resultrows = $this->connection->Execute("SELECT COUNT(*) FROM $table $condition"); 4088 if ($resultrows) { 4089 $lnumrows = reset($resultrows->fields); 4090 } 4091 } 4092 } 4093 return $lnumrows; 4094 } 4095 4096 4097 /** 4098 * @return the current row in the recordset. If at EOF, will return the last row. 0-based. 4099 */ 4100 function CurrentRow() { 4101 return $this->_currentRow; 4102 } 4103 4104 /** 4105 * synonym for CurrentRow -- for ADO compat 4106 * 4107 * @return the current row in the recordset. If at EOF, will return the last row. 0-based. 4108 */ 4109 function AbsolutePosition() { 4110 return $this->_currentRow; 4111 } 4112 4113 /** 4114 * @return the number of columns in the recordset. Some databases will set this to 0 4115 * if no records are returned, others will return the number of columns in the query. 4116 */ 4117 function FieldCount() { 4118 return $this->_numOfFields; 4119 } 4120 4121 4122 /** 4123 * Get the ADOFieldObject of a specific column. 4124 * 4125 * @param fieldoffset is the column position to access(0-based). 4126 * 4127 * @return the ADOFieldObject for that column, or false. 4128 */ 4129 function FetchField($fieldoffset = -1) { 4130 // must be defined by child class 4131 4132 return false; 4133 } 4134 4135 /** 4136 * Get the ADOFieldObjects of all columns in an array. 4137 * 4138 */ 4139 function FieldTypesArray() { 4140 $arr = array(); 4141 for ($i=0, $max=$this->_numOfFields; $i < $max; $i++) 4142 $arr[] = $this->FetchField($i); 4143 return $arr; 4144 } 4145 4146 /** 4147 * Return the fields array of the current row as an object for convenience. 4148 * The default case is lowercase field names. 4149 * 4150 * @return the object with the properties set to the fields of the current row 4151 */ 4152 function FetchObj() { 4153 $o = $this->FetchObject(false); 4154 return $o; 4155 } 4156 4157 /** 4158 * Return the fields array of the current row as an object for convenience. 4159 * The default case is uppercase. 4160 * 4161 * @param $isupper to set the object property names to uppercase 4162 * 4163 * @return the object with the properties set to the fields of the current row 4164 */ 4165 function FetchObject($isupper=true) { 4166 if (empty($this->_obj)) { 4167 $this->_obj = new ADOFetchObj(); 4168 $this->_names = array(); 4169 for ($i=0; $i <$this->_numOfFields; $i++) { 4170 $f = $this->FetchField($i); 4171 $this->_names[] = $f->name; 4172 } 4173 } 4174 $i = 0; 4175 if (PHP_VERSION >= 5) { 4176 $o = clone($this->_obj); 4177 } else { 4178 $o = $this->_obj; 4179 } 4180 4181 for ($i=0; $i <$this->_numOfFields; $i++) { 4182 $name = $this->_names[$i]; 4183 if ($isupper) { 4184 $n = strtoupper($name); 4185 } else { 4186 $n = $name; 4187 } 4188 4189 $o->$n = $this->Fields($name); 4190 } 4191 return $o; 4192 } 4193 4194 /** 4195 * Return the fields array of the current row as an object for convenience. 4196 * The default is lower-case field names. 4197 * 4198 * @return the object with the properties set to the fields of the current row, 4199 * or false if EOF 4200 * 4201 * Fixed bug reported by tim@orotech.net 4202 */ 4203 function FetchNextObj() { 4204 $o = $this->FetchNextObject(false); 4205 return $o; 4206 } 4207 4208 4209 /** 4210 * Return the fields array of the current row as an object for convenience. 4211 * The default is upper case field names. 4212 * 4213 * @param $isupper to set the object property names to uppercase 4214 * 4215 * @return the object with the properties set to the fields of the current row, 4216 * or false if EOF 4217 * 4218 * Fixed bug reported by tim@orotech.net 4219 */ 4220 function FetchNextObject($isupper=true) { 4221 $o = false; 4222 if ($this->_numOfRows != 0 && !$this->EOF) { 4223 $o = $this->FetchObject($isupper); 4224 $this->_currentRow++; 4225 if ($this->_fetch()) { 4226 return $o; 4227 } 4228 } 4229 $this->EOF = true; 4230 return $o; 4231 } 4232 4233 /** 4234 * Get the metatype of the column. This is used for formatting. This is because 4235 * many databases use different names for the same type, so we transform the original 4236 * type to our standardised version which uses 1 character codes: 4237 * 4238 * @param t is the type passed in. Normally is ADOFieldObject->type. 4239 * @param len is the maximum length of that field. This is because we treat character 4240 * fields bigger than a certain size as a 'B' (blob). 4241 * @param fieldobj is the field object returned by the database driver. Can hold 4242 * additional info (eg. primary_key for mysql). 4243 * 4244 * @return the general type of the data: 4245 * C for character < 250 chars 4246 * X for teXt (>= 250 chars) 4247 * B for Binary 4248 * N for numeric or floating point 4249 * D for date 4250 * T for timestamp 4251 * L for logical/Boolean 4252 * I for integer 4253 * R for autoincrement counter/integer 4254 * 4255 * 4256 */ 4257 function MetaType($t,$len=-1,$fieldobj=false) { 4258 if (is_object($t)) { 4259 $fieldobj = $t; 4260 $t = $fieldobj->type; 4261 $len = $fieldobj->max_length; 4262 } 4263 4264 // changed in 2.32 to hashing instead of switch stmt for speed... 4265 static $typeMap = array( 4266 'VARCHAR' => 'C', 4267 'VARCHAR2' => 'C', 4268 'CHAR' => 'C', 4269 'C' => 'C', 4270 'STRING' => 'C', 4271 'NCHAR' => 'C', 4272 'NVARCHAR' => 'C', 4273 'VARYING' => 'C', 4274 'BPCHAR' => 'C', 4275 'CHARACTER' => 'C', 4276 'INTERVAL' => 'C', # Postgres 4277 'MACADDR' => 'C', # postgres 4278 'VAR_STRING' => 'C', # mysql 4279 ## 4280 'LONGCHAR' => 'X', 4281 'TEXT' => 'X', 4282 'NTEXT' => 'X', 4283 'M' => 'X', 4284 'X' => 'X', 4285 'CLOB' => 'X', 4286 'NCLOB' => 'X', 4287 'LVARCHAR' => 'X', 4288 ## 4289 'BLOB' => 'B', 4290 'IMAGE' => 'B', 4291 'BINARY' => 'B', 4292 'VARBINARY' => 'B', 4293 'LONGBINARY' => 'B', 4294 'B' => 'B', 4295 ## 4296 'YEAR' => 'D', // mysql 4297 'DATE' => 'D', 4298 'D' => 'D', 4299 ## 4300 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server 4301 ## 4302 'SMALLDATETIME' => 'T', 4303 'TIME' => 'T', 4304 'TIMESTAMP' => 'T', 4305 'DATETIME' => 'T', 4306 'DATETIME2' => 'T', 4307 'TIMESTAMPTZ' => 'T', 4308 'T' => 'T', 4309 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql 4310 ## 4311 'BOOL' => 'L', 4312 'BOOLEAN' => 'L', 4313 'BIT' => 'L', 4314 'L' => 'L', 4315 ## 4316 'COUNTER' => 'R', 4317 'R' => 'R', 4318 'SERIAL' => 'R', // ifx 4319 'INT IDENTITY' => 'R', 4320 ## 4321 'INT' => 'I', 4322 'INT2' => 'I', 4323 'INT4' => 'I', 4324 'INT8' => 'I', 4325 'INTEGER' => 'I', 4326 'INTEGER UNSIGNED' => 'I', 4327 'SHORT' => 'I', 4328 'TINYINT' => 'I', 4329 'SMALLINT' => 'I', 4330 'I' => 'I', 4331 ## 4332 'LONG' => 'N', // interbase is numeric, oci8 is blob 4333 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers 4334 'DECIMAL' => 'N', 4335 'DEC' => 'N', 4336 'REAL' => 'N', 4337 'DOUBLE' => 'N', 4338 'DOUBLE PRECISION' => 'N', 4339 'SMALLFLOAT' => 'N', 4340 'FLOAT' => 'N', 4341 'NUMBER' => 'N', 4342 'NUM' => 'N', 4343 'NUMERIC' => 'N', 4344 'MONEY' => 'N', 4345 4346 ## informix 9.2 4347 'SQLINT' => 'I', 4348 'SQLSERIAL' => 'I', 4349 'SQLSMINT' => 'I', 4350 'SQLSMFLOAT' => 'N', 4351 'SQLFLOAT' => 'N', 4352 'SQLMONEY' => 'N', 4353 'SQLDECIMAL' => 'N', 4354 'SQLDATE' => 'D', 4355 'SQLVCHAR' => 'C', 4356 'SQLCHAR' => 'C', 4357 'SQLDTIME' => 'T', 4358 'SQLINTERVAL' => 'N', 4359 'SQLBYTES' => 'B', 4360 'SQLTEXT' => 'X', 4361 ## informix 10 4362 "SQLINT8" => 'I8', 4363 "SQLSERIAL8" => 'I8', 4364 "SQLNCHAR" => 'C', 4365 "SQLNVCHAR" => 'C', 4366 "SQLLVARCHAR" => 'X', 4367 "SQLBOOL" => 'L' 4368 ); 4369 4370 $tmap = false; 4371 $t = strtoupper($t); 4372 $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N'; 4373 switch ($tmap) { 4374 case 'C': 4375 // is the char field is too long, return as text field... 4376 if ($this->blobSize >= 0) { 4377 if ($len > $this->blobSize) { 4378 return 'X'; 4379 } 4380 } else if ($len > 250) { 4381 return 'X'; 4382 } 4383 return 'C'; 4384 4385 case 'I': 4386 if (!empty($fieldobj->primary_key)) { 4387 return 'R'; 4388 } 4389 return 'I'; 4390 4391 case false: 4392 return 'N'; 4393 4394 case 'B': 4395 if (isset($fieldobj->binary)) { 4396 return ($fieldobj->binary) ? 'B' : 'X'; 4397 } 4398 return 'B'; 4399 4400 case 'D': 4401 if (!empty($this->connection) && !empty($this->connection->datetime)) { 4402 return 'T'; 4403 } 4404 return 'D'; 4405 4406 default: 4407 if ($t == 'LONG' && $this->dataProvider == 'oci8') { 4408 return 'B'; 4409 } 4410 return $tmap; 4411 } 4412 } 4413 4414 /** 4415 * Convert case of field names associative array, if needed 4416 * @return void 4417 */ 4418 protected function _updatefields() 4419 { 4420 if( empty($this->fields)) { 4421 return; 4422 } 4423 4424 // Determine case conversion function 4425 $fn_change_case = $this->AssocCaseConvertFunction(); 4426 if(!$fn_change_case) { 4427 // No conversion needed 4428 return; 4429 } 4430 4431 $arr = array(); 4432 4433 // Change the case 4434 foreach($this->fields as $k => $v) { 4435 if (!is_integer($k)) { 4436 $k = $fn_change_case($k); 4437 } 4438 $arr[$k] = $v; 4439 } 4440 $this->fields = $arr; 4441 } 4442 4443 function _close() {} 4444 4445 /** 4446 * set/returns the current recordset page when paginating 4447 */ 4448 function AbsolutePage($page=-1) { 4449 if ($page != -1) { 4450 $this->_currentPage = $page; 4451 } 4452 return $this->_currentPage; 4453 } 4454 4455 /** 4456 * set/returns the status of the atFirstPage flag when paginating 4457 */ 4458 function AtFirstPage($status=false) { 4459 if ($status != false) { 4460 $this->_atFirstPage = $status; 4461 } 4462 return $this->_atFirstPage; 4463 } 4464 4465 function LastPageNo($page = false) { 4466 if ($page != false) { 4467 $this->_lastPageNo = $page; 4468 } 4469 return $this->_lastPageNo; 4470 } 4471 4472 /** 4473 * set/returns the status of the atLastPage flag when paginating 4474 */ 4475 function AtLastPage($status=false) { 4476 if ($status != false) { 4477 $this->_atLastPage = $status; 4478 } 4479 return $this->_atLastPage; 4480 } 4481 4482 } // end class ADORecordSet 4483 4484 //============================================================================================== 4485 // CLASS ADORecordSet_array 4486 //============================================================================================== 4487 4488 /** 4489 * This class encapsulates the concept of a recordset created in memory 4490 * as an array. This is useful for the creation of cached recordsets. 4491 * 4492 * Note that the constructor is different from the standard ADORecordSet 4493 */ 4494 class ADORecordSet_array extends ADORecordSet 4495 { 4496 var $databaseType = 'array'; 4497 4498 var $_array; // holds the 2-dimensional data array 4499 var $_types; // the array of types of each column (C B I L M) 4500 var $_colnames; // names of each column in array 4501 var $_skiprow1; // skip 1st row because it holds column names 4502 var $_fieldobjects; // holds array of field objects 4503 var $canSeek = true; 4504 var $affectedrows = false; 4505 var $insertid = false; 4506 var $sql = ''; 4507 var $compat = false; 4508 4509 /** 4510 * Constructor 4511 */ 4512 function __construct($fakeid=1) { 4513 global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH; 4514 4515 // fetch() on EOF does not delete $this->fields 4516 $this->compat = !empty($ADODB_COMPAT_FETCH); 4517 parent::__construct($fakeid); // fake queryID 4518 $this->fetchMode = $ADODB_FETCH_MODE; 4519 } 4520 4521 function _transpose($addfieldnames=true) { 4522 global $ADODB_INCLUDED_LIB; 4523 4524 if (empty($ADODB_INCLUDED_LIB)) { 4525 include (ADODB_DIR.'/adodb-lib.inc.php'); 4526 } 4527 $hdr = true; 4528 4529 $fobjs = $addfieldnames ? $this->_fieldobjects : false; 4530 adodb_transpose($this->_array, $newarr, $hdr, $fobjs); 4531 //adodb_pr($newarr); 4532 4533 $this->_skiprow1 = false; 4534 $this->_array = $newarr; 4535 $this->_colnames = $hdr; 4536 4537 adodb_probetypes($newarr,$this->_types); 4538 4539 $this->_fieldobjects = array(); 4540 4541 foreach($hdr as $k => $name) { 4542 $f = new ADOFieldObject(); 4543 $f->name = $name; 4544 $f->type = $this->_types[$k]; 4545 $f->max_length = -1; 4546 $this->_fieldobjects[] = $f; 4547 } 4548 $this->fields = reset($this->_array); 4549 4550 $this->_initrs(); 4551 4552 } 4553 4554 /** 4555 * Setup the array. 4556 * 4557 * @param array is a 2-dimensional array holding the data. 4558 * The first row should hold the column names 4559 * unless paramter $colnames is used. 4560 * @param typearr holds an array of types. These are the same types 4561 * used in MetaTypes (C,B,L,I,N). 4562 * @param [colnames] array of column names. If set, then the first row of 4563 * $array should not hold the column names. 4564 */ 4565 function InitArray($array,$typearr,$colnames=false) { 4566 $this->_array = $array; 4567 $this->_types = $typearr; 4568 if ($colnames) { 4569 $this->_skiprow1 = false; 4570 $this->_colnames = $colnames; 4571 } else { 4572 $this->_skiprow1 = true; 4573 $this->_colnames = $array[0]; 4574 } 4575 $this->Init(); 4576 } 4577 /** 4578 * Setup the Array and datatype file objects 4579 * 4580 * @param array is a 2-dimensional array holding the data. 4581 * The first row should hold the column names 4582 * unless paramter $colnames is used. 4583 * @param fieldarr holds an array of ADOFieldObject's. 4584 */ 4585 function InitArrayFields(&$array,&$fieldarr) { 4586 $this->_array = $array; 4587 $this->_skiprow1= false; 4588 if ($fieldarr) { 4589 $this->_fieldobjects = $fieldarr; 4590 } 4591 $this->Init(); 4592 } 4593 4594 function GetArray($nRows=-1) { 4595 if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) { 4596 return $this->_array; 4597 } else { 4598 $arr = ADORecordSet::GetArray($nRows); 4599 return $arr; 4600 } 4601 } 4602 4603 function _initrs() { 4604 $this->_numOfRows = sizeof($this->_array); 4605 if ($this->_skiprow1) { 4606 $this->_numOfRows -= 1; 4607 } 4608 4609 $this->_numOfFields = (isset($this->_fieldobjects)) 4610 ? sizeof($this->_fieldobjects) 4611 : sizeof($this->_types); 4612 } 4613 4614 /* Use associative array to get fields array */ 4615 function Fields($colname) { 4616 $mode = isset($this->adodbFetchMode) ? $this->adodbFetchMode : $this->fetchMode; 4617 4618 if ($mode & ADODB_FETCH_ASSOC) { 4619 if (!isset($this->fields[$colname]) && !is_null($this->fields[$colname])) { 4620 $colname = strtolower($colname); 4621 } 4622 return $this->fields[$colname]; 4623 } 4624 if (!$this->bind) { 4625 $this->bind = array(); 4626 for ($i=0; $i < $this->_numOfFields; $i++) { 4627 $o = $this->FetchField($i); 4628 $this->bind[strtoupper($o->name)] = $i; 4629 } 4630 } 4631 return $this->fields[$this->bind[strtoupper($colname)]]; 4632 } 4633 4634 function FetchField($fieldOffset = -1) { 4635 if (isset($this->_fieldobjects)) { 4636 return $this->_fieldobjects[$fieldOffset]; 4637 } 4638 $o = new ADOFieldObject(); 4639 $o->name = $this->_colnames[$fieldOffset]; 4640 $o->type = $this->_types[$fieldOffset]; 4641 $o->max_length = -1; // length not known 4642 4643 return $o; 4644 } 4645 4646 function _seek($row) { 4647 if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) { 4648 $this->_currentRow = $row; 4649 if ($this->_skiprow1) { 4650 $row += 1; 4651 } 4652 $this->fields = $this->_array[$row]; 4653 return true; 4654 } 4655 return false; 4656 } 4657 4658 function MoveNext() { 4659 if (!$this->EOF) { 4660 $this->_currentRow++; 4661 4662 $pos = $this->_currentRow; 4663 4664 if ($this->_numOfRows <= $pos) { 4665 if (!$this->compat) { 4666 $this->fields = false; 4667 } 4668 } else { 4669 if ($this->_skiprow1) { 4670 $pos += 1; 4671 } 4672 $this->fields = $this->_array[$pos]; 4673 return true; 4674 } 4675 $this->EOF = true; 4676 } 4677 4678 return false; 4679 } 4680 4681 function _fetch() { 4682 $pos = $this->_currentRow; 4683 4684 if ($this->_numOfRows <= $pos) { 4685 if (!$this->compat) { 4686 $this->fields = false; 4687 } 4688 return false; 4689 } 4690 if ($this->_skiprow1) { 4691 $pos += 1; 4692 } 4693 $this->fields = $this->_array[$pos]; 4694 return true; 4695 } 4696 4697 function _close() { 4698 return true; 4699 } 4700 4701 } // ADORecordSet_array 4702 4703 //============================================================================================== 4704 // HELPER FUNCTIONS 4705 //============================================================================================== 4706 4707 /** 4708 * Synonym for ADOLoadCode. Private function. Do not use. 4709 * 4710 * @deprecated 4711 */ 4712 function ADOLoadDB($dbType) { 4713 return ADOLoadCode($dbType); 4714 } 4715 4716 /** 4717 * Load the code for a specific database driver. Private function. Do not use. 4718 */ 4719 function ADOLoadCode($dbType) { 4720 global $ADODB_LASTDB; 4721 4722 if (!$dbType) { 4723 return false; 4724 } 4725 $db = strtolower($dbType); 4726 switch ($db) { 4727 case 'ado': 4728 if (PHP_VERSION >= 5) { 4729 $db = 'ado5'; 4730 } 4731 $class = 'ado'; 4732 break; 4733 4734 case 'ifx': 4735 case 'maxsql': 4736 $class = $db = 'mysqlt'; 4737 break; 4738 4739 case 'pgsql': 4740 case 'postgres': 4741 $class = $db = 'postgres8'; 4742 break; 4743 4744 default: 4745 $class = $db; break; 4746 } 4747 4748 $file = "drivers/adodb-$db.inc.php"; 4749 @include_once(ADODB_DIR . '/' . $file); 4750 $ADODB_LASTDB = $class; 4751 if (class_exists("ADODB_" . $class)) { 4752 return $class; 4753 } 4754 4755 //ADOConnection::outp(adodb_pr(get_declared_classes(),true)); 4756 if (!file_exists($file)) { 4757 ADOConnection::outp("Missing file: $file"); 4758 } else { 4759 ADOConnection::outp("Syntax error in file: $file"); 4760 } 4761 return false; 4762 } 4763 4764 /** 4765 * synonym for ADONewConnection for people like me who cannot remember the correct name 4766 */ 4767 function NewADOConnection($db='') { 4768 $tmp = ADONewConnection($db); 4769 return $tmp; 4770 } 4771 4772 /** 4773 * Instantiate a new Connection class for a specific database driver. 4774 * 4775 * @param [db] is the database Connection object to create. If undefined, 4776 * use the last database driver that was loaded by ADOLoadCode(). 4777 * 4778 * @return the freshly created instance of the Connection class. 4779 */ 4780 function ADONewConnection($db='') { 4781 global $ADODB_NEWCONNECTION, $ADODB_LASTDB; 4782 4783 if (!defined('ADODB_ASSOC_CASE')) { 4784 define('ADODB_ASSOC_CASE', ADODB_ASSOC_CASE_NATIVE); 4785 } 4786 $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false; 4787 if (($at = strpos($db,'://')) !== FALSE) { 4788 $origdsn = $db; 4789 $fakedsn = 'fake'.substr($origdsn,$at); 4790 if (($at2 = strpos($origdsn,'@/')) !== FALSE) { 4791 // special handling of oracle, which might not have host 4792 $fakedsn = str_replace('@/','@adodb-fakehost/',$fakedsn); 4793 } 4794 4795 if ((strpos($origdsn, 'sqlite')) !== FALSE && stripos($origdsn, '%2F') === FALSE) { 4796 // special handling for SQLite, it only might have the path to the database file. 4797 // If you try to connect to a SQLite database using a dsn 4798 // like 'sqlite:///path/to/database', the 'parse_url' php function 4799 // will throw you an exception with a message such as "unable to parse url" 4800 list($scheme, $path) = explode('://', $origdsn); 4801 $dsna['scheme'] = $scheme; 4802 if ($qmark = strpos($path,'?')) { 4803 $dsn['query'] = substr($path,$qmark+1); 4804 $path = substr($path,0,$qmark); 4805 } 4806 $dsna['path'] = '/' . urlencode($path); 4807 } else 4808 $dsna = @parse_url($fakedsn); 4809 4810 if (!$dsna) { 4811 return false; 4812 } 4813 $dsna['scheme'] = substr($origdsn,0,$at); 4814 if ($at2 !== FALSE) { 4815 $dsna['host'] = ''; 4816 } 4817 4818 if (strncmp($origdsn,'pdo',3) == 0) { 4819 $sch = explode('_',$dsna['scheme']); 4820 if (sizeof($sch)>1) { 4821 $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : ''; 4822 if ($sch[1] == 'sqlite') { 4823 $dsna['host'] = rawurlencode($sch[1].':'.rawurldecode($dsna['host'])); 4824 } else { 4825 $dsna['host'] = rawurlencode($sch[1].':host='.rawurldecode($dsna['host'])); 4826 } 4827 $dsna['scheme'] = 'pdo'; 4828 } 4829 } 4830 4831 $db = @$dsna['scheme']; 4832 if (!$db) { 4833 return false; 4834 } 4835 $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : ''; 4836 $dsna['user'] = isset($dsna['user']) ? rawurldecode($dsna['user']) : ''; 4837 $dsna['pass'] = isset($dsna['pass']) ? rawurldecode($dsna['pass']) : ''; 4838 $dsna['path'] = isset($dsna['path']) ? rawurldecode(substr($dsna['path'],1)) : ''; # strip off initial / 4839 4840 if (isset($dsna['query'])) { 4841 $opt1 = explode('&',$dsna['query']); 4842 foreach($opt1 as $k => $v) { 4843 $arr = explode('=',$v); 4844 $opt[$arr[0]] = isset($arr[1]) ? rawurldecode($arr[1]) : 1; 4845 } 4846 } else { 4847 $opt = array(); 4848 } 4849 } 4850 /* 4851 * phptype: Database backend used in PHP (mysql, odbc etc.) 4852 * dbsyntax: Database used with regards to SQL syntax etc. 4853 * protocol: Communication protocol to use (tcp, unix etc.) 4854 * hostspec: Host specification (hostname[:port]) 4855 * database: Database to use on the DBMS server 4856 * username: User name for login 4857 * password: Password for login 4858 */ 4859 if (!empty($ADODB_NEWCONNECTION)) { 4860 $obj = $ADODB_NEWCONNECTION($db); 4861 4862 } 4863 4864 if(empty($obj)) { 4865 4866 if (!isset($ADODB_LASTDB)) { 4867 $ADODB_LASTDB = ''; 4868 } 4869 if (empty($db)) { 4870 $db = $ADODB_LASTDB; 4871 } 4872 if ($db != $ADODB_LASTDB) { 4873 $db = ADOLoadCode($db); 4874 } 4875 4876 if (!$db) { 4877 if (isset($origdsn)) { 4878 $db = $origdsn; 4879 } 4880 if ($errorfn) { 4881 // raise an error 4882 $ignore = false; 4883 $errorfn('ADONewConnection', 'ADONewConnection', -998, 4884 "could not load the database driver for '$db'", 4885 $db,false,$ignore); 4886 } else { 4887 ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false); 4888 } 4889 return false; 4890 } 4891 4892 $cls = 'ADODB_'.$db; 4893 if (!class_exists($cls)) { 4894 adodb_backtrace(); 4895 return false; 4896 } 4897 4898 $obj = new $cls(); 4899 } 4900 4901 # constructor should not fail 4902 if ($obj) { 4903 if ($errorfn) { 4904 $obj->raiseErrorFn = $errorfn; 4905 } 4906 if (isset($dsna)) { 4907 if (isset($dsna['port'])) { 4908 $obj->port = $dsna['port']; 4909 } 4910 foreach($opt as $k => $v) { 4911 switch(strtolower($k)) { 4912 case 'new': 4913 $nconnect = true; $persist = true; break; 4914 case 'persist': 4915 case 'persistent': $persist = $v; break; 4916 case 'debug': $obj->debug = (integer) $v; break; 4917 #ibase 4918 case 'role': $obj->role = $v; break; 4919 case 'dialect': $obj->dialect = (integer) $v; break; 4920 case 'charset': $obj->charset = $v; $obj->charSet=$v; break; 4921 case 'buffers': $obj->buffers = $v; break; 4922 case 'fetchmode': $obj->SetFetchMode($v); break; 4923 #ado 4924 case 'charpage': $obj->charPage = $v; break; 4925 #mysql, mysqli 4926 case 'clientflags': $obj->clientFlags = $v; break; 4927 #mysql, mysqli, postgres 4928 case 'port': $obj->port = $v; break; 4929 #mysqli 4930 case 'socket': $obj->socket = $v; break; 4931 #oci8 4932 case 'nls_date_format': $obj->NLS_DATE_FORMAT = $v; break; 4933 case 'cachesecs': $obj->cacheSecs = $v; break; 4934 case 'memcache': 4935 $varr = explode(':',$v); 4936 $vlen = sizeof($varr); 4937 if ($vlen == 0) { 4938 break; 4939 } 4940 $obj->memCache = true; 4941 $obj->memCacheHost = explode(',',$varr[0]); 4942 if ($vlen == 1) { 4943 break; 4944 } 4945 $obj->memCachePort = $varr[1]; 4946 if ($vlen == 2) { 4947 break; 4948 } 4949 $obj->memCacheCompress = $varr[2] ? true : false; 4950 break; 4951 } 4952 } 4953 if (empty($persist)) { 4954 $ok = $obj->Connect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']); 4955 } else if (empty($nconnect)) { 4956 $ok = $obj->PConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']); 4957 } else { 4958 $ok = $obj->NConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']); 4959 } 4960 4961 if (!$ok) { 4962 return false; 4963 } 4964 } 4965 } 4966 return $obj; 4967 } 4968 4969 4970 4971 // $perf == true means called by NewPerfMonitor(), otherwise for data dictionary 4972 function _adodb_getdriver($provider,$drivername,$perf=false) { 4973 switch ($provider) { 4974 case 'odbtp': 4975 if (strncmp('odbtp_',$drivername,6)==0) { 4976 return substr($drivername,6); 4977 } 4978 case 'odbc' : 4979 if (strncmp('odbc_',$drivername,5)==0) { 4980 return substr($drivername,5); 4981 } 4982 case 'ado' : 4983 if (strncmp('ado_',$drivername,4)==0) { 4984 return substr($drivername,4); 4985 } 4986 case 'native': 4987 break; 4988 default: 4989 return $provider; 4990 } 4991 4992 switch($drivername) { 4993 case 'mysqlt': 4994 case 'mysqli': 4995 $drivername='mysql'; 4996 break; 4997 case 'postgres7': 4998 case 'postgres8': 4999 $drivername = 'postgres'; 5000 break; 5001 case 'firebird15': 5002 $drivername = 'firebird'; 5003 break; 5004 case 'oracle': 5005 $drivername = 'oci8'; 5006 break; 5007 case 'access': 5008 if ($perf) { 5009 $drivername = ''; 5010 } 5011 break; 5012 case 'db2' : 5013 case 'sapdb' : 5014 break; 5015 default: 5016 $drivername = 'generic'; 5017 break; 5018 } 5019 return $drivername; 5020 } 5021 5022 function NewPerfMonitor(&$conn) { 5023 $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType,true); 5024 if (!$drivername || $drivername == 'generic') { 5025 return false; 5026 } 5027 include_once (ADODB_DIR.'/adodb-perf.inc.php'); 5028 @include_once(ADODB_DIR."/perf/perf-$drivername.inc.php"); 5029 $class = "Perf_$drivername"; 5030 if (!class_exists($class)) { 5031 return false; 5032 } 5033 $perf = new $class($conn); 5034 5035 return $perf; 5036 } 5037 5038 function NewDataDictionary(&$conn,$drivername=false) { 5039 if (!$drivername) { 5040 $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType); 5041 } 5042 5043 include_once (ADODB_DIR.'/adodb-lib.inc.php'); 5044 include_once (ADODB_DIR.'/adodb-datadict.inc.php'); 5045 $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php"; 5046 5047 if (!file_exists($path)) { 5048 ADOConnection::outp("Dictionary driver '$path' not available"); 5049 return false; 5050 } 5051 include_once($path); 5052 $class = "ADODB2_$drivername"; 5053 $dict = new $class(); 5054 $dict->dataProvider = $conn->dataProvider; 5055 $dict->connection = $conn; 5056 $dict->upperName = strtoupper($drivername); 5057 $dict->quote = $conn->nameQuote; 5058 if (!empty($conn->_connectionID)) { 5059 $dict->serverInfo = $conn->ServerInfo(); 5060 } 5061 5062 return $dict; 5063 } 5064 5065 5066 5067 /* 5068 Perform a print_r, with pre tags for better formatting. 5069 */ 5070 function adodb_pr($var,$as_string=false) { 5071 if ($as_string) { 5072 ob_start(); 5073 } 5074 5075 if (isset($_SERVER['HTTP_USER_AGENT'])) { 5076 echo " <pre>\n";print_r($var);echo "</pre>\n"; 5077 } else { 5078 print_r($var); 5079 } 5080 5081 if ($as_string) { 5082 $s = ob_get_contents(); 5083 ob_end_clean(); 5084 return $s; 5085 } 5086 } 5087 5088 /* 5089 Perform a stack-crawl and pretty print it. 5090 5091 @param printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then). 5092 @param levels Number of levels to display 5093 */ 5094 function adodb_backtrace($printOrArr=true,$levels=9999,$ishtml=null) { 5095 global $ADODB_INCLUDED_LIB; 5096 if (empty($ADODB_INCLUDED_LIB)) { 5097 include (ADODB_DIR.'/adodb-lib.inc.php'); 5098 } 5099 return _adodb_backtrace($printOrArr,$levels,0,$ishtml); 5100 } 5101 5102 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body