PHPOpenChat PHP Cross Reference Customer Relationship Management

Source: /include/adodb/adodb.inc.php - 3824 lines - 112996 bytes - Summary - Text - Print

   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.61 24 Feb 2005  (c) 2000-2005 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://php.weblogs.com/adodb<br>

  32      Manual is at http://php.weblogs.com/adodb_manual

  33        

  34   */
  35   
  36   if (!defined('_ADODB_LAYER')) {
  37       define('_ADODB_LAYER',1);
  38      
  39      //==============================================================================================    

  40      // CONSTANT DEFINITIONS

  41      //==============================================================================================    

  42  
  43  
  44      /** 

  45       * Set ADODB_DIR to the directory where this file resides...

  46       * This constant was formerly called $ADODB_RootPath

  47       */
  48      if (!defined('ADODB_DIR')) define('ADODB_DIR',dirname(__FILE__));
  49      
  50      //==============================================================================================    

  51      // GLOBAL VARIABLES

  52      //==============================================================================================    

  53  
  54      GLOBAL 
  55          $ADODB_vers,         // database version
  56          $ADODB_COUNTRECS,    // count number of records returned - slows down query
  57          $ADODB_CACHE_DIR,    // directory to cache recordsets
  58          $ADODB_EXTENSION,   // ADODB extension installed
  59          $ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF
  60           $ADODB_FETCH_MODE;    // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...

  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.0) {
 115              define('ADODB_PHPVER',0x5000);
 116          } else if ($_adodb_ver > 4.299999) { # 4.3
 117              define('ADODB_PHPVER',0x4300);
 118          } else if ($_adodb_ver > 4.199999) { # 4.2
 119              define('ADODB_PHPVER',0x4200);
 120          } else if (strnatcmp(PHP_VERSION,'4.0.5')>=0) {
 121              define('ADODB_PHPVER',0x4050);
 122          } else {
 123              define('ADODB_PHPVER',0x4000);
 124          }
 125      }
 126      
 127      //if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);

 128  
 129      
 130      /**

 131           Accepts $src and $dest arrays, replacing string $data

 132      */
 133  	function ADODB_str_replace($src, $dest, $data)
 134      {
 135          if (ADODB_PHPVER >= 0x4050) return str_replace($src,$dest,$data);
 136          
 137          $s = reset($src);
 138          $d = reset($dest);
 139          while ($s !== false) {
 140              $data = str_replace($s,$d,$data);
 141              $s = next($src);
 142              $d = next($dest);
 143          }
 144          return $data;
 145      }
 146      
 147  	function ADODB_Setup()
 148      {
 149      GLOBAL 
 150          $ADODB_vers,         // database version
 151          $ADODB_COUNTRECS,    // count number of records returned - slows down query
 152          $ADODB_CACHE_DIR,    // directory to cache recordsets
 153           $ADODB_FETCH_MODE,
 154          $ADODB_FORCE_TYPE;
 155          
 156          $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
 157          $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE;
 158  
 159  
 160          if (!isset($ADODB_CACHE_DIR)) {
 161              $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp';

 162          } else {
 163              // do not accept url based paths, eg. http:/ or ftp:/

 164              if (strpos($ADODB_CACHE_DIR,'://') !== false) 
 165                  die("Illegal path http:// or ftp://");
 166          }
 167          
 168              
 169          // Initialize random number generator for randomizing cache flushes

 170          srand(((double)microtime())*1000000);
 171          
 172          /**

 173           * ADODB version as a string.

 174           */
 175          $ADODB_vers = 'V4.61 24 Feb 2005  (c) 2000-2005 John Lim (jlim#natsoft.com.my). All rights reserved. Released BSD & LGPL.';
 176      
 177          /**

 178           * Determines whether recordset->RecordCount() is used. 

 179           * Set to false for highest performance -- RecordCount() will always return -1 then

 180           * for databases that provide "virtual" recordcounts...

 181           */
 182          if (!isset($ADODB_COUNTRECS)) $ADODB_COUNTRECS = true; 
 183      }
 184      
 185      
 186      //==============================================================================================    

 187      // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB

 188      //==============================================================================================    

 189      
 190      ADODB_Setup();
 191  
 192      //==============================================================================================    

 193      // CLASS ADOFieldObject

 194      //==============================================================================================    

 195      /**

 196       * Helper class for FetchFields -- holds info on a column

 197       */
 198      class ADOFieldObject { 
 199          var $name = '';
 200          var $max_length=0;
 201          var $type="";
 202  /*

 203          // additional fields by dannym... (danny_milo@yahoo.com)

 204          var $not_null = false; 

 205          // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^

 206          // so we can as well make not_null standard (leaving it at "false" does not harm anyways)

 207  

 208          var $has_default = false; // this one I have done only in mysql and postgres for now ... 

 209              // others to come (dannym)

 210          var $default_value; // default, if any, and supported. Check has_default first.

 211  */
 212      }
 213      
 214  
 215      
 216  	function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection)
 217      {
 218          //print "Errorno ($fn errno=$errno m=$errmsg) ";

 219          $thisConnection->_transOK = false;
 220          if ($thisConnection->_oldRaiseFn) {
 221              $fn = $thisConnection->_oldRaiseFn;
 222              $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
 223          }
 224      }
 225      
 226      //==============================================================================================    

 227      // CLASS ADOConnection

 228      //==============================================================================================    

 229      
 230      /**

 231       * Connection object. For connecting to databases, and executing queries.

 232       */ 
 233      class ADOConnection {
 234      //

 235      // PUBLIC VARS 

 236      //

 237      var $dataProvider = 'native';
 238      var $databaseType = '';        /// RDBMS currently in use, eg. odbc, mysql, mssql                    

 239      var $database = '';            /// Name of database to be used.    

 240      var $host = '';             /// The hostname of the database server    

 241      var $user = '';             /// The username which is used to connect to the database server. 

 242      var $password = '';         /// Password for the username. For security, we no longer store it.

 243      var $debug = false;         /// if set to true will output sql statements

 244      var $maxblobsize = 262144;     /// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxpro

 245      var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase    

 246      var $substr = 'substr';        /// substring operator

 247      var $length = 'length';        /// string length operator

 248      var $random = 'rand()';        /// random function

 249      var $upperCase = 'upper';        /// uppercase function

 250      var $fmtDate = "'Y-m-d'";    /// used by DBDate() as the default date format used by the database

 251      var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt.

 252      var $true = '1';             /// string that represents TRUE for a database

 253      var $false = '0';             /// string that represents FALSE for a database

 254      var $replaceQuote = "\\'";     /// string to use to replace quotes

 255      var $nameQuote = '"';        /// string to use to quote identifiers and names

 256      var $charSet=false;         /// character set to use - only for interbase, postgres and oci8

 257      var $metaDatabasesSQL = '';
 258      var $metaTablesSQL = '';
 259      var $uniqueOrderBy = false; /// All order by columns have to be unique

 260      var $emptyDate = '&nbsp;';
 261      var $emptyTimeStamp = '&nbsp;';
 262      var $lastInsID = false;
 263      //--

 264      var $hasInsertID = false;         /// supports autoincrement ID?

 265      var $hasAffectedRows = false;     /// supports affected rows for update/delete?

 266      var $hasTop = false;            /// support mssql/access SELECT TOP 10 * FROM TABLE

 267      var $hasLimit = false;            /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10

 268      var $readOnly = false;             /// this is a readonly database - used by phpLens

 269      var $hasMoveFirst = false;  /// has ability to run MoveFirst(), scrolling backwards

 270      var $hasGenID = false;         /// can generate sequences using GenID();

 271      var $hasTransactions = true; /// has transactions

 272      //--

 273      var $genID = 0;             /// sequence id used by GenID();

 274      var $raiseErrorFn = false;     /// error function to call

 275      var $isoDates = false; /// accepts dates in ISO format

 276      var $cacheSecs = 3600; /// cache for 1 hour

 277      var $sysDate = false; /// name of function that returns the current date

 278      var $sysTimeStamp = false; /// name of function that returns the current timestamp

 279      var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets

 280      
 281      var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' '

 282      var $numCacheHits = 0; 
 283      var $numCacheMisses = 0;
 284      var $pageExecuteCountRows = true;
 285      var $uniqueSort = false; /// indicates that all fields in order by must be unique

 286      var $leftOuter = false; /// operator to use for left outer join in WHERE clause

 287      var $rightOuter = false; /// operator to use for right outer join in WHERE clause

 288      var $ansiOuter = false; /// whether ansi outer join syntax supported

 289      var $autoRollback = false; // autoRollback on PConnect().

 290      var $poorAffectedRows = false; // affectedRows not working or unreliable

 291      
 292      var $fnExecute = false;
 293      var $fnCacheExecute = false;
 294      var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char

 295      var $rsPrefix = "ADORecordSet_";
 296      
 297      var $autoCommit = true;     /// do not modify this yourself - actually private

 298      var $transOff = 0;             /// temporarily disable transactions

 299      var $transCnt = 0;             /// count of nested transactions

 300      
 301      var $fetchMode=false;
 302       //

 303       // PRIVATE VARS

 304       //

 305      var $_oldRaiseFn =  false;
 306      var $_transOK = null;
 307      var $_connectionID    = false;    /// The returned link identifier whenever a successful database connection is made.    

 308      var $_errorMsg = false;        /// A variable which was used to keep the returned last error message.  The value will

 309                                  /// then returned by the errorMsg() function    

 310      var $_errorCode = false;    /// Last error code, not guaranteed to be used - only by oci8                    

 311      var $_queryID = false;        /// This variable keeps the last created result link identifier

 312      
 313      var $_isPersistentConnection = false;    /// A boolean variable to state whether its a persistent connection or normal connection.    */

 314      var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.

 315      var $_evalAll = false;
 316      var $_affected = false;
 317      var $_logsql = false;
 318      
 319  
 320      
 321      /**

 322       * Constructor

 323       */
 324  	function ADOConnection()            
 325      {
 326          die('Virtual Class -- cannot instantiate');
 327      }
 328      
 329  	function Version()
 330      {
 331      global $ADODB_vers;
 332      
 333          return (float) substr($ADODB_vers,1);
 334      }
 335      
 336      /**

 337          Get server version info...

 338          

 339          @returns An array with 2 elements: $arr['string'] is the description string, 

 340              and $arr[version] is the version (also a string).

 341      */
 342  	function ServerInfo()
 343      {
 344          return array('description' => '', 'version' => '');
 345      }
 346      
 347  	function IsConnected()
 348      {
 349          return !empty($this->_connectionID);
 350      }
 351      
 352  	function _findvers($str)
 353      {
 354          if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) return $arr[1];
 355          else return '';
 356      }
 357      
 358      /**

 359      * All error messages go through this bottleneck function.

 360      * You can define your own handler by defining the function name in ADODB_OUTP.

 361      */
 362  	function outp($msg,$newline=true)
 363      {
 364      global $HTTP_SERVER_VARS,$ADODB_FLUSH,$ADODB_OUTP;
 365      
 366          if (defined('ADODB_OUTP')) {
 367              $fn = ADODB_OUTP;
 368              $fn($msg,$newline);
 369              return;
 370          } else if (isset($ADODB_OUTP)) {
 371              $fn = $ADODB_OUTP;
 372              $fn($msg,$newline);
 373              return;
 374          }
 375          
 376          if ($newline) $msg .= "<br>\n";
 377          
 378          if (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']) || !$newline) echo $msg;
 379          else echo strip_tags($msg);
 380      
 381          
 382          if (!empty($ADODB_FLUSH) && ob_get_length() !== false) flush(); //  do not flush if output buffering enabled - useless - thx to Jesse Mullan 

 383          
 384      }
 385      
 386  	function Time()
 387      {
 388          $rs =& $this->_Execute("select $this->sysTimeStamp");
 389          if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields));
 390          
 391          return false;
 392      }
 393      
 394      /**

 395       * Connect to database

 396       *

 397       * @param [argHostname]        Host to connect to

 398       * @param [argUsername]        Userid to login

 399       * @param [argPassword]        Associated password

 400       * @param [argDatabaseName]    database

 401       * @param [forceNew]        force new connection

 402       *

 403       * @return true or false

 404       */      
 405  	function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) 
 406      {
 407          if ($argHostname != "") $this->host = $argHostname;
 408          if ($argUsername != "") $this->user = $argUsername;
 409          if ($argPassword != "") $this->password = $argPassword; // not stored for security reasons

 410          if ($argDatabaseName != "") $this->database = $argDatabaseName;        
 411          
 412          $this->_isPersistentConnection = false;    
 413          if ($forceNew) {
 414              if ($rez=$this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
 415          } else {
 416               if ($rez=$this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
 417          }
 418          if (isset($rez)) {
 419              $err = $this->ErrorMsg();
 420              if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
 421              $ret = false;
 422          } else {
 423              $err = "Missing extension for ".$this->dataProvider;
 424              $ret = 0;
 425          }
 426          if ($fn = $this->raiseErrorFn) 
 427              $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
 428          
 429          
 430          $this->_connectionID = false;
 431          if ($this->debug) ADOConnection::outp( $this->host.': '.$err);
 432          return $ret;
 433      }    
 434      
 435  	function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
 436      {
 437          return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
 438      }
 439      
 440      
 441      /**

 442       * Always force a new connection to database - currently only works with oracle

 443       *

 444       * @param [argHostname]        Host to connect to

 445       * @param [argUsername]        Userid to login

 446       * @param [argPassword]        Associated password

 447       * @param [argDatabaseName]    database

 448       *

 449       * @return true or false

 450       */      
 451  	function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") 
 452      {
 453          return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
 454      }
 455      
 456      /**

 457       * Establish persistent connect to database

 458       *

 459       * @param [argHostname]        Host to connect to

 460       * @param [argUsername]        Userid to login

 461       * @param [argPassword]        Associated password

 462       * @param [argDatabaseName]    database

 463       *

 464       * @return return true or false

 465       */    
 466  	function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
 467      {
 468          if (defined('ADODB_NEVER_PERSIST')) 
 469              return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
 470          
 471          if ($argHostname != "") $this->host = $argHostname;
 472          if ($argUsername != "") $this->user = $argUsername;
 473          if ($argPassword != "") $this->password = $argPassword;
 474          if ($argDatabaseName != "") $this->database = $argDatabaseName;        
 475              
 476          $this->_isPersistentConnection = true;    
 477          if ($rez = $this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
 478          if (isset($rez)) {
 479              $err = $this->ErrorMsg();
 480              if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
 481              $ret = false;
 482          } else {
 483              $err = "Missing extension for ".$this->dataProvider;
 484              $ret = 0;
 485          }
 486          if ($fn = $this->raiseErrorFn) {
 487              $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
 488          }
 489          
 490          $this->_connectionID = false;
 491          if ($this->debug) ADOConnection::outp( $this->host.': '.$err);
 492          return $ret;
 493      }
 494  
 495      // Format date column in sql string given an input format that understands Y M D

 496  	function SQLDate($fmt, $col=false)
 497      {    
 498          if (!$col) $col = $this->sysDate;
 499          return $col; // child class implement

 500      }
 501      
 502      /**

 503       * Should prepare the sql statement and return the stmt resource.

 504       * For databases that do not support this, we return the $sql. To ensure

 505       * compatibility with databases that do not support prepare:

 506       *

 507       *   $stmt = $db->Prepare("insert into table (id, name) values (?,?)");

 508       *   $db->Execute($stmt,array(1,'Jill')) or die('insert failed');

 509       *   $db->Execute($stmt,array(2,'Joe')) or die('insert failed');

 510       *

 511       * @param sql    SQL to send to database

 512       *

 513       * @return return FALSE, or the prepared statement, or the original sql if

 514       *             if the database does not support prepare.

 515       *

 516       */    
 517  	function Prepare($sql)
 518      {
 519          return $sql;
 520      }
 521      
 522      /**

 523       * Some databases, eg. mssql require a different function for preparing

 524       * stored procedures. So we cannot use Prepare().

 525       *

 526       * Should prepare the stored procedure  and return the stmt resource.

 527       * For databases that do not support this, we return the $sql. To ensure

 528       * compatibility with databases that do not support prepare:

 529       *

 530       * @param sql    SQL to send to database

 531       *

 532       * @return return FALSE, or the prepared statement, or the original sql if

 533       *             if the database does not support prepare.

 534       *

 535       */    
 536  	function PrepareSP($sql,$param=true)
 537      {
 538          return $this->Prepare($sql,$param);
 539      }
 540      
 541      /**

 542      * PEAR DB Compat

 543      */
 544  	function Quote($s)
 545      {
 546          return $this->qstr($s,false);
 547      }
 548      
 549      /**

 550       Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de>

 551      */
 552  	function QMagic($s)
 553      {
 554          return $this->qstr($s,get_magic_quotes_gpc());
 555      }
 556  
 557      function q(&$s)
 558      {
 559          $s = $this->qstr($s,false);
 560      }
 561      
 562      /**

 563      * PEAR DB Compat - do not use internally. 

 564      */
 565  	function ErrorNative()
 566      {
 567          return $this->ErrorNo();
 568      }
 569  
 570      
 571     /**

 572      * PEAR DB Compat - do not use internally. 

 573      */
 574  	function nextId($seq_name)
 575      {
 576          return $this->GenID($seq_name);
 577      }
 578  
 579      /**

 580      *     Lock a row, will escalate and lock the table if row locking not supported

 581      *    will normally free the lock at the end of the transaction

 582      *

 583      *  @param $table    name of table to lock

 584      *  @param $where    where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock

 585      */
 586  	function RowLock($table,$where)
 587      {
 588          return false;
 589      }
 590      
 591  	function CommitLock($table)
 592      {
 593          return $this->CommitTrans();
 594      }
 595      
 596  	function RollbackLock($table)
 597      {
 598          return $this->RollbackTrans();
 599      }
 600      
 601      /**

 602      * PEAR DB Compat - do not use internally. 

 603      *

 604      * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical

 605      *     for easy porting :-)

 606      *

 607      * @param mode    The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM

 608      * @returns        The previous fetch mode

 609      */
 610  	function SetFetchMode($mode)
 611      {    
 612          $old = $this->fetchMode;
 613          $this->fetchMode = $mode;
 614          
 615          if ($old === false) {
 616          global $ADODB_FETCH_MODE;
 617              return $ADODB_FETCH_MODE;
 618          }
 619          return $old;
 620      }
 621      
 622  
 623      /**

 624      * PEAR DB Compat - do not use internally. 

 625      */
 626      function &Query($sql, $inputarr=false)
 627      {
 628          $rs = &$this->Execute($sql, $inputarr);
 629          if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
 630          return $rs;
 631      }
 632  
 633      
 634      /**

 635      * PEAR DB Compat - do not use internally

 636      */
 637      function &LimitQuery($sql, $offset, $count, $params=false)
 638      {
 639          $rs = &$this->SelectLimit($sql, $count, $offset, $params); 
 640          if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
 641          return $rs;
 642      }
 643  
 644      
 645      /**

 646      * PEAR DB Compat - do not use internally

 647      */
 648  	function Disconnect()
 649      {
 650          return $this->Close();
 651      }
 652      
 653      /*

 654           Returns placeholder for parameter, eg.

 655           $DB->Param('a')

 656           

 657           will return ':a' for Oracle, and '?' for most other databases...

 658           

 659           For databases that require positioned params, eg $1, $2, $3 for postgresql,

 660               pass in Param(false) before setting the first parameter.

 661      */
 662  	function Param($name,$type='C')
 663      {
 664          return '?';
 665      }
 666      
 667      /*

 668          InParameter and OutParameter are self-documenting versions of Parameter().

 669      */
 670  	function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
 671      {
 672          return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
 673      }
 674      
 675      /*

 676      */
 677  	function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
 678      {
 679          return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);
 680      
 681      }
 682      
 683      /* 

 684      Usage in oracle

 685          $stmt = $db->Prepare('select * from table where id =:myid and group=:group');

 686          $db->Parameter($stmt,$id,'myid');

 687          $db->Parameter($stmt,$group,'group',64);

 688          $db->Execute();

 689          

 690          @param $stmt Statement returned by Prepare() or PrepareSP().

 691          @param $var PHP variable to bind to

 692          @param $name Name of stored procedure variable name to bind to.

 693          @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.

 694          @param [$maxLen] Holds an maximum length of the variable.

 695          @param [$type] The data type of $var. Legal values depend on driver.

 696  

 697      */
 698  	function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
 699      {
 700          return false;
 701      }
 702      
 703      /**

 704          Improved method of initiating a transaction. Used together with CompleteTrans().

 705          Advantages include:

 706          

 707          a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.

 708             Only the outermost block is treated as a transaction.<br>

 709          b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>

 710          c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block

 711             are disabled, making it backward compatible.

 712      */
 713  	function StartTrans($errfn = 'ADODB_TransMonitor')
 714      {
 715          if ($this->transOff > 0) {
 716              $this->transOff += 1;
 717              return;
 718          }
 719          
 720          $this->_oldRaiseFn = $this->raiseErrorFn;
 721          $this->raiseErrorFn = $errfn;
 722          $this->_transOK = true;
 723          
 724          if ($this->debug && $this->transCnt > 0) ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
 725          $this->BeginTrans();
 726          $this->transOff = 1;
 727      }
 728      
 729      
 730      /**

 731          Used together with StartTrans() to end a transaction. Monitors connection

 732          for sql errors, and will commit or rollback as appropriate.

 733          

 734          @autoComplete if true, monitor sql errors and commit and rollback as appropriate, 

 735          and if set to false force rollback even if no SQL error detected.

 736          @returns true on commit, false on rollback.

 737      */
 738  	function CompleteTrans($autoComplete = true)
 739      {
 740          if ($this->transOff > 1) {
 741              $this->transOff -= 1;
 742              return true;
 743          }
 744          $this->raiseErrorFn = $this->_oldRaiseFn;
 745          
 746          $this->transOff = 0;
 747          if ($this->_transOK && $autoComplete) {
 748              if (!$this->CommitTrans()) {
 749                  $this->_transOK = false;
 750                  if ($this->debug) ADOConnection::outp("Smart Commit failed");
 751              } else
 752                  if ($this->debug) ADOConnection::outp("Smart Commit occurred");
 753          } else {
 754              $this->RollbackTrans();
 755              if ($this->debug) ADOCOnnection::outp("Smart Rollback occurred");
 756          }
 757          
 758          return $this->_transOK;
 759      }
 760      
 761      /*

 762          At the end of a StartTrans/CompleteTrans block, perform a rollback.

 763      */
 764  	function FailTrans()
 765      {
 766          if ($this->debug) 
 767              if ($this->transOff == 0) {
 768                  ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
 769              } else {
 770                  ADOConnection::outp("FailTrans was called");
 771                  adodb_backtrace();
 772              }
 773          $this->_transOK = false;
 774      }
 775      
 776      /**

 777          Check if transaction has failed, only for Smart Transactions.

 778      */
 779  	function HasFailedTrans()
 780      {
 781          if ($this->transOff > 0) return $this->_transOK == false;
 782          return false;
 783      }
 784      
 785      /**

 786       * Execute SQL 

 787       *

 788       * @param sql        SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)

 789       * @param [inputarr]    holds the input data to bind to. Null elements will be set to null.

 790       * @return         RecordSet or false

 791       */
 792      function &Execute($sql,$inputarr=false) 
 793      {
 794          if ($this->fnExecute) {
 795              $fn = $this->fnExecute;
 796              $ret =& $fn($this,$sql,$inputarr);
 797              if (isset($ret)) return $ret;
 798          }
 799          if ($inputarr) {
 800              if (!is_array($inputarr)) $inputarr = array($inputarr);
 801              
 802              $element0 = reset($inputarr);
 803              # is_object check because oci8 descriptors can be passed in

 804              $array_2d = is_array($element0) && !is_object(reset($element0));
 805              
 806              if (!is_array($sql) && !$this->_bindInputArray) {
 807                  $sqlarr = explode('?',$sql);
 808                      
 809                  if (!$array_2d) $inputarr = array($inputarr);
 810                  foreach($inputarr as $arr) {
 811                      $sql = ''; $i = 0;
 812                      foreach($arr as $v) {
 813                          $sql .= $sqlarr[$i];
 814                          // from Ron Baldwin <ron.baldwin#sourceprose.com>

 815                          // Only quote string types    

 816                          $typ = gettype($v);
 817                          if ($typ == 'string')
 818                              $sql .= $this->qstr($v);
 819                          else if ($typ == 'double')
 820                              $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1

 821                          else if ($v === null)
 822                              $sql .= 'NULL';
 823                          else
 824                              $sql .= $v;
 825                          $i += 1;
 826                      }
 827                      if (isset($sqlarr[$i])) {
 828                          $sql .= $sqlarr[$i];
 829                          if ($i+1 != sizeof($sqlarr)) ADOConnection::outp( "Input Array does not match ?: ".htmlspecialchars($sql));
 830                      } else if ($i != sizeof($sqlarr))    
 831                          ADOConnection::outp( "Input array does not match ?: ".htmlspecialchars($sql));
 832          
 833                      $ret =& $this->_Execute($sql);
 834                      if (!$ret) return $ret;
 835                  }    
 836              } else {
 837                  if ($array_2d) {
 838                      $stmt = $this->Prepare($sql);
 839                      foreach($inputarr as $arr) {
 840                          $ret =& $this->_Execute($stmt,$arr);
 841                          if (!$ret) return $ret;
 842                      }
 843                  } else {
 844                      $ret =& $this->_Execute($sql,$inputarr);
 845                  }
 846              }
 847          } else {
 848              $ret =& $this->_Execute($sql,false);
 849          }
 850  
 851          return $ret;
 852      }
 853      
 854      
 855      function &_Execute($sql,$inputarr=false)
 856      {
 857  
 858          if ($this->debug) {
 859              global $ADODB_INCLUDED_LIB;
 860              if (empty($ADODB_INCLUDED_LIB)) include_once (ADODB_DIR.'/adodb-lib.inc.php');
 861              $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr);
 862          } else {
 863              $this->_queryID = @$this->_query($sql,$inputarr);
 864          }
 865          
 866          /************************

 867          // OK, query executed

 868          *************************/
 869  
 870          if ($this->_queryID === false) { // error handling if query fails
 871              if ($this->debug == 99) adodb_backtrace(true,5);    
 872              $fn = $this->raiseErrorFn;
 873              if ($fn) {
 874                  $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
 875              } 
 876              $false = false;
 877              return $false;
 878          } 
 879          
 880          if ($this->_queryID === true) { // return simplified recordset for inserts/updates/deletes with lower overhead
 881              $rs =& new ADORecordSet_empty();
 882              return $rs;
 883          }
 884          
 885          // return real recordset from select statement

 886          $rsclass = $this->rsPrefix.$this->databaseType;
 887          $rs =& new $rsclass($this->_queryID,$this->fetchMode);
 888          $rs->connection = &$this; // Pablo suggestion

 889          $rs->Init();
 890          if (is_array($sql)) $rs->sql = $sql[0];
 891          else $rs->sql = $sql;
 892          if ($rs->_numOfRows <= 0) {
 893          global $ADODB_COUNTRECS;
 894              if ($ADODB_COUNTRECS) {
 895                  if (!$rs->EOF) { 
 896                      $rs = &$this->_rs2rs($rs,-1,-1,!is_array($sql));
 897                      $rs->_queryID = $this->_queryID;
 898                  } else
 899                      $rs->_numOfRows = 0;
 900              }
 901          }
 902          return $rs;
 903      }
 904  
 905  	function CreateSequence($seqname='adodbseq',$startID=1)
 906      {
 907          if (empty($this->_genSeqSQL)) return false;
 908          return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
 909      }
 910  
 911  	function DropSequence($seqname='adodbseq')
 912      {
 913          if (empty($this->_dropSeqSQL)) return false;
 914          return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
 915      }
 916  
 917      /**

 918       * Generates a sequence id and stores it in $this->genID;

 919       * GenID is only available if $this->hasGenID = true;

 920       *

 921       * @param seqname        name of sequence to use

 922       * @param startID        if sequence does not exist, start at this ID

 923       * @return        0 if not supported, otherwise a sequence id

 924       */
 925  	function GenID($seqname='adodbseq',$startID=1)
 926      {
 927          if (!$this->hasGenID) {
 928              return 0; // formerly returns false pre 1.60

 929          }
 930          
 931          $getnext = sprintf($this->_genIDSQL,$seqname);
 932          
 933          $holdtransOK = $this->_transOK;
 934          @($rs = $this->Execute($getnext));
 935          if (!$rs) {
 936              $this->_transOK = $holdtransOK; //if the status was ok before reset

 937              $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
 938              $rs = $this->Execute($getnext);
 939          }
 940          if ($rs && !$rs->EOF) $this->genID = reset($rs->fields);
 941          else $this->genID = 0; // false

 942      
 943          if ($rs) $rs->Close();
 944  
 945          return $this->genID;
 946      }    
 947  
 948      /**

 949       * @param $table string name of the table, not needed by all databases (eg. mysql), default ''

 950       * @param $column string name of the column, not needed by all databases (eg. mysql), default ''

 951       * @return  the last inserted ID. Not all databases support this.

 952       */ 
 953  	function Insert_ID($table='',$column='')
 954      {
 955          if ($this->_logsql && $this->lastInsID) return $this->lastInsID;
 956          if ($this->hasInsertID) return $this->_insertid($table,$column);
 957          if ($this->debug) {
 958              ADOConnection::outp( '<p>Insert_ID error</p>');
 959              adodb_backtrace();
 960          }
 961          return false;
 962      }
 963  
 964  
 965      /**

 966       * Portable Insert ID. Pablo Roca <pabloroca#mvps.org>

 967       *

 968       * @return  the last inserted ID. All databases support this. But aware possible

 969       * problems in multiuser environments. Heavy test this before deploying.

 970       */ 
 971  	function PO_Insert_ID($table="", $id="") 
 972      {
 973         if ($this->hasInsertID){
 974             return $this->Insert_ID($table,$id);
 975         } else {
 976             return $this->GetOne("SELECT MAX($id) FROM $table");
 977         }
 978      }
 979  
 980      /**

 981      * @return # rows affected by UPDATE/DELETE

 982      */ 
 983  	function Affected_Rows()
 984      {
 985          if ($this->hasAffectedRows) {
 986              if ($this->fnExecute === 'adodb_log_sql') {
 987                  if ($this->_logsql && $this->_affected !== false) return $this->_affected;
 988              }
 989              $val = $this->_affectedrows();
 990              return ($val < 0) ? false : $val;
 991          }
 992                    
 993          if ($this->debug) ADOConnection::outp( '<p>Affected_Rows error</p>',false);
 994          return false;
 995      }
 996      
 997      
 998      /**

 999       * @return  the last error message

1000       */
1001  	function ErrorMsg()
1002      {
1003          return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
1004      }
1005      
1006      
1007      /**

1008       * @return the last error number. Normally 0 means no error.

1009       */
1010  	function ErrorNo() 
1011      {
1012          return ($this->_errorMsg) ? -1 : 0;
1013      }
1014      
1015  	function MetaError($err=false)
1016      {
1017          include_once (ADODB_DIR."/adodb-error.inc.php");
1018          if ($err === false) $err = $this->ErrorNo();
1019          return adodb_error($this->dataProvider,$this->databaseType,$err);
1020      }
1021      
1022  	function MetaErrorMsg($errno)
1023      {
1024          include_once (ADODB_DIR."/adodb-error.inc.php");
1025          return adodb_errormsg($errno);
1026      }
1027      
1028      /**

1029       * @returns an array with the primary key columns in it.

1030       */
1031  	function MetaPrimaryKeys($table, $owner=false)
1032      {
1033      // owner not used in base class - see oci8

1034          $p = array();
1035          $objs =& $this->MetaColumns($table);
1036          if ($objs) {
1037              foreach($objs as $v) {
1038                  if (!empty($v->primary_key))
1039                      $p[] = $v->name;
1040              }
1041          }
1042          if (sizeof($p)) return $p;
1043          if (function_exists('ADODB_VIEW_PRIMARYKEYS'))
1044              return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);
1045          return false;
1046      }
1047      
1048      /**

1049       * @returns assoc array where keys are tables, and values are foreign keys

1050       */
1051  	function MetaForeignKeys($table, $owner=false, $upper=false)
1052      {
1053          return false;
1054      }
1055      /**

1056       * Choose a database to connect to. Many databases do not support this.

1057       *

1058       * @param dbName     is the name of the database to select

1059       * @return         true or false

1060       */
1061  	function SelectDB($dbName) 
1062      {return false;}
1063      
1064      
1065      /**

1066      * Will select, getting rows from $offset (1-based), for $nrows. 

1067      * This simulates the MySQL "select * from table limit $offset,$nrows" , and

1068      * the PostgreSQL "select * from table limit $nrows offset $offset". Note that

1069      * MySQL and PostgreSQL parameter ordering is the opposite of the other.

1070      * eg. 

1071      *  SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)

1072      *  SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)

1073      *

1074      * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)

1075      * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set

1076      *

1077      * @param sql

1078      * @param [offset]    is the row to start calculations from (1-based)

1079      * @param [nrows]        is the number of rows to get

1080      * @param [inputarr]    array of bind variables

1081      * @param [secs2cache]        is a private parameter only used by jlim

1082      * @return        the recordset ($rs->databaseType == 'array')

1083       */
1084      function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
1085      {
1086          if ($this->hasTop && $nrows > 0) {
1087          // suggested by Reinhard Balling. Access requires top after distinct 

1088           // Informix requires first before distinct - F Riosa

1089              $ismssql = (strpos($this->databaseType,'mssql') !== false);
1090              if ($ismssql) $isaccess = false;
1091              else $isaccess = (strpos($this->databaseType,'access') !== false);
1092              
1093              if ($offset <= 0) {
1094                  
1095                      // access includes ties in result

1096                      if ($isaccess) {
1097                          $sql = preg_replace(
1098                          '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
1099  
1100                          if ($secs2cache>0) {
1101                              $ret =& $this->CacheExecute($secs2cache, $sql,$inputarr);
1102                          } else {
1103                              $ret =& $this->Execute($sql,$inputarr);
1104                          }
1105                          return $ret; // PHP5 fix

1106                      } else if ($ismssql){
1107                          $sql = preg_replace(
1108                          '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
1109                      } else {
1110                          $sql = preg_replace(
1111                          '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
1112                      }
1113              } else {
1114                  $nn = $nrows + $offset;
1115                  if ($isaccess || $ismssql) {
1116                      $sql = preg_replace(
1117                      '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1118                  } else {
1119                      $sql = preg_replace(
1120                      '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1121                  }
1122              }
1123          }
1124          
1125          // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer  rows

1126          // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.

1127          global $ADODB_COUNTRECS;
1128          
1129          $savec = $ADODB_COUNTRECS;
1130          $ADODB_COUNTRECS = false;
1131              
1132          if ($offset>0){
1133              if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1134              else $rs = &$this->Execute($sql,$inputarr);
1135          } else {
1136              if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1137              else $rs = &$this->Execute($sql,$inputarr);
1138          }
1139          $ADODB_COUNTRECS = $savec;
1140          if ($rs && !$rs->EOF) {
1141              $rs =& $this->_rs2rs($rs,$nrows,$offset);
1142          }
1143          //print_r($rs);

1144          return $rs;
1145      }
1146      
1147      /**

1148      * Create serializable recordset. Breaks rs link to connection.

1149      *

1150      * @param rs            the recordset to serialize

1151      */
1152      function &SerializableRS(&$rs)
1153      {
1154          $rs2 =& $this->_rs2rs($rs);
1155          $ignore = false;
1156          $rs2->connection =& $ignore;
1157          
1158          return $rs2;
1159      }
1160      
1161      /**

1162      * Convert database recordset to an array recordset

1163      * input recordset's cursor should be at beginning, and

1164      * old $rs will be closed.

1165      *

1166      * @param rs            the recordset to copy

1167      * @param [nrows]      number of rows to retrieve (optional)

1168      * @param [offset]     offset by number of rows (optional)

1169      * @return             the new recordset

1170      */
1171      function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true)
1172      {
1173          if (! $rs) {
1174              $false = false;
1175              return $false;
1176          }
1177          $dbtype = $rs->databaseType;
1178          if (!$dbtype) {
1179              $rs = &$rs;  // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?

1180              return $rs;
1181          }
1182          if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {
1183              $rs->MoveFirst();
1184              $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?

1185              return $rs;
1186          }
1187          $flds = array();
1188          for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
1189              $flds[] = $rs->FetchField($i);
1190          }
1191  
1192          $arr =& $rs->GetArrayLimit($nrows,$offset);
1193          //print_r($arr);

1194          if ($close) $rs->Close();
1195          
1196          $arrayClass = $this->arrayClass;
1197          
1198          $rs2 =& new $arrayClass();
1199          $rs2->connection = &$this;
1200          $rs2->sql = $rs->sql;
1201          $rs2->dataProvider = $this->dataProvider;
1202          $rs2->InitArrayFields($arr,$flds);
1203          $rs2->fetchMode = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
1204          return $rs2;
1205      }
1206      
1207      /*

1208      * Return all rows. Compat with PEAR DB

1209      */
1210      function &GetAll($sql, $inputarr=false)
1211      {
1212          $arr =& $this->GetArray($sql,$inputarr);
1213          return $arr;
1214      }
1215      
1216      function &GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false)
1217      {
1218          $rs =& $this->Execute($sql, $inputarr);
1219          if (!$rs) {
1220              $false = false;
1221              return $false;
1222          }
1223          $arr =& $rs->GetAssoc($force_array,$first2cols);
1224          return $arr;
1225      }
1226      
1227      function &CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false)
1228      {
1229          if (!is_numeric($secs2cache)) {
1230              $first2cols = $force_array;
1231              $force_array = $inputarr;
1232          }
1233          $rs =& $this->CacheExecute($secs2cache, $sql, $inputarr);
1234          if (!$rs) {
1235              $false = false;
1236              return $false;
1237          }
1238          $arr =& $rs->GetAssoc($force_array,$first2cols);
1239          return $arr;
1240      }
1241      
1242      /**

1243      * Return first element of first row of sql statement. Recordset is disposed

1244      * for you.

1245      *

1246      * @param sql            SQL statement

1247      * @param [inputarr]        input bind array

1248      */
1249  	function GetOne($sql,$inputarr=false)
1250      {
1251      global $ADODB_COUNTRECS;
1252          $crecs = $ADODB_COUNTRECS;
1253          $ADODB_COUNTRECS = false;
1254          
1255          $ret = false;
1256          $rs = &$this->Execute($sql,$inputarr);
1257          if ($rs) {    
1258              if (!$rs->EOF) $ret = reset($rs->fields);
1259              $rs->Close();
1260          }
1261          $ADODB_COUNTRECS = $crecs;
1262          return $ret;
1263      }
1264      
1265  	function CacheGetOne($secs2cache,$sql=false,$inputarr=false)
1266      {
1267          $ret = false;
1268          $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1269          if ($rs) {        
1270              if (!$rs->EOF) $ret = reset($rs->fields);
1271              $rs->Close();
1272          } 
1273          
1274          return $ret;
1275      }
1276      
1277  	function GetCol($sql, $inputarr = false, $trim = false)
1278      {
1279            $rv = false;
1280            $rs = &$this->Execute($sql, $inputarr);
1281            if ($rs) {
1282              $rv = array();
1283                 if ($trim) {
1284                  while (!$rs->EOF) {
1285                      $rv[] = trim(reset($rs->fields));
1286                      $rs->MoveNext();
1287                     }
1288              } else {
1289                  while (!$rs->EOF) {
1290                      $rv[] = reset($rs->fields);
1291                      $rs->MoveNext();
1292                     }
1293              }
1294                 $rs->Close();
1295            }
1296            return $rv;
1297      }
1298      
1299  	function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false)
1300      {
1301            $rv = false;
1302            $rs = &$this->CacheExecute($secs, $sql, $inputarr);
1303            if ($rs) {
1304              if ($trim) {
1305                  while (!$rs->EOF) {
1306                      $rv[] = trim(reset($rs->fields));
1307                      $rs->MoveNext();
1308                     }
1309              } else {
1310                  while (!$rs->EOF) {
1311                      $rv[] = reset($rs->fields);
1312                      $rs->MoveNext();
1313                     }
1314              }
1315                 $rs->Close();
1316            }
1317            return $rv;
1318      }
1319   
1320      /*

1321          Calculate the offset of a date for a particular database and generate

1322              appropriate SQL. Useful for calculating future/past dates and storing

1323              in a database.

1324              

1325          If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.

1326      */
1327  	function OffsetDate($dayFraction,$date=false)
1328      {        
1329          if (!$date) $date = $this->sysDate;
1330          return  '('.$date.'+'.$dayFraction.')';
1331      }
1332      
1333      
1334      /**

1335      *

1336      * @param sql            SQL statement

1337      * @param [inputarr]        input bind array

1338      */
1339      function &GetArray($sql,$inputarr=false)
1340      {
1341      global $ADODB_COUNTRECS;
1342          
1343          $savec = $ADODB_COUNTRECS;
1344          $ADODB_COUNTRECS = false;
1345          $rs =& $this->Execute($sql,$inputarr);
1346          $ADODB_COUNTRECS = $savec;
1347          if (!$rs) 
1348              if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
1349              else {
1350                  $false = false;
1351                  return $false;
1352              }
1353          $arr =& $rs->GetArray();
1354          $rs->Close();
1355          return $arr;
1356      }
1357      
1358      function &CacheGetAll($secs2cache,$sql=false,$inputarr=false)
1359      {
1360          return $this->CacheGetArray($secs2cache,$sql,$inputarr);
1361      }
1362      
1363      function &CacheGetArray($secs2cache,$sql=false,$inputarr=false)
1364      {
1365      global $ADODB_COUNTRECS;
1366          
1367          $savec = $ADODB_COUNTRECS;
1368          $ADODB_COUNTRECS = false;
1369          $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1370          $ADODB_COUNTRECS = $savec;
1371          
1372          if (!$rs) 
1373              if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
1374              else {
1375                  $false = false;
1376                  return $false;
1377              }
1378          $arr =& $rs->GetArray();
1379          $rs->Close();
1380          return $arr;
1381      }
1382      
1383      
1384      
1385      /**

1386      * Return one row of sql statement. Recordset is disposed for you.

1387      *

1388      * @param sql            SQL statement

1389      * @param [inputarr]        input bind array

1390      */
1391      function &GetRow($sql,$inputarr=false)
1392      {
1393      global $ADODB_COUNTRECS;
1394          $crecs = $ADODB_COUNTRECS;
1395          $ADODB_COUNTRECS = false;
1396          
1397          $rs =& $this->Execute($sql,$inputarr);
1398          
1399          $ADODB_COUNTRECS = $crecs;
1400          if ($rs) {
1401              if (!$rs->EOF) $arr = $rs->fields;
1402              else $arr = array();
1403              $rs->Close();
1404              return $arr;
1405          }
1406          
1407          $false = false;
1408          return $false;
1409      }
1410      
1411      function &CacheGetRow($secs2cache,$sql=false,$inputarr=false)
1412      {
1413          $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1414          if ($rs) {
1415              $arr = false;
1416              if (!$rs->EOF) $arr = $rs->fields;
1417              $rs->Close();
1418              return $arr;
1419          }
1420          $false = false;
1421          return $false;
1422      }
1423      
1424      /**

1425      * Insert or replace a single record. Note: this is not the same as MySQL's replace. 

1426      * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.

1427      * Also note that no table locking is done currently, so it is possible that the

1428      * record be inserted twice by two programs...

1429      *

1430      * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');

1431      *

1432      * $table        table name

1433      * $fieldArray    associative array of data (you must quote strings yourself).

1434      * $keyCol        the primary key field name or if compound key, array of field names

1435      * autoQuote        set to true to use a hueristic to quote strings. Works with nulls and numbers

1436      *                    but does not work with dates nor SQL functions.

1437      * has_autoinc    the primary key is an auto-inc field, so skip in insert.

1438      *

1439      * Currently blob replace not supported

1440      *

1441      * returns 0 = fail, 1 = update, 2 = insert 

1442      */
1443      
1444  	function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false)
1445      {
1446          global $ADODB_INCLUDED_LIB;
1447          if (empty($ADODB_INCLUDED_LIB)) include_once (ADODB_DIR.'/adodb-lib.inc.php');
1448          
1449          return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);
1450      }
1451      
1452      
1453      /**

1454      * Will select, getting rows from $offset (1-based), for $nrows. 

1455      * This simulates the MySQL "select * from table limit $offset,$nrows" , and

1456      * the PostgreSQL "select * from table limit $nrows offset $offset". Note that

1457      * MySQL and PostgreSQL parameter ordering is the opposite of the other.

1458      * eg. 

1459      *  CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)

1460      *  CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)

1461      *

1462      * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set

1463      *

1464      * @param [secs2cache]    seconds to cache data, set to 0 to force query. This is optional

1465      * @param sql

1466      * @param [offset]    is the row to start calculations from (1-based)

1467      * @param [nrows]    is the number of rows to get

1468      * @param [inputarr]    array of bind variables

1469      * @return        the recordset ($rs->databaseType == 'array')

1470       */
1471      function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false)
1472      {    
1473          if (!is_numeric($secs2cache)) {
1474              if ($sql === false) $sql = -1;
1475              if ($offset == -1) $offset = false;
1476                                        // sql,    nrows, offset,inputarr

1477              $rs =& $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs);
1478          } else {
1479              if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()");
1480              $rs =& $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
1481          }
1482          return $rs;
1483      }
1484      
1485      /**

1486      * Flush cached recordsets that match a particular $sql statement. 

1487      * If $sql == false, then we purge all files in the cache.

1488       */
1489  	function CacheFlush($sql=false,$inputarr=false)
1490      {
1491      global $ADODB_CACHE_DIR;
1492      
1493          if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
1494              if (strncmp(PHP_OS,'WIN',3) === 0) {
1495                  $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
1496              } else {
1497                  //$cmd = 'find "'.$ADODB_CACHE_DIR.'" -type f -maxdepth 1 -print0 | xargs -0 rm -f';

1498                  $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/[0-9a-f][0-9a-f]/'; 
1499                  // old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`';

1500              }
1501              if ($this->debug) {
1502                  ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>");
1503              } else {
1504                  exec($cmd);
1505              }
1506              return;
1507          } 
1508          
1509          global $ADODB_INCLUDED_CSV;
1510          if (empty($ADODB_INCLUDED_CSV)) include_once (ADODB_DIR.'/adodb-csvlib.inc.php');
1511          
1512          $f = $this->_gencachename($sql.serialize($inputarr),false);
1513          adodb_write_file($f,''); // is adodb_write_file needed?

1514          if (!@unlink($f)) {
1515              if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f");
1516          }
1517      }
1518      
1519      /**

1520      * Private function to generate filename for caching.

1521      * Filename is generated based on:

1522      *

1523      *  - sql statement

1524      *  - database type (oci8, ibase, ifx, etc)

1525      *  - database name

1526      *  - userid

1527      *  - setFetchMode (adodb 4.23)

1528      *

1529      * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR). 

1530      * Assuming that we can have 50,000 files per directory with good performance, 

1531      * then we can scale to 12.8 million unique cached recordsets. Wow!

1532       */
1533  	function _gencachename($sql,$createdir)
1534      {
1535      global $ADODB_CACHE_DIR;
1536      static $notSafeMode;
1537          
1538          if ($this->fetchMode === false) { 
1539          global $ADODB_FETCH_MODE;
1540              $mode = $ADODB_FETCH_MODE;
1541          } else {
1542              $mode = $this->fetchMode;
1543          }
1544          $m = md5($sql.$this->databaseType.$this->database.$this->user.$mode);
1545          
1546          if (!isset($notSafeMode)) $notSafeMode = !ini_get('safe_mode');
1547          $dir = ($notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($m,0,2) : $ADODB_CACHE_DIR;
1548              
1549          if ($createdir && $notSafeMode && !file_exists($dir)) {
1550              $oldu = umask(0);
1551              if (!mkdir($dir,0771)) 
1552                  if ($this->debug) ADOConnection::outp( "Unable to mkdir $dir for $sql");
1553              umask($oldu);
1554          }
1555          return $dir.'/adodb_'.$m.'.cache';
1556      }
1557      
1558      
1559      /**

1560       * Execute SQL, caching recordsets.

1561       *

1562       * @param [secs2cache]    seconds to cache data, set to 0 to force query. 

1563       *                      This is an optional parameter.

1564       * @param sql        SQL statement to execute

1565       * @param [inputarr]    holds the input data  to bind to

1566       * @return         RecordSet or false

1567       */
1568      function &CacheExecute($secs2cache,$sql=false,$inputarr=false)
1569      {
1570          if (!is_numeric($secs2cache)) {
1571              $inputarr = $sql;
1572              $sql = $secs2cache;
1573              $secs2cache = $this->cacheSecs;
1574          }
1575          global $ADODB_INCLUDED_CSV;
1576          if (empty($ADODB_INCLUDED_CSV)) include_once (ADODB_DIR.'/adodb-csvlib.inc.php');
1577          
1578          if (is_array($sql)) $sql = $sql[0];
1579              
1580          $md5file = $this->_gencachename($sql.serialize($inputarr),true);
1581          $err = '';
1582          
1583          if ($secs2cache > 0){
1584              $rs = &csv2rs($md5file,$err,$secs2cache,$this->arrayClass);
1585              $this->numCacheHits += 1;
1586          } else {
1587              $err='Timeout 1';
1588              $rs = false;
1589              $this->numCacheMisses += 1;
1590          }
1591          if (!$rs) {
1592          // no cached rs found

1593              if ($this->debug) {
1594                  if (get_magic_quotes_runtime()) {
1595                      ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
1596                  }
1597                  if ($this->debug !== -1) ADOConnection::outp( " $md5file cache failure: $err (see sql below)");
1598              }
1599              
1600              $rs = &$this->Execute($sql,$inputarr);
1601  
1602              if ($rs) {
1603                  $eof = $rs->EOF;
1604                  $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately

1605                  $txt = _rs2serialize($rs,false,$sql); // serialize

1606          
1607                  if (!adodb_write_file($md5file,$txt,$this->debug)) {
1608                      if ($fn = $this->raiseErrorFn) {
1609                          $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);
1610                      }
1611                      if ($this->debug) ADOConnection::outp( " Cache write error");
1612                  }
1613                  if ($rs->EOF && !$eof) {
1614                      $rs->MoveFirst();
1615                      //$rs = &csv2rs($md5file,$err);        

1616                      $rs->connection = &$this; // Pablo suggestion

1617                  }  
1618                  
1619              } else
1620                  @unlink($md5file);
1621          } else {
1622              $this->_errorMsg = '';
1623              $this->_errorCode = 0;
1624              
1625              if ($this->fnCacheExecute) {
1626                  $fn = $this->fnCacheExecute;
1627                  $fn($this, $secs2cache, $sql, $inputarr);
1628              }
1629          // ok, set cached object found

1630              $rs->connection = &$this; // Pablo suggestion

1631              if ($this->debug){ 
1632              global $HTTP_SERVER_VARS;
1633                      
1634                  $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
1635                  $ttl = $rs->timeCreated + $secs2cache - time();
1636                  $s = is_array($sql) ? $sql[0] : $sql;
1637                  if ($inBrowser) $s = '<i>'.htmlspecialchars($s).'</i>';
1638                  
1639                  ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
1640              }
1641          }
1642          return $rs;
1643      }
1644      
1645      
1646      /* 

1647          Similar to PEAR DB's autoExecute(), except that 

1648          $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE

1649          If $mode == 'UPDATE', then $where is compulsory as a safety measure.

1650          

1651          $forceUpdate means that even if the data has not changed, perform update.

1652       */
1653  	function AutoExecute($table, $fields_values, $mode = 'INSERT', $where = FALSE, $forceUpdate=true, $magicq=false) 
1654      {
1655          //$flds = array_keys($fields_values);

1656          //$fldstr = implode(', ',$flds);

1657          $sql = 'SELECT * FROM '.$table;  
1658          if ($where!==FALSE) $sql .= ' WHERE '.$where;
1659          else if ($mode == 'UPDATE') {
1660              ADOConnection::outp('AutoExecute: Illegal mode=UPDATE with empty WHERE clause');
1661              return false;
1662          }
1663  
1664          $rs =& $this->SelectLimit($sql,1);
1665          if (!$rs) return false; // table does not exist

1666          
1667          switch((string) $mode) {
1668          case 'UPDATE':
1669          case '2':
1670              $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq);
1671              break;
1672          case 'INSERT':
1673          case '1':
1674              $sql = $this->GetInsertSQL($rs, $fields_values, $magicq);
1675              break;
1676          default:
1677              ADOConnection::outp("AutoExecute: Unknown mode=$mode");
1678              return false;
1679          }
1680          if ($sql) return $this->Execute($sql);
1681          return false;
1682      }
1683      
1684      
1685      /**

1686       * Generates an Update Query based on an existing recordset.

1687       * $arrFields is an associative array of fields with the value

1688       * that should be assigned.

1689       *

1690       * Note: This function should only be used on a recordset

1691       *       that is run against a single table and sql should only 

1692       *         be a simple select stmt with no groupby/orderby/limit

1693       *

1694       * "Jonathan Younger" <jyounger@unilab.com>

1695         */
1696  	function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null)
1697      {
1698          global $ADODB_INCLUDED_LIB;
1699  
1700          //********************************************************//

1701          //This is here to maintain compatibility

1702          //with older adodb versions. Sets force type to force nulls if $forcenulls is set.

1703          if (!isset($force)) {
1704                  global $ADODB_FORCE_TYPE;
1705                  $force = $ADODB_FORCE_TYPE;
1706          }
1707          //********************************************************//

1708  
1709          if (empty($ADODB_INCLUDED_LIB)) include_once (ADODB_DIR.'/adodb-lib.inc.php');
1710          return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
1711      }
1712  
1713      
1714      
1715  
1716      /**

1717       * Generates an Insert Query based on an existing recordset.

1718       * $arrFields is an associative array of fields with the value

1719       * that should be assigned.

1720       *

1721       * Note: This function should only be used on a recordset

1722       *       that is run against a single table.

1723         */
1724  	function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null)
1725      {    
1726          global $ADODB_INCLUDED_LIB;
1727          if (!isset($force)) {
1728              global $ADODB_FORCE_TYPE;
1729              $force = $ADODB_FORCE_TYPE;
1730              
1731          }
1732          if (empty($ADODB_INCLUDED_LIB)) include_once (ADODB_DIR.'/adodb-lib.inc.php');
1733          return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
1734      }
1735      
1736  
1737      /**

1738      * Update a blob column, given a where clause. There are more sophisticated

1739      * blob handling functions that we could have implemented, but all require

1740      * a very complex API. Instead we have chosen something that is extremely

1741      * simple to understand and use. 

1742      *

1743      * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.

1744      *

1745      * Usage to update a $blobvalue which has a primary key blob_id=1 into a 

1746      * field blobtable.blobcolumn:

1747      *

1748      *    UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');

1749      *

1750      * Insert example:

1751      *

1752      *    $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');

1753      *    $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');

1754      */
1755      
1756  	function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
1757      {
1758          return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
1759      }
1760  
1761      /**

1762      * Usage:

1763      *    UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');

1764      *    

1765      *    $blobtype supports 'BLOB' and 'CLOB'

1766      *

1767      *    $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');

1768      *    $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');

1769      */
1770  	function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
1771      {
1772          $fd = fopen($path,'rb');
1773          if ($fd === false) return false;
1774          $val = fread($fd,filesize($path));
1775          fclose($fd);
1776          return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
1777      }
1778      
1779  	function BlobDecode($blob)
1780      {
1781          return $blob;
1782      }
1783      
1784  	function BlobEncode($blob)
1785      {
1786          return $blob;
1787      }
1788      
1789  	function SetCharSet($charset)
1790      {
1791          return false;
1792      }
1793      
1794  	function IfNull( $field, $ifNull ) 
1795      {
1796          return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
1797      }
1798      
1799  	function LogSQL($enable=true)
1800      {
1801          include_once (ADODB_DIR.'/adodb-perf.inc.php');
1802          
1803          if ($enable) $this->fnExecute = 'adodb_log_sql';
1804          else $this->fnExecute = false;
1805          
1806          $old = $this->_logsql;    
1807          $this->_logsql = $enable;
1808          if ($enable && !$old) $this->_affected = false;
1809          return $old;
1810      }
1811      
1812  	function GetCharSet()
1813      {
1814          return false;
1815      }
1816      
1817      /**

1818      * Usage:

1819      *    UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');

1820      *

1821      *    $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');

1822      *    $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');

1823      */
1824  	function UpdateClob($table,$column,$val,$where)
1825      {
1826          return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
1827      }
1828      
1829      
1830      /**

1831      *  Change the SQL connection locale to a specified locale.

1832      *  This is used to get the date formats written depending on the client locale.

1833      */
1834  	function SetDateLocale($locale = 'En')
1835      {
1836          $this->locale = $locale;
1837          switch ($locale)
1838          {
1839              case 'En':
1840                  $this->fmtDate="'Y-m-d'";
1841                  $this->fmtTimeStamp = "'Y-m-d H:i:s'";
1842                  break;
1843                  
1844              case 'Us':
1845                  $this->fmtDate = "'m-d-Y'";
1846                  $this->fmtTimeStamp = "'m-d-Y H:i:s'";
1847                  break;
1848                  
1849              case 'Nl':
1850              case 'Fr':
1851              case 'Ro':
1852              case 'It':
1853                  $this->fmtDate="'d-m-Y'";
1854                  $this->fmtTimeStamp = "'d-m-Y H:i:s'";
1855                  break;
1856                  
1857              case 'Ge':
1858                  $this->fmtDate="'d.m.Y'";
1859                  $this->fmtTimeStamp = "'d.m.Y H:i:s'";
1860                  break;
1861                  
1862              default:
1863                  $this->fmtDate="'Y-m-d'";
1864                  $this->fmtTimeStamp = "'Y-m-d H:i:s'";
1865                  break;
1866          }
1867      }
1868  
1869      
1870      /**

1871       * Close Connection

1872       */
1873  	function Close()
1874      {
1875          $rez = $this->_close();
1876          $this->_connectionID = false;
1877          return $rez;
1878      }
1879      
1880      /**

1881       * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().

1882       *

1883       * @return true if succeeded or false if database does not support transactions

1884       */
1885  	function BeginTrans() {return false;}
1886      
1887      
1888      /**

1889       * If database does not support transactions, always return true as data always commited

1890       *

1891       * @param $ok  set to false to rollback transaction, true to commit

1892       *

1893       * @return true/false.

1894       */
1895  	function CommitTrans($ok=true) 
1896      { return true;}
1897      
1898      
1899      /**

1900       * If database does not support transactions, rollbacks always fail, so return false

1901       *

1902       * @return true/false.

1903       */
1904  	function RollbackTrans() 
1905      { return false;}
1906  
1907  
1908      /**

1909       * return the databases that the driver can connect to. 

1910       * Some databases will return an empty array.

1911       *

1912       * @return an array of database names.

1913       */
1914  		function MetaDatabases() 
1915          {
1916          global $ADODB_FETCH_MODE;
1917          
1918              if ($this->metaDatabasesSQL) {
1919                  $save = $ADODB_FETCH_MODE; 
1920                  $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 
1921                  
1922                  if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
1923                  
1924                  $arr = $this->GetCol($this->metaDatabasesSQL);
1925                  if (isset($savem)) $this->SetFetchMode($savem);
1926                  $ADODB_FETCH_MODE = $save; 
1927              
1928                  return $arr;
1929              }
1930              
1931              return false;
1932          }
1933          
1934      /**

1935       * @param ttype can either be 'VIEW' or 'TABLE' or false. 

1936       *         If false, both views and tables are returned.

1937       *        "VIEW" returns only views

1938       *        "TABLE" returns only tables

1939       * @param showSchema returns the schema/user with the table name, eg. USER.TABLE

1940       * @param mask  is the input mask - only supported by oci8 and postgresql

1941       *

1942       * @return  array of tables for current database.

1943       */ 
1944      function &MetaTables($ttype=false,$showSchema=false,$mask=false) 
1945      {
1946      global $ADODB_FETCH_MODE;
1947      
1948          
1949          $false = false;
1950          if ($mask) {
1951              return $false;
1952          }
1953          if ($this->metaTablesSQL) {
1954              $save = $ADODB_FETCH_MODE; 
1955              $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 
1956              
1957              if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
1958              
1959              $rs = $this->Execute($this->metaTablesSQL);
1960              if (isset($savem)) $this->SetFetchMode($savem);
1961              $ADODB_FETCH_MODE = $save; 
1962              
1963              if ($rs === false) return $false;
1964              $arr =& $rs->GetArray();
1965              $arr2 = array();
1966              
1967              if ($hast = ($ttype && isset($arr[0][1]))) { 
1968                  $showt = strncmp($ttype,'T',1);
1969              }
1970              
1971              for ($i=0; $i < sizeof($arr); $i++) {
1972                  if ($hast) {
1973                      if ($showt == 0) {
1974                          if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]);
1975                      } else {
1976                          if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]);
1977                      }
1978                  } else
1979                      $arr2[] = trim($arr[$i][0]);
1980              }
1981              $rs->Close();
1982              return $arr2;
1983          }
1984          return $false;
1985      }
1986      
1987      
1988  	function _findschema(&$table,&$schema)
1989      {
1990          if (!$schema && ($at = strpos($table,'.')) !== false) {
1991              $schema = substr($table,0,$at);
1992              $table = substr($table,$at+1);
1993          }
1994      }
1995      
1996      /**

1997       * List columns in a database as an array of ADOFieldObjects. 

1998       * See top of file for definition of object.

1999       *

2000       * @param table    table name to query

2001       * @param upper    uppercase table name (required by some databases)

2002       * @schema is optional database schema to use - not supported by all databases.

2003       *

2004       * @return  array of ADOFieldObjects for current table.

2005       */
2006      function &MetaColumns($table,$upper=true) 
2007      {
2008      global $ADODB_FETCH_MODE;
2009          
2010          $false = false;
2011          
2012          if (!empty($this->metaColumnsSQL)) {
2013          
2014              $schema = false;
2015              $this->_findschema($table,$schema);
2016          
2017              $save = $ADODB_FETCH_MODE;
2018              $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2019              if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
2020              $rs = $this->Execute(sprintf($this->metaColumnsSQL,($upper)?strtoupper($table):$table));
2021              if (isset($savem)) $this->SetFetchMode($savem);
2022              $ADODB_FETCH_MODE = $save;
2023              if ($rs === false || $rs->EOF) return $false;
2024  
2025              $retarr = array();
2026              while (!$rs->EOF) { //print_r($rs->fields);
2027                  $fld =& new ADOFieldObject();
2028                  $fld->name = $rs->fields[0];
2029                  $fld->type = $rs->fields[1];
2030                  if (isset($rs->fields[3]) && $rs->fields[3]) {
2031                      if ($rs->fields[3]>0) $fld->max_length = $rs->fields[3];
2032                      $fld->scale = $rs->fields[4];
2033                      if ($fld->scale>0) $fld->max_length += 1;
2034                  } else
2035                      $fld->max_length = $rs->fields[2];
2036                      
2037                  if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;    
2038                  else $retarr[strtoupper($fld->name)] = $fld;
2039                  $rs->MoveNext();
2040              }
2041              $rs->Close();
2042              return $retarr;    
2043          }
2044          return $false;
2045      }
2046      
2047      /**

2048        * List indexes on a table as an array.

2049        * @param table  table name to query

2050        * @param primary true to only show primary keys. Not actually used for most databases

2051        *

2052        * @return array of indexes on current table. Each element represents an index, and is itself an associative array.

2053        

2054           Array (

2055              [name_of_index] => Array

2056                (

2057                [unique] => true or false

2058                [columns] => Array

2059                (

2060                    [0] => firstname

2061                    [1] => lastname

2062                )

2063          )        

2064        */
2065       function &MetaIndexes($table, $primary = false, $owner = false)
2066       {
2067               $false = false;
2068              return false;
2069       }
2070  
2071      /**

2072       * List columns names in a table as an array. 

2073       * @param table    table name to query

2074       *

2075       * @return  array of column names for current table.

2076       */ 
2077      function &MetaColumnNames($table, $numIndexes=false) 
2078      {
2079          $objarr =& $this->MetaColumns($table);
2080          if (!is_array($objarr)) {
2081              $false = false;
2082              return $false;
2083          }
2084          $arr = array();
2085          if ($numIndexes) {
2086              $i = 0;
2087              foreach($objarr as $v) $arr[$i++] = $v->name;
2088          } else
2089              foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name;
2090          
2091          return $arr;
2092      }
2093              
2094      /**

2095       * Different SQL databases used different methods to combine strings together.

2096       * This function provides a wrapper. 

2097       * 

2098       * param s    variable number of string parameters

2099       *

2100       * Usage: $db->Concat($str1,$str2);

2101       * 

2102       * @return concatenated string

2103       */      
2104  	function Concat()
2105      {    
2106          $arr = func_get_args();
2107          return implode($this->concat_operator, $arr);
2108      }
2109      
2110      
2111      /**

2112       * Converts a date "d" to a string that the database can understand.

2113       *

2114       * @param d    a date in Unix date time format.

2115       *

2116       * @return  date string in database date format

2117       */
2118  	function DBDate($d)
2119      {
2120          if (empty($d) && $d !== 0) return 'null';
2121  
2122          if (is_string($d) && !is_numeric($d)) {
2123              if ($d === 'null' || strncmp($d,"'",1) === 0) return $d;
2124              if ($this->isoDates) return "'$d'";
2125              $d = ADOConnection::UnixDate($d);
2126          }
2127  
2128          return adodb_date($this->fmtDate,$d);
2129      }
2130      
2131      
2132      /**

2133       * Converts a timestamp "ts" to a string that the database can understand.

2134       *

2135       * @param ts    a timestamp in Unix date time format.

2136       *

2137       * @return  timestamp string in database timestamp format

2138       */
2139  	function DBTimeStamp($ts)
2140      {
2141          if (empty($ts) && $ts !== 0) return 'null';
2142  
2143          # strlen(14) allows YYYYMMDDHHMMSS format

2144          if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) 
2145              return adodb_date($this->fmtTimeStamp,$ts);
2146          
2147          if ($ts === 'null') return $ts;
2148          if ($this->isoDates && strlen($ts) !== 14) return "'$ts'";
2149          
2150          $ts = ADOConnection::UnixTimeStamp($ts);
2151          return adodb_date($this->fmtTimeStamp,$ts);
2152      }
2153      
2154      /**

2155       * Also in ADORecordSet.

2156       * @param $v is a date string in YYYY-MM-DD format

2157       *

2158       * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format

2159       */
2160  	function UnixDate($v)
2161      {
2162          if (is_object($v)) {
2163          // odbtp support

2164          //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )

2165              return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2166          }
2167      
2168          if (is_numeric($v) && strlen($v) !== 8) return $v;
2169          if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", 
2170              ($v), $rr)) return false;
2171  
2172          if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;
2173          // h-m-s-MM-DD-YY

2174          return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2175      }
2176      
2177  
2178      /**

2179       * Also in ADORecordSet.

2180       * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format

2181       *

2182       * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format

2183       */
2184  	function UnixTimeStamp($v)
2185      {
2186          if (is_object($v)) {
2187          // odbtp support

2188          //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )

2189              return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2190          }
2191          
2192          if (!preg_match( 
2193              "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 
2194              ($v), $rr)) return false;
2195              
2196          if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) return 0;
2197      
2198          // h-m-s-MM-DD-YY

2199          if (!isset($rr[5])) return  adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2200          return  @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
2201      }
2202      
2203      /**

2204       * Also in ADORecordSet.

2205       *

2206       * Format database date based on user defined format.

2207       *

2208       * @param v      is the character date in YYYY-MM-DD format, returned by database

2209       * @param fmt     is the format to apply to it, using date()

2210       *

2211       * @return a date formated as user desires

2212       */
2213       
2214  	function UserDate($v,$fmt='Y-m-d',$gmt=false)
2215      {
2216          $tt = $this->UnixDate($v);
2217  
2218          // $tt == -1 if pre TIMESTAMP_FIRST_YEAR

2219          if (($tt === false || $tt == -1) && $v != false) return $v;
2220          else if ($tt == 0) return $this->emptyDate;
2221          else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
2222          }
2223          
2224          return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2225      
2226      }
2227      
2228          /**

2229       *

2230       * @param v      is the character timestamp in YYYY-MM-DD hh:mm:ss format

2231       * @param fmt     is the format to apply to it, using date()

2232       *

2233       * @return a timestamp formated as user desires

2234       */
2235  	function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false)
2236      {
2237          # strlen(14) allows YYYYMMDDHHMMSS format

2238          if (is_numeric($v) && strlen($v)<14) return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v);
2239          $tt = $this->UnixTimeStamp($v);
2240          // $tt == -1 if pre TIMESTAMP_FIRST_YEAR

2241          if (($tt === false || $tt == -1) && $v != false) return $v;
2242          if ($tt == 0) return $this->emptyTimeStamp;
2243          return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2244      }
2245      
2246      /**

2247      * Quotes a string, without prefixing nor appending quotes. 

2248      */
2249  	function addq($s,$magic_quotes=false)
2250      {
2251          if (!$magic_quotes) {
2252          
2253              if ($this->replaceQuote[0] == '\\'){
2254                  // only since php 4.0.5

2255                  $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2256                  //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));

2257              }
2258              return  str_replace("'",$this->replaceQuote,$s);
2259          }
2260          
2261          // undo magic quotes for "

2262          $s = str_replace('\\"','"',$s);
2263          
2264          if ($this->replaceQuote == "\\'")  // ' already quoted, no need to change anything
2265              return $s;
2266          else {// change \' to '' for sybase/mssql
2267              $s = str_replace('\\\\','\\',$s);
2268              return str_replace("\\'",$this->replaceQuote,$s);
2269          }
2270      }
2271      
2272      /**

2273       * Correctly quotes a string so that all strings are escaped. We prefix and append

2274       * to the string single-quotes.

2275       * An example is  $db->qstr("Don't bother",magic_quotes_runtime());

2276       * 

2277       * @param s            the string to quote

2278       * @param [magic_quotes]    if $s is GET/POST var, set to get_magic_quotes_gpc().

2279       *                This undoes the stupidity of magic quotes for GPC.

2280       *

2281       * @return  quoted string to be sent back to database

2282       */
2283  	function qstr($s,$magic_quotes=false)
2284      {    
2285          if (!$magic_quotes) {
2286          
2287              if ($this->replaceQuote[0] == '\\'){
2288                  // only since php 4.0.5

2289                  $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2290                  //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));

2291              }
2292              return  "'".str_replace("'",$this->replaceQuote,$s)."'";
2293          }
2294          
2295          // undo magic quotes for "

2296          $s = str_replace('\\"','"',$s);
2297          
2298          if ($this->replaceQuote == "\\'")  // ' already quoted, no need to change anything
2299              return "'$s'";
2300          else {// change \' to '' for sybase/mssql
2301              $s = str_replace('\\\\','\\',$s);
2302              return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
2303          }
2304      }
2305      
2306      
2307      /**

2308      * Will select the supplied $page number from a recordset, given that it is paginated in pages of 

2309      * $nrows rows per page. It also saves two boolean values saying if the given page is the first 

2310      * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.

2311      *

2312      * See readme.htm#ex8 for an example of usage.

2313      *

2314      * @param sql

2315      * @param nrows        is the number of rows per page to get

2316      * @param page        is the page number to get (1-based)

2317      * @param [inputarr]    array of bind variables

2318      * @param [secs2cache]        is a private parameter only used by jlim

2319      * @return        the recordset ($rs->databaseType == 'array')

2320      *

2321      * NOTE: phpLens uses a different algorithm and does not use PageExecute().

2322      *

2323      */
2324      function &PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0) 
2325      {
2326          global $ADODB_INCLUDED_LIB;
2327          if (empty($ADODB_INCLUDED_LIB)) include_once (ADODB_DIR.'/adodb-lib.inc.php');
2328          if ($this->pageExecuteCountRows) $rs =& _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2329          else $rs =& _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2330          return $rs;
2331      }
2332      
2333          
2334      /**

2335      * Will select the supplied $page number from a recordset, given that it is paginated in pages of 

2336      * $nrows rows per page. It also saves two boolean values saying if the given page is the first 

2337      * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.

2338      *

2339      * @param secs2cache    seconds to cache data, set to 0 to force query

2340      * @param sql

2341      * @param nrows        is the number of rows per page to get

2342      * @param page        is the page number to get (1-based)

2343      * @param [inputarr]    array of bind variables

2344      * @return        the recordset ($rs->databaseType == 'array')

2345      */
2346      function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false) 
2347      {
2348          /*switch($this->dataProvider) {

2349          case 'postgres':

2350          case 'mysql': 

2351              break;

2352          default: $secs2cache = 0; break;

2353          }*/
2354          $rs =& $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
2355          return $rs;
2356      }
2357  
2358  } // end class ADOConnection

2359      
2360      
2361      
2362      //==============================================================================================    

2363      // CLASS ADOFetchObj

2364      //==============================================================================================    

2365          
2366      /**

2367      * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().

2368      */
2369      class ADOFetchObj {
2370      };
2371      
2372      //==============================================================================================    

2373      // CLASS ADORecordSet_empty

2374      //==============================================================================================    

2375      
2376      /**

2377      * Lightweight recordset when there are no records to be returned

2378      */
2379      class ADORecordSet_empty
2380      {
2381          var $dataProvider = 'empty';
2382          var $databaseType = false;
2383          var $EOF = true;
2384          var $_numOfRows = 0;
2385          var $fields = false;
2386          var $connection = false;
2387  		function RowCount() {return 0;}
2388  		function RecordCount() {return 0;}
2389  		function PO_RecordCount(){return 0;}
2390  		function Close(){return true;}
2391  		function FetchRow() {return false;}
2392  		function FieldCount(){ return 0;}
2393  		function Init() {}
2394      }
2395      
2396      //==============================================================================================    

2397      // DATE AND TIME FUNCTIONS

2398      //==============================================================================================    

2399      include_once (ADODB_DIR.'/adodb-time.inc.php');
2400      
2401      //==============================================================================================    

2402      // CLASS ADORecordSet

2403      //==============================================================================================    

2404  
2405      if (PHP_VERSION < 5) include_once (ADODB_DIR.'/adodb-php4.inc.php');
2406      else include_once (ADODB_DIR.'/adodb-iterator.inc.php');
2407     /**

2408       * RecordSet class that represents the dataset returned by the database.

2409       * To keep memory overhead low, this class holds only the current row in memory.

2410       * No prefetching of data is done, so the RecordCount() can return -1 ( which

2411       * means recordcount not known).

2412       */
2413      class ADORecordSet extends ADODB_BASE_RS {
2414      /*

2415       * public variables    

2416       */
2417      var $dataProvider = "native";
2418      var $fields = false;     /// holds the current row data

2419      var $blobSize = 100;     /// any varchar/char field this size or greater is treated as a blob

2420                              /// in other words, we use a text area for editing.

2421      var $canSeek = false;     /// indicates that seek is supported

2422      var $sql;                 /// sql text

2423      var $EOF = false;        /// Indicates that the current record position is after the last record in a Recordset object. 

2424      
2425      var $emptyTimeStamp = '&nbsp;'; /// what to display when $time==0

2426      var $emptyDate = '&nbsp;'; /// what to display when $time==0

2427      var $debug = false;
2428      var $timeCreated=0;     /// datetime in Unix format rs created -- for cached recordsets

2429  
2430      var $bind = false;         /// used by Fields() to hold array - should be private?

2431      var $fetchMode;            /// default fetch mode

2432      var $connection = false; /// the parent connection

2433      /*

2434       *    private variables    

2435       */
2436      var $_numOfRows = -1;    /** number of rows, or -1 */
2437      var $_numOfFields = -1;    /** number of fields in recordset */
2438      var $_queryID = -1;        /** This variable keeps the result link identifier.    */
2439      var $_currentRow = -1;    /** This variable keeps the current row in the Recordset.    */
2440      var $_closed = false;     /** has recordset been closed */
2441      var $_inited = false;     /** Init() should only be called once */
2442      var $_obj;                 /** Used by FetchObj */
2443      var $_names;            /** Used by FetchObj */
2444      
2445      var $_currentPage = -1;    /** Added by Iván Oliva to implement recordset pagination */
2446      var $_atFirstPage = false;    /** Added by Iván Oliva to implement recordset pagination */
2447      var $_atLastPage = false;    /** Added by Iván Oliva to implement recordset pagination */
2448      var $_lastPageNo = -1; 
2449      var $_maxRecordCount = 0;
2450      var $datetime = false;
2451      
2452      /**

2453       * Constructor

2454       *

2455       * @param queryID      this is the queryID returned by ADOConnection->_query()

2456       *

2457       */
2458  	function ADORecordSet($queryID) 
2459      {
2460          $this->_queryID = $queryID;
2461      }
2462      
2463      
2464      
2465  	function Init()
2466      {
2467          if ($this->_inited) return;
2468          $this->_inited = true;
2469          if ($this->_queryID) @$this->_initrs();
2470          else {
2471              $this->_numOfRows = 0;
2472              $this->_numOfFields = 0;
2473          }
2474          if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
2475              
2476              $this->_currentRow = 0;
2477              if ($this->EOF = ($this->_fetch() === false)) {
2478                  $this->_numOfRows = 0; // _numOfRows could be -1

2479              }
2480          } else {
2481              $this->EOF = true;
2482          }
2483      }
2484      
2485      
2486      /**

2487       * Generate a SELECT tag string from a recordset, and return the string.

2488       * If the recordset has 2 cols, we treat the 1st col as the containing 

2489       * the text to display to the user, and 2nd col as the return value. Default

2490       * strings are compared with the FIRST column.

2491       *

2492       * @param name          name of SELECT tag

2493       * @param [defstr]        the value to hilite. Use an array for multiple hilites for listbox.

2494       * @param [blank1stItem]    true to leave the 1st item in list empty

2495       * @param [multiple]        true for listbox, false for popup

2496       * @param [size]        #rows to show for listbox. not used by popup

2497       * @param [selectAttr]        additional attributes to defined for SELECT tag.

2498       *                useful for holding javascript onChange='...' handlers.

2499       & @param [compareFields0]    when we have 2 cols in recordset, we compare the defstr with 

2500       *                column 0 (1st col) if this is true. This is not documented.

2501       *

2502       * @return HTML

2503       *

2504       * changes by glen.davies@cce.ac.nz to support multiple hilited items

2505       */
2506  	function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
2507              $size=0, $selectAttr='',$compareFields0=true)
2508      {
2509          global $ADODB_INCLUDED_LIB;
2510          if (empty($ADODB_INCLUDED_LIB)) include_once (ADODB_DIR.'/adodb-lib.inc.php');
2511          return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
2512              $size, $selectAttr,$compareFields0);
2513      }
2514      
2515      /**

2516       * Generate a SELECT tag string from a recordset, and return the string.

2517       * If the recordset has 2 cols, we treat the 1st col as the containing 

2518       * the text to display to the user, and 2nd col as the return value. Default

2519       * strings are compared with the SECOND column.

2520       *

2521       */
2522  	function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='')    
2523      {
2524          global $ADODB_INCLUDED_LIB;
2525          if (empty($ADODB_INCLUDED_LIB)) include_once (ADODB_DIR.'/adodb-lib.inc.php');
2526          return _adodb_getmenu($this,$name,$defstr,$blank1stItem,$multiple,
2527              $size, $selectAttr,false);
2528      }
2529  
2530  
2531      /**

2532       * return recordset as a 2-dimensional array.

2533       *

2534       * @param [nRows]  is the number of rows to return. -1 means every row.

2535       *

2536       * @return an array indexed by the rows (0-based) from the recordset

2537       */
2538      function &GetArray($nRows = -1) 
2539      {
2540      global $ADODB_EXTENSION; if ($ADODB_EXTENSION) return adodb_getall($this,$nRows);
2541          
2542          $results = array();
2543          $cnt = 0;
2544          while (!$this->EOF && $nRows != $cnt) {
2545              $results[] = $this->fields;
2546              $this->MoveNext();
2547              $cnt++;
2548          }
2549          return $results;
2550      }
2551      
2552      function &GetAll($nRows = -1)
2553      {
2554          $arr =& $this->GetArray($nRows);
2555          return $arr;
2556      }
2557      
2558      /*

2559      * Some databases allow multiple recordsets to be returned. This function

2560      * will return true if there is a next recordset, or false if no more.

2561      */
2562  	function NextRecordSet()
2563      {
2564          return false;
2565      }
2566      
2567      /**

2568       * return recordset as a 2-dimensional array. 

2569       * Helper function for ADOConnection->SelectLimit()

2570       *

2571       * @param offset    is the row to start calculations from (1-based)

2572       * @param [nrows]    is the number of rows to return

2573       *

2574       * @return an array indexed by the rows (0-based) from the recordset

2575       */
2576      function &GetArrayLimit($nrows,$offset=-1) 
2577      {    
2578          if ($offset <= 0) {
2579              $arr =& $this->GetArray($nrows);
2580              return $arr;
2581          } 
2582          
2583          $this->Move($offset);
2584          
2585          $results = array();
2586          $cnt = 0;
2587          while (!$this->EOF && $nrows != $cnt) {
2588              $results[$cnt++] = $this->fields;
2589              $this->MoveNext();
2590          }
2591          
2592          return $results;
2593      }
2594      
2595      
2596      /**

2597       * Synonym for GetArray() for compatibility with ADO.

2598       *

2599       * @param [nRows]  is the number of rows to return. -1 means every row.

2600       *

2601       * @return an array indexed by the rows (0-based) from the recordset

2602       */
2603      function &GetRows($nRows = -1) 
2604      {
2605          $arr =& $this->GetArray($nRows);
2606          return $arr;
2607      }
2608      
2609      /**

2610       * return whole recordset as a 2-dimensional associative array if there are more than 2 columns. 

2611       * The first column is treated as the key and is not included in the array. 

2612       * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless

2613       * $force_array == true.

2614       *

2615       * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional

2616       *     array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,

2617       *     read the source.

2618       *

2619       * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and 

2620       * instead of returning array[col0] => array(remaining cols), return array[col0] => col1

2621       *

2622       * @return an associative array indexed by the first column of the array, 

2623       *     or false if the  data has less than 2 cols.

2624       */
2625      function &GetAssoc($force_array = false, $first2cols = false) 
2626      {
2627      global $ADODB_EXTENSION;
2628      
2629          $cols = $this->_numOfFields;
2630          if ($cols < 2) {
2631              $false = false;
2632              return $false;
2633          }
2634          $numIndex = isset($this->fields[0]);
2635          $results = array();
2636          
2637          if (!$first2cols && ($cols > 2 || $force_array)) {
2638              if ($ADODB_EXTENSION) {
2639                  if ($numIndex) {
2640                      while (!$this->EOF) {
2641                          $results[trim($this->fields[0])] = array_slice($this->fields, 1);
2642                          adodb_movenext($this);
2643                      }
2644                  } else {
2645                      while (!$this->EOF) {
2646                          $results[trim(reset($this->fields))] = array_slice($this->fields, 1);
2647                          adodb_movenext($this);
2648                      }
2649                  }
2650              } else {
2651                  if ($numIndex) {
2652                      while (!$this->EOF) {
2653                          $results[trim($this->fields[0])] = array_slice($this->fields, 1);
2654                          $this->MoveNext();
2655                      }
2656                  } else {
2657                      while (!$this->EOF) {
2658                          $results[trim(reset($this->fields))] = array_slice($this->fields, 1);
2659                          $this->MoveNext();
2660                      }
2661                  }
2662              }
2663          } else {
2664              if ($ADODB_EXTENSION) {
2665                  // return scalar values

2666                  if ($numIndex) {
2667                      while (!$this->EOF) {
2668                      // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string

2669                          $results[trim(($this->fields[0]))] = $this->fields[1];
2670                          adodb_movenext($this);
2671                      }
2672                  } else {
2673                      while (!$this->EOF) {
2674                      // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string

2675                          $v1 = trim(reset($this->fields));
2676                          $v2 = ''.next($this->fields); 
2677                          $results[$v1] = $v2;
2678                          adodb_movenext($this);
2679                      }
2680                  }
2681              } else {
2682                  if ($numIndex) {
2683                      while (!$this->EOF) {
2684                      // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string

2685                          $results[trim(($this->fields[0]))] = $this->fields[1];
2686                          $this->MoveNext();
2687                      }
2688                  } else {
2689                      while (!$this->EOF) {
2690                      // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string

2691                          $v1 = trim(reset($this->fields));
2692                          $v2 = ''.next($this->fields); 
2693                          $results[$v1] = $v2;
2694                          $this->MoveNext();
2695                      }
2696                  }
2697              }
2698          }
2699          return $results; 
2700      }
2701      
2702      
2703      /**

2704       *

2705       * @param v      is the character timestamp in YYYY-MM-DD hh:mm:ss format

2706       * @param fmt     is the format to apply to it, using date()

2707       *

2708       * @return a timestamp formated as user desires

2709       */
2710  	function UserTimeStamp($v,$fmt='Y-m-d H:i:s')
2711      {
2712          if (is_numeric($v) && strlen($v)<14) return adodb_date($fmt,$v);
2713          $tt = $this->UnixTimeStamp($v);
2714          // $tt == -1 if pre TIMESTAMP_FIRST_YEAR

2715          if (($tt === false || $tt == -1) && $v != false) return $v;
2716          if ($tt === 0) return $this->emptyTimeStamp;
2717          return adodb_date($fmt,$tt);
2718      }
2719      
2720      
2721      /**

2722       * @param v      is the character date in YYYY-MM-DD format, returned by database

2723       * @param fmt     is the format to apply to it, using date()

2724       *

2725       * @return a date formated as user desires

2726       */
2727  	function UserDate($v,$fmt='Y-m-d')
2728      {
2729          $tt = $this->UnixDate($v);
2730          // $tt == -1 if pre TIMESTAMP_FIRST_YEAR

2731          if (($tt === false || $tt == -1) && $v != false) return $v;
2732          else if ($tt == 0) return $this->emptyDate;
2733          else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
2734          }
2735          return adodb_date($fmt,$tt);
2736      }
2737      
2738      
2739      /**

2740       * @param $v is a date string in YYYY-MM-DD format

2741       *

2742       * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format

2743       */
2744  	function UnixDate($v)
2745      {
2746          return ADOConnection::UnixDate($v);
2747      }
2748      
2749  
2750      /**

2751       * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format

2752       *

2753       * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format

2754       */
2755  	function UnixTimeStamp($v)
2756      {
2757          return ADOConnection::UnixTimeStamp($v);
2758      }
2759      
2760      
2761      /**

2762      * PEAR DB Compat - do not use internally

2763      */
2764  	function Free()
2765      {
2766          return $this->Close();
2767      }
2768      
2769      
2770      /**

2771      * PEAR DB compat, number of rows

2772      */
2773  	function NumRows()
2774      {
2775          return $this->_numOfRows;
2776      }
2777      
2778      
2779      /**

2780      * PEAR DB compat, number of cols

2781      */
2782  	function NumCols()
2783      {
2784          return $this->_numOfFields;
2785      }
2786      
2787      /**

2788      * Fetch a row, returning false if no more rows. 

2789      * This is PEAR DB compat mode.

2790      *

2791      * @return false or array containing the current record

2792      */
2793      function &FetchRow()
2794      {
2795          if ($this->EOF) {
2796              $false = false;
2797              return $false;
2798          }
2799          $arr = $this->fields;
2800          $this->_currentRow++;
2801          if (!$this->_fetch()) $this->EOF = true;
2802          return $arr;
2803      }
2804      
2805      
2806      /**

2807      * Fetch a row, returning PEAR_Error if no more rows. 

2808      * This is PEAR DB compat mode.

2809      *

2810      * @return DB_OK or error object

2811      */
2812  	function FetchInto(&$arr)
2813      {
2814          if ($this->EOF) return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false;
2815          $arr = $this->fields;
2816          $this->MoveNext();
2817          return 1; // DB_OK

2818      }
2819      
2820      
2821      /**

2822       * Move to the first row in the recordset. Many databases do NOT support this.

2823       *

2824       * @return true or false

2825       */
2826  	function MoveFirst() 
2827      {
2828          if ($this->_currentRow == 0) return true;
2829          return $this->Move(0);            
2830      }            
2831  
2832      
2833      /**

2834       * Move to the last row in the recordset. 

2835       *

2836       * @return true or false

2837       */
2838  	function MoveLast() 
2839      {
2840          if ($this->_numOfRows >= 0) return $this->Move($this->_numOfRows-1);
2841          if ($this->EOF) return false;
2842          while (!$this->EOF) {
2843              $f = $this->fields;
2844              $this->MoveNext();
2845          }
2846          $this->fields = $f;
2847          $this->EOF = false;
2848          return true;
2849      }
2850      
2851      
2852      /**

2853       * Move to next record in the recordset.

2854       *

2855       * @return true if there still rows available, or false if there are no more rows (EOF).

2856       */
2857  	function MoveNext() 
2858      {
2859          if (!$this->EOF) {
2860              $this->_currentRow++;
2861              if ($this->_fetch()) return true;
2862          }
2863          $this->EOF = true;
2864          /* -- tested error handling when scrolling cursor -- seems useless.

2865          $conn = $this->connection;

2866          if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {

2867              $fn = $conn->raiseErrorFn;

2868              $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);

2869          }

2870          */
2871          return false;
2872      }
2873      
2874      
2875      /**

2876       * Random access to a specific row in the recordset. Some databases do not support

2877       * access to previous rows in the databases (no scrolling backwards).

2878       *

2879       * @param rowNumber is the row to move to (0-based)

2880       *

2881       * @return true if there still rows available, or false if there are no more rows (EOF).

2882       */
2883  	function Move($rowNumber = 0) 
2884      {
2885          $this->EOF = false;
2886          if ($rowNumber == $this->_currentRow) return true;
2887          if ($rowNumber >= $this->_numOfRows)
2888                 if ($this->_numOfRows != -1) $rowNumber = $this->_numOfRows-2;
2889                    
2890          if ($this->canSeek) { 
2891      
2892              if ($this->_seek($rowNumber)) {
2893                  $this->_currentRow = $rowNumber;
2894                  if ($this->_fetch()) {
2895                      return true;
2896                  }
2897              } else {
2898                  $this->EOF = true;
2899                  return false;
2900              }
2901          } else {
2902              if ($rowNumber < $this->_currentRow) return false;
2903              global $ADODB_EXTENSION;
2904              if ($ADODB_EXTENSION) {
2905                  while (!$this->EOF && $this->_currentRow < $rowNumber) {
2906                      adodb_movenext($this);
2907                  }
2908              } else {
2909              
2910                  while (! $this->EOF && $this->_currentRow < $rowNumber) {
2911                      $this->_currentRow++;
2912                      
2913                      if (!$this->_fetch()) $this->EOF = true;
2914                  }
2915              }
2916              return !($this->EOF);
2917          }
2918          
2919          $this->fields = false;    
2920          $this->EOF = true;
2921          return false;
2922      }
2923      
2924          
2925      /**

2926       * Get the value of a field in the current row by column name.

2927       * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.

2928       * 

2929       * @param colname  is the field to access

2930       *

2931       * @return the value of $colname column

2932       */
2933  	function Fields($colname)
2934      {
2935          return $this->fields[$colname];
2936      }
2937      
2938  	function GetAssocKeys($upper=true)
2939      {
2940          $this->bind = array();
2941          for ($i=0; $i < $this->_numOfFields; $i++) {
2942              $o =& $this->FetchField($i);
2943              if ($upper === 2) $this->bind[$o->name] = $i;
2944              else $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $i;
2945          }
2946      }
2947      
2948    /**

2949     * Use associative array to get fields array for databases that do not support

2950     * associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it

2951     *

2952     * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC

2953     * before you execute your SQL statement, and access $rs->fields['col'] directly.

2954     *

2955     * $upper  0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField

2956     */
2957      function &GetRowAssoc($upper=1)
2958      {
2959          $record = array();
2960       //    if (!$this->fields) return $record;

2961          
2962             if (!$this->bind) {
2963              $this->GetAssocKeys($upper);
2964          }
2965          
2966          foreach($this->bind as $k => $v) {
2967              $record[$k] = $this->fields[$v];
2968          }
2969  
2970          return $record;
2971      }
2972      
2973      
2974      /**

2975       * Clean up recordset

2976       *

2977       * @return true or false

2978       */
2979  	function Close() 
2980      {
2981          // free connection object - this seems to globally free the object

2982          // and not merely the reference, so don't do this...

2983          // $this->connection = false; 

2984          if (!$this->_closed) {
2985              $this->_closed = true;
2986              return $this->_close();        
2987          } else
2988              return true;
2989      }
2990      
2991      /**

2992       * synonyms RecordCount and RowCount    

2993       *

2994       * @return the number of rows or -1 if this is not supported

2995       */
2996  	function RecordCount() {return $this->_numOfRows;}
2997      
2998      
2999      /*

3000      * If we are using PageExecute(), this will return the maximum possible rows

3001      * that can be returned when paging a recordset.

3002      */
3003  	function MaxRecordCount()
3004      {
3005          return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();
3006      }
3007      
3008      /**

3009       * synonyms RecordCount and RowCount    

3010       *

3011       * @return the number of rows or -1 if this is not supported

3012       */
3013  	function RowCount() {return $this->_numOfRows;} 
3014      
3015  
3016       /**

3017       * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>

3018       *

3019       * @return  the number of records from a previous SELECT. All databases support this.

3020       *

3021       * But aware possible problems in multiuser environments. For better speed the table

3022       * must be indexed by the condition. Heavy test this before deploying.

3023       */ 
3024  	function PO_RecordCount($table="", $condition="") {
3025          
3026          $lnumrows = $this->_numOfRows;
3027          // the database doesn't support native recordcount, so we do a workaround

3028          if ($lnumrows == -1 && $this->connection) {
3029              IF ($table) {
3030                  if ($condition) $condition = " WHERE " . $condition; 
3031                  $resultrows = &$this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
3032                  if ($resultrows) $lnumrows = reset($resultrows->fields);
3033              }
3034          }
3035          return $lnumrows;
3036      }
3037      
3038      /**

3039       * @return the current row in the recordset. If at EOF, will return the last row. 0-based.

3040       */
3041  	function CurrentRow() {return $this->_currentRow;}
3042      
3043      /**

3044       * synonym for CurrentRow -- for ADO compat

3045       *

3046       * @return the current row in the recordset. If at EOF, will return the last row. 0-based.

3047       */
3048  	function AbsolutePosition() {return $this->_currentRow;}
3049      
3050      /**

3051       * @return the number of columns in the recordset. Some databases will set this to 0

3052       * if no records are returned, others will return the number of columns in the query.

3053       */
3054  	function FieldCount() {return $this->_numOfFields;}   
3055  
3056  
3057      /**

3058       * Get the ADOFieldObject of a specific column.

3059       *

3060       * @param fieldoffset    is the column position to access(0-based).

3061       *

3062       * @return the ADOFieldObject for that column, or false.

3063       */
3064      function &FetchField($fieldoffset) 
3065      {
3066          // must be defined by child class

3067      }    
3068      
3069      /**

3070       * Get the ADOFieldObjects of all columns in an array.

3071       *

3072       */
3073      function& FieldTypesArray()
3074      {
3075          $arr = array();
3076          for ($i=0, $max=$this->_numOfFields; $i < $max; $i++) 
3077              $arr[] = $this->FetchField($i);
3078          return $arr;
3079      }
3080      
3081      /**

3082      * Return the fields array of the current row as an object for convenience.

3083      * The default case is lowercase field names.

3084      *

3085      * @return the object with the properties set to the fields of the current row

3086      */
3087      function &FetchObj()
3088      {
3089          $o =& $this->FetchObject(false);
3090          return $o;
3091      }
3092      
3093      /**

3094      * Return the fields array of the current row as an object for convenience.

3095      * The default case is uppercase.

3096      * 

3097      * @param $isupper to set the object property names to uppercase

3098      *

3099      * @return the object with the properties set to the fields of the current row

3100      */
3101      function &FetchObject($isupper=true)
3102      {
3103          if (empty($this->_obj)) {
3104              $this->_obj =& new ADOFetchObj();
3105              $this->_names = array();
3106              for ($i=0; $i <$this->_numOfFields; $i++) {
3107                  $f = $this->FetchField($i);
3108                  $this->_names[] = $f->name;
3109              }
3110          }
3111          $i = 0;
3112          if (PHP_VERSION >= 5) $o = clone($this->_obj);
3113          else $o = $this->_obj;
3114      
3115          for ($i=0; $i <$this->_numOfFields; $i++) {
3116              $name = $this->_names[$i];
3117              if ($isupper) $n = strtoupper($name);
3118              else $n = $name;
3119              
3120              $o->$n = $this->Fields($name);
3121          }
3122          return $o;
3123      }
3124      
3125      /**

3126      * Return the fields array of the current row as an object for convenience.

3127      * The default is lower-case field names.

3128      * 

3129      * @return the object with the properties set to the fields of the current row,

3130      *     or false if EOF

3131      *

3132      * Fixed bug reported by tim@orotech.net

3133      */
3134      function &FetchNextObj()
3135      {
3136          $o =& $this->FetchNextObject(false);
3137          return $o;
3138      }
3139      
3140      
3141      /**

3142      * Return the fields array of the current row as an object for convenience. 

3143      * The default is upper case field names.

3144      * 

3145      * @param $isupper to set the object property names to uppercase

3146      *

3147      * @return the object with the properties set to the fields of the current row,

3148      *     or false if EOF

3149      *

3150      * Fixed bug reported by tim@orotech.net

3151      */
3152      function &FetchNextObject($isupper=true)
3153      {
3154          $o = false;
3155          if ($this->_numOfRows != 0 && !$this->EOF) {
3156              $o = $this->FetchObject($isupper);    
3157              $this->_currentRow++;
3158              if ($this->_fetch()) return $o;
3159          }
3160          $this->EOF = true;
3161          return $o;
3162      }
3163      
3164      /**

3165       * Get the metatype of the column. This is used for formatting. This is because

3166       * many databases use different names for the same type, so we transform the original

3167       * type to our standardised version which uses 1 character codes:

3168       *

3169       * @param t  is the type passed in. Normally is ADOFieldObject->type.

3170       * @param len is the maximum length of that field. This is because we treat character

3171       *     fields bigger than a certain size as a 'B' (blob).

3172       * @param fieldobj is the field object returned by the database driver. Can hold

3173       *    additional info (eg. primary_key for mysql).

3174       * 

3175       * @return the general type of the data: 

3176       *    C for character < 250 chars

3177       *    X for teXt (>= 250 chars)

3178       *    B for Binary

3179       *     N for numeric or floating point

3180       *    D for date

3181       *    T for timestamp

3182       *     L for logical/Boolean

3183       *    I for integer

3184       *    R for autoincrement counter/integer

3185       * 

3186       *

3187      */
3188  	function MetaType($t,$len=-1,$fieldobj=false)
3189      {
3190          if (is_object($t)) {
3191              $fieldobj = $t;
3192              $t = $fieldobj->type;
3193              $len = $fieldobj->max_length;
3194          }
3195      // changed in 2.32 to hashing instead of switch stmt for speed...

3196      static $typeMap = array(
3197          'VARCHAR' => 'C',
3198          'VARCHAR2' => 'C',
3199          'CHAR' => 'C',
3200          'C' => 'C',
3201          'STRING' => 'C',
3202          'NCHAR' => 'C',
3203          'NVARCHAR' => 'C',
3204          'VARYING' => 'C',
3205          'BPCHAR' => 'C',
3206          'CHARACTER' => 'C',
3207          'INTERVAL' => 'C',  # Postgres
3208          ##

3209          'LONGCHAR' => 'X',
3210          'TEXT' => 'X',
3211          'NTEXT' => 'X',
3212          'M' => 'X',
3213          'X' => 'X',
3214          'CLOB' => 'X',
3215          'NCLOB' => 'X',
3216          'LVARCHAR' => 'X',
3217          ##

3218          'BLOB' => 'B',
3219          'IMAGE' => 'B',
3220          'BINARY' => 'B',
3221          'VARBINARY' => 'B',
3222          'LONGBINARY' => 'B',
3223          'B' => 'B',
3224          ##

3225          'YEAR' => 'D', // mysql
3226          'DATE' => 'D',
3227          'D' => 'D',
3228          ##

3229          'TIME' => 'T',
3230          'TIMESTAMP' => 'T',
3231          'DATETIME' => 'T',
3232          'TIMESTAMPTZ' => 'T',
3233          'T' => 'T',
3234          ##

3235          'BOOL' => 'L',
3236          'BOOLEAN' => 'L', 
3237          'BIT' => 'L',
3238          'L' => 'L',
3239          ##

3240          'COUNTER' => 'R',
3241          'R' => 'R',
3242          'SERIAL' => 'R', // ifx
3243          'INT IDENTITY' => 'R',
3244          ##

3245          'INT' => 'I',
3246          'INT2' => 'I',
3247          'INT4' => 'I',
3248          'INT8' => 'I',
3249          'INTEGER' => 'I',
3250          'INTEGER UNSIGNED' => 'I',
3251          'SHORT' => 'I',
3252          'TINYINT' => 'I',
3253          'SMALLINT' => 'I',
3254          'I' => 'I',
3255          ##

3256          'LONG' => 'N', // interbase is numeric, oci8 is blob
3257          'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
3258          'DECIMAL' => 'N',
3259          'DEC' => 'N',
3260          'REAL' => 'N',
3261          'DOUBLE' => 'N',
3262          'DOUBLE PRECISION' => 'N',
3263          'SMALLFLOAT' => 'N',
3264          'FLOAT' => 'N',
3265          'NUMBER' => 'N',
3266          'NUM' => 'N',
3267          'NUMERIC' => 'N',
3268          'MONEY' => 'N',
3269          
3270          ## informix 9.2

3271          'SQLINT' => 'I', 
3272          'SQLSERIAL' => 'I', 
3273          'SQLSMINT' => 'I', 
3274          'SQLSMFLOAT' => 'N', 
3275          'SQLFLOAT' => 'N', 
3276          'SQLMONEY' => 'N', 
3277          'SQLDECIMAL' => 'N', 
3278          'SQLDATE' => 'D', 
3279          'SQLVCHAR' => 'C', 
3280          'SQLCHAR' => 'C', 
3281          'SQLDTIME' => 'T', 
3282          'SQLINTERVAL' => 'N', 
3283          'SQLBYTES' => 'B', 
3284          'SQLTEXT' => 'X' 
3285          );
3286          
3287          $tmap = false;
3288          $t = strtoupper($t);
3289          $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N';
3290          switch ($tmap) {
3291          case 'C':
3292          
3293              // is the char field is too long, return as text field... 

3294              if ($this->blobSize >= 0) {
3295                  if ($len > $this->blobSize) return 'X';
3296              } else if ($len > 250) {
3297                  return 'X';
3298              }
3299              return 'C';
3300              
3301          case 'I':
3302              if (!empty($fieldobj->primary_key)) return 'R';
3303              return 'I';
3304          
3305          case false:
3306              return 'N';
3307              
3308          case 'B':
3309               if (isset($fieldobj->binary)) 
3310                   return ($fieldobj->binary) ? 'B' : 'X';
3311              return 'B';
3312          
3313          case 'D':
3314              if (!empty($this->datetime)) return 'T';
3315              return 'D';
3316              
3317          default: 
3318              if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B';
3319              return $tmap;
3320          }
3321      }
3322      
3323  	function _close() {}
3324      
3325      /**

3326       * set/returns the current recordset page when paginating

3327       */
3328  	function AbsolutePage($page=-1)
3329      {
3330          if ($page != -1) $this->_currentPage = $page;
3331          return $this->_currentPage;
3332      }
3333      
3334      /**

3335       * set/returns the status of the atFirstPage flag when paginating

3336       */
3337  	function AtFirstPage($status=false)
3338      {
3339          if ($status != false) $this->_atFirstPage = $status;
3340          return $this->_atFirstPage;
3341      }
3342      
3343  	function LastPageNo($page = false)
3344      {
3345          if ($page != false) $this->_lastPageNo = $page;
3346          return $this->_lastPageNo;
3347      }
3348      
3349      /**

3350       * set/returns the status of the atLastPage flag when paginating

3351       */
3352  	function AtLastPage($status=false)
3353      {
3354          if ($status != false) $this->_atLastPage = $status;
3355          return $this->_atLastPage;
3356      }
3357      
3358  } // end class ADORecordSet

3359      
3360      //==============================================================================================    

3361      // CLASS ADORecordSet_array

3362      //==============================================================================================    

3363      
3364      /**

3365       * This class encapsulates the concept of a recordset created in memory

3366       * as an array. This is useful for the creation of cached recordsets.

3367       * 

3368       * Note that the constructor is different from the standard ADORecordSet

3369       */
3370      
3371      class ADORecordSet_array extends ADORecordSet
3372      {
3373          var $databaseType = 'array';
3374  
3375          var $_array;     // holds the 2-dimensional data array

3376          var $_types;    // the array of types of each column (C B I L M)

3377          var $_colnames;    // names of each column in array

3378          var $_skiprow1;    // skip 1st row because it holds column names

3379          var $_fieldarr; // holds array of field objects

3380          var $canSeek = true;
3381          var $affectedrows = false;
3382          var $insertid = false;
3383          var $sql = '';
3384          var $compat = false;
3385          /**

3386           * Constructor

3387           *

3388           */
3389  		function ADORecordSet_array($fakeid=1)
3390          {
3391          global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;
3392          
3393              // fetch() on EOF does not delete $this->fields

3394              $this->compat = !empty($ADODB_COMPAT_FETCH);
3395              $this->ADORecordSet($fakeid); // fake queryID        

3396              $this->fetchMode = $ADODB_FETCH_MODE;
3397          }
3398          
3399          
3400          /**

3401           * Setup the array.

3402           *

3403           * @param array        is a 2-dimensional array holding the data.

3404           *            The first row should hold the column names 

3405           *            unless paramter $colnames is used.

3406           * @param typearr    holds an array of types. These are the same types 

3407           *            used in MetaTypes (C,B,L,I,N).

3408           * @param [colnames]    array of column names. If set, then the first row of

3409           *            $array should not hold the column names.

3410           */
3411  		function InitArray($array,$typearr,$colnames=false)
3412          {
3413              $this->_array = $array;
3414              $this->_types = $typearr;    
3415              if ($colnames) {
3416                  $this->_skiprow1 = false;
3417                  $this->_colnames = $colnames;
3418              } else  {
3419                  $this->_skiprow1 = true;
3420                  $this->_colnames = $array[0];
3421              }
3422              $this->Init();
3423          }
3424          /**

3425           * Setup the Array and datatype file objects

3426           *

3427           * @param array        is a 2-dimensional array holding the data.

3428           *            The first row should hold the column names 

3429           *            unless paramter $colnames is used.

3430           * @param fieldarr    holds an array of ADOFieldObject's.

3431           */
3432  		function InitArrayFields(&$array,&$fieldarr)
3433          {
3434              $this->_array =& $array;
3435              $this->_skiprow1= false;
3436              if ($fieldarr) {
3437                  $this->_fieldobjects =& $fieldarr;
3438              } 
3439              $this->Init();
3440          }
3441          
3442          function &GetArray($nRows=-1)
3443          {
3444              if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) {
3445                  return $this->_array;
3446              } else {
3447                  $arr =& ADORecordSet::GetArray($nRows);
3448                  return $arr;
3449              }
3450          }
3451          
3452  		function _initrs()
3453          {
3454              $this->_numOfRows =  sizeof($this->_array);
3455              if ($this->_skiprow1) $this->_numOfRows -= 1;
3456          
3457              $this->_numOfFields =(isset($this->_fieldobjects)) ?
3458                   sizeof($this->_fieldobjects):sizeof($this->_types);
3459          }
3460          
3461          /* Use associative array to get fields array */

3462  		function Fields($colname)
3463          {
3464              $mode = isset($this->adodbFetchMode) ? $this->adodbFetchMode : $this->fetchMode;
3465      
3466              if ($mode & ADODB_FETCH_ASSOC) {
3467                  if (!isset($this->fields[$colname])) $colname = strtolower($colname);
3468                  return $this->fields[$colname];
3469              }
3470              if (!$this->bind) {
3471                  $this->bind = array();
3472                  for ($i=0; $i < $this->_numOfFields; $i++) {
3473                      $o = $this->FetchField($i);
3474                      $this->bind[strtoupper($o->name)] = $i;
3475                  }
3476              }
3477              return $this->fields[$this->bind[strtoupper($colname)]];
3478          }
3479          
3480          function &FetchField($fieldOffset = -1) 
3481          {
3482              if (isset($this->_fieldobjects)) {
3483                  return $this->_fieldobjects[$fieldOffset];
3484              }
3485              $o =  new ADOFieldObject();
3486              $o->name = $this->_colnames[$fieldOffset];
3487              $o->type =  $this->_types[$fieldOffset];
3488              $o->max_length = -1; // length not known

3489              
3490              return $o;
3491          }
3492              
3493  		function _seek($row)
3494          {
3495              if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) {
3496                  $this->_currentRow = $row;
3497                  if ($this->_skiprow1) $row += 1;
3498                  $this->fields = $this->_array[$row];
3499                  return true;
3500              }
3501              return false;
3502          }
3503          
3504  		function MoveNext() 
3505          {
3506              if (!$this->EOF) {        
3507                  $this->_currentRow++;
3508                  
3509                  $pos = $this->_currentRow;
3510                  
3511                  if ($this->_numOfRows <= $pos) {
3512                      if (!$this->compat) $this->fields = false;
3513                  } else {
3514                      if ($this->_skiprow1) $pos += 1;
3515                      $this->fields = $this->_array[$pos];
3516                      return true;
3517                  }        
3518                  $this->EOF = true;
3519              }
3520              
3521              return false;
3522          }    
3523      
3524  		function _fetch()
3525          {
3526              $pos = $this->_currentRow;
3527              
3528              if ($this->_numOfRows <= $pos) {
3529                  if (!$this->compat) $this->fields = false;
3530                  return false;
3531              }
3532              if ($this->_skiprow1) $pos += 1;
3533              $this->fields = $this->_array[$pos];
3534              return true;
3535          }
3536          
3537  		function _close() 
3538          {
3539              return true;    
3540          }
3541      
3542      } // ADORecordSet_array

3543  
3544      //==============================================================================================    

3545      // HELPER FUNCTIONS

3546      //==============================================================================================            

3547      
3548      /**

3549       * Synonym for ADOLoadCode. Private function. Do not use.

3550       *

3551       * @deprecated

3552       */
3553  	function ADOLoadDB($dbType) 
3554      { 
3555          return ADOLoadCode($dbType);
3556      }
3557          
3558      /**

3559       * Load the code for a specific database driver. Private function. Do not use.

3560       */
3561  	function ADOLoadCode($dbType) 
3562      {
3563      global $ADODB_LASTDB;
3564      
3565          if (!$dbType) return false;
3566          $db = strtolower($dbType);
3567          switch ($db) {
3568              case 'ado': 
3569                  if (PHP_VERSION >= 5) $db = 'ado5';
3570                  $class = 'ado'; 
3571                  break;
3572              case 'ifx':
3573              case 'maxsql': $class = $db = 'mysqlt'; break;
3574              case 'postgres':
3575              case 'postgres8':
3576              case 'pgsql': $class = $db = 'postgres7'; break;
3577              default:
3578                  $class = $db; break;
3579          }
3580          
3581          $file = ADODB_DIR."/drivers/adodb-".$db.".inc.php";
3582          @include_once($file);
3583          $ADODB_LASTDB = $class;
3584          
3585          if (class_exists("ADODB_" . $db)) return $class;
3586          
3587          //ADOConnection::outp(adodb_pr(get_declared_classes(),true));

3588          if (!file_exists($file)) ADOConnection::outp("Missing file: $file");
3589          else ADOConnection::outp("Syntax error in file: $file");
3590          return false;
3591      }
3592  
3593      /**

3594       * synonym for ADONewConnection for people like me who cannot remember the correct name

3595       */
3596      function &NewADOConnection($db='')
3597      {
3598          $tmp =& ADONewConnection($db);
3599          return $tmp;
3600      }
3601      
3602      /**

3603       * Instantiate a new Connection class for a specific database driver.

3604       *

3605       * @param [db]  is the database Connection object to create. If undefined,

3606       *     use the last database driver that was loaded by ADOLoadCode().

3607       *

3608       * @return the freshly created instance of the Connection class.

3609       */
3610      function &ADONewConnection($db='')
3611      {
3612      GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB;
3613          
3614          if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
3615          $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false;
3616          $false = false;
3617          if (strpos($db,'://')) {
3618              $origdsn = $db;
3619              $dsna = @parse_url($db);
3620              if (!$dsna) {
3621                  // special handling of oracle, which might not have host

3622                  $db = str_replace('@/','@adodb-fakehost/',$db);
3623                  $dsna = parse_url($db);
3624                  if (!$dsna) return $false;
3625                  $dsna['host'] = '';
3626              }
3627              $db = @$dsna['scheme'];
3628              if (!$db) return $false;
3629              $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : '';
3630              $dsna['user'] = isset($dsna['user']) ? rawurldecode($dsna['user']) : '';
3631              $dsna['pass'] = isset($dsna['pass']) ? rawurldecode($dsna['pass']) : '';
3632              $dsna['path'] = isset($dsna['path']) ? rawurldecode(substr($dsna['path'],1)) : ''; # strip off initial /

3633              
3634              if (isset($dsna['query'])) {
3635                  $opt1 = explode('&',$dsna['query']);
3636                  foreach($opt1 as $k => $v) {
3637                      $arr = explode('=',$v);
3638                      $opt[$arr[0]] = isset($arr[1]) ? rawurldecode($arr[1]) : 1;
3639                  }
3640              } else $opt = array();
3641          }
3642          
3643      /*

3644       *  phptype: Database backend used in PHP (mysql, odbc etc.)

3645       *  dbsyntax: Database used with regards to SQL syntax etc.

3646       *  protocol: Communication protocol to use (tcp, unix etc.)

3647       *  hostspec: Host specification (hostname[:port])

3648       *  database: Database to use on the DBMS server

3649       *  username: User name for login

3650       *  password: Password for login

3651       */
3652          if (!empty($ADODB_NEWCONNECTION)) {
3653              $obj = $ADODB_NEWCONNECTION($db);
3654  
3655          } else {
3656          
3657              if (!isset($ADODB_LASTDB)) $ADODB_LASTDB = '';
3658              if (empty($db)) $db = $ADODB_LASTDB;
3659              
3660              if ($db != $ADODB_LASTDB) $db = ADOLoadCode($db);
3661              
3662              if (!$db) {
3663                  if (isset($origdsn)) $db = $origdsn;
3664                  if ($errorfn) {
3665                      // raise an error

3666                      $ignore = false;
3667                      $errorfn('ADONewConnection', 'ADONewConnection', -998,
3668                               "could not load the database driver for '$db'",
3669                               $db,false,$ignore);
3670                  } else
3671                       ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false);
3672                      
3673                  return $false;
3674              }
3675              
3676              $cls = 'ADODB_'.$db;
3677              if (!class_exists($cls)) {
3678                  adodb_backtrace();
3679                  return $false;
3680              }
3681              
3682              $obj =& new $cls();
3683          }
3684          
3685          # constructor should not fail

3686          if ($obj) {
3687              if ($errorfn)  $obj->raiseErrorFn = $errorfn;
3688              if (isset($dsna)) {
3689              
3690                  foreach($opt as $k => $v) {
3691                      switch(strtolower($k)) {
3692                      case 'persist':
3693                      case 'persistent':     $persist = $v; break;
3694                      case 'debug':        $obj->debug = (integer) $v; break;
3695                      #ibase

3696                      case 'role':        $obj->role = $v; break;
3697                      case 'dialect':     $obj->dialect = (integer) $v; break;
3698                      case 'charset':        $obj->charset = $v; break;
3699                      case 'buffers':        $obj->buffers = $v; break;
3700                      case 'fetchmode':   $obj->SetFetchMode($v); break;
3701                      #ado

3702                      case 'charpage':    $obj->charPage = $v; break;
3703                      #mysql, mysqli

3704                      case 'clientflags': $obj->clientFlags = $v; break;
3705                      #mysqli

3706                      case 'port': $obj->port = $v; break;
3707                      case 'socket': $obj->socket = $v; break;
3708                      #oci8

3709                      case 'nls_date_format': $obj->NLS_DATE_FORMAT = $v; break;
3710                      }
3711                  }
3712                  if (empty($persist))
3713                      $ok = $obj->Connect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
3714                  else
3715                      $ok = $obj->PConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
3716                      
3717                  if (!$ok) return $false;
3718              }
3719          }
3720          return $obj;
3721      }
3722      
3723      
3724      
3725      // $perf == true means called by NewPerfMonitor()

3726  	function _adodb_getdriver($provider,$drivername,$perf=false)
3727      {
3728          switch ($provider) {
3729          case 'odbtp':   if (strncmp('odbtp_',$drivername,6)==0) return substr($drivername,6); 
3730          case 'odbc' :   if (strncmp('odbc_',$drivername,5)==0) return substr($drivername,5); 
3731          case 'ado'  :   if (strncmp('ado_',$drivername,4)==0) return substr($drivername,4);
3732          case 'native':  break;
3733          default:
3734              return $provider;
3735          }
3736          
3737          switch($drivername) {
3738          case 'oracle': $drivername = 'oci8'; break;
3739          case 'access': if ($perf) $drivername = ''; break;
3740          case 'db2'   : break;
3741          case 'sapdb' : break;
3742          default:
3743              $drivername = 'generic';
3744              break;
3745          }
3746          return $drivername;
3747      }
3748      
3749      function &NewPerfMonitor(&$conn)
3750      {
3751          $false = false;
3752          $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType,true);
3753          if (!$drivername || $drivername == 'generic') return $false;
3754          include_once (ADODB_DIR.'/adodb-perf.inc.php');
3755          @include_once(ADODB_DIR."/perf/perf-$drivername.inc.php");
3756          $class = "Perf_$drivername";
3757          if (!class_exists($class)) return $false;
3758          $perf =& new $class($conn);
3759          
3760          return $perf;
3761      }
3762      
3763      function &NewDataDictionary(&$conn,$drivername=false)
3764      {
3765          $false = false;
3766          if (!$drivername) $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType);
3767  
3768          include_once (ADODB_DIR.'/adodb-lib.inc.php');
3769          include_once (ADODB_DIR.'/adodb-datadict.inc.php');
3770          $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php";
3771  
3772          if (!file_exists($path)) {
3773              ADOConnection::outp("Database driver '$path' not available");
3774              return $false;
3775          }
3776          include_once($path);
3777          $class = "ADODB2_$drivername";
3778          $dict =& new $class();
3779          $dict->dataProvider = $conn->dataProvider;
3780          $dict->connection = &$conn;
3781          $dict->upperName = strtoupper($drivername);
3782          $dict->quote = $conn->nameQuote;
3783          if (!empty($conn->_connectionID))
3784              $dict->serverInfo = $conn->ServerInfo();
3785          
3786          return $dict;
3787      }
3788  
3789  
3790      
3791      /*

3792          Perform a print_r, with pre tags for better formatting.

3793      */
3794  	function adodb_pr($var,$as_string=false)
3795      {
3796          if ($as_string) ob_start();
3797          
3798          if (isset($_SERVER['HTTP_USER_AGENT'])) { 
3799              echo " <pre>\n";print_r($var);echo "</pre>\n";
3800          } else
3801              print_r($var);
3802              
3803          if ($as_string) {
3804              $s = ob_get_contents();
3805              ob_end_clean();
3806              return $s;
3807          }
3808      }
3809      
3810      /*

3811          Perform a stack-crawl and pretty print it.

3812          

3813          @param printOrArr  Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then).

3814          @param levels Number of levels to display

3815      */
3816  	function adodb_backtrace($printOrArr=true,$levels=9999)
3817      {
3818          global $ADODB_INCLUDED_LIB;
3819          if (empty($ADODB_INCLUDED_LIB)) include_once (ADODB_DIR.'/adodb-lib.inc.php');
3820          return _adodb_backtrace($printOrArr,$levels);
3821      }
3822      
3823  } // defined

3824  ?>

title

Description

title

Description

title

Description

title

title

Body