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