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