[ Index ]
 

Code source de Mantis 1.1.0rc3

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

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


Généré le : Thu Nov 29 09:42:17 2007 par Balluche grâce ŕ PHPXref 0.7
  Clicky Web Analytics