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