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 $rs = new ADORecordSet_empty(); 924 return $rs; 925 } 926 927 // return real recordset from select statement 928 $rsclass = $this->rsPrefix.$this->databaseType; 929 $rs = new $rsclass($this->_queryID,$this->fetchMode); 930 $rs->connection = &$this; // Pablo suggestion 931 $rs->Init(); 932 if (is_array($sql)) $rs->sql = $sql[0]; 933 else $rs->sql = $sql; 934 if ($rs->_numOfRows <= 0) { 935 global $ADODB_COUNTRECS; 936 if ($ADODB_COUNTRECS) { 937 if (!$rs->EOF) { 938 $rs = &$this->_rs2rs($rs,-1,-1,!is_array($sql)); 939 $rs->_queryID = $this->_queryID; 940 } else 941 $rs->_numOfRows = 0; 942 } 943 } 944 return $rs; 945 } 946 947 function CreateSequence($seqname='adodbseq',$startID=1) 948 { 949 if (empty($this->_genSeqSQL)) return false; 950 return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID)); 951 } 952 953 function DropSequence($seqname='adodbseq') 954 { 955 if (empty($this->_dropSeqSQL)) return false; 956 return $this->Execute(sprintf($this->_dropSeqSQL,$seqname)); 957 } 958 959 /** 960 * Generates a sequence id and stores it in $this->genID; 961 * GenID is only available if $this->hasGenID = true; 962 * 963 * @param seqname name of sequence to use 964 * @param startID if sequence does not exist, start at this ID 965 * @return 0 if not supported, otherwise a sequence id 966 */ 967 function GenID($seqname='adodbseq',$startID=1) 968 { 969 if (!$this->hasGenID) { 970 return 0; // formerly returns false pre 1.60 971 } 972 973 $getnext = sprintf($this->_genIDSQL,$seqname); 974 975 $holdtransOK = $this->_transOK; 976 977 $save_handler = $this->raiseErrorFn; 978 $this->raiseErrorFn = ''; 979 @($rs = $this->Execute($getnext)); 980 $this->raiseErrorFn = $save_handler; 981 982 if (!$rs) { 983 $this->_transOK = $holdtransOK; //if the status was ok before reset 984 $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID)); 985 $rs = $this->Execute($getnext); 986 } 987 if ($rs && !$rs->EOF) $this->genID = reset($rs->fields); 988 else $this->genID = 0; // false 989 990 if ($rs) $rs->Close(); 991 992 return $this->genID; 993 } 994 995 /** 996 * @param $table string name of the table, not needed by all databases (eg. mysql), default '' 997 * @param $column string name of the column, not needed by all databases (eg. mysql), default '' 998 * @return the last inserted ID. Not all databases support this. 999 */ 1000 function Insert_ID($table='',$column='') 1001 { 1002 if ($this->_logsql && $this->lastInsID) return $this->lastInsID; 1003 if ($this->hasInsertID) return $this->_insertid($table,$column); 1004 if ($this->debug) { 1005 ADOConnection::outp( '<p>Insert_ID error</p>'); 1006 adodb_backtrace(); 1007 } 1008 return false; 1009 } 1010 1011 1012 /** 1013 * Portable Insert ID. Pablo Roca <pabloroca#mvps.org> 1014 * 1015 * @return the last inserted ID. All databases support this. But aware possible 1016 * problems in multiuser environments. Heavy test this before deploying. 1017 */ 1018 function PO_Insert_ID($table="", $id="") 1019 { 1020 if ($this->hasInsertID){ 1021 return $this->Insert_ID($table,$id); 1022 } else { 1023 return $this->GetOne("SELECT MAX($id) FROM $table"); 1024 } 1025 } 1026 1027 /** 1028 * @return # rows affected by UPDATE/DELETE 1029 */ 1030 function Affected_Rows() 1031 { 1032 if ($this->hasAffectedRows) { 1033 if ($this->fnExecute === 'adodb_log_sql') { 1034 if ($this->_logsql && $this->_affected !== false) return $this->_affected; 1035 } 1036 $val = $this->_affectedrows(); 1037 return ($val < 0) ? false : $val; 1038 } 1039 1040 if ($this->debug) ADOConnection::outp( '<p>Affected_Rows error</p>',false); 1041 return false; 1042 } 1043 1044 1045 /** 1046 * @return the last error message 1047 */ 1048 function ErrorMsg() 1049 { 1050 if ($this->_errorMsg) return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg; 1051 else return ''; 1052 } 1053 1054 1055 /** 1056 * @return the last error number. Normally 0 means no error. 1057 */ 1058 function ErrorNo() 1059 { 1060 return ($this->_errorMsg) ? -1 : 0; 1061 } 1062 1063 function MetaError($err=false) 1064 { 1065 include_once(ADODB_DIR."/adodb-error.inc.php"); 1066 if ($err === false) $err = $this->ErrorNo(); 1067 return adodb_error($this->dataProvider,$this->databaseType,$err); 1068 } 1069 1070 function MetaErrorMsg($errno) 1071 { 1072 include_once(ADODB_DIR."/adodb-error.inc.php"); 1073 return adodb_errormsg($errno); 1074 } 1075 1076 /** 1077 * @returns an array with the primary key columns in it. 1078 */ 1079 function MetaPrimaryKeys($table, $owner=false) 1080 { 1081 // owner not used in base class - see oci8 1082 $p = array(); 1083 $objs =& $this->MetaColumns($table); 1084 if ($objs) { 1085 foreach($objs as $v) { 1086 if (!empty($v->primary_key)) 1087 $p[] = $v->name; 1088 } 1089 } 1090 if (sizeof($p)) return $p; 1091 if (function_exists('ADODB_VIEW_PRIMARYKEYS')) 1092 return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner); 1093 return false; 1094 } 1095 1096 /** 1097 * @returns assoc array where keys are tables, and values are foreign keys 1098 */ 1099 function MetaForeignKeys($table, $owner=false, $upper=false) 1100 { 1101 return false; 1102 } 1103 /** 1104 * Choose a database to connect to. Many databases do not support this. 1105 * 1106 * @param dbName is the name of the database to select 1107 * @return true or false 1108 */ 1109 function SelectDB($dbName) 1110 {return false;} 1111 1112 1113 /** 1114 * Will select, getting rows from $offset (1-based), for $nrows. 1115 * This simulates the MySQL "select * from table limit $offset,$nrows" , and 1116 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that 1117 * MySQL and PostgreSQL parameter ordering is the opposite of the other. 1118 * eg. 1119 * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based) 1120 * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based) 1121 * 1122 * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set) 1123 * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set 1124 * 1125 * @param sql 1126 * @param [offset] is the row to start calculations from (1-based) 1127 * @param [nrows] is the number of rows to get 1128 * @param [inputarr] array of bind variables 1129 * @param [secs2cache] is a private parameter only used by jlim 1130 * @return the recordset ($rs->databaseType == 'array') 1131 */ 1132 function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) 1133 { 1134 if ($this->hasTop && $nrows > 0) { 1135 // suggested by Reinhard Balling. Access requires top after distinct 1136 // Informix requires first before distinct - F Riosa 1137 $ismssql = (strpos($this->databaseType,'mssql') !== false); 1138 if ($ismssql) $isaccess = false; 1139 else $isaccess = (strpos($this->databaseType,'access') !== false); 1140 1141 if ($offset <= 0) { 1142 1143 // access includes ties in result 1144 if ($isaccess) { 1145 $sql = preg_replace( 1146 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql); 1147 1148 if ($secs2cache != 0) { 1149 $ret =& $this->CacheExecute($secs2cache, $sql,$inputarr); 1150 } else { 1151 $ret =& $this->Execute($sql,$inputarr); 1152 } 1153 return $ret; // PHP5 fix 1154 } else if ($ismssql){ 1155 $sql = preg_replace( 1156 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql); 1157 } else { 1158 $sql = preg_replace( 1159 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql); 1160 } 1161 } else { 1162 $nn = $nrows + $offset; 1163 if ($isaccess || $ismssql) { 1164 $sql = preg_replace( 1165 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql); 1166 } else { 1167 $sql = preg_replace( 1168 '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql); 1169 } 1170 } 1171 } 1172 1173 // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows 1174 // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS. 1175 global $ADODB_COUNTRECS; 1176 1177 $savec = $ADODB_COUNTRECS; 1178 $ADODB_COUNTRECS = false; 1179 1180 if ($offset>0){ 1181 if ($secs2cache != 0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr); 1182 else $rs = &$this->Execute($sql,$inputarr); 1183 } else { 1184 if ($secs2cache != 0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr); 1185 else $rs = &$this->Execute($sql,$inputarr); 1186 } 1187 $ADODB_COUNTRECS = $savec; 1188 if ($rs && !$rs->EOF) { 1189 $rs =& $this->_rs2rs($rs,$nrows,$offset); 1190 } 1191 //print_r($rs); 1192 return $rs; 1193 } 1194 1195 /** 1196 * Create serializable recordset. Breaks rs link to connection. 1197 * 1198 * @param rs the recordset to serialize 1199 */ 1200 function &SerializableRS(&$rs) 1201 { 1202 $rs2 =& $this->_rs2rs($rs); 1203 $ignore = false; 1204 $rs2->connection =& $ignore; 1205 1206 return $rs2; 1207 } 1208 1209 /** 1210 * Convert database recordset to an array recordset 1211 * input recordset's cursor should be at beginning, and 1212 * old $rs will be closed. 1213 * 1214 * @param rs the recordset to copy 1215 * @param [nrows] number of rows to retrieve (optional) 1216 * @param [offset] offset by number of rows (optional) 1217 * @return the new recordset 1218 */ 1219 function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true) 1220 { 1221 if (! $rs) { 1222 $false = false; 1223 return $false; 1224 } 1225 $dbtype = $rs->databaseType; 1226 if (!$dbtype) { 1227 $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ? 1228 return $rs; 1229 } 1230 if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) { 1231 $rs->MoveFirst(); 1232 $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ? 1233 return $rs; 1234 } 1235 $flds = array(); 1236 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) { 1237 $flds[] = $rs->FetchField($i); 1238 } 1239 1240 $arr =& $rs->GetArrayLimit($nrows,$offset); 1241 //print_r($arr); 1242 if ($close) $rs->Close(); 1243 1244 $arrayClass = $this->arrayClass; 1245 1246 $rs2 = new $arrayClass(); 1247 $rs2->connection = &$this; 1248 $rs2->sql = $rs->sql; 1249 $rs2->dataProvider = $this->dataProvider; 1250 $rs2->InitArrayFields($arr,$flds); 1251 $rs2->fetchMode = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode; 1252 return $rs2; 1253 } 1254 1255 /* 1256 * Return all rows. Compat with PEAR DB 1257 */ 1258 function &GetAll($sql, $inputarr=false) 1259 { 1260 $arr =& $this->GetArray($sql,$inputarr); 1261 return $arr; 1262 } 1263 1264 function &GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false) 1265 { 1266 $rs =& $this->Execute($sql, $inputarr); 1267 if (!$rs) { 1268 $false = false; 1269 return $false; 1270 } 1271 $arr =& $rs->GetAssoc($force_array,$first2cols); 1272 return $arr; 1273 } 1274 1275 function &CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false) 1276 { 1277 if (!is_numeric($secs2cache)) { 1278 $first2cols = $force_array; 1279 $force_array = $inputarr; 1280 } 1281 $rs =& $this->CacheExecute($secs2cache, $sql, $inputarr); 1282 if (!$rs) { 1283 $false = false; 1284 return $false; 1285 } 1286 $arr =& $rs->GetAssoc($force_array,$first2cols); 1287 return $arr; 1288 } 1289 1290 /** 1291 * Return first element of first row of sql statement. Recordset is disposed 1292 * for you. 1293 * 1294 * @param sql SQL statement 1295 * @param [inputarr] input bind array 1296 */ 1297 function GetOne($sql,$inputarr=false) 1298 { 1299 global $ADODB_COUNTRECS; 1300 $crecs = $ADODB_COUNTRECS; 1301 $ADODB_COUNTRECS = false; 1302 1303 $ret = false; 1304 $rs = &$this->Execute($sql,$inputarr); 1305 if ($rs) { 1306 if (!$rs->EOF) $ret = reset($rs->fields); 1307 $rs->Close(); 1308 } 1309 $ADODB_COUNTRECS = $crecs; 1310 return $ret; 1311 } 1312 1313 function CacheGetOne($secs2cache,$sql=false,$inputarr=false) 1314 { 1315 $ret = false; 1316 $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr); 1317 if ($rs) { 1318 if (!$rs->EOF) $ret = reset($rs->fields); 1319 $rs->Close(); 1320 } 1321 1322 return $ret; 1323 } 1324 1325 function GetCol($sql, $inputarr = false, $trim = false) 1326 { 1327 $rv = false; 1328 $rs = &$this->Execute($sql, $inputarr); 1329 if ($rs) { 1330 $rv = array(); 1331 if ($trim) { 1332 while (!$rs->EOF) { 1333 $rv[] = trim(reset($rs->fields)); 1334 $rs->MoveNext(); 1335 } 1336 } else { 1337 while (!$rs->EOF) { 1338 $rv[] = reset($rs->fields); 1339 $rs->MoveNext(); 1340 } 1341 } 1342 $rs->Close(); 1343 } 1344 return $rv; 1345 } 1346 1347 function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false) 1348 { 1349 $rv = false; 1350 $rs = &$this->CacheExecute($secs, $sql, $inputarr); 1351 if ($rs) { 1352 if ($trim) { 1353 while (!$rs->EOF) { 1354 $rv[] = trim(reset($rs->fields)); 1355 $rs->MoveNext(); 1356 } 1357 } else { 1358 while (!$rs->EOF) { 1359 $rv[] = reset($rs->fields); 1360 $rs->MoveNext(); 1361 } 1362 } 1363 $rs->Close(); 1364 } 1365 return $rv; 1366 } 1367 1368 function &Transpose(&$rs,$addfieldnames=true) 1369 { 1370 $rs2 =& $this->_rs2rs($rs); 1371 $false = false; 1372 if (!$rs2) return $false; 1373 1374 $rs2->_transpose($addfieldnames); 1375 return $rs2; 1376 } 1377 1378 /* 1379 Calculate the offset of a date for a particular database and generate 1380 appropriate SQL. Useful for calculating future/past dates and storing 1381 in a database. 1382 1383 If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour. 1384 */ 1385 function OffsetDate($dayFraction,$date=false) 1386 { 1387 if (!$date) $date = $this->sysDate; 1388 return '('.$date.'+'.$dayFraction.')'; 1389 } 1390 1391 1392 /** 1393 * 1394 * @param sql SQL statement 1395 * @param [inputarr] input bind array 1396 */ 1397 function &GetArray($sql,$inputarr=false) 1398 { 1399 global $ADODB_COUNTRECS; 1400 1401 $savec = $ADODB_COUNTRECS; 1402 $ADODB_COUNTRECS = false; 1403 $rs =& $this->Execute($sql,$inputarr); 1404 $ADODB_COUNTRECS = $savec; 1405 if (!$rs) 1406 if (defined('ADODB_PEAR')) { 1407 $cls = ADODB_PEAR_Error(); 1408 return $cls; 1409 } else { 1410 $false = false; 1411 return $false; 1412 } 1413 $arr =& $rs->GetArray(); 1414 $rs->Close(); 1415 return $arr; 1416 } 1417 1418 function &CacheGetAll($secs2cache,$sql=false,$inputarr=false) 1419 { 1420 $arr =& $this->CacheGetArray($secs2cache,$sql,$inputarr); 1421 return $arr; 1422 } 1423 1424 function &CacheGetArray($secs2cache,$sql=false,$inputarr=false) 1425 { 1426 global $ADODB_COUNTRECS; 1427 1428 $savec = $ADODB_COUNTRECS; 1429 $ADODB_COUNTRECS = false; 1430 $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr); 1431 $ADODB_COUNTRECS = $savec; 1432 1433 if (!$rs) 1434 if (defined('ADODB_PEAR')) { 1435 $cls = ADODB_PEAR_Error(); 1436 return $cls; 1437 } else { 1438 $false = false; 1439 return $false; 1440 } 1441 $arr =& $rs->GetArray(); 1442 $rs->Close(); 1443 return $arr; 1444 } 1445 1446 1447 1448 /** 1449 * Return one row of sql statement. Recordset is disposed for you. 1450 * 1451 * @param sql SQL statement 1452 * @param [inputarr] input bind array 1453 */ 1454 function &GetRow($sql,$inputarr=false) 1455 { 1456 global $ADODB_COUNTRECS; 1457 $crecs = $ADODB_COUNTRECS; 1458 $ADODB_COUNTRECS = false; 1459 1460 $rs =& $this->Execute($sql,$inputarr); 1461 1462 $ADODB_COUNTRECS = $crecs; 1463 if ($rs) { 1464 if (!$rs->EOF) $arr = $rs->fields; 1465 else $arr = array(); 1466 $rs->Close(); 1467 return $arr; 1468 } 1469 1470 $false = false; 1471 return $false; 1472 } 1473 1474 function &CacheGetRow($secs2cache,$sql=false,$inputarr=false) 1475 { 1476 $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr); 1477 if ($rs) { 1478 $arr = false; 1479 if (!$rs->EOF) $arr = $rs->fields; 1480 $rs->Close(); 1481 return $arr; 1482 } 1483 $false = false; 1484 return $false; 1485 } 1486 1487 /** 1488 * Insert or replace a single record. Note: this is not the same as MySQL's replace. 1489 * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL. 1490 * Also note that no table locking is done currently, so it is possible that the 1491 * record be inserted twice by two programs... 1492 * 1493 * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname'); 1494 * 1495 * $table table name 1496 * $fieldArray associative array of data (you must quote strings yourself). 1497 * $keyCol the primary key field name or if compound key, array of field names 1498 * autoQuote set to true to use a hueristic to quote strings. Works with nulls and numbers 1499 * but does not work with dates nor SQL functions. 1500 * has_autoinc the primary key is an auto-inc field, so skip in insert. 1501 * 1502 * Currently blob replace not supported 1503 * 1504 * returns 0 = fail, 1 = update, 2 = insert 1505 */ 1506 1507 function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false) 1508 { 1509 global $ADODB_INCLUDED_LIB; 1510 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); 1511 1512 return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc); 1513 } 1514 1515 1516 /** 1517 * Will select, getting rows from $offset (1-based), for $nrows. 1518 * This simulates the MySQL "select * from table limit $offset,$nrows" , and 1519 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that 1520 * MySQL and PostgreSQL parameter ordering is the opposite of the other. 1521 * eg. 1522 * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based) 1523 * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based) 1524 * 1525 * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set 1526 * 1527 * @param [secs2cache] seconds to cache data, set to 0 to force query. This is optional 1528 * @param sql 1529 * @param [offset] is the row to start calculations from (1-based) 1530 * @param [nrows] is the number of rows to get 1531 * @param [inputarr] array of bind variables 1532 * @return the recordset ($rs->databaseType == 'array') 1533 */ 1534 function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false) 1535 { 1536 if (!is_numeric($secs2cache)) { 1537 if ($sql === false) $sql = -1; 1538 if ($offset == -1) $offset = false; 1539 // sql, nrows, offset,inputarr 1540 $rs =& $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs); 1541 } else { 1542 if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()"); 1543 $rs =& $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); 1544 } 1545 return $rs; 1546 } 1547 1548 1549 /** 1550 * Flush cached recordsets that match a particular $sql statement. 1551 * If $sql == false, then we purge all files in the cache. 1552 */ 1553 1554 /** 1555 * Flush cached recordsets that match a particular $sql statement. 1556 * If $sql == false, then we purge all files in the cache. 1557 */ 1558 function CacheFlush($sql=false,$inputarr=false) 1559 { 1560 global $ADODB_CACHE_DIR; 1561 1562 if ($this->memCache) { 1563 global $ADODB_INCLUDED_MEMCACHE; 1564 1565 $key = false; 1566 if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR.'/adodb-memcache.lib.inc.php'); 1567 if ($sql) $key = $this->_gencachename($sql.serialize($inputarr),false,true); 1568 FlushMemCache($key, $this->memCacheHost, $this->memCachePort, $this->debug); 1569 return; 1570 } 1571 1572 if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) { 1573 /*if (strncmp(PHP_OS,'WIN',3) === 0) 1574 $dir = str_replace('/', '\\', $ADODB_CACHE_DIR); 1575 else */ 1576 $dir = $ADODB_CACHE_DIR; 1577 1578 if ($this->debug) { 1579 ADOConnection::outp( "CacheFlush: $dir<br><pre>\n", $this->_dirFlush($dir),"</pre>"); 1580 } else { 1581 $this->_dirFlush($dir); 1582 } 1583 return; 1584 } 1585 1586 global $ADODB_INCLUDED_CSV; 1587 if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php'); 1588 1589 $f = $this->_gencachename($sql.serialize($inputarr),false); 1590 adodb_write_file($f,''); // is adodb_write_file needed? 1591 if (!@unlink($f)) { 1592 if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f"); 1593 } 1594 } 1595 1596 /** 1597 * Private function to erase all of the files and subdirectories in a directory. 1598 * 1599 * Just specify the directory, and tell it if you want to delete the directory or just clear it out. 1600 * Note: $kill_top_level is used internally in the function to flush subdirectories. 1601 */ 1602 function _dirFlush($dir, $kill_top_level = false) { 1603 if(!$dh = @opendir($dir)) return; 1604 1605 while (($obj = readdir($dh))) { 1606 if($obj=='.' || $obj=='..') 1607 continue; 1608 1609 if (!@unlink($dir.'/'.$obj)) 1610 $this->_dirFlush($dir.'/'.$obj, true); 1611 } 1612 if ($kill_top_level === true) 1613 @rmdir($dir); 1614 return true; 1615 } 1616 1617 1618 function xCacheFlush($sql=false,$inputarr=false) 1619 { 1620 global $ADODB_CACHE_DIR; 1621 1622 if ($this->memCache) { 1623 global $ADODB_INCLUDED_MEMCACHE; 1624 $key = false; 1625 if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR.'/adodb-memcache.lib.inc.php'); 1626 if ($sql) $key = $this->_gencachename($sql.serialize($inputarr),false,true); 1627 flushmemCache($key, $this->memCacheHost, $this->memCachePort, $this->debug); 1628 return; 1629 } 1630 1631 if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) { 1632 if (strncmp(PHP_OS,'WIN',3) === 0) { 1633 $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache'; 1634 } else { 1635 //$cmd = 'find "'.$ADODB_CACHE_DIR.'" -type f -maxdepth 1 -print0 | xargs -0 rm -f'; 1636 $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/[0-9a-f][0-9a-f]/'; 1637 // old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`'; 1638 } 1639 if ($this->debug) { 1640 ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>"); 1641 } else { 1642 exec($cmd); 1643 } 1644 return; 1645 } 1646 1647 global $ADODB_INCLUDED_CSV; 1648 if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php'); 1649 1650 $f = $this->_gencachename($sql.serialize($inputarr),false); 1651 adodb_write_file($f,''); // is adodb_write_file needed? 1652 if (!@unlink($f)) { 1653 if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f"); 1654 } 1655 } 1656 1657 /** 1658 * Private function to generate filename for caching. 1659 * Filename is generated based on: 1660 * 1661 * - sql statement 1662 * - database type (oci8, ibase, ifx, etc) 1663 * - database name 1664 * - userid 1665 * - setFetchMode (adodb 4.23) 1666 * 1667 * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR). 1668 * Assuming that we can have 50,000 files per directory with good performance, 1669 * then we can scale to 12.8 million unique cached recordsets. Wow! 1670 */ 1671 function _gencachename($sql,$createdir,$memcache=false) 1672 { 1673 global $ADODB_CACHE_DIR; 1674 static $notSafeMode; 1675 1676 if ($this->fetchMode === false) { 1677 global $ADODB_FETCH_MODE; 1678 $mode = $ADODB_FETCH_MODE; 1679 } else { 1680 $mode = $this->fetchMode; 1681 } 1682 $m = md5($sql.$this->databaseType.$this->database.$this->user.$mode); 1683 if ($memcache) return $m; 1684 1685 if (!isset($notSafeMode)) $notSafeMode = !ini_get('safe_mode'); 1686 $dir = ($notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($m,0,2) : $ADODB_CACHE_DIR; 1687 1688 if ($createdir && $notSafeMode && !file_exists($dir)) { 1689 $oldu = umask(0); 1690 if (!mkdir($dir,0771)) 1691 if ($this->debug) ADOConnection::outp( "Unable to mkdir $dir for $sql"); 1692 umask($oldu); 1693 } 1694 return $dir.'/adodb_'.$m.'.cache'; 1695 } 1696 1697 1698 /** 1699 * Execute SQL, caching recordsets. 1700 * 1701 * @param [secs2cache] seconds to cache data, set to 0 to force query. 1702 * This is an optional parameter. 1703 * @param sql SQL statement to execute 1704 * @param [inputarr] holds the input data to bind to 1705 * @return RecordSet or false 1706 */ 1707 function &CacheExecute($secs2cache,$sql=false,$inputarr=false) 1708 { 1709 1710 1711 if (!is_numeric($secs2cache)) { 1712 $inputarr = $sql; 1713 $sql = $secs2cache; 1714 $secs2cache = $this->cacheSecs; 1715 } 1716 1717 if (is_array($sql)) { 1718 $sqlparam = $sql; 1719 $sql = $sql[0]; 1720 } else 1721 $sqlparam = $sql; 1722 1723 if ($this->memCache) { 1724 global $ADODB_INCLUDED_MEMCACHE; 1725 if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR.'/adodb-memcache.lib.inc.php'); 1726 $md5file = $this->_gencachename($sql.serialize($inputarr),false,true); 1727 } else { 1728 global $ADODB_INCLUDED_CSV; 1729 if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php'); 1730 $md5file = $this->_gencachename($sql.serialize($inputarr),true); 1731 } 1732 1733 $err = ''; 1734 1735 if ($secs2cache > 0){ 1736 if ($this->memCache) 1737 $rs = &getmemCache($md5file,$err,$secs2cache, $this->memCacheHost, $this->memCachePort); 1738 else 1739 $rs = &csv2rs($md5file,$err,$secs2cache,$this->arrayClass); 1740 $this->numCacheHits += 1; 1741 } else { 1742 $err='Timeout 1'; 1743 $rs = false; 1744 $this->numCacheMisses += 1; 1745 } 1746 if (!$rs) { 1747 // no cached rs found 1748 if ($this->debug) { 1749 if (get_magic_quotes_runtime() && !$this->memCache) { 1750 ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :("); 1751 } 1752 if ($this->debug !== -1) ADOConnection::outp( " $md5file cache failure: $err (see sql below)"); 1753 } 1754 1755 $rs = &$this->Execute($sqlparam,$inputarr); 1756 1757 if ($rs && $this->memCache) { 1758 $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately 1759 if(!putmemCache($md5file, $rs, $this->memCacheHost, $this->memCachePort, $this->memCacheCompress, $this->debug)) { 1760 if ($fn = $this->raiseErrorFn) 1761 $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this); 1762 if ($this->debug) ADOConnection::outp( " Cache write error"); 1763 } 1764 } else 1765 if ($rs) { 1766 $eof = $rs->EOF; 1767 $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately 1768 $txt = _rs2serialize($rs,false,$sql); // serialize 1769 1770 if (!adodb_write_file($md5file,$txt,$this->debug)) { 1771 if ($fn = $this->raiseErrorFn) { 1772 $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this); 1773 } 1774 if ($this->debug) ADOConnection::outp( " Cache write error"); 1775 } 1776 if ($rs->EOF && !$eof) { 1777 $rs->MoveFirst(); 1778 //$rs = &csv2rs($md5file,$err); 1779 $rs->connection = &$this; // Pablo suggestion 1780 } 1781 1782 } else 1783 if (!$this->memCache) 1784 @unlink($md5file); 1785 } else { 1786 $this->_errorMsg = ''; 1787 $this->_errorCode = 0; 1788 1789 if ($this->fnCacheExecute) { 1790 $fn = $this->fnCacheExecute; 1791 $fn($this, $secs2cache, $sql, $inputarr); 1792 } 1793 // ok, set cached object found 1794 $rs->connection = &$this; // Pablo suggestion 1795 if ($this->debug){ 1796 1797 $inBrowser = isset($_SERVER['HTTP_USER_AGENT']); 1798 $ttl = $rs->timeCreated + $secs2cache - time(); 1799 $s = is_array($sql) ? $sql[0] : $sql; 1800 if ($inBrowser) $s = '<i>'.htmlspecialchars($s).'</i>'; 1801 1802 ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]"); 1803 } 1804 } 1805 return $rs; 1806 } 1807 1808 1809 /* 1810 Similar to PEAR DB's autoExecute(), except that 1811 $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE 1812 If $mode == 'UPDATE', then $where is compulsory as a safety measure. 1813 1814 $forceUpdate means that even if the data has not changed, perform update. 1815 */ 1816 function& AutoExecute($table, $fields_values, $mode = 'INSERT', $where = FALSE, $forceUpdate=true, $magicq=false) 1817 { 1818 $false = false; 1819 $sql = 'SELECT * FROM '.$table; 1820 if ($where!==FALSE) $sql .= ' WHERE '.$where; 1821 else if ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) { 1822 ADOConnection::outp('AutoExecute: Illegal mode=UPDATE with empty WHERE clause'); 1823 return $false; 1824 } 1825 1826 $rs =& $this->SelectLimit($sql,1); 1827 if (!$rs) return $false; // table does not exist 1828 $rs->tableName = $table; 1829 1830 switch((string) $mode) { 1831 case 'UPDATE': 1832 case '2': 1833 $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq); 1834 break; 1835 case 'INSERT': 1836 case '1': 1837 $sql = $this->GetInsertSQL($rs, $fields_values, $magicq); 1838 break; 1839 default: 1840 ADOConnection::outp("AutoExecute: Unknown mode=$mode"); 1841 return $false; 1842 } 1843 $ret = false; 1844 if ($sql) $ret = $this->Execute($sql); 1845 if ($ret) $ret = true; 1846 return $ret; 1847 } 1848 1849 1850 /** 1851 * Generates an Update Query based on an existing recordset. 1852 * $arrFields is an associative array of fields with the value 1853 * that should be assigned. 1854 * 1855 * Note: This function should only be used on a recordset 1856 * that is run against a single table and sql should only 1857 * be a simple select stmt with no groupby/orderby/limit 1858 * 1859 * "Jonathan Younger" <jyounger@unilab.com> 1860 */ 1861 function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null) 1862 { 1863 global $ADODB_INCLUDED_LIB; 1864 1865 //********************************************************// 1866 //This is here to maintain compatibility 1867 //with older adodb versions. Sets force type to force nulls if $forcenulls is set. 1868 if (!isset($force)) { 1869 global $ADODB_FORCE_TYPE; 1870 $force = $ADODB_FORCE_TYPE; 1871 } 1872 //********************************************************// 1873 1874 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); 1875 return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force); 1876 } 1877 1878 /** 1879 * Generates an Insert Query based on an existing recordset. 1880 * $arrFields is an associative array of fields with the value 1881 * that should be assigned. 1882 * 1883 * Note: This function should only be used on a recordset 1884 * that is run against a single table. 1885 */ 1886 function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null) 1887 { 1888 global $ADODB_INCLUDED_LIB; 1889 if (!isset($force)) { 1890 global $ADODB_FORCE_TYPE; 1891 $force = $ADODB_FORCE_TYPE; 1892 1893 } 1894 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); 1895 return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force); 1896 } 1897 1898 1899 /** 1900 * Update a blob column, given a where clause. There are more sophisticated 1901 * blob handling functions that we could have implemented, but all require 1902 * a very complex API. Instead we have chosen something that is extremely 1903 * simple to understand and use. 1904 * 1905 * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course. 1906 * 1907 * Usage to update a $blobvalue which has a primary key blob_id=1 into a 1908 * field blobtable.blobcolumn: 1909 * 1910 * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1'); 1911 * 1912 * Insert example: 1913 * 1914 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); 1915 * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1'); 1916 */ 1917 1918 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') 1919 { 1920 return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false; 1921 } 1922 1923 /** 1924 * Usage: 1925 * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1'); 1926 * 1927 * $blobtype supports 'BLOB' and 'CLOB' 1928 * 1929 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); 1930 * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1'); 1931 */ 1932 function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') 1933 { 1934 $fd = fopen($path,'rb'); 1935 if ($fd === false) return false; 1936 $val = fread($fd,filesize($path)); 1937 fclose($fd); 1938 return $this->UpdateBlob($table,$column,$val,$where,$blobtype); 1939 } 1940 1941 function BlobDecode($blob) 1942 { 1943 return $blob; 1944 } 1945 1946 function BlobEncode($blob) 1947 { 1948 return $blob; 1949 } 1950 1951 function SetCharSet($charset) 1952 { 1953 return false; 1954 } 1955 1956 function IfNull( $field, $ifNull ) 1957 { 1958 return " CASE WHEN $field is null THEN $ifNull ELSE $field END "; 1959 } 1960 1961 function LogSQL($enable=true) 1962 { 1963 include_once(ADODB_DIR.'/adodb-perf.inc.php'); 1964 1965 if ($enable) $this->fnExecute = 'adodb_log_sql'; 1966 else $this->fnExecute = false; 1967 1968 $old = $this->_logsql; 1969 $this->_logsql = $enable; 1970 if ($enable && !$old) $this->_affected = false; 1971 return $old; 1972 } 1973 1974 function GetCharSet() 1975 { 1976 return false; 1977 } 1978 1979 /** 1980 * Usage: 1981 * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB'); 1982 * 1983 * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)'); 1984 * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1'); 1985 */ 1986 function UpdateClob($table,$column,$val,$where) 1987 { 1988 return $this->UpdateBlob($table,$column,$val,$where,'CLOB'); 1989 } 1990 1991 // not the fastest implementation - quick and dirty - jlim 1992 // for best performance, use the actual $rs->MetaType(). 1993 function MetaType($t,$len=-1,$fieldobj=false) 1994 { 1995 1996 if (empty($this->_metars)) { 1997 $rsclass = $this->rsPrefix.$this->databaseType; 1998 $this->_metars = new $rsclass(false,$this->fetchMode); 1999 $this->_metars->connection =& $this; 2000 } 2001 return $this->_metars->MetaType($t,$len,$fieldobj); 2002 } 2003 2004 2005 /** 2006 * Change the SQL connection locale to a specified locale. 2007 * This is used to get the date formats written depending on the client locale. 2008 */ 2009 function SetDateLocale($locale = 'En') 2010 { 2011 $this->locale = $locale; 2012 switch (strtoupper($locale)) 2013 { 2014 case 'EN': 2015 $this->fmtDate="'Y-m-d'"; 2016 $this->fmtTimeStamp = "'Y-m-d H:i:s'"; 2017 break; 2018 2019 case 'US': 2020 $this->fmtDate = "'m-d-Y'"; 2021 $this->fmtTimeStamp = "'m-d-Y H:i:s'"; 2022 break; 2023 2024 case 'PT_BR': 2025 case 'NL': 2026 case 'FR': 2027 case 'RO': 2028 case 'IT': 2029 $this->fmtDate="'d-m-Y'"; 2030 $this->fmtTimeStamp = "'d-m-Y H:i:s'"; 2031 break; 2032 2033 case 'GE': 2034 $this->fmtDate="'d.m.Y'"; 2035 $this->fmtTimeStamp = "'d.m.Y H:i:s'"; 2036 break; 2037 2038 default: 2039 $this->fmtDate="'Y-m-d'"; 2040 $this->fmtTimeStamp = "'Y-m-d H:i:s'"; 2041 break; 2042 } 2043 } 2044 2045 function &GetActiveRecordsClass($class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false) 2046 { 2047 global $_ADODB_ACTIVE_DBS; 2048 2049 $save = $this->SetFetchMode(ADODB_FETCH_NUM); 2050 if (empty($whereOrderBy)) $whereOrderBy = '1=1'; 2051 $rows = $this->GetAll("select * from ".$table.' WHERE '.$whereOrderBy,$bindarr); 2052 $this->SetFetchMode($save); 2053 2054 $false = false; 2055 2056 if ($rows === false) { 2057 return $false; 2058 } 2059 2060 2061 if (!isset($_ADODB_ACTIVE_DBS)) { 2062 include(ADODB_DIR.'/adodb-active-record.inc.php'); 2063 } 2064 if (!class_exists($class)) { 2065 ADOConnection::outp("Unknown class $class in GetActiveRcordsClass()"); 2066 return $false; 2067 } 2068 $arr = array(); 2069 foreach($rows as $row) { 2070 2071 $obj = new $class($table,$primkeyArr,$this); 2072 if ($obj->ErrorMsg()){ 2073 $this->_errorMsg = $obj->ErrorMsg(); 2074 return $false; 2075 } 2076 $obj->Set($row); 2077 $arr[] = $obj; 2078 } 2079 return $arr; 2080 } 2081 2082 function &GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false) 2083 { 2084 $arr =& $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr); 2085 return $arr; 2086 } 2087 2088 /** 2089 * Close Connection 2090 */ 2091 function Close() 2092 { 2093 $rez = $this->_close(); 2094 $this->_connectionID = false; 2095 return $rez; 2096 } 2097 2098 /** 2099 * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans(). 2100 * 2101 * @return true if succeeded or false if database does not support transactions 2102 */ 2103 function BeginTrans() 2104 { 2105 if ($this->debug) ADOConnection::outp("BeginTrans: Transactions not supported for this driver"); 2106 return false; 2107 } 2108 2109 /* set transaction mode */ 2110 function SetTransactionMode( $transaction_mode ) 2111 { 2112 $transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider); 2113 $this->_transmode = $transaction_mode; 2114 } 2115/* 2116http://msdn2.microsoft.com/en-US/ms173763.aspx 2117http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html 2118http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html 2119http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm 2120*/ 2121 function MetaTransaction($mode,$db) 2122 { 2123 $mode = strtoupper($mode); 2124 $mode = str_replace('ISOLATION LEVEL ','',$mode); 2125 2126 switch($mode) { 2127 2128 case 'READ UNCOMMITTED': 2129 switch($db) { 2130 case 'oci8': 2131 case 'oracle': 2132 return 'ISOLATION LEVEL READ COMMITTED'; 2133 default: 2134 return 'ISOLATION LEVEL READ UNCOMMITTED'; 2135 } 2136 break; 2137 2138 case 'READ COMMITTED': 2139 return 'ISOLATION LEVEL READ COMMITTED'; 2140 break; 2141 2142 case 'REPEATABLE READ': 2143 switch($db) { 2144 case 'oci8': 2145 case 'oracle': 2146 return 'ISOLATION LEVEL SERIALIZABLE'; 2147 default: 2148 return 'ISOLATION LEVEL REPEATABLE READ'; 2149 } 2150 break; 2151 2152 case 'SERIALIZABLE': 2153 return 'ISOLATION LEVEL SERIALIZABLE'; 2154 break; 2155 2156 default: 2157 return $mode; 2158 } 2159 } 2160 2161 /** 2162 * If database does not support transactions, always return true as data always commited 2163 * 2164 * @param $ok set to false to rollback transaction, true to commit 2165 * 2166 * @return true/false. 2167 */ 2168 function CommitTrans($ok=true) 2169 { return true;} 2170 2171 2172 /** 2173 * If database does not support transactions, rollbacks always fail, so return false 2174 * 2175 * @return true/false. 2176 */ 2177 function RollbackTrans() 2178 { return false;} 2179 2180 2181 /** 2182 * return the databases that the driver can connect to. 2183 * Some databases will return an empty array. 2184 * 2185 * @return an array of database names. 2186 */ 2187 function MetaDatabases() 2188 { 2189 global $ADODB_FETCH_MODE; 2190 2191 if ($this->metaDatabasesSQL) { 2192 $save = $ADODB_FETCH_MODE; 2193 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 2194 2195 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); 2196 2197 $arr = $this->GetCol($this->metaDatabasesSQL); 2198 if (isset($savem)) $this->SetFetchMode($savem); 2199 $ADODB_FETCH_MODE = $save; 2200 2201 return $arr; 2202 } 2203 2204 return false; 2205 } 2206 2207 2208 /** 2209 * @param ttype can either be 'VIEW' or 'TABLE' or false. 2210 * If false, both views and tables are returned. 2211 * "VIEW" returns only views 2212 * "TABLE" returns only tables 2213 * @param showSchema returns the schema/user with the table name, eg. USER.TABLE 2214 * @param mask is the input mask - only supported by oci8 and postgresql 2215 * 2216 * @return array of tables for current database. 2217 */ 2218 function &MetaTables($ttype=false,$showSchema=false,$mask=false) 2219 { 2220 global $ADODB_FETCH_MODE; 2221 2222 2223 $false = false; 2224 if ($mask) { 2225 return $false; 2226 } 2227 if ($this->metaTablesSQL) { 2228 $save = $ADODB_FETCH_MODE; 2229 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 2230 2231 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); 2232 2233 $rs = $this->Execute($this->metaTablesSQL); 2234 if (isset($savem)) $this->SetFetchMode($savem); 2235 $ADODB_FETCH_MODE = $save; 2236 2237 if ($rs === false) return $false; 2238 $arr =& $rs->GetArray(); 2239 $arr2 = array(); 2240 2241 if ($hast = ($ttype && isset($arr[0][1]))) { 2242 $showt = strncmp($ttype,'T',1); 2243 } 2244 2245 for ($i=0; $i < sizeof($arr); $i++) { 2246 if ($hast) { 2247 if ($showt == 0) { 2248 if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]); 2249 } else { 2250 if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]); 2251 } 2252 } else 2253 $arr2[] = trim($arr[$i][0]); 2254 } 2255 $rs->Close(); 2256 return $arr2; 2257 } 2258 return $false; 2259 } 2260 2261 2262 function _findschema(&$table,&$schema) 2263 { 2264 if (!$schema && ($at = strpos($table,'.')) !== false) { 2265 $schema = substr($table,0,$at); 2266 $table = substr($table,$at+1); 2267 } 2268 } 2269 2270 /** 2271 * List columns in a database as an array of ADOFieldObjects. 2272 * See top of file for definition of object. 2273 * 2274 * @param $table table name to query 2275 * @param $normalize makes table name case-insensitive (required by some databases) 2276 * @schema is optional database schema to use - not supported by all databases. 2277 * 2278 * @return array of ADOFieldObjects for current table. 2279 */ 2280 function &MetaColumns($table,$normalize=true) 2281 { 2282 global $ADODB_FETCH_MODE; 2283 2284 $false = false; 2285 2286 if (!empty($this->metaColumnsSQL)) { 2287 2288 $schema = false; 2289 $this->_findschema($table,$schema); 2290 2291 $save = $ADODB_FETCH_MODE; 2292 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 2293 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); 2294 $rs = $this->Execute(sprintf($this->metaColumnsSQL,($normalize)?strtoupper($table):$table)); 2295 if (isset($savem)) $this->SetFetchMode($savem); 2296 $ADODB_FETCH_MODE = $save; 2297 if ($rs === false || $rs->EOF) return $false; 2298 2299 $retarr = array(); 2300 while (!$rs->EOF) { //print_r($rs->fields); 2301 $fld = new ADOFieldObject(); 2302 $fld->name = $rs->fields[0]; 2303 $fld->type = $rs->fields[1]; 2304 if (isset($rs->fields[3]) && $rs->fields[3]) { 2305 if ($rs->fields[3]>0) $fld->max_length = $rs->fields[3]; 2306 $fld->scale = $rs->fields[4]; 2307 if ($fld->scale>0) $fld->max_length += 1; 2308 } else 2309 $fld->max_length = $rs->fields[2]; 2310 2311 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; 2312 else $retarr[strtoupper($fld->name)] = $fld; 2313 $rs->MoveNext(); 2314 } 2315 $rs->Close(); 2316 return $retarr; 2317 } 2318 return $false; 2319 } 2320 2321 /** 2322 * List indexes on a table as an array. 2323 * @param table table name to query 2324 * @param primary true to only show primary keys. Not actually used for most databases 2325 * 2326 * @return array of indexes on current table. Each element represents an index, and is itself an associative array. 2327 2328 Array ( 2329 [name_of_index] => Array 2330 ( 2331 [unique] => true or false 2332 [columns] => Array 2333 ( 2334 [0] => firstname 2335 [1] => lastname 2336 ) 2337 ) 2338 */ 2339 function &MetaIndexes($table, $primary = false, $owner = false) 2340 { 2341 $false = false; 2342 return $false; 2343 } 2344 2345 /** 2346 * List columns names in a table as an array. 2347 * @param table table name to query 2348 * 2349 * @return array of column names for current table. 2350 */ 2351 function &MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */) 2352 { 2353 $objarr =& $this->MetaColumns($table); 2354 if (!is_array($objarr)) { 2355 $false = false; 2356 return $false; 2357 } 2358 $arr = array(); 2359 if ($numIndexes) { 2360 $i = 0; 2361 if ($useattnum) { 2362 foreach($objarr as $v) 2363 $arr[$v->attnum] = $v->name; 2364 2365 } else 2366 foreach($objarr as $v) $arr[$i++] = $v->name; 2367 } else 2368 foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name; 2369 2370 return $arr; 2371 } 2372 2373 /** 2374 * Different SQL databases used different methods to combine strings together. 2375 * This function provides a wrapper. 2376 * 2377 * param s variable number of string parameters 2378 * 2379 * Usage: $db->Concat($str1,$str2); 2380 * 2381 * @return concatenated string 2382 */ 2383 function Concat() 2384 { 2385 $arr = func_get_args(); 2386 return implode($this->concat_operator, $arr); 2387 } 2388 2389 2390 /** 2391 * Converts a date "d" to a string that the database can understand. 2392 * 2393 * @param d a date in Unix date time format. 2394 * 2395 * @return date string in database date format 2396 */ 2397 function DBDate($d) 2398 { 2399 if (empty($d) && $d !== 0) return 'null'; 2400 2401 if (is_string($d) && !is_numeric($d)) { 2402 if ($d === 'null' || strncmp($d,"'",1) === 0) return $d; 2403 if ($this->isoDates) return "'$d'"; 2404 $d = ADOConnection::UnixDate($d); 2405 } 2406 2407 return adodb_date($this->fmtDate,$d); 2408 } 2409 2410 function BindDate($d) 2411 { 2412 $d = $this->DBDate($d); 2413 if (strncmp($d,"'",1)) return $d; 2414 2415 return substr($d,1,strlen($d)-2); 2416 } 2417 2418 function BindTimeStamp($d) 2419 { 2420 $d = $this->DBTimeStamp($d); 2421 if (strncmp($d,"'",1)) return $d; 2422 2423 return substr($d,1,strlen($d)-2); 2424 } 2425 2426 2427 /** 2428 * Converts a timestamp "ts" to a string that the database can understand. 2429 * 2430 * @param ts a timestamp in Unix date time format. 2431 * 2432 * @return timestamp string in database timestamp format 2433 */ 2434 function DBTimeStamp($ts) 2435 { 2436 if (empty($ts) && $ts !== 0) return 'null'; 2437 2438 # strlen(14) allows YYYYMMDDHHMMSS format 2439 if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) 2440 return adodb_date($this->fmtTimeStamp,$ts); 2441 2442 if ($ts === 'null') return $ts; 2443 if ($this->isoDates && strlen($ts) !== 14) return "'$ts'"; 2444 2445 $ts = ADOConnection::UnixTimeStamp($ts); 2446 return adodb_date($this->fmtTimeStamp,$ts); 2447 } 2448 2449 /** 2450 * Also in ADORecordSet. 2451 * @param $v is a date string in YYYY-MM-DD format 2452 * 2453 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format 2454 */ 2455 function UnixDate($v) 2456 { 2457 if (is_object($v)) { 2458 // odbtp support 2459 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) 2460 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year); 2461 } 2462 2463 if (is_numeric($v) && strlen($v) !== 8) return $v; 2464 if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", 2465 ($v), $rr)) return false; 2466 2467 if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0; 2468 // h-m-s-MM-DD-YY 2469 return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]); 2470 } 2471 2472 2473 /** 2474 * Also in ADORecordSet. 2475 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format 2476 * 2477 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format 2478 */ 2479 function UnixTimeStamp($v) 2480 { 2481 if (is_object($v)) { 2482 // odbtp support 2483 //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) 2484 return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year); 2485 } 2486 2487 if (!preg_match( 2488 "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 2489 ($v), $rr)) return false; 2490 2491 if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) return 0; 2492 2493 // h-m-s-MM-DD-YY 2494 if (!isset($rr[5])) return adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]); 2495 return @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]); 2496 } 2497 2498 /** 2499 * Also in ADORecordSet. 2500 * 2501 * Format database date based on user defined format. 2502 * 2503 * @param v is the character date in YYYY-MM-DD format, returned by database 2504 * @param fmt is the format to apply to it, using date() 2505 * 2506 * @return a date formated as user desires 2507 */ 2508 2509 function UserDate($v,$fmt='Y-m-d',$gmt=false) 2510 { 2511 $tt = $this->UnixDate($v); 2512 2513 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR 2514 if (($tt === false || $tt == -1) && $v != false) return $v; 2515 else if ($tt == 0) return $this->emptyDate; 2516 else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR 2517 } 2518 2519 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt); 2520 2521 } 2522 2523 /** 2524 * 2525 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format 2526 * @param fmt is the format to apply to it, using date() 2527 * 2528 * @return a timestamp formated as user desires 2529 */ 2530 function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false) 2531 { 2532 if (!isset($v)) return $this->emptyTimeStamp; 2533 # strlen(14) allows YYYYMMDDHHMMSS format 2534 if (is_numeric($v) && strlen($v)<14) return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v); 2535 $tt = $this->UnixTimeStamp($v); 2536 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR 2537 if (($tt === false || $tt == -1) && $v != false) return $v; 2538 if ($tt == 0) return $this->emptyTimeStamp; 2539 return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt); 2540 } 2541 2542 function escape($s,$magic_quotes=false) 2543 { 2544 return $this->addq($s,$magic_quotes); 2545 } 2546 2547 /** 2548 * Quotes a string, without prefixing nor appending quotes. 2549 */ 2550 function addq($s,$magic_quotes=false) 2551 { 2552 if (!$magic_quotes) { 2553 2554 if ($this->replaceQuote[0] == '\\'){ 2555 // only since php 4.0.5 2556 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); 2557 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s)); 2558 } 2559 return str_replace("'",$this->replaceQuote,$s); 2560 } 2561 2562 // undo magic quotes for " 2563 $s = str_replace('\\"','"',$s); 2564 2565 if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything 2566 return $s; 2567 else {// change \' to '' for sybase/mssql 2568 $s = str_replace('\\\\','\\',$s); 2569 return str_replace("\\'",$this->replaceQuote,$s); 2570 } 2571 } 2572 2573 /** 2574 * Correctly quotes a string so that all strings are escaped. We prefix and append 2575 * to the string single-quotes. 2576 * An example is $db->qstr("Don't bother",magic_quotes_runtime()); 2577 * 2578 * @param s the string to quote 2579 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc(). 2580 * This undoes the stupidity of magic quotes for GPC. 2581 * 2582 * @return quoted string to be sent back to database 2583 */ 2584 function qstr($s,$magic_quotes=false) 2585 { 2586 if (!$magic_quotes) { 2587 2588 if ($this->replaceQuote[0] == '\\'){ 2589 // only since php 4.0.5 2590 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); 2591 //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s)); 2592 } 2593 return "'".str_replace("'",$this->replaceQuote,$s)."'"; 2594 } 2595 2596 // undo magic quotes for " 2597 $s = str_replace('\\"','"',$s); 2598 2599 if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything 2600 return "'$s'"; 2601 else {// change \' to '' for sybase/mssql 2602 $s = str_replace('\\\\','\\',$s); 2603 return "'".str_replace("\\'",$this->replaceQuote,$s)."'"; 2604 } 2605 } 2606 2607 2608 /** 2609 * Will select the supplied $page number from a recordset, given that it is paginated in pages of 2610 * $nrows rows per page. It also saves two boolean values saying if the given page is the first 2611 * and/or last one of the recordset. Added by Iv�n Oliva to provide recordset pagination. 2612 * 2613 * See readme.htm#ex8 for an example of usage. 2614 * 2615 * @param sql 2616 * @param nrows is the number of rows per page to get 2617 * @param page is the page number to get (1-based) 2618 * @param [inputarr] array of bind variables 2619 * @param [secs2cache] is a private parameter only used by jlim 2620 * @return the recordset ($rs->databaseType == 'array') 2621 * 2622 * NOTE: phpLens uses a different algorithm and does not use PageExecute(). 2623 * 2624 */ 2625 function &PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0) 2626 { 2627 global $ADODB_INCLUDED_LIB; 2628 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); 2629 if ($this->pageExecuteCountRows) $rs =& _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache); 2630 else $rs =& _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache); 2631 return $rs; 2632 } 2633 2634 2635 /** 2636 * Will select the supplied $page number from a recordset, given that it is paginated in pages of 2637 * $nrows rows per page. It also saves two boolean values saying if the given page is the first 2638 * and/or last one of the recordset. Added by Iv�n Oliva to provide recordset pagination. 2639 * 2640 * @param secs2cache seconds to cache data, set to 0 to force query 2641 * @param sql 2642 * @param nrows is the number of rows per page to get 2643 * @param page is the page number to get (1-based) 2644 * @param [inputarr] array of bind variables 2645 * @return the recordset ($rs->databaseType == 'array') 2646 */ 2647 function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false) 2648 { 2649 /*switch($this->dataProvider) { 2650 case 'postgres': 2651 case 'mysql': 2652 break; 2653 default: $secs2cache = 0; break; 2654 }*/ 2655 $rs =& $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache); 2656 return $rs; 2657 } 2658 2659} // end class ADOConnection 2660 2661 2662 2663 //============================================================================================== 2664 // CLASS ADOFetchObj 2665 //============================================================================================== 2666 2667 /** 2668 * Internal placeholder for record objects. Used by ADORecordSet->FetchObj(). 2669 */ 2670 class ADOFetchObj { 2671 }; 2672 2673 //============================================================================================== 2674 // CLASS ADORecordSet_empty 2675 //============================================================================================== 2676 2677 /** 2678 * Lightweight recordset when there are no records to be returned 2679 */ 2680 class ADORecordSet_empty 2681 { 2682 var $dataProvider = 'empty'; 2683 var $databaseType = false; 2684 var $EOF = true; 2685 var $_numOfRows = 0; 2686 var $fields = false; 2687 var $connection = false; 2688 function RowCount() {return 0;} 2689 function RecordCount() {return 0;} 2690 function PO_RecordCount(){return 0;} 2691 function Close(){return true;} 2692 function FetchRow() {return false;} 2693 function FieldCount(){ return 0;} 2694 function Init() {} 2695 } 2696 2697 //============================================================================================== 2698 // DATE AND TIME FUNCTIONS 2699 //============================================================================================== 2700 if (!defined('ADODB_DATE_VERSION')) include(ADODB_DIR.'/adodb-time.inc.php'); 2701 2702 //============================================================================================== 2703 // CLASS ADORecordSet 2704 //============================================================================================== 2705 2706 if (PHP_VERSION < 5) include_once(ADODB_DIR.'/adodb-php4.inc.php'); 2707 else include_once(ADODB_DIR.'/adodb-iterator.inc.php'); 2708 /** 2709 * RecordSet class that represents the dataset returned by the database. 2710 * To keep memory overhead low, this class holds only the current row in memory. 2711 * No prefetching of data is done, so the RecordCount() can return -1 ( which 2712 * means recordcount not known). 2713 */ 2714 class ADORecordSet extends ADODB_BASE_RS { 2715 /* 2716 * public variables 2717 */ 2718 var $dataProvider = "native"; 2719 var $fields = false; /// holds the current row data 2720 var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob 2721 /// in other words, we use a text area for editing. 2722 var $canSeek = false; /// indicates that seek is supported 2723 var $sql; /// sql text 2724 var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object. 2725 2726 var $emptyTimeStamp = ' '; /// what to display when $time==0 2727 var $emptyDate = ' '; /// what to display when $time==0 2728 var $debug = false; 2729 var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsets 2730 2731 var $bind = false; /// used by Fields() to hold array - should be private? 2732 var $fetchMode; /// default fetch mode 2733 var $connection = false; /// the parent connection 2734 /* 2735 * private variables 2736 */ 2737 var $_numOfRows = -1; /** number of rows, or -1 */ 2738 var $_numOfFields = -1; /** number of fields in recordset */ 2739 var $_queryID = -1; /** This variable keeps the result link identifier. */ 2740 var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */ 2741 var $_closed = false; /** has recordset been closed */ 2742 var $_inited = false; /** Init() should only be called once */ 2743 var $_obj; /** Used by FetchObj */ 2744 var $_names; /** Used by FetchObj */ 2745 2746 var $_currentPage = -1; /** Added by Iv�n Oliva to implement recordset pagination */ 2747 var $_atFirstPage = false; /** Added by Iv�n Oliva to implement recordset pagination */ 2748 var $_atLastPage = false; /** Added by Iv�n Oliva to implement recordset pagination */ 2749 var $_lastPageNo = -1; 2750 var $_maxRecordCount = 0; 2751 var $datetime = false; 2752 2753 /** 2754 * Constructor 2755 * 2756 * @param queryID this is the queryID returned by ADOConnection->_query() 2757 * 2758 */ 2759 function ADORecordSet($queryID) 2760 { 2761 $this->_queryID = $queryID; 2762 } 2763 2764 2765 2766 function Init() 2767 { 2768 if ($this->_inited) return; 2769 $this->_inited = true; 2770 if ($this->_queryID) @$this->_initrs(); 2771 else { 2772 $this->_numOfRows = 0; 2773 $this->_numOfFields = 0; 2774 } 2775 if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) { 2776 2777 $this->_currentRow = 0; 2778 if ($this->EOF = ($this->_fetch() === false)) { 2779 $this->_numOfRows = 0; // _numOfRows could be -1 2780 } 2781 } else { 2782 $this->EOF = true; 2783 } 2784 } 2785 2786 2787 /** 2788 * Generate a SELECT tag string from a recordset, and return the string. 2789 * If the recordset has 2 cols, we treat the 1st col as the containing 2790 * the text to display to the user, and 2nd col as the return value. Default 2791 * strings are compared with the FIRST column. 2792 * 2793 * @param name name of SELECT tag 2794 * @param [defstr] the value to hilite. Use an array for multiple hilites for listbox. 2795 * @param [blank1stItem] true to leave the 1st item in list empty 2796 * @param [multiple] true for listbox, false for popup 2797 * @param [size] #rows to show for listbox. not used by popup 2798 * @param [selectAttr] additional attributes to defined for SELECT tag. 2799 * useful for holding javascript onChange='...' handlers. 2800 & @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with 2801 * column 0 (1st col) if this is true. This is not documented. 2802 * 2803 * @return HTML 2804 * 2805 * changes by glen.davies@cce.ac.nz to support multiple hilited items 2806 */ 2807 function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false, 2808 $size=0, $selectAttr='',$compareFields0=true) 2809 { 2810 global $ADODB_INCLUDED_LIB; 2811 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); 2812 return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple, 2813 $size, $selectAttr,$compareFields0); 2814 } 2815 2816 2817 2818 /** 2819 * Generate a SELECT tag string from a recordset, and return the string. 2820 * If the recordset has 2 cols, we treat the 1st col as the containing 2821 * the text to display to the user, and 2nd col as the return value. Default 2822 * strings are compared with the SECOND column. 2823 * 2824 */ 2825 function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='') 2826 { 2827 return $this->GetMenu($name,$defstr,$blank1stItem,$multiple, 2828 $size, $selectAttr,false); 2829 } 2830 2831 /* 2832 Grouped Menu 2833 */ 2834 function GetMenu3($name,$defstr='',$blank1stItem=true,$multiple=false, 2835 $size=0, $selectAttr='') 2836 { 2837 global $ADODB_INCLUDED_LIB; 2838 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); 2839 return _adodb_getmenu_gp($this, $name,$defstr,$blank1stItem,$multiple, 2840 $size, $selectAttr,false); 2841 } 2842 2843 /** 2844 * return recordset as a 2-dimensional array. 2845 * 2846 * @param [nRows] is the number of rows to return. -1 means every row. 2847 * 2848 * @return an array indexed by the rows (0-based) from the recordset 2849 */ 2850 function &GetArray($nRows = -1) 2851 { 2852 global $ADODB_EXTENSION; if ($ADODB_EXTENSION) { 2853 $results = adodb_getall($this,$nRows); 2854 return $results; 2855 } 2856 $results = array(); 2857 $cnt = 0; 2858 while (!$this->EOF && $nRows != $cnt) { 2859 $results[] = $this->fields; 2860 $this->MoveNext(); 2861 $cnt++; 2862 } 2863 return $results; 2864 } 2865 2866 function &GetAll($nRows = -1) 2867 { 2868 $arr =& $this->GetArray($nRows); 2869 return $arr; 2870 } 2871 2872 /* 2873 * Some databases allow multiple recordsets to be returned. This function 2874 * will return true if there is a next recordset, or false if no more. 2875 */ 2876 function NextRecordSet() 2877 { 2878 return false; 2879 } 2880 2881 /** 2882 * return recordset as a 2-dimensional array. 2883 * Helper function for ADOConnection->SelectLimit() 2884 * 2885 * @param offset is the row to start calculations from (1-based) 2886 * @param [nrows] is the number of rows to return 2887 * 2888 * @return an array indexed by the rows (0-based) from the recordset 2889 */ 2890 function &GetArrayLimit($nrows,$offset=-1) 2891 { 2892 if ($offset <= 0) { 2893 $arr =& $this->GetArray($nrows); 2894 return $arr; 2895 } 2896 2897 $this->Move($offset); 2898 2899 $results = array(); 2900 $cnt = 0; 2901 while (!$this->EOF && $nrows != $cnt) { 2902 $results[$cnt++] = $this->fields; 2903 $this->MoveNext(); 2904 } 2905 2906 return $results; 2907 } 2908 2909 2910 /** 2911 * Synonym for GetArray() for compatibility with ADO. 2912 * 2913 * @param [nRows] is the number of rows to return. -1 means every row. 2914 * 2915 * @return an array indexed by the rows (0-based) from the recordset 2916 */ 2917 function &GetRows($nRows = -1) 2918 { 2919 $arr =& $this->GetArray($nRows); 2920 return $arr; 2921 } 2922 2923 /** 2924 * return whole recordset as a 2-dimensional associative array if there are more than 2 columns. 2925 * The first column is treated as the key and is not included in the array. 2926 * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless 2927 * $force_array == true. 2928 * 2929 * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional 2930 * array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing, 2931 * read the source. 2932 * 2933 * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and 2934 * instead of returning array[col0] => array(remaining cols), return array[col0] => col1 2935 * 2936 * @return an associative array indexed by the first column of the array, 2937 * or false if the data has less than 2 cols. 2938 */ 2939 function &GetAssoc($force_array = false, $first2cols = false) 2940 { 2941 global $ADODB_EXTENSION; 2942 2943 $cols = $this->_numOfFields; 2944 if ($cols < 2) { 2945 $false = false; 2946 return $false; 2947 } 2948 $numIndex = isset($this->fields[0]); 2949 $results = array(); 2950 2951 if (!$first2cols && ($cols > 2 || $force_array)) { 2952 if ($ADODB_EXTENSION) { 2953 if ($numIndex) { 2954 while (!$this->EOF) { 2955 $results[trim($this->fields[0])] = array_slice($this->fields, 1); 2956 adodb_movenext($this); 2957 } 2958 } else { 2959 while (!$this->EOF) { 2960 // Fix for array_slice re-numbering numeric associative keys 2961 $keys = array_slice(array_keys($this->fields), 1); 2962 $sliced_array = array(); 2963 2964 foreach($keys as $key) { 2965 $sliced_array[$key] = $this->fields[$key]; 2966 } 2967 2968 $results[trim(reset($this->fields))] = $sliced_array; 2969 adodb_movenext($this); 2970 } 2971 } 2972 } else { 2973 if ($numIndex) { 2974 while (!$this->EOF) { 2975 $results[trim($this->fields[0])] = array_slice($this->fields, 1); 2976 $this->MoveNext(); 2977 } 2978 } else { 2979 while (!$this->EOF) { 2980 // Fix for array_slice re-numbering numeric associative keys 2981 $keys = array_slice(array_keys($this->fields), 1); 2982 $sliced_array = array(); 2983 2984 foreach($keys as $key) { 2985 $sliced_array[$key] = $this->fields[$key]; 2986 } 2987 2988 $results[trim(reset($this->fields))] = $sliced_array; 2989 $this->MoveNext(); 2990 } 2991 } 2992 } 2993 } else { 2994 if ($ADODB_EXTENSION) { 2995 // return scalar values 2996 if ($numIndex) { 2997 while (!$this->EOF) { 2998 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string 2999 $results[trim(($this->fields[0]))] = $this->fields[1]; 3000 adodb_movenext($this); 3001 } 3002 } else { 3003 while (!$this->EOF) { 3004 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string 3005 $v1 = trim(reset($this->fields)); 3006 $v2 = ''.next($this->fields); 3007 $results[$v1] = $v2; 3008 adodb_movenext($this); 3009 } 3010 } 3011 } else { 3012 if ($numIndex) { 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 $results[trim(($this->fields[0]))] = $this->fields[1]; 3016 $this->MoveNext(); 3017 } 3018 } else { 3019 while (!$this->EOF) { 3020 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string 3021 $v1 = trim(reset($this->fields)); 3022 $v2 = ''.next($this->fields); 3023 $results[$v1] = $v2; 3024 $this->MoveNext(); 3025 } 3026 } 3027 } 3028 } 3029 3030 $ref =& $results; # workaround accelerator incompat with PHP 4.4 :( 3031 return $ref; 3032 } 3033 3034 3035 /** 3036 * 3037 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format 3038 * @param fmt is the format to apply to it, using date() 3039 * 3040 * @return a timestamp formated as user desires 3041 */ 3042 function UserTimeStamp($v,$fmt='Y-m-d H:i:s') 3043 { 3044 if (is_numeric($v) && strlen($v)<14) return adodb_date($fmt,$v); 3045 $tt = $this->UnixTimeStamp($v); 3046 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR 3047 if (($tt === false || $tt == -1) && $v != false) return $v; 3048 if ($tt === 0) return $this->emptyTimeStamp; 3049 return adodb_date($fmt,$tt); 3050 } 3051 3052 3053 /** 3054 * @param v is the character date in YYYY-MM-DD format, returned by database 3055 * @param fmt is the format to apply to it, using date() 3056 * 3057 * @return a date formated as user desires 3058 */ 3059 function UserDate($v,$fmt='Y-m-d') 3060 { 3061 $tt = $this->UnixDate($v); 3062 // $tt == -1 if pre TIMESTAMP_FIRST_YEAR 3063 if (($tt === false || $tt == -1) && $v != false) return $v; 3064 else if ($tt == 0) return $this->emptyDate; 3065 else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR 3066 } 3067 return adodb_date($fmt,$tt); 3068 } 3069 3070 3071 /** 3072 * @param $v is a date string in YYYY-MM-DD format 3073 * 3074 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format 3075 */ 3076 function UnixDate($v) 3077 { 3078 return ADOConnection::UnixDate($v); 3079 } 3080 3081 3082 /** 3083 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format 3084 * 3085 * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format 3086 */ 3087 function UnixTimeStamp($v) 3088 { 3089 return ADOConnection::UnixTimeStamp($v); 3090 } 3091 3092 3093 /** 3094 * PEAR DB Compat - do not use internally 3095 */ 3096 function Free() 3097 { 3098 return $this->Close(); 3099 } 3100 3101 3102 /** 3103 * PEAR DB compat, number of rows 3104 */ 3105 function NumRows() 3106 { 3107 return $this->_numOfRows; 3108 } 3109 3110 3111 /** 3112 * PEAR DB compat, number of cols 3113 */ 3114 function NumCols() 3115 { 3116 return $this->_numOfFields; 3117 } 3118 3119 /** 3120 * Fetch a row, returning false if no more rows. 3121 * This is PEAR DB compat mode. 3122 * 3123 * @return false or array containing the current record 3124 */ 3125 function &FetchRow() 3126 { 3127 if ($this->EOF) { 3128 $false = false; 3129 return $false; 3130 } 3131 $arr = $this->fields; 3132 $this->_currentRow++; 3133 if (!$this->_fetch()) $this->EOF = true; 3134 return $arr; 3135 } 3136 3137 3138 /** 3139 * Fetch a row, returning PEAR_Error if no more rows. 3140 * This is PEAR DB compat mode. 3141 * 3142 * @return DB_OK or error object 3143 */ 3144 function FetchInto(&$arr) 3145 { 3146 if ($this->EOF) return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false; 3147 $arr = $this->fields; 3148 $this->MoveNext(); 3149 return 1; // DB_OK 3150 } 3151 3152 3153 /** 3154 * Move to the first row in the recordset. Many databases do NOT support this. 3155 * 3156 * @return true or false 3157 */ 3158 function MoveFirst() 3159 { 3160 if ($this->_currentRow == 0) return true; 3161 return $this->Move(0); 3162 } 3163 3164 3165 /** 3166 * Move to the last row in the recordset. 3167 * 3168 * @return true or false 3169 */ 3170 function MoveLast() 3171 { 3172 if ($this->_numOfRows >= 0) return $this->Move($this->_numOfRows-1); 3173 if ($this->EOF) return false; 3174 while (!$this->EOF) { 3175 $f = $this->fields; 3176 $this->MoveNext(); 3177 } 3178 $this->fields = $f; 3179 $this->EOF = false; 3180 return true; 3181 } 3182 3183 3184 /** 3185 * Move to next record in the recordset. 3186 * 3187 * @return true if there still rows available, or false if there are no more rows (EOF). 3188 */ 3189 function MoveNext() 3190 { 3191 if (!$this->EOF) { 3192 $this->_currentRow++; 3193 if ($this->_fetch()) return true; 3194 } 3195 $this->EOF = true; 3196 /* -- tested error handling when scrolling cursor -- seems useless. 3197 $conn = $this->connection; 3198 if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) { 3199 $fn = $conn->raiseErrorFn; 3200 $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database); 3201 } 3202 */ 3203 return false; 3204 } 3205 3206 3207 /** 3208 * Random access to a specific row in the recordset. Some databases do not support 3209 * access to previous rows in the databases (no scrolling backwards). 3210 * 3211 * @param rowNumber is the row to move to (0-based) 3212 * 3213 * @return true if there still rows available, or false if there are no more rows (EOF). 3214 */ 3215 function Move($rowNumber = 0) 3216 { 3217 $this->EOF = false; 3218 if ($rowNumber == $this->_currentRow) return true; 3219 if ($rowNumber >= $this->_numOfRows) 3220 if ($this->_numOfRows != -1) $rowNumber = $this->_numOfRows-2; 3221 3222 if ($this->canSeek) { 3223 3224 if ($this->_seek($rowNumber)) { 3225 $this->_currentRow = $rowNumber; 3226 if ($this->_fetch()) { 3227 return true; 3228 } 3229 } else { 3230 $this->EOF = true; 3231 return false; 3232 } 3233 } else { 3234 if ($rowNumber < $this->_currentRow) return false; 3235 global $ADODB_EXTENSION; 3236 if ($ADODB_EXTENSION) { 3237 while (!$this->EOF && $this->_currentRow < $rowNumber) { 3238 adodb_movenext($this); 3239 } 3240 } else { 3241 3242 while (! $this->EOF && $this->_currentRow < $rowNumber) { 3243 $this->_currentRow++; 3244 3245 if (!$this->_fetch()) $this->EOF = true; 3246 } 3247 } 3248 return !($this->EOF); 3249 } 3250 3251 $this->fields = false; 3252 $this->EOF = true; 3253 return false; 3254 } 3255 3256 3257 /** 3258 * Get the value of a field in the current row by column name. 3259 * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM. 3260 * 3261 * @param colname is the field to access 3262 * 3263 * @return the value of $colname column 3264 */ 3265 function Fields($colname) 3266 { 3267 return $this->fields[$colname]; 3268 } 3269 3270 function GetAssocKeys($upper=true) 3271 { 3272 $this->bind = array(); 3273 for ($i=0; $i < $this->_numOfFields; $i++) { 3274 $o = $this->FetchField($i); 3275 if ($upper === 2) $this->bind[$o->name] = $i; 3276 else $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $i; 3277 } 3278 } 3279 3280 /** 3281 * Use associative array to get fields array for databases that do not support 3282 * associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it 3283 * 3284 * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC 3285 * before you execute your SQL statement, and access $rs->fields['col'] directly. 3286 * 3287 * $upper 0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField 3288 */ 3289 function &GetRowAssoc($upper=1) 3290 { 3291 $record = array(); 3292 // if (!$this->fields) return $record; 3293 3294 if (!$this->bind) { 3295 $this->GetAssocKeys($upper); 3296 } 3297 3298 foreach($this->bind as $k => $v) { 3299 $record[$k] = $this->fields[$v]; 3300 } 3301 3302 return $record; 3303 } 3304 3305 3306 /** 3307 * Clean up recordset 3308 * 3309 * @return true or false 3310 */ 3311 function Close() 3312 { 3313 // free connection object - this seems to globally free the object 3314 // and not merely the reference, so don't do this... 3315 // $this->connection = false; 3316 if (!$this->_closed) { 3317 $this->_closed = true; 3318 return $this->_close(); 3319 } else 3320 return true; 3321 } 3322 3323 /** 3324 * synonyms RecordCount and RowCount 3325 * 3326 * @return the number of rows or -1 if this is not supported 3327 */ 3328 function RecordCount() {return $this->_numOfRows;} 3329 3330 3331 /* 3332 * If we are using PageExecute(), this will return the maximum possible rows 3333 * that can be returned when paging a recordset. 3334 */ 3335 function MaxRecordCount() 3336 { 3337 return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount(); 3338 } 3339 3340 /** 3341 * synonyms RecordCount and RowCount 3342 * 3343 * @return the number of rows or -1 if this is not supported 3344 */ 3345 function RowCount() {return $this->_numOfRows;} 3346 3347 3348 /** 3349 * Portable RecordCount. Pablo Roca <pabloroca@mvps.org> 3350 * 3351 * @return the number of records from a previous SELECT. All databases support this. 3352 * 3353 * But aware possible problems in multiuser environments. For better speed the table 3354 * must be indexed by the condition. Heavy test this before deploying. 3355 */ 3356 function PO_RecordCount($table="", $condition="") { 3357 3358 $lnumrows = $this->_numOfRows; 3359 // the database doesn't support native recordcount, so we do a workaround 3360 if ($lnumrows == -1 && $this->connection) { 3361 IF ($table) { 3362 if ($condition) $condition = " WHERE " . $condition; 3363 $resultrows = &$this->connection->Execute("SELECT COUNT(*) FROM $table $condition"); 3364 if ($resultrows) $lnumrows = reset($resultrows->fields); 3365 } 3366 } 3367 return $lnumrows; 3368 } 3369 3370 3371 /** 3372 * @return the current row in the recordset. If at EOF, will return the last row. 0-based. 3373 */ 3374 function CurrentRow() {return $this->_currentRow;} 3375 3376 /** 3377 * synonym for CurrentRow -- for ADO compat 3378 * 3379 * @return the current row in the recordset. If at EOF, will return the last row. 0-based. 3380 */ 3381 function AbsolutePosition() {return $this->_currentRow;} 3382 3383 /** 3384 * @return the number of columns in the recordset. Some databases will set this to 0 3385 * if no records are returned, others will return the number of columns in the query. 3386 */ 3387 function FieldCount() {return $this->_numOfFields;} 3388 3389 3390 /** 3391 * Get the ADOFieldObject of a specific column. 3392 * 3393 * @param fieldoffset is the column position to access(0-based). 3394 * 3395 * @return the ADOFieldObject for that column, or false. 3396 */ 3397 function &FetchField($fieldoffset = -1) 3398 { 3399 // must be defined by child class 3400 3401 $false = false; 3402 return $false; 3403 } 3404 3405 /** 3406 * Get the ADOFieldObjects of all columns in an array. 3407 * 3408 */ 3409 function& FieldTypesArray() 3410 { 3411 $arr = array(); 3412 for ($i=0, $max=$this->_numOfFields; $i < $max; $i++) 3413 $arr[] = $this->FetchField($i); 3414 return $arr; 3415 } 3416 3417 /** 3418 * Return the fields array of the current row as an object for convenience. 3419 * The default case is lowercase field names. 3420 * 3421 * @return the object with the properties set to the fields of the current row 3422 */ 3423 function &FetchObj() 3424 { 3425 $o =& $this->FetchObject(false); 3426 return $o; 3427 } 3428 3429 /** 3430 * Return the fields array of the current row as an object for convenience. 3431 * The default case is uppercase. 3432 * 3433 * @param $isupper to set the object property names to uppercase 3434 * 3435 * @return the object with the properties set to the fields of the current row 3436 */ 3437 function &FetchObject($isupper=true) 3438 { 3439 if (empty($this->_obj)) { 3440 $this->_obj = new ADOFetchObj(); 3441 $this->_names = array(); 3442 for ($i=0; $i <$this->_numOfFields; $i++) { 3443 $f = $this->FetchField($i); 3444 $this->_names[] = $f->name; 3445 } 3446 } 3447 $i = 0; 3448 if (PHP_VERSION >= 5) $o = clone($this->_obj); 3449 else $o = $this->_obj; 3450 3451 for ($i=0; $i <$this->_numOfFields; $i++) { 3452 $name = $this->_names[$i]; 3453 if ($isupper) $n = strtoupper($name); 3454 else $n = $name; 3455 3456 $o->$n = $this->Fields($name); 3457 } 3458 return $o; 3459 } 3460 3461 /** 3462 * Return the fields array of the current row as an object for convenience. 3463 * The default is lower-case field names. 3464 * 3465 * @return the object with the properties set to the fields of the current row, 3466 * or false if EOF 3467 * 3468 * Fixed bug reported by tim@orotech.net 3469 */ 3470 function &FetchNextObj() 3471 { 3472 $o =& $this->FetchNextObject(false); 3473 return $o; 3474 } 3475 3476 3477 /** 3478 * Return the fields array of the current row as an object for convenience. 3479 * The default is upper case field names. 3480 * 3481 * @param $isupper to set the object property names to uppercase 3482 * 3483 * @return the object with the properties set to the fields of the current row, 3484 * or false if EOF 3485 * 3486 * Fixed bug reported by tim@orotech.net 3487 */ 3488 function &FetchNextObject($isupper=true) 3489 { 3490 $o = false; 3491 if ($this->_numOfRows != 0 && !$this->EOF) { 3492 $o = $this->FetchObject($isupper); 3493 $this->_currentRow++; 3494 if ($this->_fetch()) return $o; 3495 } 3496 $this->EOF = true; 3497 return $o; 3498 } 3499 3500 /** 3501 * Get the metatype of the column. This is used for formatting. This is because 3502 * many databases use different names for the same type, so we transform the original 3503 * type to our standardised version which uses 1 character codes: 3504 * 3505 * @param t is the type passed in. Normally is ADOFieldObject->type. 3506 * @param len is the maximum length of that field. This is because we treat character 3507 * fields bigger than a certain size as a 'B' (blob). 3508 * @param fieldobj is the field object returned by the database driver. Can hold 3509 * additional info (eg. primary_key for mysql). 3510 * 3511 * @return the general type of the data: 3512 * C for character < 250 chars 3513 * X for teXt (>= 250 chars) 3514 * B for Binary 3515 * N for numeric or floating point 3516 * D for date 3517 * T for timestamp 3518 * L for logical/Boolean 3519 * I for integer 3520 * R for autoincrement counter/integer 3521 * 3522 * 3523 */ 3524 function MetaType($t,$len=-1,$fieldobj=false) 3525 { 3526 if (is_object($t)) { 3527 $fieldobj = $t; 3528 $t = $fieldobj->type; 3529 $len = $fieldobj->max_length; 3530 } 3531 // changed in 2.32 to hashing instead of switch stmt for speed... 3532 static $typeMap = array( 3533 'VARCHAR' => 'C', 3534 'VARCHAR2' => 'C', 3535 'CHAR' => 'C', 3536 'C' => 'C', 3537 'STRING' => 'C', 3538 'NCHAR' => 'C', 3539 'NVARCHAR' => 'C', 3540 'VARYING' => 'C', 3541 'BPCHAR' => 'C', 3542 'CHARACTER' => 'C', 3543 'INTERVAL' => 'C', # Postgres 3544 'MACADDR' => 'C', # postgres 3545 ## 3546 'LONGCHAR' => 'X', 3547 'TEXT' => 'X', 3548 'NTEXT' => 'X', 3549 'M' => 'X', 3550 'X' => 'X', 3551 'CLOB' => 'X', 3552 'NCLOB' => 'X', 3553 'LVARCHAR' => 'X', 3554 ## 3555 'BLOB' => 'B', 3556 'IMAGE' => 'B', 3557 'BINARY' => 'B', 3558 'VARBINARY' => 'B', 3559 'LONGBINARY' => 'B', 3560 'B' => 'B', 3561 ## 3562 'YEAR' => 'D', // mysql 3563 'DATE' => 'D', 3564 'D' => 'D', 3565 ## 3566 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server 3567 ## 3568 'TIME' => 'T', 3569 'TIMESTAMP' => 'T', 3570 'DATETIME' => 'T', 3571 'TIMESTAMPTZ' => 'T', 3572 'T' => 'T', 3573 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql 3574 ## 3575 'BOOL' => 'L', 3576 'BOOLEAN' => 'L', 3577 'BIT' => 'L', 3578 'L' => 'L', 3579 ## 3580 'COUNTER' => 'R', 3581 'R' => 'R', 3582 'SERIAL' => 'R', // ifx 3583 'INT IDENTITY' => 'R', 3584 ## 3585 'INT' => 'I', 3586 'INT2' => 'I', 3587 'INT4' => 'I', 3588 'INT8' => 'I', 3589 'INTEGER' => 'I', 3590 'INTEGER UNSIGNED' => 'I', 3591 'SHORT' => 'I', 3592 'TINYINT' => 'I', 3593 'SMALLINT' => 'I', 3594 'I' => 'I', 3595 ## 3596 'LONG' => 'N', // interbase is numeric, oci8 is blob 3597 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers 3598 'DECIMAL' => 'N', 3599 'DEC' => 'N', 3600 'REAL' => 'N', 3601 'DOUBLE' => 'N', 3602 'DOUBLE PRECISION' => 'N', 3603 'SMALLFLOAT' => 'N', 3604 'FLOAT' => 'N', 3605 'NUMBER' => 'N', 3606 'NUM' => 'N', 3607 'NUMERIC' => 'N', 3608 'MONEY' => 'N', 3609 3610 ## informix 9.2 3611 'SQLINT' => 'I', 3612 'SQLSERIAL' => 'I', 3613 'SQLSMINT' => 'I', 3614 'SQLSMFLOAT' => 'N', 3615 'SQLFLOAT' => 'N', 3616 'SQLMONEY' => 'N', 3617 'SQLDECIMAL' => 'N', 3618 'SQLDATE' => 'D', 3619 'SQLVCHAR' => 'C', 3620 'SQLCHAR' => 'C', 3621 'SQLDTIME' => 'T', 3622 'SQLINTERVAL' => 'N', 3623 'SQLBYTES' => 'B', 3624 'SQLTEXT' => 'X', 3625 ## informix 10 3626 "SQLINT8" => 'I8', 3627 "SQLSERIAL8" => 'I8', 3628 "SQLNCHAR" => 'C', 3629 "SQLNVCHAR" => 'C', 3630 "SQLLVARCHAR" => 'X', 3631 "SQLBOOL" => 'L' 3632 ); 3633 3634 $tmap = false; 3635 $t = strtoupper($t); 3636 $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N'; 3637 switch ($tmap) { 3638 case 'C': 3639 3640 // is the char field is too long, return as text field... 3641 if ($this->blobSize >= 0) { 3642 if ($len > $this->blobSize) return 'X'; 3643 } else if ($len > 250) { 3644 return 'X'; 3645 } 3646 return 'C'; 3647 3648 case 'I': 3649 if (!empty($fieldobj->primary_key)) return 'R'; 3650 return 'I'; 3651 3652 case false: 3653 return 'N'; 3654 3655 case 'B': 3656 if (isset($fieldobj->binary)) 3657 return ($fieldobj->binary) ? 'B' : 'X'; 3658 return 'B'; 3659 3660 case 'D': 3661 if (!empty($this->connection) && !empty($this->connection->datetime)) return 'T'; 3662 return 'D'; 3663 3664 default: 3665 if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B'; 3666 return $tmap; 3667 } 3668 } 3669 3670 3671 function _close() {} 3672 3673 /** 3674 * set/returns the current recordset page when paginating 3675 */ 3676 function AbsolutePage($page=-1) 3677 { 3678 if ($page != -1) $this->_currentPage = $page; 3679 return $this->_currentPage; 3680 } 3681 3682 /** 3683 * set/returns the status of the atFirstPage flag when paginating 3684 */ 3685 function AtFirstPage($status=false) 3686 { 3687 if ($status != false) $this->_atFirstPage = $status; 3688 return $this->_atFirstPage; 3689 } 3690 3691 function LastPageNo($page = false) 3692 { 3693 if ($page != false) $this->_lastPageNo = $page; 3694 return $this->_lastPageNo; 3695 } 3696 3697 /** 3698 * set/returns the status of the atLastPage flag when paginating 3699 */ 3700 function AtLastPage($status=false) 3701 { 3702 if ($status != false) $this->_atLastPage = $status; 3703 return $this->_atLastPage; 3704 } 3705 3706} // end class ADORecordSet 3707 3708 //============================================================================================== 3709 // CLASS ADORecordSet_array 3710 //============================================================================================== 3711 3712 /** 3713 * This class encapsulates the concept of a recordset created in memory 3714 * as an array. This is useful for the creation of cached recordsets. 3715 * 3716 * Note that the constructor is different from the standard ADORecordSet 3717 */ 3718 3719 class ADORecordSet_array extends ADORecordSet 3720 { 3721 var $databaseType = 'array'; 3722 3723 var $_array; // holds the 2-dimensional data array 3724 var $_types; // the array of types of each column (C B I L M) 3725 var $_colnames; // names of each column in array 3726 var $_skiprow1; // skip 1st row because it holds column names 3727 var $_fieldobjects; // holds array of field objects 3728 var $canSeek = true; 3729 var $affectedrows = false; 3730 var $insertid = false; 3731 var $sql = ''; 3732 var $compat = false; 3733 /** 3734 * Constructor 3735 * 3736 */ 3737 function ADORecordSet_array($fakeid=1) 3738 { 3739 global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH; 3740 3741 // fetch() on EOF does not delete $this->fields 3742 $this->compat = !empty($ADODB_COMPAT_FETCH); 3743 $this->ADORecordSet($fakeid); // fake queryID 3744 $this->fetchMode = $ADODB_FETCH_MODE; 3745 } 3746 3747 function _transpose($addfieldnames=true) 3748 { 3749 global $ADODB_INCLUDED_LIB; 3750 3751 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); 3752 $hdr = true; 3753 3754 $fobjs = $addfieldnames ? $this->_fieldobjects : false; 3755 adodb_transpose($this->_array, $newarr, $hdr, $fobjs); 3756 //adodb_pr($newarr); 3757 3758 $this->_skiprow1 = false; 3759 $this->_array =& $newarr; 3760 $this->_colnames = $hdr; 3761 3762 adodb_probetypes($newarr,$this->_types); 3763 3764 $this->_fieldobjects = array(); 3765 3766 foreach($hdr as $k => $name) { 3767 $f = new ADOFieldObject(); 3768 $f->name = $name; 3769 $f->type = $this->_types[$k]; 3770 $f->max_length = -1; 3771 $this->_fieldobjects[] = $f; 3772 } 3773 $this->fields = reset($this->_array); 3774 3775 $this->_initrs(); 3776 3777 } 3778 3779 /** 3780 * Setup the array. 3781 * 3782 * @param array is a 2-dimensional array holding the data. 3783 * The first row should hold the column names 3784 * unless paramter $colnames is used. 3785 * @param typearr holds an array of types. These are the same types 3786 * used in MetaTypes (C,B,L,I,N). 3787 * @param [colnames] array of column names. If set, then the first row of 3788 * $array should not hold the column names. 3789 */ 3790 function InitArray($array,$typearr,$colnames=false) 3791 { 3792 $this->_array = $array; 3793 $this->_types = $typearr; 3794 if ($colnames) { 3795 $this->_skiprow1 = false; 3796 $this->_colnames = $colnames; 3797 } else { 3798 $this->_skiprow1 = true; 3799 $this->_colnames = $array[0]; 3800 } 3801 $this->Init(); 3802 } 3803 /** 3804 * Setup the Array and datatype file objects 3805 * 3806 * @param array is a 2-dimensional array holding the data. 3807 * The first row should hold the column names 3808 * unless paramter $colnames is used. 3809 * @param fieldarr holds an array of ADOFieldObject's. 3810 */ 3811 function InitArrayFields(&$array,&$fieldarr) 3812 { 3813 $this->_array =& $array; 3814 $this->_skiprow1= false; 3815 if ($fieldarr) { 3816 $this->_fieldobjects =& $fieldarr; 3817 } 3818 $this->Init(); 3819 } 3820 3821 function &GetArray($nRows=-1) 3822 { 3823 if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) { 3824 return $this->_array; 3825 } else { 3826 $arr =& ADORecordSet::GetArray($nRows); 3827 return $arr; 3828 } 3829 } 3830 3831 function _initrs() 3832 { 3833 $this->_numOfRows = sizeof($this->_array); 3834 if ($this->_skiprow1) $this->_numOfRows -= 1; 3835 3836 $this->_numOfFields =(isset($this->_fieldobjects)) ? 3837 sizeof($this->_fieldobjects):sizeof($this->_types); 3838 } 3839 3840 /* Use associative array to get fields array */ 3841 function Fields($colname) 3842 { 3843 $mode = isset($this->adodbFetchMode) ? $this->adodbFetchMode : $this->fetchMode; 3844 3845 if ($mode & ADODB_FETCH_ASSOC) { 3846 if (!isset($this->fields[$colname])) $colname = strtolower($colname); 3847 return $this->fields[$colname]; 3848 } 3849 if (!$this->bind) { 3850 $this->bind = array(); 3851 for ($i=0; $i < $this->_numOfFields; $i++) { 3852 $o = $this->FetchField($i); 3853 $this->bind[strtoupper($o->name)] = $i; 3854 } 3855 } 3856 return $this->fields[$this->bind[strtoupper($colname)]]; 3857 } 3858 3859 function &FetchField($fieldOffset = -1) 3860 { 3861 if (isset($this->_fieldobjects)) { 3862 return $this->_fieldobjects[$fieldOffset]; 3863 } 3864 $o = new ADOFieldObject(); 3865 $o->name = $this->_colnames[$fieldOffset]; 3866 $o->type = $this->_types[$fieldOffset]; 3867 $o->max_length = -1; // length not known 3868 3869 return $o; 3870 } 3871 3872 function _seek($row) 3873 { 3874 if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) { 3875 $this->_currentRow = $row; 3876 if ($this->_skiprow1) $row += 1; 3877 $this->fields = $this->_array[$row]; 3878 return true; 3879 } 3880 return false; 3881 } 3882 3883 function MoveNext() 3884 { 3885 if (!$this->EOF) { 3886 $this->_currentRow++; 3887 3888 $pos = $this->_currentRow; 3889 3890 if ($this->_numOfRows <= $pos) { 3891 if (!$this->compat) $this->fields = false; 3892 } else { 3893 if ($this->_skiprow1) $pos += 1; 3894 $this->fields = $this->_array[$pos]; 3895 return true; 3896 } 3897 $this->EOF = true; 3898 } 3899 3900 return false; 3901 } 3902 3903 function _fetch() 3904 { 3905 $pos = $this->_currentRow; 3906 3907 if ($this->_numOfRows <= $pos) { 3908 if (!$this->compat) $this->fields = false; 3909 return false; 3910 } 3911 if ($this->_skiprow1) $pos += 1; 3912 $this->fields = $this->_array[$pos]; 3913 return true; 3914 } 3915 3916 function _close() 3917 { 3918 return true; 3919 } 3920 3921 } // ADORecordSet_array 3922 3923 //============================================================================================== 3924 // HELPER FUNCTIONS 3925 //============================================================================================== 3926 3927 /** 3928 * Synonym for ADOLoadCode. Private function. Do not use. 3929 * 3930 * @deprecated 3931 */ 3932 function ADOLoadDB($dbType) 3933 { 3934 return ADOLoadCode($dbType); 3935 } 3936 3937 /** 3938 * Load the code for a specific database driver. Private function. Do not use. 3939 */ 3940 function ADOLoadCode($dbType) 3941 { 3942 global $ADODB_LASTDB; 3943 3944 if (!$dbType) return false; 3945 $db = strtolower($dbType); 3946 switch ($db) { 3947 case 'ado': 3948 if (PHP_VERSION >= 5) $db = 'ado5'; 3949 $class = 'ado'; 3950 break; 3951 case 'ifx': 3952 case 'maxsql': $class = $db = 'mysqlt'; break; 3953 case 'postgres': 3954 case 'postgres8': 3955 case 'pgsql': $class = $db = 'postgres7'; break; 3956 default: 3957 $class = $db; break; 3958 } 3959 3960 $file = ADODB_DIR."/drivers/adodb-".$db.".inc.php"; 3961 @include_once($file); 3962 $ADODB_LASTDB = $class; 3963 if (class_exists("ADODB_" . $class)) return $class; 3964 3965 //ADOConnection::outp(adodb_pr(get_declared_classes(),true)); 3966 if (!file_exists($file)) ADOConnection::outp("Missing file: $file"); 3967 else ADOConnection::outp("Syntax error in file: $file"); 3968 return false; 3969 } 3970 3971 /** 3972 * synonym for ADONewConnection for people like me who cannot remember the correct name 3973 */ 3974 function &NewADOConnection($db='') 3975 { 3976 $tmp =& ADONewConnection($db); 3977 return $tmp; 3978 } 3979 3980 /** 3981 * Instantiate a new Connection class for a specific database driver. 3982 * 3983 * @param [db] is the database Connection object to create. If undefined, 3984 * use the last database driver that was loaded by ADOLoadCode(). 3985 * 3986 * @return the freshly created instance of the Connection class. 3987 */ 3988 function &ADONewConnection($db='') 3989 { 3990 GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB; 3991 3992 if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2); 3993 $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false; 3994 $false = false; 3995 if ($at = strpos($db,'://')) { 3996 $origdsn = $db; 3997 if (PHP_VERSION < 5) $dsna = @parse_url($db); 3998 else { 3999 $fakedsn = 'fake'.substr($db,$at); 4000 $dsna = @parse_url($fakedsn); 4001 $dsna['scheme'] = substr($db,0,$at); 4002 4003 if (strncmp($db,'pdo',3) == 0) { 4004 $sch = explode('_',$dsna['scheme']); 4005 if (sizeof($sch)>1) { 4006 $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : ''; 4007 $dsna['host'] = rawurlencode($sch[1].':host='.rawurldecode($dsna['host'])); 4008 $dsna['scheme'] = 'pdo'; 4009 } 4010 } 4011 } 4012 4013 if (!$dsna) { 4014 // special handling of oracle, which might not have host 4015 $db = str_replace('@/','@adodb-fakehost/',$db); 4016 $dsna = parse_url($db); 4017 if (!$dsna) return $false; 4018 $dsna['host'] = ''; 4019 } 4020 $db = @$dsna['scheme']; 4021 if (!$db) return $false; 4022 $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : ''; 4023 $dsna['user'] = isset($dsna['user']) ? rawurldecode($dsna['user']) : ''; 4024 $dsna['pass'] = isset($dsna['pass']) ? rawurldecode($dsna['pass']) : ''; 4025 $dsna['path'] = isset($dsna['path']) ? rawurldecode(substr($dsna['path'],1)) : ''; # strip off initial / 4026 4027 if (isset($dsna['query'])) { 4028 $opt1 = explode('&',$dsna['query']); 4029 foreach($opt1 as $k => $v) { 4030 $arr = explode('=',$v); 4031 $opt[$arr[0]] = isset($arr[1]) ? rawurldecode($arr[1]) : 1; 4032 } 4033 } else $opt = array(); 4034 } 4035 /* 4036 * phptype: Database backend used in PHP (mysql, odbc etc.) 4037 * dbsyntax: Database used with regards to SQL syntax etc. 4038 * protocol: Communication protocol to use (tcp, unix etc.) 4039 * hostspec: Host specification (hostname[:port]) 4040 * database: Database to use on the DBMS server 4041 * username: User name for login 4042 * password: Password for login 4043 */ 4044 if (!empty($ADODB_NEWCONNECTION)) { 4045 $obj = $ADODB_NEWCONNECTION($db); 4046 4047 } else { 4048 4049 if (!isset($ADODB_LASTDB)) $ADODB_LASTDB = ''; 4050 if (empty($db)) $db = $ADODB_LASTDB; 4051 4052 if ($db != $ADODB_LASTDB) $db = ADOLoadCode($db); 4053 4054 if (!$db) { 4055 if (isset($origdsn)) $db = $origdsn; 4056 if ($errorfn) { 4057 // raise an error 4058 $ignore = false; 4059 $errorfn('ADONewConnection', 'ADONewConnection', -998, 4060 "could not load the database driver for '$db'", 4061 $db,false,$ignore); 4062 } else 4063 ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false); 4064 4065 return $false; 4066 } 4067 4068 $cls = 'ADODB_'.$db; 4069 if (!class_exists($cls)) { 4070 adodb_backtrace(); 4071 return $false; 4072 } 4073 4074 $obj = new $cls(); 4075 } 4076 4077 # constructor should not fail 4078 if ($obj) { 4079 if ($errorfn) $obj->raiseErrorFn = $errorfn; 4080 if (isset($dsna)) { 4081 if (isset($dsna['port'])) $obj->port = $dsna['port']; 4082 foreach($opt as $k => $v) { 4083 switch(strtolower($k)) { 4084 case 'new': 4085 $nconnect = true; $persist = true; break; 4086 case 'persist': 4087 case 'persistent': $persist = $v; break; 4088 case 'debug': $obj->debug = (integer) $v; break; 4089 #ibase 4090 case 'role': $obj->role = $v; break; 4091 case 'dialect': $obj->dialect = (integer) $v; break; 4092 case 'charset': $obj->charset = $v; $obj->charSet=$v; break; 4093 case 'buffers': $obj->buffers = $v; break; 4094 case 'fetchmode': $obj->SetFetchMode($v); break; 4095 #ado 4096 case 'charpage': $obj->charPage = $v; break; 4097 #mysql, mysqli 4098 case 'clientflags': $obj->clientFlags = $v; break; 4099 #mysql, mysqli, postgres 4100 case 'port': $obj->port = $v; break; 4101 #mysqli 4102 case 'socket': $obj->socket = $v; break; 4103 #oci8 4104 case 'nls_date_format': $obj->NLS_DATE_FORMAT = $v; break; 4105 } 4106 } 4107 if (empty($persist)) 4108 $ok = $obj->Connect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']); 4109 else if (empty($nconnect)) 4110 $ok = $obj->PConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']); 4111 else 4112 $ok = $obj->NConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']); 4113 4114 if (!$ok) return $false; 4115 } 4116 } 4117 return $obj; 4118 } 4119 4120 4121 4122 // $perf == true means called by NewPerfMonitor(), otherwise for data dictionary 4123 function _adodb_getdriver($provider,$drivername,$perf=false) 4124 { 4125 switch ($provider) { 4126 case 'odbtp': if (strncmp('odbtp_',$drivername,6)==0) return substr($drivername,6); 4127 case 'odbc' : if (strncmp('odbc_',$drivername,5)==0) return substr($drivername,5); 4128 case 'ado' : if (strncmp('ado_',$drivername,4)==0) return substr($drivername,4); 4129 case 'native': break; 4130 default: 4131 return $provider; 4132 } 4133 4134 switch($drivername) { 4135 case 'mysqlt': 4136 case 'mysqli': 4137 $drivername='mysql'; 4138 break; 4139 case 'postgres7': 4140 case 'postgres8': 4141 $drivername = 'postgres'; 4142 break; 4143 case 'firebird15': $drivername = 'firebird'; break; 4144 case 'oracle': $drivername = 'oci8'; break; 4145 case 'access': if ($perf) $drivername = ''; break; 4146 case 'db2' : break; 4147 case 'sapdb' : break; 4148 default: 4149 $drivername = 'generic'; 4150 break; 4151 } 4152 return $drivername; 4153 } 4154 4155 function &NewPerfMonitor(&$conn) 4156 { 4157 $false = false; 4158 $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType,true); 4159 if (!$drivername || $drivername == 'generic') return $false; 4160 include_once(ADODB_DIR.'/adodb-perf.inc.php'); 4161 @include_once(ADODB_DIR."/perf/perf-$drivername.inc.php"); 4162 $class = "Perf_$drivername"; 4163 if (!class_exists($class)) return $false; 4164 $perf = new $class($conn); 4165 4166 return $perf; 4167 } 4168 4169 function &NewDataDictionary(&$conn,$drivername=false) 4170 { 4171 $false = false; 4172 if (!$drivername) $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType); 4173 4174 include_once(ADODB_DIR.'/adodb-lib.inc.php'); 4175 include_once(ADODB_DIR.'/adodb-datadict.inc.php'); 4176 $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php"; 4177 4178 if (!file_exists($path)) { 4179 ADOConnection::outp("Dictionary driver '$path' not available"); 4180 return $false; 4181 } 4182 include_once($path); 4183 $class = "ADODB2_$drivername"; 4184 $dict = new $class(); 4185 $dict->dataProvider = $conn->dataProvider; 4186 $dict->connection = &$conn; 4187 $dict->upperName = strtoupper($drivername); 4188 $dict->quote = $conn->nameQuote; 4189 if (!empty($conn->_connectionID)) 4190 $dict->serverInfo = $conn->ServerInfo(); 4191 4192 return $dict; 4193 } 4194 4195 4196 4197 /* 4198 Perform a print_r, with pre tags for better formatting. 4199 */ 4200 function adodb_pr($var,$as_string=false) 4201 { 4202 if ($as_string) ob_start(); 4203 4204 if (isset($_SERVER['HTTP_USER_AGENT'])) { 4205 echo " <pre>\n";print_r($var);echo "</pre>\n"; 4206 } else 4207 print_r($var); 4208 4209 if ($as_string) { 4210 $s = ob_get_contents(); 4211 ob_end_clean(); 4212 return $s; 4213 } 4214 } 4215 4216 /* 4217 Perform a stack-crawl and pretty print it. 4218 4219 @param printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then). 4220 @param levels Number of levels to display 4221 */ 4222 function adodb_backtrace($printOrArr=true,$levels=9999) 4223 { 4224 global $ADODB_INCLUDED_LIB; 4225 if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); 4226 return _adodb_backtrace($printOrArr,$levels); 4227 } 4228 4229 4230} 4231?> 4232