[ Index ]

PHP Cross Reference of vtigercrm-6.1.0

title

Body

[close]

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

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


Generated: Fri Nov 28 20:08:37 2014 Cross-referenced by PHPXref 0.7.1