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