[ Index ]

PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008]

title

Body

[close]

/lib/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.98 13 Feb 2008  (c) 2000-2008 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.98 13 Feb 2008 (c) 2000-2008 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            
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            } else
1349              $rv = false;
1350            return $rv;
1351      }
1352      
1353  	function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false)
1354      {
1355            $rs = &$this->CacheExecute($secs, $sql, $inputarr);
1356            if ($rs) {
1357              $rv = array();
1358              if ($trim) {
1359                  while (!$rs->EOF) {
1360                      $rv[] = trim(reset($rs->fields));
1361                      $rs->MoveNext();
1362                     }
1363              } else {
1364                  while (!$rs->EOF) {
1365                      $rv[] = reset($rs->fields);
1366                      $rs->MoveNext();
1367                     }
1368              }
1369                 $rs->Close();
1370            } else        
1371                $rv = false;
1372            
1373          return $rv;
1374      }
1375      
1376      function &Transpose(&$rs,$addfieldnames=true)
1377      {
1378          $rs2 =& $this->_rs2rs($rs);
1379          $false = false;
1380          if (!$rs2) return $false;
1381          
1382          $rs2->_transpose($addfieldnames);
1383          return $rs2;
1384      }
1385   
1386      /*
1387          Calculate the offset of a date for a particular database and generate
1388              appropriate SQL. Useful for calculating future/past dates and storing
1389              in a database.
1390              
1391          If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
1392      */
1393  	function OffsetDate($dayFraction,$date=false)
1394      {        
1395          if (!$date) $date = $this->sysDate;
1396          return  '('.$date.'+'.$dayFraction.')';
1397      }
1398      
1399      
1400      /**
1401      *
1402      * @param sql            SQL statement
1403      * @param [inputarr]        input bind array
1404      */
1405      function &GetArray($sql,$inputarr=false)
1406      {
1407      global $ADODB_COUNTRECS;
1408          
1409          $savec = $ADODB_COUNTRECS;
1410          $ADODB_COUNTRECS = false;
1411          $rs =& $this->Execute($sql,$inputarr);
1412          $ADODB_COUNTRECS = $savec;
1413          if (!$rs) 
1414              if (defined('ADODB_PEAR')) {
1415                  $cls = ADODB_PEAR_Error();
1416                  return $cls;
1417              } else {
1418                  $false = false;
1419                  return $false;
1420              }
1421          $arr =& $rs->GetArray();
1422          $rs->Close();
1423          return $arr;
1424      }
1425      
1426      function &CacheGetAll($secs2cache,$sql=false,$inputarr=false)
1427      {
1428          $arr =& $this->CacheGetArray($secs2cache,$sql,$inputarr);
1429          return $arr;
1430      }
1431      
1432      function &CacheGetArray($secs2cache,$sql=false,$inputarr=false)
1433      {
1434      global $ADODB_COUNTRECS;
1435          
1436          $savec = $ADODB_COUNTRECS;
1437          $ADODB_COUNTRECS = false;
1438          $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1439          $ADODB_COUNTRECS = $savec;
1440          
1441          if (!$rs) 
1442              if (defined('ADODB_PEAR')) {
1443                  $cls = ADODB_PEAR_Error();
1444                  return $cls;
1445              } else {
1446                  $false = false;
1447                  return $false;
1448              }
1449          $arr =& $rs->GetArray();
1450          $rs->Close();
1451          return $arr;
1452      }
1453      
1454  	function GetRandRow($sql, $arr= false)
1455      {
1456          $rezarr = $this->GetAll($sql, $arr);
1457          $sz = sizeof($rez);
1458          return $rezarr[abs(rand()) % $sz];
1459      }
1460      
1461      /**
1462      * Return one row of sql statement. Recordset is disposed for you.
1463      *
1464      * @param sql            SQL statement
1465      * @param [inputarr]        input bind array
1466      */
1467      function &GetRow($sql,$inputarr=false)
1468      {
1469      global $ADODB_COUNTRECS;
1470          $crecs = $ADODB_COUNTRECS;
1471          $ADODB_COUNTRECS = false;
1472          
1473          $rs =& $this->Execute($sql,$inputarr);
1474          
1475          $ADODB_COUNTRECS = $crecs;
1476          if ($rs) {
1477              if (!$rs->EOF) $arr = $rs->fields;
1478              else $arr = array();
1479              $rs->Close();
1480              return $arr;
1481          }
1482          
1483          $false = false;
1484          return $false;
1485      }
1486      
1487      function &CacheGetRow($secs2cache,$sql=false,$inputarr=false)
1488      {
1489          $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1490          if ($rs) {
1491              $arr = array();
1492              if (!$rs->EOF) $arr = $rs->fields;
1493              $rs->Close();
1494              return $arr;
1495          }
1496          $false = false;
1497          return $false;
1498      }
1499      
1500      /**
1501      * Insert or replace a single record. Note: this is not the same as MySQL's replace. 
1502      * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
1503      * Also note that no table locking is done currently, so it is possible that the
1504      * record be inserted twice by two programs...
1505      *
1506      * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
1507      *
1508      * $table        table name
1509      * $fieldArray    associative array of data (you must quote strings yourself).
1510      * $keyCol        the primary key field name or if compound key, array of field names
1511      * autoQuote        set to true to use a hueristic to quote strings. Works with nulls and numbers
1512      *                    but does not work with dates nor SQL functions.
1513      * has_autoinc    the primary key is an auto-inc field, so skip in insert.
1514      *
1515      * Currently blob replace not supported
1516      *
1517      * returns 0 = fail, 1 = update, 2 = insert 
1518      */
1519      
1520  	function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false)
1521      {
1522          global $ADODB_INCLUDED_LIB;
1523          if (empty($ADODB_INCLUDED_LIB)) include (ADODB_DIR.'/adodb-lib.inc.php');
1524          
1525          return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);
1526      }
1527      
1528      
1529      /**
1530      * Will select, getting rows from $offset (1-based), for $nrows. 
1531      * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1532      * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1533      * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1534      * eg. 
1535      *  CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
1536      *  CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
1537      *
1538      * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
1539      *
1540      * @param [secs2cache]    seconds to cache data, set to 0 to force query. This is optional
1541      * @param sql
1542      * @param [offset]    is the row to start calculations from (1-based)
1543      * @param [nrows]    is the number of rows to get
1544      * @param [inputarr]    array of bind variables
1545      * @return        the recordset ($rs->databaseType == 'array')
1546       */
1547      function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false)
1548      {    
1549          if (!is_numeric($secs2cache)) {
1550              if ($sql === false) $sql = -1;
1551              if ($offset == -1) $offset = false;
1552                                        // sql,    nrows, offset,inputarr
1553              $rs =& $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs);
1554          } else {
1555              if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()");
1556              $rs =& $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
1557          }
1558          return $rs;
1559      }
1560      
1561      
1562      /**
1563      * Flush cached recordsets that match a particular $sql statement. 
1564      * If $sql == false, then we purge all files in the cache.
1565       */
1566      
1567      /**
1568     * Flush cached recordsets that match a particular $sql statement. 
1569     * If $sql == false, then we purge all files in the cache.
1570      */
1571  	function CacheFlush($sql=false,$inputarr=false)
1572      {
1573      global $ADODB_CACHE_DIR;
1574      
1575          if ($this->memCache) {
1576          global $ADODB_INCLUDED_MEMCACHE;
1577          
1578              $key = false;
1579              if (empty($ADODB_INCLUDED_MEMCACHE)) include (ADODB_DIR.'/adodb-memcache.lib.inc.php');
1580              if ($sql) $key = $this->_gencachename($sql.serialize($inputarr),false,true);
1581              FlushMemCache($key, $this->memCacheHost, $this->memCachePort, $this->debug);
1582              return;
1583          }
1584      
1585          if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
1586           /*if (strncmp(PHP_OS,'WIN',3) === 0)
1587              $dir = str_replace('/', '\\', $ADODB_CACHE_DIR);
1588           else */
1589              $dir = $ADODB_CACHE_DIR;
1590              
1591           if ($this->debug) {
1592              ADOConnection::outp( "CacheFlush: $dir<br><pre>\n". $this->_dirFlush($dir)."</pre>");
1593           } else {
1594              $this->_dirFlush($dir);
1595           }
1596           return;
1597        } 
1598        
1599        global $ADODB_INCLUDED_CSV;
1600        if (empty($ADODB_INCLUDED_CSV)) include (ADODB_DIR.'/adodb-csvlib.inc.php');
1601        
1602        $f = $this->_gencachename($sql.serialize($inputarr),false);
1603        adodb_write_file($f,''); // is adodb_write_file needed?
1604        if (!@unlink($f)) {
1605           if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f");
1606        }
1607     }
1608     
1609     /**
1610     * Private function to erase all of the files and subdirectories in a directory.
1611     *
1612     * Just specify the directory, and tell it if you want to delete the directory or just clear it out.
1613     * Note: $kill_top_level is used internally in the function to flush subdirectories.
1614     */
1615     function _dirFlush($dir, $kill_top_level = false) 
1616     {
1617        if(!$dh = @opendir($dir)) return;
1618        
1619        while (($obj = readdir($dh))) {
1620           if($obj=='.' || $obj=='..') continue;
1621          $f = $dir.'/'.$obj;
1622          
1623          if (strpos($obj,'.cache')) @unlink($f);
1624          if (is_dir($f)) $this->_dirFlush($f, true);
1625        }
1626        if ($kill_top_level === true) @rmdir($dir);
1627        return true;
1628     }
1629     
1630     
1631  	function xCacheFlush($sql=false,$inputarr=false)
1632      {
1633      global $ADODB_CACHE_DIR;
1634      
1635          if ($this->memCache) {
1636              global $ADODB_INCLUDED_MEMCACHE;
1637              $key = false;
1638              if (empty($ADODB_INCLUDED_MEMCACHE)) include (ADODB_DIR.'/adodb-memcache.lib.inc.php');
1639              if ($sql) $key = $this->_gencachename($sql.serialize($inputarr),false,true);
1640              flushmemCache($key, $this->memCacheHost, $this->memCachePort, $this->debug);
1641              return;
1642          }
1643  
1644          if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
1645              if (strncmp(PHP_OS,'WIN',3) === 0) {
1646                  $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
1647              } else {
1648                  //$cmd = 'find "'.$ADODB_CACHE_DIR.'" -type f -maxdepth 1 -print0 | xargs -0 rm -f';
1649                  $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/[0-9a-f][0-9a-f]/'; 
1650                  // old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`';
1651              }
1652              if ($this->debug) {
1653                  ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>");
1654              } else {
1655                  exec($cmd);
1656              }
1657              return;
1658          } 
1659          
1660          global $ADODB_INCLUDED_CSV;
1661          if (empty($ADODB_INCLUDED_CSV)) include (ADODB_DIR.'/adodb-csvlib.inc.php');
1662          
1663          $f = $this->_gencachename($sql.serialize($inputarr),false);
1664          adodb_write_file($f,''); // is adodb_write_file needed?
1665          if (!@unlink($f)) {
1666              if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f");
1667          }
1668      }
1669      
1670      /**
1671      * Private function to generate filename for caching.
1672      * Filename is generated based on:
1673      *
1674      *  - sql statement
1675      *  - database type (oci8, ibase, ifx, etc)
1676      *  - database name
1677      *  - userid
1678      *  - setFetchMode (adodb 4.23)
1679      *
1680      * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR). 
1681      * Assuming that we can have 50,000 files per directory with good performance, 
1682      * then we can scale to 12.8 million unique cached recordsets. Wow!
1683       */
1684  	function _gencachename($sql,$createdir,$memcache=false)
1685      {
1686      global $ADODB_CACHE_DIR;
1687      static $notSafeMode;
1688          
1689          if ($this->fetchMode === false) { 
1690          global $ADODB_FETCH_MODE;
1691              $mode = $ADODB_FETCH_MODE;
1692          } else {
1693              $mode = $this->fetchMode;
1694          }
1695          $m = md5($sql.$this->databaseType.$this->database.$this->user.$mode);
1696          if ($memcache) return $m;
1697          
1698          if (!isset($notSafeMode)) $notSafeMode = !ini_get('safe_mode');
1699          $dir = ($notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($m,0,2) : $ADODB_CACHE_DIR;
1700              
1701          if ($createdir && $notSafeMode && !file_exists($dir)) {
1702              $oldu = umask(0);
1703              if (!@mkdir($dir,0771)) 
1704                   if(!is_dir($dir) && $this->debug) ADOConnection::outp( "Unable to mkdir $dir for $sql");
1705              umask($oldu);
1706          }
1707          return $dir.'/adodb_'.$m.'.cache';
1708      }
1709      
1710      
1711      /**
1712       * Execute SQL, caching recordsets.
1713       *
1714       * @param [secs2cache]    seconds to cache data, set to 0 to force query. 
1715       *                      This is an optional parameter.
1716       * @param sql        SQL statement to execute
1717       * @param [inputarr]    holds the input data  to bind to
1718       * @return         RecordSet or false
1719       */
1720      function &CacheExecute($secs2cache,$sql=false,$inputarr=false)
1721      {
1722  
1723              
1724          if (!is_numeric($secs2cache)) {
1725              $inputarr = $sql;
1726              $sql = $secs2cache;
1727              $secs2cache = $this->cacheSecs;
1728          }
1729          
1730          if (is_array($sql)) {
1731              $sqlparam = $sql;
1732              $sql = $sql[0];
1733          } else
1734              $sqlparam = $sql;
1735              
1736          if ($this->memCache) {
1737              global $ADODB_INCLUDED_MEMCACHE;
1738              if (empty($ADODB_INCLUDED_MEMCACHE)) include (ADODB_DIR.'/adodb-memcache.lib.inc.php');
1739              $md5file = $this->_gencachename($sql.serialize($inputarr),false,true);
1740          } else {
1741          global $ADODB_INCLUDED_CSV;
1742              if (empty($ADODB_INCLUDED_CSV)) include (ADODB_DIR.'/adodb-csvlib.inc.php');
1743              $md5file = $this->_gencachename($sql.serialize($inputarr),true);
1744          }
1745  
1746          $err = '';
1747          
1748          if ($secs2cache > 0){
1749              if ($this->memCache)
1750                  $rs = &getmemCache($md5file,$err,$secs2cache, $this->memCacheHost, $this->memCachePort);
1751              else
1752                  $rs = &csv2rs($md5file,$err,$secs2cache,$this->arrayClass);
1753              $this->numCacheHits += 1;
1754          } else {
1755              $err='Timeout 1';
1756              $rs = false;
1757              $this->numCacheMisses += 1;
1758          }
1759          if (!$rs) {
1760          // no cached rs found
1761              if ($this->debug) {
1762                  if (get_magic_quotes_runtime() && !$this->memCache) {
1763                      ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
1764                  }
1765                  if ($this->debug !== -1) ADOConnection::outp( " $md5file cache failure: $err (see sql below)");
1766              }
1767              
1768              $rs = &$this->Execute($sqlparam,$inputarr);
1769  
1770              if ($rs && $this->memCache) {
1771                  $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately
1772                  if(!putmemCache($md5file, $rs, $this->memCacheHost, $this->memCachePort, $this->memCacheCompress, $this->debug)) {
1773                      if ($fn = $this->raiseErrorFn)
1774                          $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);
1775                      if ($this->debug) ADOConnection::outp( " Cache write error");
1776                  }
1777              } else if ($rs) {
1778                  $eof = $rs->EOF;
1779                  $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately
1780                  $txt = _rs2serialize($rs,false,$sql); // serialize
1781          
1782                  $ok = adodb_write_file($md5file,$txt,$this->debug);
1783                  if (!$ok) {
1784                      if ($ok === false) {
1785                          $em = 'Cache write error';
1786                          $en = -32000;
1787                          
1788                          if ($fn = $this->raiseErrorFn) {
1789                              $fn($this->databaseType,'CacheExecute', $en, $em, $md5file,$sql,$this);
1790                          }
1791                      } else {
1792                          $em = 'Cache file locked warning';
1793                          $en = -32001;
1794                          // do not call error handling for just a warning
1795                      }
1796                      
1797                      if ($this->debug) ADOConnection::outp( " ".$em);
1798                  }
1799                  if ($rs->EOF && !$eof) {
1800                      $rs->MoveFirst();
1801                      //$rs = &csv2rs($md5file,$err);        
1802                      $rs->connection = &$this; // Pablo suggestion
1803                  }  
1804                  
1805              } else
1806              if (!$this->memCache)
1807                  @unlink($md5file);
1808          } else {
1809              $this->_errorMsg = '';
1810              $this->_errorCode = 0;
1811              
1812              if ($this->fnCacheExecute) {
1813                  $fn = $this->fnCacheExecute;
1814                  $fn($this, $secs2cache, $sql, $inputarr);
1815              }
1816          // ok, set cached object found
1817              $rs->connection = &$this; // Pablo suggestion
1818              if ($this->debug){ 
1819                      
1820                  $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
1821                  $ttl = $rs->timeCreated + $secs2cache - time();
1822                  $s = is_array($sql) ? $sql[0] : $sql;
1823                  if ($inBrowser) $s = '<i>'.htmlspecialchars($s).'</i>';
1824                  
1825                  ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
1826              }
1827          }
1828          return $rs;
1829      }
1830      
1831      
1832      /* 
1833          Similar to PEAR DB's autoExecute(), except that 
1834          $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
1835          If $mode == 'UPDATE', then $where is compulsory as a safety measure.
1836          
1837          $forceUpdate means that even if the data has not changed, perform update.
1838       */
1839      function& AutoExecute($table, $fields_values, $mode = 'INSERT', $where = FALSE, $forceUpdate=true, $magicq=false) 
1840      {
1841          $false = false;
1842          $sql = 'SELECT * FROM '.$table;  
1843          if ($where!==FALSE) $sql .= ' WHERE '.$where;
1844          else if ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) {
1845              ADOConnection::outp('AutoExecute: Illegal mode=UPDATE with empty WHERE clause');
1846              return $false;
1847          }
1848  
1849          $rs =& $this->SelectLimit($sql,1);
1850          if (!$rs) return $false; // table does not exist
1851          $rs->tableName = $table;
1852          
1853          switch((string) $mode) {
1854          case 'UPDATE':
1855          case '2':
1856              $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq);
1857              break;
1858          case 'INSERT':
1859          case '1':
1860              $sql = $this->GetInsertSQL($rs, $fields_values, $magicq);
1861              break;
1862          default:
1863              ADOConnection::outp("AutoExecute: Unknown mode=$mode");
1864              return $false;
1865          }
1866          $ret = false;
1867          if ($sql) $ret = $this->Execute($sql);
1868          if ($ret) $ret = true;
1869          return $ret;
1870      }
1871      
1872      
1873      /**
1874       * Generates an Update Query based on an existing recordset.
1875       * $arrFields is an associative array of fields with the value
1876       * that should be assigned.
1877       *
1878       * Note: This function should only be used on a recordset
1879       *       that is run against a single table and sql should only 
1880       *         be a simple select stmt with no groupby/orderby/limit
1881       *
1882       * "Jonathan Younger" <jyounger@unilab.com>
1883         */
1884  	function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null)
1885      {
1886          global $ADODB_INCLUDED_LIB;
1887  
1888          //********************************************************//
1889          //This is here to maintain compatibility
1890          //with older adodb versions. Sets force type to force nulls if $forcenulls is set.
1891          if (!isset($force)) {
1892                  global $ADODB_FORCE_TYPE;
1893                  $force = $ADODB_FORCE_TYPE;
1894          }
1895          //********************************************************//
1896  
1897          if (empty($ADODB_INCLUDED_LIB)) include (ADODB_DIR.'/adodb-lib.inc.php');
1898          return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
1899      }
1900  
1901      /**
1902       * Generates an Insert Query based on an existing recordset.
1903       * $arrFields is an associative array of fields with the value
1904       * that should be assigned.
1905       *
1906       * Note: This function should only be used on a recordset
1907       *       that is run against a single table.
1908         */
1909  	function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null)
1910      {    
1911          global $ADODB_INCLUDED_LIB;
1912          if (!isset($force)) {
1913              global $ADODB_FORCE_TYPE;
1914              $force = $ADODB_FORCE_TYPE;
1915              
1916          }
1917          if (empty($ADODB_INCLUDED_LIB)) include (ADODB_DIR.'/adodb-lib.inc.php');
1918          return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
1919      }
1920      
1921  
1922      /**
1923      * Update a blob column, given a where clause. There are more sophisticated
1924      * blob handling functions that we could have implemented, but all require
1925      * a very complex API. Instead we have chosen something that is extremely
1926      * simple to understand and use. 
1927      *
1928      * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
1929      *
1930      * Usage to update a $blobvalue which has a primary key blob_id=1 into a 
1931      * field blobtable.blobcolumn:
1932      *
1933      *    UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
1934      *
1935      * Insert example:
1936      *
1937      *    $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
1938      *    $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
1939      */
1940      
1941  	function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
1942      {
1943          return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
1944      }
1945  
1946      /**
1947      * Usage:
1948      *    UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
1949      *    
1950      *    $blobtype supports 'BLOB' and 'CLOB'
1951      *
1952      *    $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
1953      *    $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
1954      */
1955  	function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
1956      {
1957          $fd = fopen($path,'rb');
1958          if ($fd === false) return false;
1959          $val = fread($fd,filesize($path));
1960          fclose($fd);
1961          return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
1962      }
1963      
1964  	function BlobDecode($blob)
1965      {
1966          return $blob;
1967      }
1968      
1969  	function BlobEncode($blob)
1970      {
1971          return $blob;
1972      }
1973      
1974  	function SetCharSet($charset)
1975      {
1976          return false;
1977      }
1978      
1979  	function IfNull( $field, $ifNull ) 
1980      {
1981          return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
1982      }
1983      
1984  	function LogSQL($enable=true)
1985      {
1986          include_once (ADODB_DIR.'/adodb-perf.inc.php');
1987          
1988          if ($enable) $this->fnExecute = 'adodb_log_sql';
1989          else $this->fnExecute = false;
1990