[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1