[ Index ]
 

Code source de vtiger CRM 5.0.2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/adodb/ -> adodb.inc.php (source)

   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 = '&nbsp;';
 260      var $emptyTimeStamp = '&nbsp;';
 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 = '&nbsp;'; /// what to display when $time==0
2643      var $emptyDate = '&nbsp;'; /// 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  ?>


Généré le : Sun Feb 25 10:22:19 2007 par Balluche grâce ŕ PHPXref 0.7