Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
<?php
< /* < * Set tabs to 4 for best viewing.
> /** > * ADOdb Library main include file.
*
< * Latest version is available at http://adodb.org/
> * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
*
< * This is the main include file for ADOdb. < * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php
> * @package ADOdb > * @link https://adodb.org Project's web site and documentation > * @link https://github.com/ADOdb/ADOdb Source code and issue tracker > * > * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause > * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option, > * any later version. This means you can use it in proprietary products. > * See the LICENSE.md file distributed with this source code for details. > * @license BSD-3-Clause > * @license LGPL-2.1-or-later
*
< * The ADOdb files are formatted so that doxygen can be used to generate documentation. < * Doxygen is a documentation generation tool and can be downloaded from http://doxygen.org/ < */ < < /** < \mainpage < < @version v5.20.16 12-Jan-2020 < @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved. < @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community < < Released under both BSD license and Lesser GPL library license. You can choose which license < you prefer. < < PHP's database access functions are not standardised. This creates a need for a database < class library to hide the differences between the different database API's (encapsulate < the differences) so we can easily switch databases. < < We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, DB2, < Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access, < ADO, SAP DB, SQLite and ODBC. We have had successful reports of connecting to Progress and < other databases via ODBC.
> * @copyright 2000-2013 John Lim > * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
*/ if (!defined('_ADODB_LAYER')) { define('_ADODB_LAYER',1); // The ADOdb extension is no longer maintained and effectively unsupported // since v5.04. The library will not function properly if it is present. if(defined('ADODB_EXTENSION')) { $msg = "Unsupported ADOdb Extension (v" . ADODB_EXTENSION . ") detected! " . "Disable it to use ADOdb"; $errorfn = defined('ADODB_ERROR_HANDLER') ? ADODB_ERROR_HANDLER : false; if ($errorfn) { $conn = false; $errorfn('ADOdb', basename(__FILE__), -9999, $msg, null, null, $conn); } else { die($msg . PHP_EOL); } } //============================================================================================== // CONSTANT DEFINITIONS //============================================================================================== /** * Set ADODB_DIR to the directory where this file resides... * This constant was formerly called $ADODB_RootPath */ if (!defined('ADODB_DIR')) { define('ADODB_DIR',dirname(__FILE__)); } //============================================================================================== // GLOBAL VARIABLES //============================================================================================== GLOBAL $ADODB_vers, // database version $ADODB_COUNTRECS, // count number of records returned - slows down query $ADODB_CACHE_DIR, // directory to cache recordsets $ADODB_CACHE, $ADODB_CACHE_CLASS,
< $ADODB_EXTENSION, // ADODB extension installed
$ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF $ADODB_FETCH_MODE, // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default... $ADODB_GETONE_EOF, $ADODB_QUOTE_FIELDNAMES; // Allows you to force quotes (backticks) around field names in queries generated by getinsertsql and getupdatesql. //============================================================================================== // GLOBAL SETUP //==============================================================================================
< $ADODB_EXTENSION = defined('ADODB_EXTENSION'); < < // ******************************************************** < // Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3). < // Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi < // < // 0 = ignore empty fields. All empty fields in array are ignored. < // 1 = force null. All empty, php null and string 'null' fields are changed to sql NULL values. < // 2 = force empty. All empty, php null and string 'null' fields are changed to sql empty '' or 0 values. < // 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. <
> /********************************************************* > * Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3). > * Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi > * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:adodb_force_type > * > * 0 = ignore empty fields. All empty fields in array are ignored. > * 1 = force null. All empty, php null and string 'null' fields are > * changed to sql NULL values. > * 2 = force empty. All empty, php null and string 'null' fields are > * changed to sql empty '' or 0 values. > * 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. > * 4 = force value. Like 1 but numeric empty fields are set to zero. > */
define('ADODB_FORCE_IGNORE',0); define('ADODB_FORCE_NULL',1); define('ADODB_FORCE_EMPTY',2); define('ADODB_FORCE_VALUE',3);
> define('ADODB_FORCE_NULL_AND_ZERO',4);
// ********************************************************
< if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) {
> /** > * Constants for returned values from the charMax and textMax methods. > * If not specifically defined in the driver, methods return the NOTSET value. > */ > define ('ADODB_STRINGMAX_NOTSET', -1); > define ('ADODB_STRINGMAX_NOLIMIT',-2); > > /* > * Defines the the default meta type returned > * when ADOdb encounters a type that it is not > * defined in the metaTypes. > */ > if (!defined('ADODB_DEFAULT_METATYPE')) > define ('ADODB_DEFAULT_METATYPE','N');
define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>'); // allow [ ] @ ` " and . in table names define('ADODB_TABLE_REGEX','([]0-9a-z_\:\"\`\.\@\[-]*)'); // prefetching used by oracle if (!defined('ADODB_PREFETCH_ROWS')) { define('ADODB_PREFETCH_ROWS',10); } /** * Fetch mode * * Set global variable $ADODB_FETCH_MODE to one of these constants or use * the SetFetchMode() method to control how recordset fields are returned * when fetching data. * * - NUM: array() * - ASSOC: array('id' => 456, 'name' => 'john') * - BOTH: array(0 => 456, 'id' => 456, 1 => 'john', 'name' => 'john') * - DEFAULT: driver-dependent */ define('ADODB_FETCH_DEFAULT', 0); define('ADODB_FETCH_NUM', 1); define('ADODB_FETCH_ASSOC', 2); define('ADODB_FETCH_BOTH', 3); /** * Associative array case constants * * By defining the ADODB_ASSOC_CASE constant to one of these values, it is * possible to control the case of field names (associative array's keys) * when operating in ADODB_FETCH_ASSOC fetch mode. * - LOWER: $rs->fields['orderid'] * - UPPER: $rs->fields['ORDERID'] * - NATIVE: $rs->fields['OrderID'] (or whatever the RDBMS will return) * * The default is to use native case-names. * * NOTE: This functionality is not implemented everywhere, it currently * works only with: mssql, odbc, oci8 and ibase derived drivers */ define('ADODB_ASSOC_CASE_LOWER', 0); define('ADODB_ASSOC_CASE_UPPER', 1); define('ADODB_ASSOC_CASE_NATIVE', 2); if (!defined('TIMESTAMP_FIRST_YEAR')) { define('TIMESTAMP_FIRST_YEAR',100); } /** * AutoExecute constants * (moved from adodb-pear.inc.php since they are only used in here) */ define('DB_AUTOQUERY_INSERT', 1); define('DB_AUTOQUERY_UPDATE', 2);
< // PHP's version scheme makes converting to numbers difficult - workaround < $_adodb_ver = (float) PHP_VERSION; < if ($_adodb_ver >= 5.2) { < define('ADODB_PHPVER',0x5200); < } else if ($_adodb_ver >= 5.0) { < define('ADODB_PHPVER',0x5000); < } else { < die("PHP5 or later required. You are running ".PHP_VERSION); < } < unset($_adodb_ver); < } < < < /** < Accepts $src and $dest arrays, replacing string $data < */ < function ADODB_str_replace($src, $dest, $data) { < if (ADODB_PHPVER >= 0x4050) { < return str_replace($src,$dest,$data); < } < < $s = reset($src); < $d = reset($dest); < while ($s !== false) { < $data = str_replace($s,$d,$data); < $s = next($src); < $d = next($dest); < } < return $data; < }
function ADODB_Setup() { GLOBAL $ADODB_vers, // database version $ADODB_COUNTRECS, // count number of records returned - slows down query $ADODB_CACHE_DIR, // directory to cache recordsets $ADODB_FETCH_MODE, $ADODB_CACHE, $ADODB_CACHE_CLASS, $ADODB_FORCE_TYPE, $ADODB_GETONE_EOF, $ADODB_QUOTE_FIELDNAMES; if (empty($ADODB_CACHE_CLASS)) { $ADODB_CACHE_CLASS = 'ADODB_Cache_File' ; } $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT; $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE; $ADODB_GETONE_EOF = null; if (!isset($ADODB_CACHE_DIR)) { $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp'; } else { // do not accept url based paths, eg. http:/ or ftp:/ if (strpos($ADODB_CACHE_DIR,'://') !== false) { die("Illegal path http:// or ftp://"); } } /** * ADODB version as a string. */
< $ADODB_vers = 'v5.20.16 12-Jan-2020';
> $ADODB_vers = 'v5.22.5 2023-04-03';
/** * Determines whether recordset->RecordCount() is used. * Set to false for highest performance -- RecordCount() will always return -1 then * for databases that provide "virtual" recordcounts... */ if (!isset($ADODB_COUNTRECS)) { $ADODB_COUNTRECS = true; } } //============================================================================================== // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB //============================================================================================== ADODB_Setup(); //============================================================================================== // CLASS ADOFieldObject //============================================================================================== /**
< * Helper class for FetchFields -- holds info on a column
> * Helper class for FetchFields -- holds info on a column. > * > * Note: Dynamic properties are required here, as some drivers may require > * the object to hold database-specific field metadata.
*/
> #[\AllowDynamicProperties]
class ADOFieldObject { var $name = ''; var $max_length=0; var $type=""; /* // additional fields by dannym... (danny_milo@yahoo.com) var $not_null = false; // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^ // so we can as well make not_null standard (leaving it at "false" does not harm anyways) var $has_default = false; // this one I have done only in mysql and postgres for now ... // others to come (dannym) var $default_value; // default, if any, and supported. Check has_default first. */ }
> /** function _adodb_safedate($s) { > * Parse date string to prevent injection attack. return str_replace(array("'", '\\'), '', $s); > * } > * @param string $s > * // parse date string to prevent injection attack > * @return string // date string will have one quote at beginning e.g. '3434343' > */
< // parse date string to prevent injection attack < // date string will have one quote at beginning e.g. '3434343'
> /** > * Parse date string to prevent injection attack. > * Date string will have one quote at beginning e.g. '3434343' > * > * @param string $s > * > * @return string > */
if ($s[0] !== "'") { $s2 = "'".$s[0]; } else { $s2 = "'"; } for($i=1; $i<$len; $i++) { $ch = $s[$i]; if ($ch === '\\') { $s2 .= "'"; break; } elseif ($ch === "'") { $s2 .= $ch; break; } $s2 .= $ch; } return strlen($s2) == 0 ? 'null' : $s2; }
< < // for transaction handling <
> /** > * For transaction handling. > * > * @param $dbms > * @param $fn > * @param $errno > * @param $errmsg > * @param $p1 > * @param $p2 > * @param $thisConnection > */
function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection) { //print "Errorno ($fn errno=$errno m=$errmsg) "; $thisConnection->_transOK = false; if ($thisConnection->_oldRaiseFn) {
< $fn = $thisConnection->_oldRaiseFn; < $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
> $errfn = $thisConnection->_oldRaiseFn; > $errfn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
} }
< //------------------ < // class for caching
> /** > * Class ADODB_Cache_File > */
class ADODB_Cache_File { var $createdir = true; // requires creation of temp dirs function __construct() { global $ADODB_INCLUDED_CSV; if (empty($ADODB_INCLUDED_CSV)) { include_once(ADODB_DIR.'/adodb-csvlib.inc.php'); } }
< // write serialised recordset to cache item/file
> /** > * Write serialised RecordSet to cache item/file. > * > * @param $filename > * @param $contents > * @param $debug > * @param $secs2cache > * > * @return bool|int > */
function writecache($filename, $contents, $debug, $secs2cache) { return adodb_write_file($filename, $contents,$debug); }
< // load serialised recordset and unserialise it
> /** > * load serialised RecordSet and unserialise it > * > * @param $filename > * @param $err > * @param $secs2cache > * @param $rsClass > * > * @return ADORecordSet > */
function &readcache($filename, &$err, $secs2cache, $rsClass) { $rs = csv2rs($filename,$err,$secs2cache,$rsClass); return $rs; }
< // flush all items in cache
> /** > * Flush all items in cache. > * > * @param bool $debug > * > * @return bool|void > */
function flushall($debug=false) { global $ADODB_CACHE_DIR; $rez = false; if (strlen($ADODB_CACHE_DIR) > 1) { $rez = $this->_dirFlush($ADODB_CACHE_DIR); if ($debug) { ADOConnection::outp( "flushall: $ADODB_CACHE_DIR<br><pre>\n". $rez."</pre>"); } } return $rez; }
< // flush one file in cache
> /** > * Flush one file in cache. > * > * @param string $f > * @param bool $debug > */
function flushcache($f, $debug=false) { if (!@unlink($f)) { if ($debug) { ADOConnection::outp( "flushcache: failed for $f"); } } }
> /** function getdirname($hash) { > * @param string $hash global $ADODB_CACHE_DIR; > * if (!isset($this->notSafeMode)) { > * @return string $this->notSafeMode = !ini_get('safe_mode'); > */
< if (!isset($this->notSafeMode)) { < $this->notSafeMode = !ini_get('safe_mode'); < } < return ($this->notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($hash,0,2) : $ADODB_CACHE_DIR;
> return $ADODB_CACHE_DIR . '/' . substr($hash, 0, 2);
< // create temp directories
> /** > * Create temp directories. > * > * @param string $hash > * @param bool $debug > * > * @return string > */
function createdir($hash, $debug) { global $ADODB_CACHE_PERMS; $dir = $this->getdirname($hash);
< if ($this->notSafeMode && !file_exists($dir)) {
> if (!file_exists($dir)) {
$oldu = umask(0); if (!@mkdir($dir, empty($ADODB_CACHE_PERMS) ? 0771 : $ADODB_CACHE_PERMS)) { if(!is_dir($dir) && $debug) { ADOConnection::outp("Cannot create $dir"); } } umask($oldu); } return $dir; } /** * Private function to erase all of the files and subdirectories in a directory. * * Just specify the directory, and tell it if you want to delete the directory or just clear it out. * Note: $kill_top_level is used internally in the function to flush subdirectories. */ function _dirFlush($dir, $kill_top_level = false) { if(!$dh = @opendir($dir)) return; while (($obj = readdir($dh))) { if($obj=='.' || $obj=='..') continue; $f = $dir.'/'.$obj; if (strpos($obj,'.cache')) { @unlink($f); } if (is_dir($f)) { $this->_dirFlush($f, true); } } if ($kill_top_level === true) { @rmdir($dir); } return true; } } //============================================================================================== // CLASS ADOConnection //============================================================================================== /** * Connection object. For connecting to databases, and executing queries. */ abstract class ADOConnection { // // PUBLIC VARS // var $dataProvider = 'native'; var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql
< var $database = ''; /// Name of database to be used.
> > /** > * @var string Current database name. > * > * This used to be stored in the $databaseName property, which was marked > * as deprecated in 4.66 and removed in 5.22.5. > */ > public $database = ''; > > /** > * @var string If the driver is PDO, then the dsnType is e.g. sqlsrv, otherwise empty > */ > public $dsnType = ''; >
var $host = ''; /// The hostname of the database server var $port = ''; /// The port of the database server var $user = ''; /// The username which is used to connect to the database server. var $password = ''; /// Password for the username. For security, we no longer store it. var $debug = false; /// if set to true will output sql statements var $maxblobsize = 262144; /// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxpro var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase var $substr = 'substr'; /// substring operator var $length = 'length'; /// string length ofperator var $random = 'rand()'; /// random function var $upperCase = 'upper'; /// uppercase function var $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the database var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt. var $true = '1'; /// string that represents TRUE for a database var $false = '0'; /// string that represents FALSE for a database var $replaceQuote = "\\'"; /// string to use to replace quotes var $nameQuote = '"'; /// string to use to quote identifiers and names
> var $leftBracket = '['; /// left square bracked for t-sql styled column names var $charSet=false; /// character set to use - only for interbase, postgres and oci8 > var $rightBracket = ']'; /// right square bracked for t-sql styled column names
var $metaDatabasesSQL = '';
> var $metaTablesSQL = ''; > /** @var string SQL statement to get databases */
var $uniqueOrderBy = false; /// All order by columns have to be unique
> var $emptyDate = '&nbsp;'; > /** @var string SQL statement to get database tables */
var $emptyTimeStamp = '&nbsp;';
> var $lastInsID = false; > /** @var string SQL statement to get table columns. */ //-- > var $metaColumnsSQL; var $hasInsertID = false; /// supports autoincrement ID? > var $hasAffectedRows = false; /// supports affected rows for update/delete? > /** var $hasTop = false; /// support mssql/access SELECT TOP 10 * FROM TABLE > * SQL statement to get the last IDENTITY value inserted into an IDENTITY var $hasLimit = false; /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10 > * column in the same scope. var $readOnly = false; /// this is a readonly database - used by phpLens > * @see https://learn.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql var $hasMoveFirst = false; /// has ability to run MoveFirst(), scrolling backwards > * @var string var $hasGenID = false; /// can generate sequences using GenID(); > */ var $hasTransactions = true; /// has transactions > var $identitySQL; //-- > var $genID = 0; /// sequence id used by GenID(); > /** @var string SQL statement to create a Sequence . */ var $raiseErrorFn = false; /// error function to call > var $_genSeqSQL; var $isoDates = false; /// accepts dates in ISO format > var $cacheSecs = 3600; /// cache for 1 hour > /** @var string SQL statement to drop a Sequence. */ > var $_dropSeqSQL; // memcache > var $memCache = false; /// should we use memCache instead of caching in files > /** @var string SQL statement to generate a Sequence ID. */ var $memCacheHost; /// memCache host > var $_genIDSQL; var $memCachePort = 11211; /// memCache port >
< var $raiseErrorFn = false; /// error function to call
> > /** @var bool|callable Error function to call */ > var $raiseErrorFn = false; >
< // memcache < var $memCache = false; /// should we use memCache instead of caching in files < var $memCacheHost; /// memCache host < var $memCachePort = 11211; /// memCache port < var $memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib)
> /***************************************** > * memcached server options > ******************************************/ > > /** > * Use memCache library instead of caching in files. > * @var bool $memCache > */ > public $memCache = false; > > /** > * The memcache server(s) to connect to. Can be defined as: > * - a single host name/ip address > * - a list of hosts/ip addresses > * - an array of server connection data (weighted server groups). > * @link https://adodb.org/dokuwiki/doku.php?id=v5:userguide:memcached > * @var string|array $memCacheHost > */ > public $memCacheHost; > > /** > * Default port number. > * The default port can be overridden if memcache server connection data > * is provided as an array {@see $memCacheHost}. > * @var int $memCachePort > */ > public $memCachePort = 11211; > > /** > * Enable compression of stored items. > * @var bool $memCacheCompress > */ > public $memCacheCompress = false; > > /** > * An array of memcached options. > * Only used with memcached; memcache ignores this setting. > * @link https://www.php.net/manual/en/memcached.constants.php > * @var array $memCacheOptions > */ > public $memCacheOptions = array();
var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' ' var $numCacheHits = 0; var $numCacheMisses = 0; var $pageExecuteCountRows = true; var $uniqueSort = false; /// indicates that all fields in order by must be unique var $leftOuter = false; /// operator to use for left outer join in WHERE clause var $rightOuter = false; /// operator to use for right outer join in WHERE clause var $ansiOuter = false; /// whether ansi outer join syntax supported var $autoRollback = false; // autoRollback on PConnect(). var $poorAffectedRows = false; // affectedRows not working or unreliable
> /** @var bool|callable Execute function to call */
var $fnExecute = false;
> var $fnCacheExecute = false; > /** @var bool|callable Cache execution function to call */
var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char
>
var $rsPrefix = "ADORecordSet_"; var $autoCommit = true; /// do not modify this yourself - actually private var $transOff = 0; /// temporarily disable transactions var $transCnt = 0; /// count of nested transactions var $fetchMode=false; var $null2null = 'null'; // in autoexecute/getinsertsql/getupdatesql, this value will be converted to a null var $bulkBind = false; // enable 2D Execute array
> // > /** @var string SQL statement executed by some drivers after successful connection. */ // PRIVATE VARS > public $connectStmt = ''; // >
var $_oldRaiseFn = false; var $_transOK = null;
< var $_connectionID = false; /// The returned link identifier whenever a successful database connection is made. < var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will < /// then returned by the errorMsg() function < var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8
> /** @var resource Identifier for the native database connection */ > var $_connectionID = false; > > /** > * Stores the last returned error message. > * @see ADOConnection::errorMsg() > * @var string|false > */ > var $_errorMsg = false; > > /** > * Stores the last returned error code. > * Not guaranteed to be used. Only some drivers actually populate it. > * @var int|false > */ > var $_errorCode = false; >
var $_queryID = false; /// This variable keeps the last created result link identifier var $_isPersistentConnection = false; /// A boolean variable to state whether its a persistent connection or normal connection. */ var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.
< var $_evalAll = false;
> > /** > * Eval string used to filter data. > * Only used in the deprecated Text driver. > * @see https://adodb.org/dokuwiki/doku.php?id=v5:database:text#workaround > * @var string > */ > var $evalAll = false; >
var $_affected = false; var $_logsql = false; var $_transmode = ''; // transaction mode
< /* < * Additional parameters that may be passed to drivers in the connect string < * Driver must be coded to accept the parameters
> /** > * Additional parameters that may be passed to drivers in the connect string. > * > * Data is stored as an array of arrays and not a simple associative array, > * because some drivers (e.g. mysql) allow multiple parameters with the same > * key to be set. > * @link https://github.com/ADOdb/ADOdb/issues/187 > * > * @see setConnectionParameter() > * > * @var array $connectionParameters Set of ParameterName => Value pairs
*/ protected $connectionParameters = array();
> /* /** > * A simple associative array of user-defined custom actual/meta types * Adds a parameter to the connection string. > */ * > public $customActualTypes = array(); * These parameters are added to the connection string when connecting, > * if the driver is coded to use it. > /* * > * An array of user-defined custom meta/actual types. * @param string $parameter The name of the parameter to set > * $this->customMetaTypes[$meta] = array( * @param string $value The value of the parameter > * 'actual'=>'', * > * 'dictionary'=>'', * @return null > * 'handler'=>'', * > * 'callback'=>'' * @example, for mssqlnative driver ('CharacterSet','UTF-8') > * ); */ > */ final public function setConnectionParameter($parameter,$value) > public $customMetaTypes = array(); { > > /** @var ADORecordSet Recordset used to retrieve MetaType information */ $this->connectionParameters[$parameter] = $value; > var $_metars; > } > /** @var string a specified locale. */ > var $locale; static function Version() { > global $ADODB_vers; > > /** // Semantic Version number matching regex > * Default Constructor. $regex = '^[vV]?(\d+\.\d+\.\d+' // Version number (X.Y.Z) with optional 'V' > * We define it even though it does not actually do anything. This avoids . '(?:-(?:' // Optional preprod version: a '-' > * getting a PHP Fatal error: Cannot call constructor if a subclass tries . 'dev|' // followed by 'dev' > * to call its parent constructor. . '(?:(?:alpha|beta|rc)(?:\.\d+))' // or a preprod suffix and version number > */ . '))?)(?:\s|$)'; // Whitespace or end of string > public function __construct() > { if (!preg_match("/$regex/", $ADODB_vers, $matches)) { > } // This should normally not happen... Return whatever is between the start >
< * These parameters are added to the connection string when connecting, < * if the driver is coded to use it.
> * Parameters must be added before the connection is established; > * they are then passed on to the connect statement, which will. > * process them if the driver supports this feature. > * > * Example usage: > * - mssqlnative: setConnectionParameter('CharacterSet','UTF-8'); > * - mysqli: setConnectionParameter(MYSQLI_SET_CHARSET_NAME,'utf8mb4'); > * > * If used in a portable environment, parameters set in this manner should > * be predicated on the database provider, as unexpected results may occur > * if applied to the wrong database.
< * @return null < * < * @example, for mssqlnative driver ('CharacterSet','UTF-8')
> * @return bool True if success, false otherwise (e.g. parameter is not valid)
< final public function setConnectionParameter($parameter,$value) < { < < $this->connectionParameters[$parameter] = $value; <
> public function setConnectionParameter($parameter, $value) { > $this->connectionParameters[] = array($parameter=>$value); > return true;
> /** @returns An array with 2 elements: $arr['string'] is the description string, > * ADOdb version. and $arr[version] is the version (also a string). > * */ > * @return string function ServerInfo() { > */
< Get server version info...
> * Set a custom meta type with a corresponding actual > * > * @param string $metaType The Custom ADOdb metatype > * @param string $dictionaryType The database dictionary type > * @param string $actualType The database actual type > * @param bool $handleAsType handle like an existing Metatype > * @param mixed $callBack A pre-processing function > * > * @return bool success if the actual exists > */ > final public function setCustomMetaType( > $metaType, > $dictionaryType, > $actualType, > $handleAsType=false, > $callback=false){ > > $this->customMetaTypes[strtoupper($metaType)] = array( > 'actual'=>$actualType, > 'dictionary'=>strtoupper($dictionaryType), > 'handler'=>$handleAsType, > 'callback'=>$callback > );
< @returns An array with 2 elements: $arr['string'] is the description string, < and $arr[version] is the version (also a string).
> /* > * Create a reverse lookup for the actualType > */ > $this->customActualTypes[$actualType] = $metaType; > > return true; > } > > /** > * Get a list of custom meta types. > * > * @return string[] > */ > final public function getCustomMetaTypes() > { > return $this->customMetaTypes; > } > > > /** > * Get server version info. > * > * @return string[] Array with 2 string elements: version and description
function IsConnected() {
> /** return !empty($this->_connectionID); > * Return true if connected to the database. } > * > * @return bool function _findvers($str) { > */
if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) {
> /** return $arr[1]; > * Find version string. } else { > * return ''; > * @param string $str } > * } > * @return string > */
/** * All error messages go through this bottleneck function.
> *
* You can define your own handler by defining the function name in ADODB_OUTP.
> * */ > * @param string $msg Message to print static function outp($msg,$newline=true) { > * @param bool $newline True to add a newline after printing $msg
global $ADODB_FLUSH,$ADODB_OUTP; if (defined('ADODB_OUTP')) { $fn = ADODB_OUTP; $fn($msg,$newline); return; } else if (isset($ADODB_OUTP)) {
< $fn = $ADODB_OUTP; < $fn($msg,$newline);
> call_user_func($ADODB_OUTP,$msg,$newline);
return; } if ($newline) { $msg .= "<br>\n"; } if (isset($_SERVER['HTTP_USER_AGENT']) || !$newline) { echo $msg; } else { echo strip_tags($msg); } if (!empty($ADODB_FLUSH) && ob_get_length() !== false) { flush(); // do not flush if output buffering enabled - useless - thx to Jesse Mullan } }
> /** function Time() { > * Return the database server's current date and time. $rs = $this->_Execute("select $this->sysTimeStamp"); > * @return int|false if ($rs && !$rs->EOF) { > */
return $this->UnixTimeStamp(reset($rs->fields)); } return false; } /** * Parses the hostname to extract the port. * Overwrites $this->host and $this->port, only if a port is specified. * The Hostname can be fully or partially qualified, * ie: "db.mydomain.com:5432" or "ldaps://ldap.mydomain.com:636" * Any specified scheme such as ldap:// or ldaps:// is maintained. */ protected function parseHostNameAndPort() { $parsed_url = parse_url($this->host); if (is_array($parsed_url) && isset($parsed_url['host']) && isset($parsed_url['port'])) { if ( isset($parsed_url['scheme']) ) { // If scheme is specified (ie: ldap:// or ldaps://, make sure we retain that. $this->host = $parsed_url['scheme'] . "://" . $parsed_url['host']; } else { $this->host = $parsed_url['host']; } $this->port = $parsed_url['port']; } } /**
< * Connect to database
> * Connect to database.
*
< * @param [argHostname] Host to connect to < * @param [argUsername] Userid to login < * @param [argPassword] Associated password < * @param [argDatabaseName] database < * @param [forceNew] force new connection
> * @param string $argHostname Host to connect to > * @param string $argUsername Userid to login > * @param string $argPassword Associated password > * @param string $argDatabaseName Database name > * @param bool $forceNew Force new connection
*
< * @return true or false
> * @return bool
*/ function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) { if ($argHostname != "") { $this->host = $argHostname; } // Overwrites $this->host and $this->port if a port is specified. $this->parseHostNameAndPort(); if ($argUsername != "") { $this->user = $argUsername; } if ($argPassword != "") { $this->password = 'not stored'; // not stored for security reasons } if ($argDatabaseName != "") { $this->database = $argDatabaseName; } $this->_isPersistentConnection = false; if ($forceNew) { if ($rez=$this->_nconnect($this->host, $this->user, $argPassword, $this->database)) { return true; } } else { if ($rez=$this->_connect($this->host, $this->user, $argPassword, $this->database)) { return true; } } if (isset($rez)) { $err = $this->ErrorMsg(); $errno = $this->ErrorNo(); if (empty($err)) { $err = "Connection error to server '$argHostname' with user '$argUsername'"; } } else { $err = "Missing extension for ".$this->dataProvider; $errno = 0; } if ($fn = $this->raiseErrorFn) { $fn($this->databaseType, 'CONNECT', $errno, $err, $this->host, $this->database, $this); } $this->_connectionID = false; if ($this->debug) { ADOConnection::outp( $this->host.': '.$err); } return false; }
> /** function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) { > * Always force a new connection to database. return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName); > * } > * @param string $argHostname Host to connect to > * @param string $argUsername Userid to login > * @param string $argPassword Associated password /** > * @param string $argDatabaseName Database name * Always force a new connection to database - currently only works with oracle > * * > * @return bool * @param [argHostname] Host to connect to > */
<
< * Always force a new connection to database - currently only works with oracle
> * Always force a new connection to database. > * > * Currently this only works with Oracle.
< * @param [argHostname] Host to connect to < * @param [argUsername] Userid to login < * @param [argPassword] Associated password < * @param [argDatabaseName] database
> * @param string $argHostname Host to connect to > * @param string $argUsername Userid to login > * @param string $argPassword Associated password > * @param string $argDatabaseName Database name
< * @return true or false
> * @return bool
return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true); } /**
< * Establish persistent connect to database
> * Establish persistent connection to database.
*
< * @param [argHostname] Host to connect to < * @param [argUsername] Userid to login < * @param [argPassword] Associated password < * @param [argDatabaseName] database
> * @param string $argHostname Host to connect to > * @param string $argUsername Userid to login > * @param string $argPassword Associated password > * @param string $argDatabaseName Database name
*
< * @return return true or false
> * @return bool
*/ function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") { if (defined('ADODB_NEVER_PERSIST')) { return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName); } if ($argHostname != "") { $this->host = $argHostname; } // Overwrites $this->host and $this->port if a port is specified. $this->parseHostNameAndPort(); if ($argUsername != "") { $this->user = $argUsername; } if ($argPassword != "") { $this->password = 'not stored'; } if ($argDatabaseName != "") { $this->database = $argDatabaseName; } $this->_isPersistentConnection = true; if ($rez = $this->_pconnect($this->host, $this->user, $argPassword, $this->database)) { return true; } if (isset($rez)) { $err = $this->ErrorMsg(); if (empty($err)) { $err = "Connection error to server '$argHostname' with user '$argUsername'"; } $ret = false; } else { $err = "Missing extension for ".$this->dataProvider;
< $ret = 0;
> $ret = false;
} if ($fn = $this->raiseErrorFn) { $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this); } $this->_connectionID = false; if ($this->debug) { ADOConnection::outp( $this->host.': '.$err); } return $ret; }
> /** function outp_throw($msg,$src='WARN',$sql='') { > * Throw an exception if the handler is defined or prints the message if not. if (defined('ADODB_ERROR_HANDLER') && ADODB_ERROR_HANDLER == 'adodb_throw') { > * @param string $msg Message adodb_throw($this->databaseType,$src,-9999,$msg,$sql,false,$this); > * @param string $src the name of the calling function (in uppercase) return; > * @param string $sql Optional offending SQL statement } > */
ADOConnection::outp($msg); }
< // create cache class. Code is backward compat with old memcache implementation
> /** > * Create cache class. > * > * Code is backwards-compatible with old memcache implementation. > */
function _CreateCache() { global $ADODB_CACHE, $ADODB_CACHE_CLASS; if ($this->memCache) { global $ADODB_INCLUDED_MEMCACHE; if (empty($ADODB_INCLUDED_MEMCACHE)) { include_once(ADODB_DIR.'/adodb-memcache.lib.inc.php'); } $ADODB_CACHE = new ADODB_Cache_MemCache($this); } else { $ADODB_CACHE = new $ADODB_CACHE_CLASS($this); } }
< // Format date column in sql string given an input format that understands Y M D < function SQLDate($fmt, $col=false) {
> /** > * Format date column in sql string. > * > * See https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:sqldate > * for documentation on supported formats. > * > * @param string $fmt Format string > * @param string $col Date column; use system date if not specified. > * > * @return string > */ > function SQLDate($fmt, $col = '') {
if (!$col) { $col = $this->sysDate; } return $col; // child class implement } /**
< * Should prepare the sql statement and return the stmt resource. < * For databases that do not support this, we return the $sql. To ensure < * compatibility with databases that do not support prepare: < * < * $stmt = $db->Prepare("insert into table (id, name) values (?,?)"); < * $db->Execute($stmt,array(1,'Jill')) or die('insert failed'); < * $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
> * Prepare an SQL statement and return the statement resource.
*
< * @param sql SQL to send to database
> * For databases that do not support prepared statements, we return the > * provided SQL statement as-is, to ensure compatibility:
*
< * @return return FALSE, or the prepared statement, or the original sql if < * if the database does not support prepare.
> * $stmt = $db->prepare("insert into table (id, name) values (?,?)"); > * $db->execute($stmt, array(1,'Jill')) or die('insert failed'); > * $db->execute($stmt, array(2,'Joe')) or die('insert failed');
*
> * @param string $sql SQL to send to database */ > * function Prepare($sql) { > * @return mixed|false The prepared statement, or the original sql if the return $sql; > * database does not support prepare.
} /**
> * Releases a previously prepared statement. * Some databases, eg. mssql require a different function for preparing > * * stored procedures. So we cannot use Prepare(). > * @param mixed $stmt Statement resource, as returned by {@see prepare()} * > * * Should prepare the stored procedure and return the stmt resource. > * @return bool * For databases that do not support this, we return the $sql. To ensure > */ * compatibility with databases that do not support prepare: > function releaseStatement(&$stmt) { * > return true; * @param sql SQL to send to database > } * > * @return return FALSE, or the prepared statement, or the original sql if > /** * if the database does not support prepare. > * Prepare a Stored Procedure and return the statement resource. * > *
< * Should prepare the stored procedure and return the stmt resource. < * For databases that do not support this, we return the $sql. To ensure < * compatibility with databases that do not support prepare: < * < * @param sql SQL to send to database
> * For databases that do not support this, we return the $sql.
< * @return return FALSE, or the prepared statement, or the original sql if < * if the database does not support prepare.
> * @param string $sql SQL to send to database > * @param bool $param
*/
> * @return mixed|false The prepared statement, or the original sql if the function Quote($s) { > * database does not support prepare.
< * PEAR DB Compat
> * PEAR DB Compat - alias for qStr. > * @param $s > * @return string
< return $this->qstr($s,false);
> return $this->qstr($s);
/**
< * Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de>
> * Quotes a string so that all strings are escaped. > * Wrapper for qstr with magic_quotes = false. > * > * @param string &$s
*/
< function QMagic($s) { < return $this->qstr($s,get_magic_quotes_gpc()); < } <
function q(&$s) { //if (!empty($this->qNull && $s == 'null') { // return $s; //}
< $s = $this->qstr($s,false);
> $s = $this->qstr($s);
} /** * PEAR DB Compat - do not use internally.
> * @return int
*/ function ErrorNative() { return $this->ErrorNo(); } /** * PEAR DB Compat - do not use internally.
> * @param string $seq_name */ > * @return int
function nextId($seq_name) { return $this->GenID($seq_name); } /**
< * Lock a row, will escalate and lock the table if row locking not supported < * will normally free the lock at the end of the transaction
> * Lock a row. > * Will escalate and lock the table if row locking is not supported. > * Will normally free the lock at the end of the transaction. > * > * @param string $table name of table to lock > * @param string $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock > * @param string $col
*
< * @param $table name of table to lock < * @param $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
> * @return bool
*/ function RowLock($table,$where,$col='1 as adodbignore') { return false; }
> /** function CommitLock($table) { > * @param string $table return $this->CommitTrans(); > * @return true } > */
> /** function RollbackLock($table) { > * @param string $table return $this->RollbackTrans(); > * @return true } > */
/** * PEAR DB Compat - do not use internally. * * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical * for easy porting :-) *
< * @param mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM < * @returns The previous fetch mode
> * @param int $mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM > * > * @return int Previous fetch mode
*/ function SetFetchMode($mode) { $old = $this->fetchMode; $this->fetchMode = $mode; if ($old === false) { global $ADODB_FETCH_MODE; return $ADODB_FETCH_MODE; } return $old; }
<
/** * PEAR DB Compat - do not use internally.
> * */ > * @param string $sql function Query($sql, $inputarr=false) { > * @param array|bool $inputarr $rs = $this->Execute($sql, $inputarr); > * if (!$rs && defined('ADODB_PEAR')) { > * @return ADORecordSet|bool
return ADODB_PEAR_Error(); } return $rs; }
<
/** * PEAR DB Compat - do not use internally */ function LimitQuery($sql, $offset, $count, $params=false) { $rs = $this->SelectLimit($sql, $count, $offset, $params); if (!$rs && defined('ADODB_PEAR')) { return ADODB_PEAR_Error(); } return $rs; } /** * PEAR DB Compat - do not use internally */ function Disconnect() { return $this->Close(); } /**
< * Returns a placeholder for query parameters
> * Returns a placeholder for query parameters. > *
* e.g. $DB->Param('a') will return * - '?' for most databases * - ':a' for Oracle * - '$1', '$2', etc. for PostgreSQL
< * @param string $name parameter's name, false to force a reset of the < * number to 1 (for databases that require positioned < * params such as PostgreSQL; note that ADOdb will < * automatically reset this when executing a query )
> * > * @param mixed $name parameter's name. > * For databases that require positioned params (e.g. PostgreSQL), > * a "falsy" value can be used to force resetting the placeholder > * count; using boolean 'false' will reset it without actually > * returning a placeholder. ADOdb will also automatically reset > * the count when executing a query.
* @param string $type (unused) * @return string query parameter placeholder */ function Param($name,$type='C') { return '?'; }
< /* < InParameter and OutParameter are self-documenting versions of Parameter().
> /** > * Self-documenting version of Parameter(). > * > * @param $stmt > * @param &$var > * @param $name > * @param int $maxLen > * @param bool $type > * > * @return bool
*/ function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) { return $this->Parameter($stmt,$var,$name,false,$maxLen,$type); }
< /*
> /** > * Self-documenting version of Parameter(). > * > * @param $stmt > * @param $var > * @param $name > * @param int $maxLen > * @param bool $type > * > * @return bool
*/ function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) { return $this->Parameter($stmt,$var,$name,true,$maxLen,$type); }
< < /* < Usage in oracle < $stmt = $db->Prepare('select * from table where id =:myid and group=:group'); < $db->Parameter($stmt,$id,'myid'); < $db->Parameter($stmt,$group,'group',64); < $db->Execute(); < < @param $stmt Statement returned by Prepare() or PrepareSP(). < @param $var PHP variable to bind to < @param $name Name of stored procedure variable name to bind to. < @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8. < @param [$maxLen] Holds an maximum length of the variable. < @param [$type] The data type of $var. Legal values depend on driver. <
> /** > * > * Usage in oracle > * $stmt = $db->Prepare('select * from table where id =:myid and group=:group'); > * $db->Parameter($stmt,$id,'myid'); > * $db->Parameter($stmt,$group,'group',64); > * $db->Execute(); > * > * @param mixed &$stmt Statement returned by Prepare() or PrepareSP(). > * @param mixed &$var PHP variable to bind to > * @param string $name Name of stored procedure variable name to bind to. > * @param int|bool $isOutput Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8. > * @param int $maxLen Holds an maximum length of the variable. > * @param mixed $type The data type of $var. Legal values depend on driver. > * > * @return bool
*/ function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) { return false; } function IgnoreErrors($saveErrs=false) { if (!$saveErrs) { $saveErrs = array($this->raiseErrorFn,$this->_transOK); $this->raiseErrorFn = false; return $saveErrs; } else { $this->raiseErrorFn = $saveErrs[0]; $this->_transOK = $saveErrs[1]; } } /** * Improved method of initiating a transaction. Used together with CompleteTrans(). * Advantages include: * * a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans. * Only the outermost block is treated as a transaction.<br> * b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br> * c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block * are disabled, making it backward compatible. */ function StartTrans($errfn = 'ADODB_TransMonitor') { if ($this->transOff > 0) { $this->transOff += 1; return true; } $this->_oldRaiseFn = $this->raiseErrorFn; $this->raiseErrorFn = $errfn; $this->_transOK = true; if ($this->debug && $this->transCnt > 0) { ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans"); } $ok = $this->BeginTrans(); $this->transOff = 1; return $ok; } /**
< Used together with StartTrans() to end a transaction. Monitors connection < for sql errors, and will commit or rollback as appropriate. < < @autoComplete if true, monitor sql errors and commit and rollback as appropriate, < and if set to false force rollback even if no SQL error detected. < @returns true on commit, false on rollback.
> * Complete a transation. > * > * Used together with StartTrans() to end a transaction. Monitors connection > * for sql errors, and will commit or rollback as appropriate. > * > * @param bool autoComplete if true, monitor sql errors and commit and > * rollback as appropriate, and if set to false > * force rollback even if no SQL error detected. > * @returns true on commit, false on rollback.
*/ function CompleteTrans($autoComplete = true) { if ($this->transOff > 1) { $this->transOff -= 1; return true; } $this->raiseErrorFn = $this->_oldRaiseFn; $this->transOff = 0; if ($this->_transOK && $autoComplete) { if (!$this->CommitTrans()) { $this->_transOK = false; if ($this->debug) { ADOConnection::outp("Smart Commit failed"); } } else { if ($this->debug) { ADOConnection::outp("Smart Commit occurred"); } } } else { $this->_transOK = false; $this->RollbackTrans(); if ($this->debug) {
< ADOCOnnection::outp("Smart Rollback occurred");
> ADOConnection::outp("Smart Rollback occurred");
} } return $this->_transOK; }
< /* < At the end of a StartTrans/CompleteTrans block, perform a rollback.
> /** > * At the end of a StartTrans/CompleteTrans block, perform a rollback.
*/ function FailTrans() { if ($this->debug) if ($this->transOff == 0) { ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans"); } else { ADOConnection::outp("FailTrans was called"); adodb_backtrace(); } $this->_transOK = false; } /**
< Check if transaction has failed, only for Smart Transactions.
> * Check if transaction has failed, only for Smart Transactions.
*/ function HasFailedTrans() { if ($this->transOff > 0) { return $this->_transOK == false; } return false; } /** * Execute SQL *
< * @param sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text) < * @param [inputarr] holds the input data to bind to. Null elements will be set to null. < * @return RecordSet or false
> * @param string $sql SQL statement to execute, or possibly an array > * holding prepared statement ($sql[0] will hold sql text) > * @param array|bool $inputarr holds the input data to bind to. > * Null elements will be set to null. > * > * @return ADORecordSet|bool
*/
< function Execute($sql,$inputarr=false) {
> public function Execute($sql, $inputarr = false) {
if ($this->fnExecute) { $fn = $this->fnExecute; $ret = $fn($this,$sql,$inputarr); if (isset($ret)) { return $ret; } } if ($inputarr !== false) { if (!is_array($inputarr)) { $inputarr = array($inputarr); } $element0 = reset($inputarr); # is_object check because oci8 descriptors can be passed in $array_2d = $this->bulkBind && is_array($element0) && !is_object(reset($element0)); //remove extra memory copy of input -mikefedyk unset($element0); if (!is_array($sql) && !$this->_bindInputArray) { // @TODO this would consider a '?' within a string as a parameter... $sqlarr = explode('?',$sql); $nparams = sizeof($sqlarr)-1; if (!$array_2d) { // When not Bind Bulk - convert to array of arguments list $inputarr = array($inputarr); } else { // Bulk bind - Make sure all list of params have the same number of elements $countElements = array_map('count', $inputarr); if (1 != count(array_unique($countElements))) { $this->outp_throw( "[bulk execute] Input array has different number of params [" . print_r($countElements, true) . "].", 'Execute' ); return false; } unset($countElements); } // Make sure the number of parameters provided in the input // array matches what the query expects $element0 = reset($inputarr); if ($nparams != count($element0)) { $this->outp_throw( "Input array has " . count($element0) . " params, does not match query: '" . htmlspecialchars($sql) . "'", 'Execute' ); return false; } // clean memory unset($element0); foreach($inputarr as $arr) { $sql = ''; $i = 0; foreach ($arr as $v) { $sql .= $sqlarr[$i]; // from Ron Baldwin <ron.baldwin#sourceprose.com> // Only quote string types $typ = gettype($v); if ($typ == 'string') { //New memory copy of input created here -mikefedyk $sql .= $this->qstr($v); } else if ($typ == 'double') { $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1 } else if ($typ == 'boolean') { $sql .= $v ? $this->true : $this->false; } else if ($typ == 'object') { if (method_exists($v, '__toString')) { $sql .= $this->qstr($v->__toString()); } else { $sql .= $this->qstr((string) $v); } } else if ($v === null) { $sql .= 'NULL'; } else { $sql .= $v; } $i += 1; if ($i == $nparams) { break; } } // while if (isset($sqlarr[$i])) { $sql .= $sqlarr[$i]; if ($i+1 != sizeof($sqlarr)) { $this->outp_throw( "Input Array does not match ?: ".htmlspecialchars($sql),'Execute'); } } else if ($i != sizeof($sqlarr)) { $this->outp_throw( "Input array does not match ?: ".htmlspecialchars($sql),'Execute'); } $ret = $this->_Execute($sql); if (!$ret) { return $ret; } } } else { if ($array_2d) { if (is_string($sql)) { $stmt = $this->Prepare($sql); } else { $stmt = $sql; } foreach($inputarr as $arr) { $ret = $this->_Execute($stmt,$arr); if (!$ret) { return $ret; } } } else { $ret = $this->_Execute($sql,$inputarr); } } } else { $ret = $this->_Execute($sql,false); } return $ret; } function _Execute($sql,$inputarr=false) { // ExecuteCursor() may send non-string queries (such as arrays), // so we need to ignore those. if( is_string($sql) ) { // Strips keyword used to help generate SELECT COUNT(*) queries // from SQL if it exists.
< $sql = ADODB_str_replace( '_ADODB_COUNT', '', $sql );
> // TODO: obsoleted by #715 - kept for backwards-compatibility > $sql = str_replace( '_ADODB_COUNT', '', $sql );
} if ($this->debug) { global $ADODB_INCLUDED_LIB; if (empty($ADODB_INCLUDED_LIB)) {
< include(ADODB_DIR.'/adodb-lib.inc.php');
> include_once(ADODB_DIR.'/adodb-lib.inc.php');
} $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr); } else { $this->_queryID = @$this->_query($sql,$inputarr); } // ************************ // OK, query executed // ************************ // error handling if query fails if ($this->_queryID === false) {
< if ($this->debug == 99) { < adodb_backtrace(true,5); < }
$fn = $this->raiseErrorFn; if ($fn) { $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this); } return false; } // return simplified recordset for inserts/updates/deletes with lower overhead if ($this->_queryID === true) { $rsclass = $this->rsPrefix.'empty'; $rs = (class_exists($rsclass)) ? new $rsclass(): new ADORecordSet_empty(); return $rs; }
< // return real recordset from select statement
> if ($this->dataProvider == 'pdo' && $this->databaseType != 'pdo') { > // PDO uses a slightly different naming convention for the > // recordset class if the database type is changed, so we must > // treat it specifically. The mysql driver leaves the > // databaseType as pdo > $rsclass = $this->rsPrefix . 'pdo_' . $this->databaseType; > } else {
$rsclass = $this->rsPrefix.$this->databaseType;
> } $rs = new $rsclass($this->_queryID,$this->fetchMode); > $rs->connection = $this; // Pablo suggestion > // return real recordset from select statement
$rs->Init(); if (is_array($sql)) { $rs->sql = $sql[0]; } else { $rs->sql = $sql; } if ($rs->_numOfRows <= 0) { global $ADODB_COUNTRECS; if ($ADODB_COUNTRECS) { if (!$rs->EOF) { $rs = $this->_rs2rs($rs,-1,-1,!is_array($sql)); $rs->_queryID = $this->_queryID; } else $rs->_numOfRows = 0; } } return $rs; } function CreateSequence($seqname='adodbseq',$startID=1) { if (empty($this->_genSeqSQL)) { return false; } return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID)); } function DropSequence($seqname='adodbseq') { if (empty($this->_dropSeqSQL)) { return false; } return $this->Execute(sprintf($this->_dropSeqSQL,$seqname)); } /**
< * Generates a sequence id and stores it in $this->genID;
> * Generates a sequence id and stores it in $this->genID. > *
* GenID is only available if $this->hasGenID = true; *
< * @param seqname name of sequence to use < * @param startID if sequence does not exist, start at this ID < * @return 0 if not supported, otherwise a sequence id
> * @param string $seqname Name of sequence to use > * @param int $startID If sequence does not exist, start at this ID > * > * @return int Sequence id, 0 if not supported
*/ function GenID($seqname='adodbseq',$startID=1) { if (!$this->hasGenID) { return 0; // formerly returns false pre 1.60 } $getnext = sprintf($this->_genIDSQL,$seqname); $holdtransOK = $this->_transOK; $save_handler = $this->raiseErrorFn; $this->raiseErrorFn = ''; @($rs = $this->Execute($getnext)); $this->raiseErrorFn = $save_handler; if (!$rs) { $this->_transOK = $holdtransOK; //if the status was ok before reset $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID)); $rs = $this->Execute($getnext); } if ($rs && !$rs->EOF) { $this->genID = reset($rs->fields); } else { $this->genID = 0; // false } if ($rs) { $rs->Close(); } return $this->genID; } /**
< * @param $table string name of the table, not needed by all databases (eg. mysql), default '' < * @param $column string name of the column, not needed by all databases (eg. mysql), default '' < * @return the last inserted ID. Not all databases support this.
> * Returns the last inserted ID. > * > * Not all databases support this feature. Some do not require to specify > * table or column name (e.g. MySQL). > * > * @param string $table Table name, default '' > * @param string $column Column name, default '' > * > * @return int The last inserted ID.
*/ function Insert_ID($table='',$column='') { if ($this->_logsql && $this->lastInsID) { return $this->lastInsID; } if ($this->hasInsertID) {
< return $this->_insertid($table,$column);
> return $this->_insertID($table,$column);
} if ($this->debug) { ADOConnection::outp( '<p>Insert_ID error</p>'); adodb_backtrace(); } return false; }
> /** > * Enable or disable the Last Insert Id functionality. /** > * * Portable Insert ID. Pablo Roca <pabloroca#mvps.org> > * If the Driver supports it, this function allows setting {@see $hasInsertID}. * > * * @return the last inserted ID. All databases support this. But aware possible > * @param bool $enable False to disable * problems in multiuser environments. Heavy test this before deploying. > */ */ > public function enableLastInsertID($enable = true) {} function PO_Insert_ID($table="", $id="") { > if ($this->hasInsertID){ > /** return $this->Insert_ID($table,$id); > * Return the id of the last row that has been inserted in a table. } else { > * return $this->GetOne("SELECT MAX($id) FROM $table"); > * @param string $table } > * @param string $column } > * > * @return int|false /** > */ * @return # rows affected by UPDATE/DELETE > protected function _insertID($table = '', $column = '') */ > { function Affected_Rows() { > return false; if ($this->hasAffectedRows) { > }
< * @return the last inserted ID. All databases support this. But aware possible < * problems in multiuser environments. Heavy test this before deploying.
> * @param string $table > * @param string $id > > * @return mixed The last inserted ID. All databases support this, but be > * aware of possible problems in multiuser environments. > * Heavily test this before deploying.
< * @return # rows affected by UPDATE/DELETE
> * @return int|false Number of rows affected by UPDATE/DELETE
} } $val = $this->_affectedrows(); return ($val < 0) ? false : $val; } if ($this->debug) { ADOConnection::outp( '<p>Affected_Rows error</p>',false); } return false; } /**
< * @return the last error message
> * @return string the last error message
*/ function ErrorMsg() { if ($this->_errorMsg) { return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg; } else { return ''; } } /**
< * @return the last error number. Normally 0 means no error.
> * @return int the last error number. Normally 0 means no error.
*/ function ErrorNo() { return ($this->_errorMsg) ? -1 : 0; } function MetaError($err=false) { include_once(ADODB_DIR."/adodb-error.inc.php"); if ($err === false) { $err = $this->ErrorNo(); } return adodb_error($this->dataProvider,$this->databaseType,$err); } function MetaErrorMsg($errno) { include_once(ADODB_DIR."/adodb-error.inc.php"); return adodb_errormsg($errno); } /** * @returns an array with the primary key columns in it. */ function MetaPrimaryKeys($table, $owner=false) { // owner not used in base class - see oci8 $p = array(); $objs = $this->MetaColumns($table); if ($objs) { foreach($objs as $v) { if (!empty($v->primary_key)) { $p[] = $v->name; } } } if (sizeof($p)) { return $p; } if (function_exists('ADODB_VIEW_PRIMARYKEYS')) { return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner); } return false; } /**
< * @returns assoc array where keys are tables, and values are foreign keys
> * Returns a list of Foreign Keys associated with a specific table. > * > * If there are no foreign keys then the function returns false. > * > * @param string $table The name of the table to get the foreign keys for. > * @param string $owner Table owner/schema. > * @param bool $upper If true, only matches the table with the uppercase name. > * @param bool $associative Returns the result in associative mode; > * if ADODB_FETCH_MODE is already associative, then > * this parameter is discarded. > * > * @return string[]|false An array where keys are tables, and values are foreign keys; > * false if no foreign keys could be found.
*/
< function MetaForeignKeys($table, $owner=false, $upper=false) {
> function metaForeignKeys($table, $owner = '', $upper = false, $associative = false) {
return false; }
>
/** * Choose a database to connect to. Many databases do not support this. *
< * @param dbName is the name of the database to select < * @return true or false
> * @param string $dbName the name of the database to select > * @return bool
*/ function SelectDB($dbName) {return false;} /**
> * Select a limited number of rows. * Will select, getting rows from $offset (1-based), for $nrows. > *
* This simulates the MySQL "select * from table limit $offset,$nrows" , and * the PostgreSQL "select * from table limit $nrows offset $offset". Note that * MySQL and PostgreSQL parameter ordering is the opposite of the other. * eg. * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based) * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based) * * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set) * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set *
< * @param sql < * @param [offset] is the row to start calculations from (1-based) < * @param [nrows] is the number of rows to get < * @param [inputarr] array of bind variables < * @param [secs2cache] is a private parameter only used by jlim < * @return the recordset ($rs->databaseType == 'array')
> * @param string $sql > * @param int $offset Row to start calculations from (1-based) > * @param int $nrows Number of rows to get > * @param array|bool $inputarr Array of bind variables > * @param int $secs2cache Private parameter only used by jlim > * > * @return ADORecordSet The recordset ($rs->databaseType == 'array')
*/ function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) { $nrows = (int)$nrows; $offset = (int)$offset; if ($this->hasTop && $nrows > 0) { // suggested by Reinhard Balling. Access requires top after distinct // Informix requires first before distinct - F Riosa $ismssql = (strpos($this->databaseType,'mssql') !== false); if ($ismssql) { $isaccess = false; } else { $isaccess = (strpos($this->databaseType,'access') !== false); } if ($offset <= 0) { // access includes ties in result if ($isaccess) { $sql = preg_replace(
< '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
> '/(^\s*select\s+(distinctrow|distinct)?)/i', > '\\1 '.$this->hasTop.' '.$nrows.' ', > $sql > );
if ($secs2cache != 0) { $ret = $this->CacheExecute($secs2cache, $sql,$inputarr); } else { $ret = $this->Execute($sql,$inputarr); } return $ret; // PHP5 fix } else if ($ismssql){ $sql = preg_replace(
< '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
> '/(^\s*select\s+(distinctrow|distinct)?)/i', > '\\1 '.$this->hasTop.' '.$nrows.' ', > $sql > );
} else { $sql = preg_replace(
< '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
> '/(^\s*select\s)/i', > '\\1 '.$this->hasTop.' '.$nrows.' ', > $sql > );
} } else { $nn = $nrows + $offset; if ($isaccess || $ismssql) { $sql = preg_replace(
< '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
> '/(^\s*select\s+(distinctrow|distinct)?)/i', > '\\1 '.$this->hasTop.' '.$nn.' ', > $sql > );
} else { $sql = preg_replace(
< '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
> '/(^\s*select\s)/i', > '\\1 '.$this->hasTop.' '.$nn.' ', > $sql > );
} } } // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS. global $ADODB_COUNTRECS;
> try {
$savec = $ADODB_COUNTRECS; $ADODB_COUNTRECS = false;
<
if ($secs2cache != 0) { $rs = $this->CacheExecute($secs2cache,$sql,$inputarr); } else { $rs = $this->Execute($sql,$inputarr); }
<
> } finally {
$ADODB_COUNTRECS = $savec;
> } if ($rs && !$rs->EOF) { >
$rs = $this->_rs2rs($rs,$nrows,$offset); } //print_r($rs); return $rs; } /** * Create serializable recordset. Breaks rs link to connection. *
< * @param rs the recordset to serialize
> * @param ADORecordSet $rs the recordset to serialize > * > * @return ADORecordSet_array|bool the new recordset
*/ function SerializableRS(&$rs) { $rs2 = $this->_rs2rs($rs); $ignore = false; $rs2->connection = $ignore; return $rs2; } /**
< * Convert database recordset to an array recordset < * input recordset's cursor should be at beginning, and < * old $rs will be closed. < * < * @param rs the recordset to copy < * @param [nrows] number of rows to retrieve (optional) < * @param [offset] offset by number of rows (optional) < * @return the new recordset
> * Convert a database recordset to an array recordset. > * > * Input recordset's cursor should be at beginning, and old $rs will be closed. > * > * @param ADORecordSet $rs the recordset to copy > * @param int $nrows number of rows to retrieve (optional) > * @param int $offset offset by number of rows (optional) > * @param bool $close > * > * @return ADORecordSet_array|ADORecordSet|bool the new recordset
*/ function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true) { if (! $rs) {
< return false;
> $ret = false; > return $ret;
} $dbtype = $rs->databaseType; if (!$dbtype) { $rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ? return $rs; } if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) { $rs->MoveFirst(); $rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ? return $rs; } $flds = array(); for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) { $flds[] = $rs->FetchField($i); } $arr = $rs->GetArrayLimit($nrows,$offset); //print_r($arr); if ($close) { $rs->Close(); } $arrayClass = $this->arrayClass;
< $rs2 = new $arrayClass();
> $rs2 = new $arrayClass($fakeQueryId=1);
$rs2->connection = $this; $rs2->sql = $rs->sql; $rs2->dataProvider = $this->dataProvider; $rs2->InitArrayFields($arr,$flds); $rs2->fetchMode = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode; return $rs2; }
< /* < * Return all rows. Compat with PEAR DB
> /** > * Return all rows. > * > * Compat with PEAR DB. > * > * @param string $sql SQL statement > * @param array|bool $inputarr Input bind array > * > * @return array|false
*/ function GetAll($sql, $inputarr=false) {
< $arr = $this->GetArray($sql,$inputarr); < return $arr;
> return $this->GetArray($sql,$inputarr);
}
< function GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false) {
> /** > * Execute statement and return rows in an array. > * > * The function executes a statement and returns all of the returned rows in > * an array, or false if the statement execution fails or if only 1 column > * is requested in the SQL statement. > * If no records match the provided SQL statement, an empty array is returned. > * > * @param string $sql SQL statement > * @param array|bool $inputarr input bind array > * @param bool $force_array > * @param bool $first2cols > * > * @return array|bool > */ > public function GetAssoc($sql, $inputarr = false, $force_array = false, $first2cols = false) {
$rs = $this->Execute($sql, $inputarr);
>
if (!$rs) {
> /* return false; > * Execution failure } > */
< $arr = $rs->GetAssoc($force_array,$first2cols); < return $arr;
> return $rs->GetAssoc($force_array, $first2cols);
}
< function CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false) {
> /** > * Search for the results of an executed query in the cache. > * > * @param int $secs2cache > * @param string|bool $sql SQL statement > * @param array|bool $inputarr input bind array > * @param bool $force_array > * @param bool $first2cols > * > * @return false|array > */ > public function CacheGetAssoc($secs2cache, $sql = false, $inputarr = false,$force_array = false, $first2cols = false) {
if (!is_numeric($secs2cache)) { $first2cols = $force_array; $force_array = $inputarr; } $rs = $this->CacheExecute($secs2cache, $sql, $inputarr); if (!$rs) { return false; }
< $arr = $rs->GetAssoc($force_array,$first2cols); < return $arr;
> return $rs->GetAssoc($force_array, $first2cols);
} /** * Return first element of first row of sql statement. Recordset is disposed * for you. *
< * @param sql SQL statement < * @param [inputarr] input bind array
> * @param string $sql SQL statement > * @param array|bool $inputarr input bind array > * @return mixed
*/
< function GetOne($sql,$inputarr=false) {
> public function GetOne($sql, $inputarr=false) {
global $ADODB_COUNTRECS,$ADODB_GETONE_EOF;
> try {
$crecs = $ADODB_COUNTRECS; $ADODB_COUNTRECS = false;
> $rs = $this->Execute($sql, $inputarr); > } finally { $ret = false; > $ADODB_COUNTRECS = $crecs; $rs = $this->Execute($sql,$inputarr); > }
< $rs = $this->Execute($sql,$inputarr);
if ($rs->EOF) { $ret = $ADODB_GETONE_EOF; } else { $ret = reset($rs->fields); } $rs->Close(); }
< $ADODB_COUNTRECS = $crecs;
return $ret; } // $where should include 'WHERE fld=value' function GetMedian($table, $field,$where = '') { $total = $this->GetOne("select count(*) from $table $where"); if (!$total) { return false; } $midrow = (integer) ($total/2); $rs = $this->SelectLimit("select $field from $table $where order by 1",1,$midrow); if ($rs && !$rs->EOF) { return reset($rs->fields); } return false; } function CacheGetOne($secs2cache,$sql=false,$inputarr=false) { global $ADODB_GETONE_EOF; $ret = false; $rs = $this->CacheExecute($secs2cache,$sql,$inputarr); if ($rs) { if ($rs->EOF) { $ret = $ADODB_GETONE_EOF; } else { $ret = reset($rs->fields); } $rs->Close(); } return $ret; }
> /** function GetCol($sql, $inputarr = false, $trim = false) { > * Executes a statement and returns each row's first column in an array. > * $rs = $this->Execute($sql, $inputarr); > * @param string $sql SQL statement if ($rs) { > * @param array|bool $inputarr input bind array $rv = array(); > * @param bool $trim enables space trimming of the returned value. if ($trim) { > * This is only relevant if the returned string while (!$rs->EOF) { > * is coming from a CHAR type field. $rv[] = trim(reset($rs->fields)); > * $rs->MoveNext(); > * @return array|bool 1D array containning the first row of the query } > */
} else { while (!$rs->EOF) { $rv[] = reset($rs->fields); $rs->MoveNext(); } } $rs->Close(); } else { $rv = false; } return $rv; } function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false) { $rs = $this->CacheExecute($secs, $sql, $inputarr); if ($rs) { $rv = array(); if ($trim) { while (!$rs->EOF) { $rv[] = trim(reset($rs->fields)); $rs->MoveNext(); } } else { while (!$rs->EOF) { $rv[] = reset($rs->fields); $rs->MoveNext(); } } $rs->Close(); } else $rv = false; return $rv; }
< function Transpose(&$rs,$addfieldnames=true) { < $rs2 = $this->_rs2rs($rs); < if (!$rs2) { < return false; < } < < $rs2->_transpose($addfieldnames); < return $rs2; < } < < /* < Calculate the offset of a date for a particular database and generate < appropriate SQL. Useful for calculating future/past dates and storing < in a database. < < If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
> /** > * Calculate the offset of a date for a particular database > * and generate appropriate SQL. > * > * Useful for calculating future/past dates and storing in a database. > * > * @param double $dayFraction 1.5 means 1.5 days from now, 1.0/24 for 1 hour > * @param string|false $date Reference date, false for system time > * > * @return string
*/ function OffsetDate($dayFraction,$date=false) { if (!$date) { $date = $this->sysDate; } return '('.$date.'+'.$dayFraction.')'; } /**
> * Executes a statement and returns a the entire recordset in an array.
*
< * @param sql SQL statement < * @param [inputarr] input bind array
> * @param string $sql SQL statement > * @param array|bool $inputarr input bind array > * > * @return array|false
*/ function GetArray($sql,$inputarr=false) { global $ADODB_COUNTRECS;
> try {
$savec = $ADODB_COUNTRECS; $ADODB_COUNTRECS = false; $rs = $this->Execute($sql,$inputarr);
> } finally {
$ADODB_COUNTRECS = $savec;
> } if (!$rs) >
if (defined('ADODB_PEAR')) {
< $cls = ADODB_PEAR_Error(); < return $cls;
> return ADODB_PEAR_Error();
} else { return false; } $arr = $rs->GetArray(); $rs->Close(); return $arr; } function CacheGetAll($secs2cache,$sql=false,$inputarr=false) {
< $arr = $this->CacheGetArray($secs2cache,$sql,$inputarr); < return $arr;
> return $this->CacheGetArray($secs2cache,$sql,$inputarr);
} function CacheGetArray($secs2cache,$sql=false,$inputarr=false) { global $ADODB_COUNTRECS;
> try {
$savec = $ADODB_COUNTRECS; $ADODB_COUNTRECS = false; $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
> } finally {
$ADODB_COUNTRECS = $savec;
> }
if (!$rs) if (defined('ADODB_PEAR')) {
< $cls = ADODB_PEAR_Error(); < return $cls;
> return ADODB_PEAR_Error();
} else { return false; } $arr = $rs->GetArray(); $rs->Close(); return $arr; } function GetRandRow($sql, $arr= false) { $rezarr = $this->GetAll($sql, $arr); $sz = sizeof($rezarr); return $rezarr[abs(rand()) % $sz]; } /** * Return one row of sql statement. Recordset is disposed for you. * Note that SelectLimit should not be called. *
< * @param sql SQL statement < * @param [inputarr] input bind array
> * @param string $sql SQL statement > * @param array|bool $inputarr input bind array > * > * @return array|false Array containing the first row of the query
*/ function GetRow($sql,$inputarr=false) { global $ADODB_COUNTRECS;
> try {
$crecs = $ADODB_COUNTRECS; $ADODB_COUNTRECS = false;
<
$rs = $this->Execute($sql,$inputarr);
<
> } finally {
$ADODB_COUNTRECS = $crecs;
> } if ($rs) { >
if (!$rs->EOF) { $arr = $rs->fields; } else { $arr = array(); } $rs->Close(); return $arr; } return false; }
> /** function CacheGetRow($secs2cache,$sql=false,$inputarr=false) { > * @param int $secs2cache $rs = $this->CacheExecute($secs2cache,$sql,$inputarr); > * @param string|false $sql if ($rs) { > * @param mixed[]|bool $inputarr if (!$rs->EOF) { > * @return mixed[]|bool $arr = $rs->fields; > */
} else { $arr = array(); } $rs->Close(); return $arr; } return false; } /** * Insert or replace a single record. Note: this is not the same as MySQL's replace. * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL. * Also note that no table locking is done currently, so it is possible that the * record be inserted twice by two programs... * * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname'); * * $table table name * $fieldArray associative array of data (you must quote strings yourself). * $keyCol the primary key field name or if compound key, array of field names
< * autoQuote set to true to use a hueristic to quote strings. Works with nulls and numbers
> * autoQuote set to true to use a heuristic to quote strings. Works with nulls and numbers
* but does not work with dates nor SQL functions. * has_autoinc the primary key is an auto-inc field, so skip in insert. * * Currently blob replace not supported * * returns 0 = fail, 1 = update, 2 = insert */ function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false) { global $ADODB_INCLUDED_LIB; if (empty($ADODB_INCLUDED_LIB)) {
< include(ADODB_DIR.'/adodb-lib.inc.php');
> include_once(ADODB_DIR.'/adodb-lib.inc.php');
} return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc); } /** * Will select, getting rows from $offset (1-based), for $nrows. * This simulates the MySQL "select * from table limit $offset,$nrows" , and * the PostgreSQL "select * from table limit $nrows offset $offset". Note that * MySQL and PostgreSQL parameter ordering is the opposite of the other. * eg. * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based) * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based) * * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set *
< * @param [secs2cache] seconds to cache data, set to 0 to force query. This is optional < * @param sql < * @param [offset] is the row to start calculations from (1-based) < * @param [nrows] is the number of rows to get < * @param [inputarr] array of bind variables < * @return the recordset ($rs->databaseType == 'array')
> * @param int $secs2cache Seconds to cache data, set to 0 to force query. This is optional > * @param string $sql > * @param int $offset Row to start calculations from (1-based) > * @param int $nrows Number of rows to get > * @param array $inputarr Array of bind variables > * > * @return ADORecordSet The recordset ($rs->databaseType == 'array')
*/ function CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false) { if (!is_numeric($secs2cache)) { if ($sql === false) { $sql = -1; } if ($offset == -1) { $offset = false; } // sql, nrows, offset,inputarr $rs = $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs); } else { if ($sql === false) { $this->outp_throw("Warning: \$sql missing from CacheSelectLimit()",'CacheSelectLimit'); } $rs = $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); } return $rs; } /** * Flush cached recordsets that match a particular $sql statement. * If $sql == false, then we purge all files in the cache. */ function CacheFlush($sql=false,$inputarr=false) { global $ADODB_CACHE_DIR, $ADODB_CACHE; # Create cache if it does not exist if (empty($ADODB_CACHE)) { $this->_CreateCache(); } if (!$sql) { $ADODB_CACHE->flushall($this->debug); return; } $f = $this->_gencachename($sql.serialize($inputarr),false); return $ADODB_CACHE->flushcache($f, $this->debug); } /** * Private function to generate filename for caching. * Filename is generated based on: * * - sql statement * - database type (oci8, ibase, ifx, etc) * - database name * - userid * - setFetchMode (adodb 4.23) *
< * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
> * We create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
* Assuming that we can have 50,000 files per directory with good performance, * then we can scale to 12.8 million unique cached recordsets. Wow! */ function _gencachename($sql,$createdir) { global $ADODB_CACHE, $ADODB_CACHE_DIR; if ($this->fetchMode === false) { global $ADODB_FETCH_MODE; $mode = $ADODB_FETCH_MODE; } else { $mode = $this->fetchMode; } $m = md5($sql.$this->databaseType.$this->database.$this->user.$mode); if (!$ADODB_CACHE->createdir) { return $m; } if (!$createdir) { $dir = $ADODB_CACHE->getdirname($m); } else { $dir = $ADODB_CACHE->createdir($m, $this->debug); } return $dir.'/adodb_'.$m.'.cache'; } /** * Execute SQL, caching recordsets. *
< * @param [secs2cache] seconds to cache data, set to 0 to force query.
> * @param int $secs2cache Seconds to cache data, set to 0 to force query.
* This is an optional parameter.
< * @param sql SQL statement to execute < * @param [inputarr] holds the input data to bind to < * @return RecordSet or false
> * @param string|bool $sql SQL statement to execute > * @param array|bool $inputarr Holds the input data to bind > * > * @return ADORecordSet RecordSet or false
*/ function CacheExecute($secs2cache,$sql=false,$inputarr=false) { global $ADODB_CACHE; if (empty($ADODB_CACHE)) { $this->_CreateCache(); } if (!is_numeric($secs2cache)) { $inputarr = $sql; $sql = $secs2cache; $secs2cache = $this->cacheSecs; } if (is_array($sql)) { $sqlparam = $sql; $sql = $sql[0]; } else $sqlparam = $sql; $md5file = $this->_gencachename($sql.serialize($inputarr),true); $err = ''; if ($secs2cache > 0){ $rs = $ADODB_CACHE->readcache($md5file,$err,$secs2cache,$this->arrayClass); $this->numCacheHits += 1; } else { $err='Timeout 1'; $rs = false; $this->numCacheMisses += 1; } if (!$rs) { // no cached rs found if ($this->debug) {
< if (get_magic_quotes_runtime() && !$this->memCache) { < ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :("); < }
if ($this->debug !== -1) { ADOConnection::outp( " $md5file cache failure: $err (this is a notice and not an error)"); } } $rs = $this->Execute($sqlparam,$inputarr); if ($rs) { $eof = $rs->EOF; $rs = $this->_rs2rs($rs); // read entire recordset into memory immediately $rs->timeCreated = time(); // used by caching $txt = _rs2serialize($rs,false,$sql); // serialize $ok = $ADODB_CACHE->writecache($md5file,$txt,$this->debug, $secs2cache); if (!$ok) { if ($ok === false) { $em = 'Cache write error'; $en = -32000; if ($fn = $this->raiseErrorFn) { $fn($this->databaseType,'CacheExecute', $en, $em, $md5file,$sql,$this); } } else { $em = 'Cache file locked warning'; $en = -32001; // do not call error handling for just a warning } if ($this->debug) { ADOConnection::outp( " ".$em); } } if ($rs->EOF && !$eof) { $rs->MoveFirst(); //$rs = csv2rs($md5file,$err); $rs->connection = $this; // Pablo suggestion } } else if (!$this->memCache) { $ADODB_CACHE->flushcache($md5file); } } else { $this->_errorMsg = ''; $this->_errorCode = 0; if ($this->fnCacheExecute) { $fn = $this->fnCacheExecute; $fn($this, $secs2cache, $sql, $inputarr); } // ok, set cached object found $rs->connection = $this; // Pablo suggestion if ($this->debug){ if ($this->debug == 99) { adodb_backtrace(); } $inBrowser = isset($_SERVER['HTTP_USER_AGENT']); $ttl = $rs->timeCreated + $secs2cache - time(); $s = is_array($sql) ? $sql[0] : $sql; if ($inBrowser) { $s = '<i>'.htmlspecialchars($s).'</i>'; } ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]"); } } return $rs; }
< /* < Similar to PEAR DB's autoExecute(), except that < $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE < If $mode == 'UPDATE', then $where is compulsory as a safety measure. < < $forceUpdate means that even if the data has not changed, perform update.
> /** > * Simple interface to insert and update records. > * > * Automatically generate and execute INSERT and UPDATE statements > * on a given table, similar to PEAR DB's autoExecute(). > * > * @param string $table Name of the table to process. > * @param array $fields_values Associative array of field names => values. > * @param string|int $mode Execution mode: 'INSERT' (default), 'UPDATE' or > * one of the DB_AUTOQUERY_xx constants. > * @param string $where SQL where clause (mandatory in UPDATE mode as a safety measure) > * @param bool $forceUpdate If true, update all provided fields, even if they have not changed; > * otherwise only modified fields are updated. > * @param bool $magic_quotes This param is not used since 5.21.0. > * It remains for backwards compatibility. > * > * @return bool > * > * @noinspection PhpUnusedParameterInspection
*/
< function AutoExecute($table, $fields_values, $mode = 'INSERT', $where = false, $forceUpdate = true, $magicq = false) { < if ($where === false && ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) ) {
> function autoExecute($table, $fields_values, $mode = 'INSERT', $where = '', $forceUpdate = true, $magic_quotes = false) { > if (empty($fields_values)) { > $this->outp_throw('AutoExecute: Empty fields array', 'AutoExecute'); > return false; > } > if (empty($where) && ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */)) {
$this->outp_throw('AutoExecute: Illegal mode=UPDATE with empty WHERE clause', 'AutoExecute'); return false; } $sql = "SELECT * FROM $table"; $rs = $this->SelectLimit($sql, 1); if (!$rs) { return false; // table does not exist } $rs->tableName = $table;
< if ($where !== false) {
> if (!empty($where)) {
$sql .= " WHERE $where"; } $rs->sql = $sql; switch($mode) { case 'UPDATE': case DB_AUTOQUERY_UPDATE:
< $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq);
> $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate);
break; case 'INSERT': case DB_AUTOQUERY_INSERT:
< $sql = $this->GetInsertSQL($rs, $fields_values, $magicq);
> $sql = $this->GetInsertSQL($rs, $fields_values);
break; default: $this->outp_throw("AutoExecute: Unknown mode=$mode", 'AutoExecute'); return false; } return $sql && $this->Execute($sql); } /** * Generates an Update Query based on an existing recordset.
> *
* $arrFields is an associative array of fields with the value * that should be assigned. * * Note: This function should only be used on a recordset * that is run against a single table and sql should only * be a simple select stmt with no groupby/orderby/limit
> * @author "Jonathan Younger" <jyounger@unilab.com> * > * * "Jonathan Younger" <jyounger@unilab.com> > * @param $rs */ > * @param $arrFields function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null) { > * @param bool $forceUpdate global $ADODB_INCLUDED_LIB; > * @param bool $magic_quotes This param is not used since 5.21.0. > * It remains for backwards compatibility. // ******************************************************** > * @param null $force
< * "Jonathan Younger" <jyounger@unilab.com>
> * @return false|string > * > * @noinspection PhpUnusedParameterInspection
< function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null) {
> function GetUpdateSQL(&$rs, $arrFields, $forceUpdate=false, $magic_quotes=false, $force=null) {
if (!isset($force)) { global $ADODB_FORCE_TYPE; $force = $ADODB_FORCE_TYPE; } // ******************************************************** if (empty($ADODB_INCLUDED_LIB)) {
< include(ADODB_DIR.'/adodb-lib.inc.php');
> include_once(ADODB_DIR.'/adodb-lib.inc.php');
}
< return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
> return _adodb_getupdatesql($this, $rs, $arrFields, $forceUpdate, $force);
} /** * Generates an Insert Query based on an existing recordset.
> *
* $arrFields is an associative array of fields with the value * that should be assigned. * * Note: This function should only be used on a recordset * that is run against a single table.
> * */ > * @param $rs function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null) { > * @param $arrFields global $ADODB_INCLUDED_LIB; > * @param bool $magic_quotes This param is not used since 5.21.0. if (!isset($force)) { > * It remains for backwards compatibility. global $ADODB_FORCE_TYPE; > * @param null $force $force = $ADODB_FORCE_TYPE; > * } > * @return false|string if (empty($ADODB_INCLUDED_LIB)) { > * include(ADODB_DIR.'/adodb-lib.inc.php'); > * @noinspection PhpUnusedParameterInspection
< function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null) {
> function GetInsertSQL(&$rs, $arrFields, $magic_quotes=false, $force=null) {
< include(ADODB_DIR.'/adodb-lib.inc.php');
> include_once(ADODB_DIR.'/adodb-lib.inc.php');
< return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
> return _adodb_getinsertsql($this, $rs, $arrFields, $force);
/**
< * Update a blob column, given a where clause. There are more sophisticated < * blob handling functions that we could have implemented, but all require < * a very complex API. Instead we have chosen something that is extremely < * simple to understand and use. < * < * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
> * Update a BLOB column, given a where clause.
*
< * Usage to update a $blobvalue which has a primary key blob_id=1 into a < * field blobtable.blobcolumn:
> * There are more sophisticated blob handling functions that we could have > * implemented, but all require a very complex API. Instead we have chosen > * something that is extremely simple to understand and use.
*
< * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
> * Sample usage: > * - update a BLOB in field table.blob_col with value $blobValue, for a > * record having primary key id=1 > * $conn->updateBlob('table', 'blob_col', $blobValue, 'id=1'); > * - insert example: > * $conn->execute('INSERT INTO table (id, blob_col) VALUES (1, null)'); > * $conn->updateBlob('table', 'blob_col', $blobValue, 'id=1');
*
< * Insert example:
> * @param string $table > * @param string $column > * @param string $val Filename containing blob data > * @param mixed $where {@see updateBlob()} > * @param string $blobtype supports 'BLOB' (default) and 'CLOB'
*
< * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); < * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
> * @return bool success
*/
< function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') {
> function updateBlob($table, $column, $val, $where, $blobtype='BLOB') {
return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false; } /**
< * Usage: < * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
> * Update a BLOB from a file. > * > * Usage example: > * $conn->updateBlobFile('table', 'blob_col', '/path/to/file', 'id=1');
*
< * $blobtype supports 'BLOB' and 'CLOB'
> * @param string $table > * @param string $column > * @param string $path Filename containing blob data > * @param mixed $where {@see updateBlob()} > * @param string $blobtype supports 'BLOB' and 'CLOB'
*
< * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); < * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
> * @return bool success
*/
< function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') {
> function updateBlobFile($table, $column, $path, $where, $blobtype='BLOB') {
$fd = fopen($path,'rb'); if ($fd === false) { return false; } $val = fread($fd,filesize($path)); fclose($fd); return $this->UpdateBlob($table,$column,$val,$where,$blobtype); } function BlobDecode($blob) { return $blob; } function BlobEncode($blob) { return $blob; }
< function GetCharSet() {
> /** > * Retrieve the client connection's current character set. > * > * @return string|false The character set, or false if it can't be determined. > */ > function getCharSet() {
return $this->charSet; }
< function SetCharSet($charset) {
> /** > * Sets the client-side character set. > * > * This is only supported for some databases. > * @see https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:setcharset > * > * @param string $charset The character set to switch to. > * > * @return bool True if the character set was changed successfully, false otherwise. > */ > function setCharSet($charset) {
$this->charSet = $charset; return true; } function IfNull( $field, $ifNull ) { return " CASE WHEN $field is null THEN $ifNull ELSE $field END "; } function LogSQL($enable=true) { include_once(ADODB_DIR.'/adodb-perf.inc.php'); if ($enable) { $this->fnExecute = 'adodb_log_sql'; } else { $this->fnExecute = false; } $old = $this->_logsql; $this->_logsql = $enable; if ($enable && !$old) { $this->_affected = false; } return $old; } /** * Usage: * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB'); * * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)'); * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1'); */ function UpdateClob($table,$column,$val,$where) { return $this->UpdateBlob($table,$column,$val,$where,'CLOB'); } // not the fastest implementation - quick and dirty - jlim // for best performance, use the actual $rs->MetaType(). function MetaType($t,$len=-1,$fieldobj=false) { if (empty($this->_metars)) { $rsclass = $this->rsPrefix.$this->databaseType; $this->_metars = new $rsclass(false,$this->fetchMode); $this->_metars->connection = $this; } return $this->_metars->MetaType($t,$len,$fieldobj); } /** * Change the SQL connection locale to a specified locale. * This is used to get the date formats written depending on the client locale. */ function SetDateLocale($locale = 'En') { $this->locale = $locale; switch (strtoupper($locale)) { case 'EN': $this->fmtDate="'Y-m-d'"; $this->fmtTimeStamp = "'Y-m-d H:i:s'"; break; case 'US': $this->fmtDate = "'m-d-Y'"; $this->fmtTimeStamp = "'m-d-Y H:i:s'"; break; case 'PT_BR': case 'NL': case 'FR': case 'RO': case 'IT': $this->fmtDate="'d-m-Y'"; $this->fmtTimeStamp = "'d-m-Y H:i:s'"; break; case 'GE': $this->fmtDate="'d.m.Y'"; $this->fmtTimeStamp = "'d.m.Y H:i:s'"; break; default: $this->fmtDate="'Y-m-d'"; $this->fmtTimeStamp = "'Y-m-d H:i:s'"; break; } } /** * GetActiveRecordsClass Performs an 'ALL' query * * @param mixed $class This string represents the class of the current active record * @param mixed $table Table used by the active record object * @param mixed $whereOrderBy Where, order, by clauses * @param mixed $bindarr * @param mixed $primkeyArr * @param array $extra Query extras: limit, offset... * @param mixed $relations Associative array: table's foreign name, "hasMany", "belongsTo" * @access public * @return void */ function GetActiveRecordsClass( $class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false, $extra=array(), $relations=array()) { global $_ADODB_ACTIVE_DBS; ## reduce overhead of adodb.inc.php -- moved to adodb-active-record.inc.php ## if adodb-active-recordx is loaded -- should be no issue as they will probably use Find() if (!isset($_ADODB_ACTIVE_DBS)) { include_once(ADODB_DIR.'/adodb-active-record.inc.php'); } return adodb_GetActiveRecordsClass($this, $class, $table, $whereOrderBy, $bindarr, $primkeyArr, $extra, $relations); } function GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false) { $arr = $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr); return $arr; } /** * Close Connection */ function Close() { $rez = $this->_close(); $this->_queryID = false; $this->_connectionID = false; return $rez; } /**
< * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
> * Begin a Transaction. > * > * Must be followed by CommitTrans() or RollbackTrans().
*
< * @return true if succeeded or false if database does not support transactions
> * @return bool true if succeeded or false if database does not support transactions
*/ function BeginTrans() { if ($this->debug) { ADOConnection::outp("BeginTrans: Transactions not supported for this driver"); } return false; } /* set transaction mode */ function SetTransactionMode( $transaction_mode ) { $transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider); $this->_transmode = $transaction_mode; } /* http://msdn2.microsoft.com/en-US/ms173763.aspx http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm */ function MetaTransaction($mode,$db) { $mode = strtoupper($mode); $mode = str_replace('ISOLATION LEVEL ','',$mode); switch($mode) { case 'READ UNCOMMITTED': switch($db) { case 'oci8': case 'oracle': return 'ISOLATION LEVEL READ COMMITTED'; default: return 'ISOLATION LEVEL READ UNCOMMITTED'; } break; case 'READ COMMITTED': return 'ISOLATION LEVEL READ COMMITTED'; break; case 'REPEATABLE READ': switch($db) { case 'oci8': case 'oracle': return 'ISOLATION LEVEL SERIALIZABLE'; default: return 'ISOLATION LEVEL REPEATABLE READ'; } break; case 'SERIALIZABLE': return 'ISOLATION LEVEL SERIALIZABLE'; break; default: return $mode; } } /**
< * If database does not support transactions, always return true as data always commited
> * Commits a transaction.
*
< * @param $ok set to false to rollback transaction, true to commit
> * If database does not support transactions, return true as data is > * always committed.
*
< * @return true/false.
> * @param bool $ok True to commit, false to rollback the transaction. > * > * @return bool true if successful
*/ function CommitTrans($ok=true) { return true; } /**
< * If database does not support transactions, rollbacks always fail, so return false
> * Rolls back a transaction. > * > * If database does not support transactions, return false as rollbacks > * always fail.
*
< * @return true/false.
> * @return bool true if successful
*/ function RollbackTrans() { return false; } /** * return the databases that the driver can connect to. * Some databases will return an empty array. *
< * @return an array of database names.
> * @return array|bool an array of database names.
*/ function MetaDatabases() { global $ADODB_FETCH_MODE; if ($this->metaDatabasesSQL) { $save = $ADODB_FETCH_MODE; $ADODB_FETCH_MODE = ADODB_FETCH_NUM; if ($this->fetchMode !== false) { $savem = $this->SetFetchMode(false); } $arr = $this->GetCol($this->metaDatabasesSQL); if (isset($savem)) { $this->SetFetchMode($savem); } $ADODB_FETCH_MODE = $save; return $arr; } return false; } /** * List procedures or functions in an array. * @param procedureNamePattern a procedure name pattern; must match the procedure name as it is stored in the database * @param catalog a catalog name; must match the catalog name as it is stored in the database; * @param schemaPattern a schema name pattern; * * @return array of procedures on current database. * * Array( * [name_of_procedure] => Array( * [type] => PROCEDURE or FUNCTION * [catalog] => Catalog_name * [schema] => Schema_name * [remarks] => explanatory comment on the procedure * ) * ) */ function MetaProcedures($procedureNamePattern = null, $catalog = null, $schemaPattern = null) { return false; } /** * @param ttype can either be 'VIEW' or 'TABLE' or false. * If false, both views and tables are returned. * "VIEW" returns only views * "TABLE" returns only tables * @param showSchema returns the schema/user with the table name, eg. USER.TABLE * @param mask is the input mask - only supported by oci8 and postgresql * * @return array of tables for current database. */ function MetaTables($ttype=false,$showSchema=false,$mask=false) { global $ADODB_FETCH_MODE; if ($mask) { return false; } if ($this->metaTablesSQL) { $save = $ADODB_FETCH_MODE; $ADODB_FETCH_MODE = ADODB_FETCH_NUM; if ($this->fetchMode !== false) { $savem = $this->SetFetchMode(false); } $rs = $this->Execute($this->metaTablesSQL); if (isset($savem)) { $this->SetFetchMode($savem); } $ADODB_FETCH_MODE = $save; if ($rs === false) { return false; } $arr = $rs->GetArray(); $arr2 = array(); if ($hast = ($ttype && isset($arr[0][1]))) { $showt = strncmp($ttype,'T',1); } for ($i=0; $i < sizeof($arr); $i++) { if ($hast) { if ($showt == 0) { if (strncmp($arr[$i][1],'T',1) == 0) { $arr2[] = trim($arr[$i][0]); } } else { if (strncmp($arr[$i][1],'V',1) == 0) { $arr2[] = trim($arr[$i][0]); } } } else $arr2[] = trim($arr[$i][0]); } $rs->Close(); return $arr2; } return false; } function _findschema(&$table,&$schema) { if (!$schema && ($at = strpos($table,'.')) !== false) { $schema = substr($table,0,$at); $table = substr($table,$at+1); } } /** * List columns in a database as an array of ADOFieldObjects. * See top of file for definition of object. * * @param $table table name to query * @param $normalize makes table name case-insensitive (required by some databases) * @schema is optional database schema to use - not supported by all databases. * * @return array of ADOFieldObjects for current table. */ function MetaColumns($table,$normalize=true) { global $ADODB_FETCH_MODE; if (!empty($this->metaColumnsSQL)) { $schema = false; $this->_findschema($table,$schema); $save = $ADODB_FETCH_MODE; $ADODB_FETCH_MODE = ADODB_FETCH_NUM; if ($this->fetchMode !== false) { $savem = $this->SetFetchMode(false); } $rs = $this->Execute(sprintf($this->metaColumnsSQL,($normalize)?strtoupper($table):$table)); if (isset($savem)) { $this->SetFetchMode($savem); } $ADODB_FETCH_MODE = $save; if ($rs === false || $rs->EOF) { return false; } $retarr = array(); while (!$rs->EOF) { //print_r($rs->fields); $fld = new ADOFieldObject(); $fld->name = $rs->fields[0]; $fld->type = $rs->fields[1]; if (isset($rs->fields[3]) && $rs->fields[3]) { if ($rs->fields[3]>0) { $fld->max_length = $rs->fields[3]; } $fld->scale = $rs->fields[4]; if ($fld->scale>0) { $fld->max_length += 1; } } else { $fld->max_length = $rs->fields[2]; } if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) { $retarr[] = $fld; } else { $retarr[strtoupper($fld->name)] = $fld; } $rs->MoveNext(); } $rs->Close(); return $retarr; } return false; } /** * List indexes on a table as an array. * @param table table name to query * @param primary true to only show primary keys. Not actually used for most databases * * @return array of indexes on current table. Each element represents an index, and is itself an associative array. * * Array( * [name_of_index] => Array( * [unique] => true or false * [columns] => Array( * [0] => firstname * [1] => lastname * ) * ) * ) */ function MetaIndexes($table, $primary = false, $owner = false) { return false; } /** * List columns names in a table as an array. * @param table table name to query * * @return array of column names for current table. */ function MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */) { $objarr = $this->MetaColumns($table); if (!is_array($objarr)) { return false; } $arr = array(); if ($numIndexes) { $i = 0; if ($useattnum) { foreach($objarr as $v) $arr[$v->attnum] = $v->name; } else foreach($objarr as $v) $arr[$i++] = $v->name; } else foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name; return $arr; } /**
> * Concatenate strings. * Different SQL databases used different methods to combine strings together. > *
* This function provides a wrapper. *
< * param s variable number of string parameters < *
* Usage: $db->Concat($str1,$str2); *
< * @return concatenated string
> * @param string $s Variable number of string parameters > * > * @return string concatenated string
*/ function Concat() { $arr = func_get_args(); return implode($this->concat_operator, $arr); } /** * Converts a date "d" to a string that the database can understand. *
< * @param d a date in Unix date time format.
> * @param mixed $d a date in Unix date time format.
*
< * @return date string in database date format
> * @return string date string in database date format
*/ function DBDate($d, $isfld=false) { if (empty($d) && $d !== 0) { return 'null'; } if ($isfld) { return $d; } if (is_object($d)) { return $d->format($this->fmtDate); } if (is_string($d) && !is_numeric($d)) { if ($d === 'null') { return $d; } if (strncmp($d,"'",1) === 0) { $d = _adodb_safedateq($d); return $d; } if ($this->isoDates) { return "'$d'"; } $d = ADOConnection::UnixDate($d); } return adodb_date($this->fmtDate,$d); } function BindDate($d) { $d = $this->DBDate($d); if (strncmp($d,"'",1)) { return $d; } return substr($d,1,strlen($d)-2); } function BindTimeStamp($d) { $d = $this->DBTimeStamp($d); if (strncmp($d,"'",1)) { return $d; } return substr($d,1,strlen($d)-2); } /** * Converts a timestamp "ts" to a string that the database can understand. *
< * @param ts a timestamp in Unix date time format.
> * @param int|object $ts A timestamp in Unix date time format.
*
< * @return timestamp string in database timestamp format
> * @return string $timestamp string in database timestamp format
*/ function DBTimeStamp($ts,$isfld=false) { if (empty($ts) && $ts !== 0) { return 'null'; } if ($isfld) { return $ts; } if (is_object($ts)) { return $ts->format($this->fmtTimeStamp); } # strlen(14) allows YYYYMMDDHHMMSS format if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) { return adodb_date($this->fmtTimeStamp,$ts); } if ($ts === 'null') { return $ts; } if ($this->isoDates && strlen($ts) !== 14) { $ts = _adodb_safedate($ts); return "'$ts'"; } $ts = ADOConnection::UnixTimeStamp($ts); return adodb_date($this->fmtTimeStamp,$ts); } /** * Also in ADORecordSet.
< * @param $v is a date string in YYYY-MM-DD format
> * @param mixed $v is a date string in YYYY-MM-DD format
*
< * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
> * @return int|false Date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
*/ static function UnixDate($v) { if (is_object($v)) { // odbtp support //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year); } if (is_numeric($v) && strlen($v) !== 8) { return $v; } if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", $v, $rr)) { return false; } if ($rr[1] <= TIMESTAMP_FIRST_YEAR) { return 0; } // h-m-s-MM-DD-YY return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]); } /** * Also in ADORecordSet.
< * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
> * @param string|object $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
*
< * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
> * @return int|false Date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
*/ static function UnixTimeStamp($v) { if (is_object($v)) { // odbtp support //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year); } if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", ($v), $rr)) return false; if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) { return 0; } // h-m-s-MM-DD-YY if (!isset($rr[5])) { return adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]); } return @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]); } /**
< * Also in ADORecordSet. < *
* Format database date based on user defined format. *
< * @param v is the character date in YYYY-MM-DD format, returned by database < * @param fmt is the format to apply to it, using date()
> * Also in ADORecordSet. > * > * @param mixed $v Date in YYYY-MM-DD format, returned by database > * @param string $fmt Format to apply, using date() > * @param bool $gmt
*
< * @return a date formated as user desires
> * @return string Formatted date
*/ function UserDate($v,$fmt='Y-m-d',$gmt=false) { $tt = $this->UnixDate($v); // $tt == -1 if pre TIMESTAMP_FIRST_YEAR if (($tt === false || $tt == -1) && $v != false) { return $v; } else if ($tt == 0) { return $this->emptyDate; } else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR } return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt); } /**
> * Format timestamp based on user defined format.
*
< * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format < * @param fmt is the format to apply to it, using date()
> * @param mixed $v Date in YYYY-MM-DD hh:mm:ss format > * @param string $fmt Format to apply, using date() > * @param bool $gmt
*
< * @return a timestamp formated as user desires
> * @return string Formatted timestamp
*/ function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false) { if (!isset($v)) { return $this->emptyTimeStamp; } # strlen(14) allows YYYYMMDDHHMMSS format if (is_numeric($v) && strlen($v)<14) { return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v); } $tt = $this->UnixTimeStamp($v); // $tt == -1 if pre TIMESTAMP_FIRST_YEAR if (($tt === false || $tt == -1) && $v != false) { return $v; } if ($tt == 0) { return $this->emptyTimeStamp; } return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt); }
> /** function escape($s,$magic_quotes=false) { > * Alias for addQ() return $this->addq($s,$magic_quotes); > * @param string $s } > * @param bool [$magic_quotes] > * @return mixed /** > * * Quotes a string, without prefixing nor appending quotes. > * @deprecated 5.21.0 */ > * @noinspection PhpUnusedParameterInspection function addq($s,$magic_quotes=false) { > */
< return $this->addq($s,$magic_quotes);
> return $this->addQ($s);
if ($this->replaceQuote[0] == '\\') {
> * // only since php 4.0.5 > * @param string $s The string to quote $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); > * @param bool $magic_quotes This param is not used since 5.21.0. //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s)); > * It remains for backwards compatibility. } > * return str_replace("'",$this->replaceQuote,$s); > * @return string Quoted string } > * > * @noinspection PhpUnusedParameterInspection
< function addq($s,$magic_quotes=false) { < if (!$magic_quotes) {
> function addQ($s, $magic_quotes=false) {
< // only since php 4.0.5 < $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); < //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
> $s = str_replace( > array('\\', "\0"), > array('\\\\', "\\\0"), > $s > );
< // undo magic quotes for " < $s = str_replace('\\"','"',$s); < < if ($this->replaceQuote == "\\'" || ini_get('magic_quotes_sybase')) { < // ' already quoted, no need to change anything < return $s; < } else { < // change \' to '' for sybase/mssql < $s = str_replace('\\\\','\\',$s); < return str_replace("\\'",$this->replaceQuote,$s); < } < } <
< * Correctly quotes a string so that all strings are escaped. We prefix and append < * to the string single-quotes. < * An example is $db->qstr("Don't bother",magic_quotes_runtime());
> * Correctly quotes a string so that all strings are escaped. > * We prefix and append to the string single-quotes. > * An example is $db->qstr("Don't bother"); > * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:qstr
< * @param s the string to quote < * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc(). < * This undoes the stupidity of magic quotes for GPC.
> * @param string $s The string to quote > * @param bool $magic_quotes This param is not used since 5.21.0. > * It remains for backwards compatibility.
< * @return quoted string to be sent back to database
> * @return string Quoted string to be sent back to database > * > * @noinspection PhpUnusedParameterInspection
< function qstr($s,$magic_quotes=false) { < if (!$magic_quotes) { < if ($this->replaceQuote[0] == '\\'){ < // only since php 4.0.5 < $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); < //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s)); < } < return "'".str_replace("'",$this->replaceQuote,$s)."'"; < } < < // undo magic quotes for " < $s = str_replace('\\"','"',$s); < < if ($this->replaceQuote == "\\'" || ini_get('magic_quotes_sybase')) { < // ' already quoted, no need to change anything < return "'$s'"; < } else { < // change \' to '' for sybase/mssql < $s = str_replace('\\\\','\\',$s); < return "'".str_replace("\\'",$this->replaceQuote,$s)."'"; < }
> function qStr($s, $magic_quotes=false) { > return "'" . $this->addQ($s) . "'";
/** * Will select the supplied $page number from a recordset, given that it is paginated in pages of * $nrows rows per page. It also saves two boolean values saying if the given page is the first * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination. * * See docs-adodb.htm#ex8 for an example of usage.
< * < * @param sql < * @param nrows is the number of rows per page to get < * @param page is the page number to get (1-based) < * @param [inputarr] array of bind variables < * @param [secs2cache] is a private parameter only used by jlim < * @return the recordset ($rs->databaseType == 'array') < *
* NOTE: phpLens uses a different algorithm and does not use PageExecute(). *
> * @param string $sql */ > * @param int $nrows Number of rows per page to get function PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0) { > * @param int $page Page number to get (1-based) global $ADODB_INCLUDED_LIB; > * @param mixed[]|bool $inputarr Array of bind variables if (empty($ADODB_INCLUDED_LIB)) { > * @param int $secs2cache Private parameter only used by jlim include(ADODB_DIR.'/adodb-lib.inc.php'); > * } > * @return mixed the recordset ($rs->databaseType == 'array')
< include(ADODB_DIR.'/adodb-lib.inc.php');
> include_once(ADODB_DIR.'/adodb-lib.inc.php');
$rs = _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache); } else { $rs = _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache); } return $rs; } /** * Will select the supplied $page number from a recordset, given that it is paginated in pages of * $nrows rows per page. It also saves two boolean values saying if the given page is the first * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination. *
< * @param secs2cache seconds to cache data, set to 0 to force query < * @param sql < * @param nrows is the number of rows per page to get < * @param page is the page number to get (1-based) < * @param [inputarr] array of bind variables < * @return the recordset ($rs->databaseType == 'array')
> * @param int $secs2cache seconds to cache data, set to 0 to force query > * @param string $sql > * @param int $nrows is the number of rows per page to get > * @param int $page is the page number to get (1-based) > * @param mixed[]|bool $inputarr array of bind variables > * @return mixed the recordset ($rs->databaseType == 'array')
*/ function CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false) { /*switch($this->dataProvider) { case 'postgres': case 'mysql': break; default: $secs2cache = 0; break; }*/
< $rs = $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache); < return $rs;
> return $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache); > } > > /** > * Returns the maximum size of a MetaType C field. If the method > * is not defined in the driver returns ADODB_STRINGMAX_NOTSET > * > * @return int > */ > function charMax() { > return ADODB_STRINGMAX_NOTSET; > } > > /** > * Returns the maximum size of a MetaType X field. If the method > * is not defined in the driver returns ADODB_STRINGMAX_NOTSET > * > * @return int > */ > function textMax() { > return ADODB_STRINGMAX_NOTSET; > } > > /** > * Returns a substring of a varchar type field > * > * Some databases have variations of the parameters, which is why > * we have an ADOdb function for it > * > * @param string $fld The field to sub-string > * @param int $start The start point > * @param int $length An optional length > * > * @return string The SQL text > */ > function substr($fld,$start,$length=0) { > $text = "{$this->substr}($fld,$start"; > if ($length > 0) > $text .= ",$length"; > $text .= ')'; > return $text; > } > > /* > * Formats the date into Month only format MM with leading zeroes > * > * @param string $fld The name of the date to format > * > * @return string The SQL text > */ > function month($fld) { > return $this->sqlDate('m',$fld); > } > > /* > * Formats the date into Day only format DD with leading zeroes > * > * @param string $fld The name of the date to format > * @return string The SQL text > */ > function day($fld) { > return $this->sqlDate('d',$fld); > } > > /* > * Formats the date into year only format YYYY > * > * @param string $fld The name of the date to format > * > * @return string The SQL text > */ > function year($fld) { > return $this->sqlDate('Y',$fld);
} /** * Get the last error recorded by PHP and clear the message. * * By clearing the message, it becomes possible to detect whether a new error * has occurred, even when it is the same error as before being repeated. *
< * @return array|null Array if an error has previously occurred. Null otherwise.
> * @return mixed[]|null Array if an error has previously occurred. Null otherwise.
*/ protected function resetLastError() { $error = error_get_last(); if (is_array($error)) { $error['message'] = ''; } return $error; } /** * Compare a previously stored error message with the last error recorded by PHP
< * to determine whether a new error has occured.
> * to determine whether a new error has occurred.
*
< * @param array|null $old Optional. Previously stored return value of error_get_last().
> * @param mixed[]|null $old Optional. Previously stored return value of error_get_last().
*
< * @return string The error message if a new error has occured < * or an empty string if no (new) errors have occured..
> * @return string The error message if a new error has occurred > * or an empty string if no (new) errors have occurred..
*/ protected function getChangedErrorMsg($old = null) { $new = error_get_last(); if (is_null($new)) {
< // No error has occured yet at all.
> // No error has occurred yet at all.
return ''; } if (is_null($old)) { // First error recorded. return $new['message']; } $changed = false; foreach($new as $key => $value) { if ($new[$key] !== $old[$key]) { $changed = true; break; } } if ($changed === true) { return $new['message']; } return ''; } } // end class ADOConnection //============================================================================================== // CLASS ADOFetchObj //============================================================================================== /** * Internal placeholder for record objects. Used by ADORecordSet->FetchObj(). */
> #[AllowDynamicProperties]
class ADOFetchObj { };
< //============================================================================================== < // CLASS ADORecordSet_empty < //============================================================================================== <
> /** > * Class ADODB_Iterator_empty > */
class ADODB_Iterator_empty implements Iterator { private $rs; function __construct($rs) { $this->rs = $rs; }
> #[\ReturnTypeWillChange]
function rewind() {}
> #[\ReturnTypeWillChange]
function valid() { return !$this->rs->EOF; }
> #[\ReturnTypeWillChange]
function key() { return false; }
> #[\ReturnTypeWillChange]
function current() { return false; }
> #[\ReturnTypeWillChange]
function next() {} function __call($func, $params) { return call_user_func_array(array($this->rs, $func), $params); }
> #[\ReturnTypeWillChange]
function hasMore() { return false; } } /** * Lightweight recordset when there are no records to be returned */ class ADORecordSet_empty implements IteratorAggregate { var $dataProvider = 'empty'; var $databaseType = false; var $EOF = true; var $_numOfRows = 0;
> /** @var bool|array */
var $fields = false; var $connection = false; function RowCount() { return 0; } function RecordCount() { return 0; } function PO_RecordCount() { return 0; } function Close() { return true; } function FetchRow() { return false; } function FieldCount() { return 0; } function Init() {}
> #[\ReturnTypeWillChange]
function getIterator() { return new ADODB_Iterator_empty($this); } function GetAssoc() { return array(); } function GetArray() { return array(); } function GetAll() { return array(); } function GetArrayLimit() { return array(); } function GetRows() { return array(); } function GetRowAssoc() { return array(); } function MaxRecordCount() { return 0; } function NumRows() { return 0; } function NumCols() { return 0; } } //============================================================================================== // DATE AND TIME FUNCTIONS //============================================================================================== if (!defined('ADODB_DATE_VERSION')) {
< include(ADODB_DIR.'/adodb-time.inc.php');
> include_once(ADODB_DIR.'/adodb-time.inc.php');
}
< //============================================================================================== < // CLASS ADORecordSet < //============================================================================================== <
> /** > * Class ADODB_Iterator > */
class ADODB_Iterator implements Iterator { private $rs; function __construct($rs) { $this->rs = $rs; }
> #[\ReturnTypeWillChange]
function rewind() { $this->rs->MoveFirst(); }
> #[\ReturnTypeWillChange]
function valid() { return !$this->rs->EOF; }
> #[\ReturnTypeWillChange]
function key() { return $this->rs->_currentRow; }
> #[\ReturnTypeWillChange]
function current() { return $this->rs->fields; }
> #[\ReturnTypeWillChange]
function next() { $this->rs->MoveNext(); } function __call($func, $params) { return call_user_func_array(array($this->rs, $func), $params); } function hasMore() { return !$this->rs->EOF; } } /** * RecordSet class that represents the dataset returned by the database.
> *
* To keep memory overhead low, this class holds only the current row in memory. * No prefetching of data is done, so the RecordCount() can return -1 ( which * means recordcount not known). */ class ADORecordSet implements IteratorAggregate {
> /** > * Used for cases when a recordset object is not created by executing a query. /** > */ * public variables > const DUMMY_QUERY_ID = -1;
*/ var $dataProvider = "native";
> var $fields = false; /// holds the current row data > /** var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob > * @var string Table name (used in _adodb_getupdatesql() and _adodb_getinsertsql())- /// in other words, we use a text area for editing. > */ var $canSeek = false; /// indicates that seek is supported > public $tableName = ''; var $sql; /// sql text > var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object. > /** @var bool|array */
var $emptyTimeStamp = '&nbsp;'; /// what to display when $time==0 var $emptyDate = '&nbsp;'; /// what to display when $time==0 var $debug = false; var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsets var $bind = false; /// used by Fields() to hold array - should be private? var $fetchMode; /// default fetch mode
< var $connection = false; /// the parent connection <
> /** @var ADOConnection The parent connection */ > var $connection = false;
/** * private variables */ var $_numOfRows = -1; /** number of rows, or -1 */ var $_numOfFields = -1; /** number of fields in recordset */
< var $_queryID = -1; /** This variable keeps the result link identifier. */
> > /** > * @var resource|int|false result link identifier > */ > var $_queryID = self::DUMMY_QUERY_ID; >
var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */ var $_closed = false; /** has recordset been closed */ var $_inited = false; /** Init() should only be called once */ var $_obj; /** Used by FetchObj */ var $_names; /** Used by FetchObj */ var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */ var $_atFirstPage = false; /** Added by Iván Oliva to implement recordset pagination */ var $_atLastPage = false; /** Added by Iván Oliva to implement recordset pagination */ var $_lastPageNo = -1; var $_maxRecordCount = 0; var $datetime = false;
> public $customActualTypes; /** > public $customMetaTypes; * Constructor > * > /** @var int Only used in _adodb_getinsertsql() */ * @param queryID this is the queryID returned by ADOConnection->_query() > public $insertSig; * > */ > /** function __construct($queryID) { > * @var ADOFieldObject[] Field metadata cache $this->_queryID = $queryID; > * @see fieldTypesArray() } > */ > protected $fieldObjectsCache; function __destruct() { > $this->Close(); > /** } > * @var int Defines the Fetch Mode for a recordset > * See the ADODB_FETCH_* constants function getIterator() { > */ return new ADODB_Iterator($this); > public $adodbFetchMode; } >
< * @param queryID this is the queryID returned by ADOConnection->_query() < *
> * @param resource|int $queryID Query ID returned by ADOConnection->_query() > * @param int|bool $mode The ADODB_FETCH_MODE value
< function __construct($queryID) {
> function __construct($queryID,$mode=false) {
include_once(ADODB_DIR.'/toexport.inc.php');
> #[\ReturnTypeWillChange]
return _adodb_export($this,',',',',false,true); } function Init() { if ($this->_inited) { return; } $this->_inited = true; if ($this->_queryID) {
< @$this->_initrs();
> @$this->_initRS();
} else { $this->_numOfRows = 0; $this->_numOfFields = 0; } if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) { $this->_currentRow = 0; if ($this->EOF = ($this->_fetch() === false)) { $this->_numOfRows = 0; // _numOfRows could be -1 } } else { $this->EOF = true; } }
> /** > * Recordset initialization stub /** > */ * Generate a SELECT tag from a recordset, and return the HTML markup. > protected function _initRS() {} * > * If the recordset has 2 columns, we treat the first one as the text to > /** * display to the user, and the second as the return value. Extra columns > * Row fetch stub * are discarded. > * @return bool * > */ * @param string $name Name of SELECT tag > protected function _fetch() {}
* @param string|array $defstr The value to highlight. Use an array for multiple highlight values. * @param bool|string $blank1stItem True to create an empty item (default), False not to add one; * 'string' to set its label and 'value:string' to assign a value to it. * @param bool $multiple True for multi-select list * @param int $size Number of rows to show (applies to multi-select box only) * @param string $selectAttr Additional attributes to defined for SELECT tag, * useful for holding javascript onChange='...' handlers, CSS class, etc. * @param bool $compareFirstCol When true (default), $defstr is compared against the value (column 2), * while false will compare against the description (column 1). * * @return string HTML */ function getMenu($name, $defstr = '', $blank1stItem = true, $multiple = false, $size = 0, $selectAttr = '', $compareFirstCol = true) { global $ADODB_INCLUDED_LIB; if (empty($ADODB_INCLUDED_LIB)) {
< include(ADODB_DIR.'/adodb-lib.inc.php');
> include_once(ADODB_DIR.'/adodb-lib.inc.php');
} return _adodb_getmenu($this, $name, $defstr, $blank1stItem, $multiple, $size, $selectAttr, $compareFirstCol); } /** * Generate a SELECT tag with groups from a recordset, and return the HTML markup. * * The recordset must have 3 columns and be ordered by the 3rd column. The * first column contains the text to display to the user, the second is the * return value and the third is the option group. Extra columns are discarded. * Default strings are compared with the SECOND column. * * @param string $name Name of SELECT tag * @param string|array $defstr The value to highlight. Use an array for multiple highlight values. * @param bool|string $blank1stItem True to create an empty item (default), False not to add one; * 'string' to set its label and 'value:string' to assign a value to it. * @param bool $multiple True for multi-select list * @param int $size Number of rows to show (applies to multi-select box only) * @param string $selectAttr Additional attributes to defined for SELECT tag, * useful for holding javascript onChange='...' handlers, CSS class, etc. * @param bool $compareFirstCol When true (default), $defstr is compared against the value (column 2), * while false will compare against the description (column 1). * * @return string HTML */ function getMenuGrouped($name, $defstr = '', $blank1stItem = true, $multiple = false, $size = 0, $selectAttr = '', $compareFirstCol = true) { global $ADODB_INCLUDED_LIB; if (empty($ADODB_INCLUDED_LIB)) {
< include(ADODB_DIR.'/adodb-lib.inc.php');
> include_once(ADODB_DIR.'/adodb-lib.inc.php');
} return _adodb_getmenu_gp($this, $name, $defstr, $blank1stItem, $multiple, $size, $selectAttr, $compareFirstCol); } /** * Generate a SELECT tag from a recordset, and return the HTML markup. * * Same as GetMenu(), except that default strings are compared with the * FIRST column (the description). * * @param string $name Name of SELECT tag * @param string|array $defstr The value to highlight. Use an array for multiple highlight values. * @param bool|string $blank1stItem True to create an empty item (default), False not to add one; * 'string' to set its label and 'value:string' to assign a value to it. * @param bool $multiple True for multi-select list * @param int $size Number of rows to show (applies to multi-select box only) * @param string $selectAttr Additional attributes to defined for SELECT tag, * useful for holding javascript onChange='...' handlers, CSS class, etc. * * @return string HTML * * @deprecated 5.21.0 Use getMenu() with $compareFirstCol = false instead. */ function getMenu2($name, $defstr = '', $blank1stItem = true, $multiple = false, $size = 0, $selectAttr = '') { return $this->getMenu($name, $defstr, $blank1stItem, $multiple, $size, $selectAttr,false); } /** * Generate a SELECT tag with groups from a recordset, and return the HTML markup. * * Same as GetMenuGrouped(), except that default strings are compared with the * FIRST column (the description). * * @param string $name Name of SELECT tag * @param string|array $defstr The value to highlight. Use an array for multiple highlight values. * @param bool|string $blank1stItem True to create an empty item (default), False not to add one; * 'string' to set its label and 'value:string' to assign a value to it. * @param bool $multiple True for multi-select list * @param int $size Number of rows to show (applies to multi-select box only) * @param string $selectAttr Additional attributes to defined for SELECT tag, * useful for holding javascript onChange='...' handlers, CSS class, etc. * * @return string HTML * * @deprecated 5.21.0 Use getMenuGrouped() with $compareFirstCol = false instead. */ function getMenu3($name, $defstr = '', $blank1stItem = true, $multiple = false, $size = 0, $selectAttr = '') { return $this->getMenuGrouped($name, $defstr, $blank1stItem, $multiple, $size, $selectAttr, false); } /** * return recordset as a 2-dimensional array. *
< * @param [nRows] is the number of rows to return. -1 means every row.
> * @param int $nRows Number of rows to return. -1 means every row.
*
< * @return an array indexed by the rows (0-based) from the recordset
> * @return array indexed by the rows (0-based) from the recordset
*/ function GetArray($nRows = -1) {
< global $ADODB_EXTENSION; if ($ADODB_EXTENSION) { < $results = adodb_getall($this,$nRows); < return $results; < }
$results = array(); $cnt = 0; while (!$this->EOF && $nRows != $cnt) { $results[] = $this->fields; $this->MoveNext(); $cnt++; } return $results; } function GetAll($nRows = -1) {
< $arr = $this->GetArray($nRows); < return $arr;
> return $this->GetArray($nRows);
}
< /* < * Some databases allow multiple recordsets to be returned. This function < * will return true if there is a next recordset, or false if no more.
> /** > * Checks if there is another available recordset. > * > * Some databases allow multiple recordsets to be returned. > * > * @return boolean true if there is a next recordset, or false if no more
*/ function NextRecordSet() { return false; } /**
< * return recordset as a 2-dimensional array.
> * Return recordset as a 2-dimensional array. > *
* Helper function for ADOConnection->SelectLimit() *
< * @param offset is the row to start calculations from (1-based) < * @param [nrows] is the number of rows to return
> * @param int $nrows Number of rows to return > * @param int $offset Starting row (1-based)
*
< * @return an array indexed by the rows (0-based) from the recordset
> * @return array an array indexed by the rows (0-based) from the recordset
*/
< function GetArrayLimit($nrows,$offset=-1) {
> function getArrayLimit($nrows, $offset=-1) {
if ($offset <= 0) {
< $arr = $this->GetArray($nrows); < return $arr;
> return $this->GetArray($nrows);
} $this->Move($offset); $results = array(); $cnt = 0; while (!$this->EOF && $nrows != $cnt) { $results[$cnt++] = $this->fields; $this->MoveNext(); } return $results; } /** * Synonym for GetArray() for compatibility with ADO. *
< * @param [nRows] is the number of rows to return. -1 means every row.
> * @param int $nRows Number of rows to return. -1 means every row.
*
< * @return an array indexed by the rows (0-based) from the recordset
> * @return array an array indexed by the rows (0-based) from the recordset
*/
< function GetRows($nRows = -1) { < $arr = $this->GetArray($nRows); < return $arr;
> function getRows($nRows = -1) { > return $this->GetArray($nRows);
} /**
< * return whole recordset as a 2-dimensional associative array if there are more than 2 columns. < * The first column is treated as the key and is not included in the array. < * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless < * $force_array == true.
> * return whole recordset as a 2-dimensional associative array if > * there are more than 2 columns. The first column is treated as the > * key and is not included in the array. If there is only 2 columns, > * it will return a 1 dimensional array of key-value pairs unless > * $force_array == true. This recordset method is currently part of > * the API, but may not be in later versions of ADOdb. By preference, use > * ADOconnnection::getAssoc()
*
< * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional < * array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,
> * @param bool $force_array (optional) Has only meaning if we have 2 data > * columns. If false, a 1 dimensional > * array is returned, otherwise a 2 dimensional > * array is returned. If this sounds confusing,
* read the source. *
< * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and < * instead of returning array[col0] => array(remaining cols), return array[col0] => col1
> * @param bool $first2cols (optional) Means if there are more than > * 2 cols, ignore the remaining cols and > * instead of returning > * array[col0] => array(remaining cols), > * return array[col0] => col1 > * > * @return mixed[]|false
*
< * @return an associative array indexed by the first column of the array, < * or false if the data has less than 2 cols.
*/
< function GetAssoc($force_array = false, $first2cols = false) { < global $ADODB_EXTENSION; < < $cols = $this->_numOfFields; < if ($cols < 2) { < return false; < }
> function getAssoc($force_array = false, $first2cols = false) > { > /* > * Insufficient rows to show data > */ > if ($this->_numOfFields < 2) > return;
< // Empty recordset
> /* > * Empty recordset > */
if (!$this->fields) { return array(); }
< // Determine whether the array is associative or 0-based numeric < $numIndex = array_keys($this->fields) == range(0, count($this->fields) - 1);
> /* > * The number of fields is half the actual returned in BOTH mode > */ > $numberOfFields = $this->_numOfFields; > > /* > * Get the fetch mode when the call was executed, this may be > * different than ADODB_FETCH_MODE > */ > $fetchMode = $this->connection->fetchMode; > if ($fetchMode == ADODB_FETCH_BOTH) { > /* > * If we are using BOTH, we present the data as if it > * was in ASSOC mode. This could be enhanced by adding > * a BOTH_ASSOC_MODE class property > * We build a template of numeric keys. you could improve the > * speed by caching this, indexed by number of keys > */ > $testKeys = array_fill(0,$numberOfFields,0); > } > > $showArrayMethod = 0; > > if ($numberOfFields == 2) > /* > * Key is always value of first element > * Value is always value of second element > */ > $showArrayMethod = 1; > > if ($force_array) > $showArrayMethod = 0; > > if ($first2cols) > $showArrayMethod = 1;
$results = array();
< if (!$first2cols && ($cols > 2 || $force_array)) { < if ($ADODB_EXTENSION) { < if ($numIndex) { < while (!$this->EOF) { < $results[trim($this->fields[0])] = array_slice($this->fields, 1); < adodb_movenext($this); < } < } else {
while (!$this->EOF) {
< // Fix for array_slice re-numbering numeric associative keys < $keys = array_slice(array_keys($this->fields), 1); < $sliced_array = array();
< foreach($keys as $key) { < $sliced_array[$key] = $this->fields[$key]; < }
> $myFields = $this->fields;
< $results[trim(reset($this->fields))] = $sliced_array; < adodb_movenext($this); < } < } < } else { < if ($numIndex) { < while (!$this->EOF) { < $results[trim($this->fields[0])] = array_slice($this->fields, 1); < $this->MoveNext();
> if ($fetchMode == ADODB_FETCH_BOTH) { > /* > * extract the associative keys > */ > $myFields = array_diff_key($myFields,$testKeys);
}
< } else { < while (!$this->EOF) { < // Fix for array_slice re-numbering numeric associative keys < $keys = array_slice(array_keys($this->fields), 1); < $sliced_array = array();
< foreach($keys as $key) { < $sliced_array[$key] = $this->fields[$key]; < }
> /* > * key is value of first element, rest is data, > * The key is not case processed > */ > $key = array_shift($myFields); > > switch ($showArrayMethod) { > case 0: > > if ($fetchMode != ADODB_FETCH_NUM) { > /* > * The driver should have already handled the key > * casing, but in case it did not. We will check and force > * this in later versions of ADOdb > */ > if (ADODB_ASSOC_CASE == ADODB_ASSOC_CASE_UPPER) > $myFields = array_change_key_case($myFields,CASE_UPPER); > > elseif (ADODB_ASSOC_CASE == ADODB_ASSOC_CASE_LOWER) > $myFields = array_change_key_case($myFields,CASE_LOWER); > > /* > * We have already shifted the key off > * the front, so the rest is the value > */ > $results[$key] = $myFields;
< $results[trim(reset($this->fields))] = $sliced_array; < $this->MoveNext(); < } < } < } < } else { < if ($ADODB_EXTENSION) { < // return scalar values < if ($numIndex) { < while (!$this->EOF) { < // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string < $results[trim(($this->fields[0]))] = $this->fields[1]; < adodb_movenext($this); < } < } else { < while (!$this->EOF) { < // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string < $v1 = trim(reset($this->fields)); < $v2 = ''.next($this->fields); < $results[$v1] = $v2; < adodb_movenext($this); < }
}
< } else { < if ($numIndex) { < while (!$this->EOF) { < // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string < $results[trim(($this->fields[0]))] = $this->fields[1]; < $this->MoveNext();
> else > /* > * I want the values in a numeric array, > * nicely re-indexed from zero > */ > $results[$key] = array_values($myFields); > break; > > case 1: > > /* > * Don't care how long the array is, > * I just want value of second column, and it doesn't > * matter whether the array is associative or numeric > */ > $results[$key] = array_shift($myFields); > break;
}
< } else { < while (!$this->EOF) { < // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string < $v1 = trim(reset($this->fields)); < $v2 = ''.next($this->fields); < $results[$v1] = $v2;
>
$this->MoveNext(); }
> /* } > * Done } > */ } > return $results;
< } < } < < $ref = $results; # workaround accelerator incompat with PHP 4.4 :( < return $ref; < } <
*
< * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format < * @param fmt is the format to apply to it, using date()
> * @param mixed $v is the character timestamp in YYYY-MM-DD hh:mm:ss format > * @param string [$fmt] is the format to apply to it, using date()
*
< * @return a timestamp formated as user desires
> * @return string a timestamp formated as user desires
*/ function UserTimeStamp($v,$fmt='Y-m-d H:i:s') { if (is_numeric($v) && strlen($v)<14) { return adodb_date($fmt,$v); } $tt = $this->UnixTimeStamp($v); // $tt == -1 if pre TIMESTAMP_FIRST_YEAR if (($tt === false || $tt == -1) && $v != false) { return $v; } if ($tt === 0) { return $this->emptyTimeStamp; } return adodb_date($fmt,$tt); } /**
< * @param v is the character date in YYYY-MM-DD format, returned by database < * @param fmt is the format to apply to it, using date()
> * @param mixed $v is the character date in YYYY-MM-DD format, returned by database > * @param string $fmt is the format to apply to it, using date()
*
< * @return a date formated as user desires
> * @return string a date formatted as user desires
*/ function UserDate($v,$fmt='Y-m-d') { $tt = $this->UnixDate($v); // $tt == -1 if pre TIMESTAMP_FIRST_YEAR if (($tt === false || $tt == -1) && $v != false) { return $v; } else if ($tt == 0) { return $this->emptyDate; } else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR } return adodb_date($fmt,$tt); } /**
< * @param $v is a date string in YYYY-MM-DD format
> * @param mixed $v is a date string in YYYY-MM-DD format
*
< * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
> * @return string date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
*/ static function UnixDate($v) { return ADOConnection::UnixDate($v); } /**
< * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
> * @param string|object $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
*
< * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
> * @return mixed date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
*/ static function UnixTimeStamp($v) { return ADOConnection::UnixTimeStamp($v); } /** * PEAR DB Compat - do not use internally */ function Free() { return $this->Close(); } /** * PEAR DB compat, number of rows
> * */ > * @return int
function NumRows() { return $this->_numOfRows; } /** * PEAR DB compat, number of cols
> * */ > * @return int
function NumCols() { return $this->_numOfFields; } /** * Fetch a row, returning false if no more rows. * This is PEAR DB compat mode. *
< * @return false or array containing the current record
> * @return mixed[]|false false or array containing the current record
*/ function FetchRow() { if ($this->EOF) { return false; } $arr = $this->fields; $this->_currentRow++; if (!$this->_fetch()) { $this->EOF = true; } return $arr; } /** * Fetch a row, returning PEAR_Error if no more rows. * This is PEAR DB compat mode. *
< * @return DB_OK or error object
> * @param mixed[]|false $arr > * > * @return mixed DB_OK or error object
*/ function FetchInto(&$arr) { if ($this->EOF) { return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false; } $arr = $this->fields; $this->MoveNext(); return 1; // DB_OK } /** * Move to the first row in the recordset. Many databases do NOT support this. *
< * @return true or false
> * @return bool true or false
*/ function MoveFirst() { if ($this->_currentRow == 0) { return true; } return $this->Move(0); } /** * Move to the last row in the recordset. *
< * @return true or false
> * @return bool true or false
*/ function MoveLast() { if ($this->_numOfRows >= 0) { return $this->Move($this->_numOfRows-1); } if ($this->EOF) { return false; } while (!$this->EOF) { $f = $this->fields; $this->MoveNext(); } $this->fields = $f; $this->EOF = false; return true; } /** * Move to next record in the recordset. *
< * @return true if there still rows available, or false if there are no more rows (EOF).
> * @return bool true if there still rows available, or false if there are no more rows (EOF).
*/ function MoveNext() { if (!$this->EOF) { $this->_currentRow++; if ($this->_fetch()) { return true; } } $this->EOF = true; /* -- tested error handling when scrolling cursor -- seems useless. $conn = $this->connection; if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) { $fn = $conn->raiseErrorFn; $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database); } */ return false; } /** * Random access to a specific row in the recordset. Some databases do not support * access to previous rows in the databases (no scrolling backwards). *
< * @param rowNumber is the row to move to (0-based)
> * @param int $rowNumber is the row to move to (0-based)
*
< * @return true if there still rows available, or false if there are no more rows (EOF).
> * @return bool true if there still rows available, or false if there are no more rows (EOF).
*/ function Move($rowNumber = 0) { $this->EOF = false; if ($rowNumber == $this->_currentRow) { return true; } if ($rowNumber >= $this->_numOfRows) { if ($this->_numOfRows != -1) { $rowNumber = $this->_numOfRows-2; } } if ($rowNumber < 0) { $this->EOF = true; return false; } if ($this->canSeek) { if ($this->_seek($rowNumber)) { $this->_currentRow = $rowNumber; if ($this->_fetch()) { return true; } } else { $this->EOF = true; return false; } } else { if ($rowNumber < $this->_currentRow) { return false; }
< global $ADODB_EXTENSION; < if ($ADODB_EXTENSION) { < while (!$this->EOF && $this->_currentRow < $rowNumber) { < adodb_movenext($this); < } < } else {
while (! $this->EOF && $this->_currentRow < $rowNumber) { $this->_currentRow++; if (!$this->_fetch()) { $this->EOF = true; } }
< }
return !($this->EOF); } $this->fields = false; $this->EOF = true; return false; }
> /** > * Adjusts the result pointer to an arbitrary row in the result. /** > * * Get the value of a field in the current row by column name. > * @param int $row The row to seek to. * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM. > * * > * @return bool False if the recordset contains no rows, otherwise true. * @param colname is the field to access > */ * > function _seek($row) {}
< * @param colname is the field to access
> * @param string $colname is the field to access
< * @return the value of $colname column
> * @return mixed the value of $colname column
function Fields($colname) { return $this->fields[$colname]; } /** * Defines the function to use for table fields case conversion * depending on ADODB_ASSOC_CASE
> * * @return string strtolower/strtoupper or false if no conversion needed > * @param int [$case] */ > *
protected function AssocCaseConvertFunction($case = ADODB_ASSOC_CASE) { switch($case) { case ADODB_ASSOC_CASE_UPPER: return 'strtoupper'; case ADODB_ASSOC_CASE_LOWER: return 'strtolower'; case ADODB_ASSOC_CASE_NATIVE: default: return false; } } /** * Builds the bind array associating keys to recordset fields *
< * @param int $upper Case for the array keys, defaults to uppercase
> * @param int [$upper] Case for the array keys, defaults to uppercase
* (see ADODB_ASSOC_CASE_xxx constants) */ function GetAssocKeys($upper = ADODB_ASSOC_CASE) { if ($this->bind) { return; } $this->bind = array(); // Define case conversion function for ASSOC fetch mode $fn_change_case = $this->AssocCaseConvertFunction($upper); // Build the bind array for ($i=0; $i < $this->_numOfFields; $i++) { $o = $this->FetchField($i); // Set the array's key if(is_numeric($o->name)) { // Just use the field ID $key = $i; } elseif( $fn_change_case ) { // Convert the key's case $key = $fn_change_case($o->name); } else { $key = $o->name; } $this->bind[$key] = $i; } } /** * Use associative array to get fields array for databases that do not support * associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it * * @param int $upper Case for the array keys, defaults to uppercase * (see ADODB_ASSOC_CASE_xxx constants)
> * @return array
*/ function GetRowAssoc($upper = ADODB_ASSOC_CASE) { $record = array(); $this->GetAssocKeys($upper); foreach($this->bind as $k => $v) { if( array_key_exists( $v, $this->fields ) ) { $record[$k] = $this->fields[$v]; } elseif( array_key_exists( $k, $this->fields ) ) { $record[$k] = $this->fields[$k]; } else { # This should not happen... trigger error ? $record[$k] = null; } } return $record; } /** * Clean up recordset *
< * @return true or false
> * @return bool
*/ function Close() { // free connection object - this seems to globally free the object // and not merely the reference, so don't do this... // $this->connection = false; if (!$this->_closed) { $this->_closed = true; return $this->_close(); } else return true; } /**
< * synonyms RecordCount and RowCount
> * Number of rows in recordset.
*
< * @return the number of rows or -1 if this is not supported
> * @return int Number of rows or -1 if this is not supported
*/
< function RecordCount() {
> function recordCount() {
return $this->_numOfRows; }
< < /*
> /**
* If we are using PageExecute(), this will return the maximum possible rows * that can be returned when paging a recordset.
> * */ > * @return int
function MaxRecordCount() {
< return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();
> return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->recordCount();
} /**
< * synonyms RecordCount and RowCount
> * Number of rows in recordset. > * Alias for {@see recordCount()}
*
< * @return the number of rows or -1 if this is not supported
> * @return int Number of rows or -1 if this is not supported
*/
< function RowCount() { < return $this->_numOfRows;
> function rowCount() { > return $this->recordCount();
}
<
/**
< * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
> * Portable RecordCount. > * > * Be aware of possible problems in multiuser environments. > * For better speed the table must be indexed by the condition. > * Heavy test this before deploying.
*
< * @return the number of records from a previous SELECT. All databases support this.
> * @param string $table > * @param string $condition
*
< * But aware possible problems in multiuser environments. For better speed the table < * must be indexed by the condition. Heavy test this before deploying.
> * @return int Number of records from a previous SELECT. All databases support this. > * > * @author Pablo Roca <pabloroca@mvps.org>
*/ function PO_RecordCount($table="", $condition="") { $lnumrows = $this->_numOfRows; // the database doesn't support native recordcount, so we do a workaround if ($lnumrows == -1 && $this->connection) { IF ($table) { if ($condition) { $condition = " WHERE " . $condition; } $resultrows = $this->connection->Execute("SELECT COUNT(*) FROM $table $condition"); if ($resultrows) { $lnumrows = reset($resultrows->fields); } } } return $lnumrows; } /** * @return the current row in the recordset. If at EOF, will return the last row. 0-based. */ function CurrentRow() { return $this->_currentRow; } /** * synonym for CurrentRow -- for ADO compat * * @return the current row in the recordset. If at EOF, will return the last row. 0-based. */ function AbsolutePosition() { return $this->_currentRow; } /** * @return the number of columns in the recordset. Some databases will set this to 0 * if no records are returned, others will return the number of columns in the query. */ function FieldCount() { return $this->_numOfFields; }
<
/**
< * Get the ADOFieldObject of a specific column.
> * Get a Field's metadata from database. > * > * Must be defined by child class.
*
< * @param fieldoffset is the column position to access(0-based).
> * @param int $fieldOffset
*
< * @return the ADOFieldObject for that column, or false.
> * @return ADOFieldObject|false
*/
< function FetchField($fieldoffset = -1) { < // must be defined by child class <
> function fetchField($fieldOffset) > {
return false; } /**
< * Get the ADOFieldObjects of all columns in an array.
> * Get Field metadata for all the recordset's columns in an array.
*
> * @return ADOFieldObject[]
*/
< function FieldTypesArray() { < $arr = array(); < for ($i=0, $max=$this->_numOfFields; $i < $max; $i++) < $arr[] = $this->FetchField($i); < return $arr;
> function fieldTypesArray() { > if (empty($this->fieldObjectsCache)) { > for ($i = 0; $i < $this->_numOfFields; $i++) { > $this->fieldObjectsCache[] = $this->fetchField($i); > } > } > return $this->fieldObjectsCache;
} /** * Return the fields array of the current row as an object for convenience. * The default case is lowercase field names. * * @return the object with the properties set to the fields of the current row */ function FetchObj() {
< $o = $this->FetchObject(false); < return $o;
> return $this->FetchObject(false);
} /** * Return the fields array of the current row as an object for convenience. * The default case is uppercase. *
< * @param $isupper to set the object property names to uppercase
> * @param bool $isUpper to set the object property names to uppercase
*
< * @return the object with the properties set to the fields of the current row
> * @return ADOFetchObj The object with properties set to the fields of the current row
*/
< function FetchObject($isupper=true) {
> function FetchObject($isUpper=true) {
if (empty($this->_obj)) { $this->_obj = new ADOFetchObj(); $this->_names = array(); for ($i=0; $i <$this->_numOfFields; $i++) { $f = $this->FetchField($i); $this->_names[] = $f->name; } }
< $i = 0; < if (PHP_VERSION >= 5) {
$o = clone($this->_obj);
< } else { < $o = $this->_obj; < }
for ($i=0; $i <$this->_numOfFields; $i++) { $name = $this->_names[$i];
< if ($isupper) {
> if ($isUpper) {
$n = strtoupper($name); } else { $n = $name; } $o->$n = $this->Fields($name); } return $o; } /** * Return the fields array of the current row as an object for convenience. * The default is lower-case field names. *
< * @return the object with the properties set to the fields of the current row, < * or false if EOF
> * @return ADOFetchObj|false The object with properties set to the fields of the current row > * or false if EOF.
* * Fixed bug reported by tim@orotech.net */ function FetchNextObj() {
< $o = $this->FetchNextObject(false); < return $o;
> return $this->FetchNextObject(false);
} /** * Return the fields array of the current row as an object for convenience. * The default is upper case field names. *
< * @param $isupper to set the object property names to uppercase
> * @param bool $isUpper to set the object property names to uppercase
*
< * @return the object with the properties set to the fields of the current row, < * or false if EOF
> * @return ADOFetchObj|false The object with properties set to the fields of the current row > * or false if EOF.
* * Fixed bug reported by tim@orotech.net */
< function FetchNextObject($isupper=true) {
> function FetchNextObject($isUpper=true) {
$o = false; if ($this->_numOfRows != 0 && !$this->EOF) {
< $o = $this->FetchObject($isupper);
> $o = $this->FetchObject($isUpper);
$this->_currentRow++; if ($this->_fetch()) { return $o; } } $this->EOF = true; return $o; } /**
< * Get the metatype of the column. This is used for formatting. This is because < * many databases use different names for the same type, so we transform the original < * type to our standardised version which uses 1 character codes: < * < * @param t is the type passed in. Normally is ADOFieldObject->type. < * @param len is the maximum length of that field. This is because we treat character < * fields bigger than a certain size as a 'B' (blob). < * @param fieldobj is the field object returned by the database driver. Can hold < * additional info (eg. primary_key for mysql). < * < * @return the general type of the data: < * C for character < 250 chars < * X for teXt (>= 250 chars) < * B for Binary < * N for numeric or floating point < * D for date < * T for timestamp < * L for logical/Boolean < * I for integer < * R for autoincrement counter/integer < *
> * Get the ADOdb metatype.
*
< */ < function MetaType($t,$len=-1,$fieldobj=false) { < if (is_object($t)) { < $fieldobj = $t; < $t = $fieldobj->type; < $len = $fieldobj->max_length;
> * Many databases use different names for the same type, so we transform > * the native type to our standardised one, which uses 1 character codes. > * @see https://adodb.org/dokuwiki/doku.php?id=v5:dictionary:dictionary_index#portable_data_types > * > * @param string|ADOFieldObject $t Native type (usually ADOFieldObject->type) > * It is also possible to provide an > * ADOFieldObject here. > * @param int $len The field's maximum length. This is because we treat > * character fields bigger than a certain size as a 'B' (blob). > * @param ADOFieldObject $fieldObj Field object returned by the database driver; > * can hold additional info (eg. primary_key for mysql). > * > * @return string The ADOdb Standard type > */ > function metaType($t, $len = -1, $fieldObj = false) { > if ($t instanceof ADOFieldObject) { > $fieldObj = $t; > $t = $fieldObj->type; > $len = $fieldObj->max_length;
} // changed in 2.32 to hashing instead of switch stmt for speed... static $typeMap = array( 'VARCHAR' => 'C', 'VARCHAR2' => 'C', 'CHAR' => 'C', 'C' => 'C', 'STRING' => 'C', 'NCHAR' => 'C', 'NVARCHAR' => 'C', 'VARYING' => 'C', 'BPCHAR' => 'C', 'CHARACTER' => 'C', 'INTERVAL' => 'C', # Postgres 'MACADDR' => 'C', # postgres 'VAR_STRING' => 'C', # mysql ## 'LONGCHAR' => 'X', 'TEXT' => 'X', 'NTEXT' => 'X', 'M' => 'X', 'X' => 'X', 'CLOB' => 'X', 'NCLOB' => 'X', 'LVARCHAR' => 'X', ## 'BLOB' => 'B', 'IMAGE' => 'B', 'BINARY' => 'B', 'VARBINARY' => 'B', 'LONGBINARY' => 'B', 'B' => 'B', ## 'YEAR' => 'D', // mysql 'DATE' => 'D', 'D' => 'D', ## 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server ## 'SMALLDATETIME' => 'T', 'TIME' => 'T', 'TIMESTAMP' => 'T', 'DATETIME' => 'T', 'DATETIME2' => 'T', 'TIMESTAMPTZ' => 'T', 'T' => 'T', 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql ## 'BOOL' => 'L', 'BOOLEAN' => 'L', 'BIT' => 'L', 'L' => 'L', ## 'COUNTER' => 'R', 'R' => 'R', 'SERIAL' => 'R', // ifx 'INT IDENTITY' => 'R', ## 'INT' => 'I', 'INT2' => 'I', 'INT4' => 'I', 'INT8' => 'I', 'INTEGER' => 'I', 'INTEGER UNSIGNED' => 'I', 'SHORT' => 'I', 'TINYINT' => 'I', 'SMALLINT' => 'I', 'I' => 'I', ## 'LONG' => 'N', // interbase is numeric, oci8 is blob 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers 'DECIMAL' => 'N', 'DEC' => 'N', 'REAL' => 'N', 'DOUBLE' => 'N', 'DOUBLE PRECISION' => 'N', 'SMALLFLOAT' => 'N', 'FLOAT' => 'N', 'NUMBER' => 'N', 'NUM' => 'N', 'NUMERIC' => 'N', 'MONEY' => 'N', ## informix 9.2 'SQLINT' => 'I', 'SQLSERIAL' => 'I', 'SQLSMINT' => 'I', 'SQLSMFLOAT' => 'N', 'SQLFLOAT' => 'N', 'SQLMONEY' => 'N', 'SQLDECIMAL' => 'N', 'SQLDATE' => 'D', 'SQLVCHAR' => 'C', 'SQLCHAR' => 'C', 'SQLDTIME' => 'T', 'SQLINTERVAL' => 'N', 'SQLBYTES' => 'B', 'SQLTEXT' => 'X', ## informix 10 "SQLINT8" => 'I8', "SQLSERIAL8" => 'I8', "SQLNCHAR" => 'C', "SQLNVCHAR" => 'C', "SQLLVARCHAR" => 'X', "SQLBOOL" => 'L' );
< $tmap = false;
$t = strtoupper($t);
< $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N';
> $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : ADODB_DEFAULT_METATYPE;
switch ($tmap) { case 'C': // is the char field is too long, return as text field... if ($this->blobSize >= 0) { if ($len > $this->blobSize) { return 'X'; } } else if ($len > 250) { return 'X'; } return 'C'; case 'I':
< if (!empty($fieldobj->primary_key)) {
> if (!empty($fieldObj->primary_key)) {
return 'R'; } return 'I'; case false: return 'N'; case 'B':
< if (isset($fieldobj->binary)) { < return ($fieldobj->binary) ? 'B' : 'X';
> if (isset($fieldObj->binary)) { > return ($fieldObj->binary) ? 'B' : 'X';
} return 'B'; case 'D': if (!empty($this->connection) && !empty($this->connection->datetime)) { return 'T'; } return 'D'; default: if ($t == 'LONG' && $this->dataProvider == 'oci8') { return 'B'; } return $tmap; } } /** * Convert case of field names associative array, if needed * @return void */ protected function _updatefields() { if( empty($this->fields)) { return; } // Determine case conversion function $fn_change_case = $this->AssocCaseConvertFunction(); if(!$fn_change_case) { // No conversion needed return; } $arr = array(); // Change the case foreach($this->fields as $k => $v) { if (!is_integer($k)) { $k = $fn_change_case($k); } $arr[$k] = $v; } $this->fields = $arr; } function _close() {} /** * set/returns the current recordset page when paginating
> * @param int $page */ > * @return int
< function AbsolutePage($page=-1) {
> function absolutePage($page=-1) {
if ($page != -1) { $this->_currentPage = $page; } return $this->_currentPage; } /** * set/returns the status of the atFirstPage flag when paginating
> * @param bool $status */ > * @return bool
function AtFirstPage($status=false) { if ($status != false) { $this->_atFirstPage = $status; } return $this->_atFirstPage; }
> /** function LastPageNo($page = false) { > * @param bool $page if ($page != false) { > * @return bool $this->_lastPageNo = $page; > */
} return $this->_lastPageNo; } /** * set/returns the status of the atLastPage flag when paginating
> * @param bool $status */ > * @return bool
function AtLastPage($status=false) { if ($status != false) { $this->_atLastPage = $status; } return $this->_atLastPage; } } // end class ADORecordSet //============================================================================================== // CLASS ADORecordSet_array //============================================================================================== /** * This class encapsulates the concept of a recordset created in memory * as an array. This is useful for the creation of cached recordsets. * * Note that the constructor is different from the standard ADORecordSet */ class ADORecordSet_array extends ADORecordSet { var $databaseType = 'array'; var $_array; // holds the 2-dimensional data array var $_types; // the array of types of each column (C B I L M) var $_colnames; // names of each column in array var $_skiprow1; // skip 1st row because it holds column names var $_fieldobjects; // holds array of field objects var $canSeek = true; var $affectedrows = false; var $insertid = false; var $sql = ''; var $compat = false; /** * Constructor
> * */ > * The parameters passed to this recordset are always fake because function __construct($fakeid=1) { > * this class does not use the queryID global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH; > * > * @param resource|int $queryID Ignored // fetch() on EOF does not delete $this->fields > * @param int|bool $mode The ADODB_FETCH_MODE value
< function __construct($fakeid=1) {
> function __construct($queryID, $mode=false) {
< parent::__construct($fakeid); // fake queryID
> parent::__construct($queryID); // fake queryID
$this->fetchMode = $ADODB_FETCH_MODE; }
< function _transpose($addfieldnames=true) { < global $ADODB_INCLUDED_LIB; < < if (empty($ADODB_INCLUDED_LIB)) { < include(ADODB_DIR.'/adodb-lib.inc.php'); < } < $hdr = true; < < $fobjs = $addfieldnames ? $this->_fieldobjects : false; < adodb_transpose($this->_array, $newarr, $hdr, $fobjs); < //adodb_pr($newarr); < < $this->_skiprow1 = false; < $this->_array = $newarr; < $this->_colnames = $hdr; < < adodb_probetypes($newarr,$this->_types); < < $this->_fieldobjects = array(); < < foreach($hdr as $k => $name) { < $f = new ADOFieldObject(); < $f->name = $name; < $f->type = $this->_types[$k]; < $f->max_length = -1; < $this->_fieldobjects[] = $f; < } < $this->fields = reset($this->_array); < < $this->_initrs(); < < }
/** * Setup the array. * * @param array is a 2-dimensional array holding the data. * The first row should hold the column names
< * unless paramter $colnames is used.
> * unless parameter $colnames is used.
* @param typearr holds an array of types. These are the same types * used in MetaTypes (C,B,L,I,N).
< * @param [colnames] array of column names. If set, then the first row of
> * @param string[]|false [$colnames] array of column names. If set, then the first row of
* $array should not hold the column names. */ function InitArray($array,$typearr,$colnames=false) { $this->_array = $array; $this->_types = $typearr; if ($colnames) { $this->_skiprow1 = false; $this->_colnames = $colnames; } else { $this->_skiprow1 = true; $this->_colnames = $array[0]; } $this->Init(); } /** * Setup the Array and datatype file objects *
< * @param array is a 2-dimensional array holding the data.
> * @param array $array 2-dimensional array holding the data
* The first row should hold the column names
< * unless paramter $colnames is used. < * @param fieldarr holds an array of ADOFieldObject's.
> * unless parameter $colnames is used. > * @param array $fieldarr Array of ADOFieldObject's.
*/ function InitArrayFields(&$array,&$fieldarr) { $this->_array = $array; $this->_skiprow1= false; if ($fieldarr) { $this->_fieldobjects = $fieldarr; } $this->Init(); }
> /** function GetArray($nRows=-1) { > * @param int [$nRows] if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) { > * @return array return $this->_array; > */
} else {
< $arr = ADORecordSet::GetArray($nRows); < return $arr;
> return ADORecordSet::GetArray($nRows);
} } function _initrs() { $this->_numOfRows = sizeof($this->_array); if ($this->_skiprow1) { $this->_numOfRows -= 1; } $this->_numOfFields = (isset($this->_fieldobjects)) ? sizeof($this->_fieldobjects) : sizeof($this->_types); }
< /* Use associative array to get fields array */
> /** > * Use associative array to get fields array > * > * @param string $colname > * @return mixed > */
function Fields($colname) { $mode = isset($this->adodbFetchMode) ? $this->adodbFetchMode : $this->fetchMode; if ($mode & ADODB_FETCH_ASSOC) { if (!isset($this->fields[$colname]) && !is_null($this->fields[$colname])) { $colname = strtolower($colname); } return $this->fields[$colname]; } if (!$this->bind) { $this->bind = array(); for ($i=0; $i < $this->_numOfFields; $i++) { $o = $this->FetchField($i); $this->bind[strtoupper($o->name)] = $i; } } return $this->fields[$this->bind[strtoupper($colname)]]; }
> /** function FetchField($fieldOffset = -1) { > * @param int [$fieldOffset] if (isset($this->_fieldobjects)) { > * return $this->_fieldobjects[$fieldOffset]; > * @return \ADOFieldObject } > */
$o = new ADOFieldObject(); $o->name = $this->_colnames[$fieldOffset]; $o->type = $this->_types[$fieldOffset]; $o->max_length = -1; // length not known return $o; }
> /** function _seek($row) { > * @param int $row if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) { > * @return bool $this->_currentRow = $row; > */
if ($this->_skiprow1) { $row += 1; } $this->fields = $this->_array[$row]; return true; } return false; }
> /** function MoveNext() { > * @return bool if (!$this->EOF) { > */
$this->_currentRow++; $pos = $this->_currentRow; if ($this->_numOfRows <= $pos) { if (!$this->compat) { $this->fields = false; } } else { if ($this->_skiprow1) { $pos += 1; } $this->fields = $this->_array[$pos]; return true; } $this->EOF = true; } return false; }
> /** function _fetch() { > * @return bool $pos = $this->_currentRow; > */
if ($this->_numOfRows <= $pos) { if (!$this->compat) { $this->fields = false; } return false; } if ($this->_skiprow1) { $pos += 1; } $this->fields = $this->_array[$pos]; return true; } function _close() { return true; } } // ADORecordSet_array //============================================================================================== // HELPER FUNCTIONS //============================================================================================== /** * Synonym for ADOLoadCode. Private function. Do not use. * * @deprecated */ function ADOLoadDB($dbType) { return ADOLoadCode($dbType); } /** * Load the code for a specific database driver. Private function. Do not use. */ function ADOLoadCode($dbType) { global $ADODB_LASTDB; if (!$dbType) { return false; } $db = strtolower($dbType); switch ($db) { case 'ado':
< if (PHP_VERSION >= 5) {
$db = 'ado5';
< }
$class = 'ado'; break; case 'ifx': case 'maxsql': $class = $db = 'mysqlt'; break; case 'pgsql': case 'postgres':
< $class = $db = 'postgres8';
> $class = $db = 'postgres9'; > break; > > case 'mysql': > // mysql extension removed in PHP 7.0 - automatically switch to mysqli > $class = $db = 'mysqli';
break; default:
< $class = $db; break;
> if (substr($db, 0, 4) === 'pdo_') { > ADOConnection::outp("Invalid database type: $db"); > return false; > } > > $class = $db; > break;
} $file = "drivers/adodb-$db.inc.php"; @include_once(ADODB_DIR . '/' . $file); $ADODB_LASTDB = $class; if (class_exists("ADODB_" . $class)) { return $class; } //ADOConnection::outp(adodb_pr(get_declared_classes(),true)); if (!file_exists($file)) { ADOConnection::outp("Missing file: $file"); } else { ADOConnection::outp("Syntax error in file: $file"); } return false; } /**
< * synonym for ADONewConnection for people like me who cannot remember the correct name
> * Synonym for ADONewConnection for people like me who cannot remember the correct name > * > * @param string [$db] > * > * @return ADOConnection|false
*/ function NewADOConnection($db='') {
< $tmp = ADONewConnection($db); < return $tmp;
> return ADONewConnection($db);
} /** * Instantiate a new Connection class for a specific database driver. *
< * @param [db] is the database Connection object to create. If undefined,
> * @param string $db Database Connection object to create. If undefined,
* use the last database driver that was loaded by ADOLoadCode(). *
< * @return the freshly created instance of the Connection class.
> * @return ADOConnection|false The freshly created instance of the Connection class > * or false in case of error.
*/ function ADONewConnection($db='') { global $ADODB_NEWCONNECTION, $ADODB_LASTDB; if (!defined('ADODB_ASSOC_CASE')) { define('ADODB_ASSOC_CASE', ADODB_ASSOC_CASE_NATIVE); }
> $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false; > /* if (($at = strpos($db,'://')) !== FALSE) { > * Are there special characters in the dsn password $origdsn = $db; > * that disrupt parse_url $fakedsn = 'fake'.substr($origdsn,$at); > */ if (($at2 = strpos($origdsn,'@/')) !== FALSE) { > $needsSpecialCharacterHandling = false; // special handling of oracle, which might not have host >
$fakedsn = str_replace('@/','@adodb-fakehost/',$fakedsn); } if ((strpos($origdsn, 'sqlite')) !== FALSE && stripos($origdsn, '%2F') === FALSE) { // special handling for SQLite, it only might have the path to the database file. // If you try to connect to a SQLite database using a dsn // like 'sqlite:///path/to/database', the 'parse_url' php function // will throw you an exception with a message such as "unable to parse url" list($scheme, $path) = explode('://', $origdsn); $dsna['scheme'] = $scheme; if ($qmark = strpos($path,'?')) { $dsn['query'] = substr($path,$qmark+1); $path = substr($path,0,$qmark); } $dsna['path'] = '/' . urlencode($path);
< } else < $dsna = @parse_url($fakedsn);
> } else { > /* > * Stop # character breaking parse_url > */ > $cFakedsn = str_replace('#','\035',$fakedsn); > if (strcmp($fakedsn,$cFakedsn) != 0) > { > /* > * There is a # in the string > */ > $needsSpecialCharacterHandling = true; > > /* > * This allows us to successfully parse the url > */ > $fakedsn = $cFakedsn; > > } > > $dsna = parse_url($fakedsn); > }
if (!$dsna) { return false; } $dsna['scheme'] = substr($origdsn,0,$at); if ($at2 !== FALSE) { $dsna['host'] = ''; } if (strncmp($origdsn,'pdo',3) == 0) { $sch = explode('_',$dsna['scheme']); if (sizeof($sch)>1) { $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : ''; if ($sch[1] == 'sqlite') { $dsna['host'] = rawurlencode($sch[1].':'.rawurldecode($dsna['host'])); } else { $dsna['host'] = rawurlencode($sch[1].':host='.rawurldecode($dsna['host'])); } $dsna['scheme'] = 'pdo'; } } $db = @$dsna['scheme']; if (!$db) { return false; }
>
$dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : ''; $dsna['user'] = isset($dsna['user']) ? rawurldecode($dsna['user']) : ''; $dsna['pass'] = isset($dsna['pass']) ? rawurldecode($dsna['pass']) : ''; $dsna['path'] = isset($dsna['path']) ? rawurldecode(substr($dsna['path'],1)) : ''; # strip off initial /
> if ($needsSpecialCharacterHandling) if (isset($dsna['query'])) { > { $opt1 = explode('&',$dsna['query']); > /* foreach($opt1 as $k => $v) { > * Revert back to the original string $arr = explode('=',$v); > */ $opt[$arr[0]] = isset($arr[1]) ? rawurldecode($arr[1]) : 1; > $dsna = str_replace('\035','#',$dsna); } > } } else { >
$opt = array(); }
>
} /* * phptype: Database backend used in PHP (mysql, odbc etc.) * dbsyntax: Database used with regards to SQL syntax etc. * protocol: Communication protocol to use (tcp, unix etc.) * hostspec: Host specification (hostname[:port]) * database: Database to use on the DBMS server * username: User name for login * password: Password for login */ if (!empty($ADODB_NEWCONNECTION)) { $obj = $ADODB_NEWCONNECTION($db); } if(empty($obj)) { if (!isset($ADODB_LASTDB)) { $ADODB_LASTDB = ''; } if (empty($db)) { $db = $ADODB_LASTDB; } if ($db != $ADODB_LASTDB) { $db = ADOLoadCode($db); } if (!$db) { if (isset($origdsn)) { $db = $origdsn; } if ($errorfn) { // raise an error $ignore = false; $errorfn('ADONewConnection', 'ADONewConnection', -998, "could not load the database driver for '$db'", $db,false,$ignore); } else { ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false); } return false; } $cls = 'ADODB_'.$db; if (!class_exists($cls)) { adodb_backtrace(); return false; } $obj = new $cls(); } # constructor should not fail if ($obj) { if ($errorfn) { $obj->raiseErrorFn = $errorfn; } if (isset($dsna)) { if (isset($dsna['port'])) { $obj->port = $dsna['port']; } foreach($opt as $k => $v) { switch(strtolower($k)) { case 'new': $nconnect = true; $persist = true; break; case 'persist': case 'persistent': $persist = $v; break; case 'debug': $obj->debug = (integer) $v; break; #ibase case 'role': $obj->role = $v; break; case 'dialect': $obj->dialect = (integer) $v; break; case 'charset': $obj->charset = $v; $obj->charSet=$v; break; case 'buffers': $obj->buffers = $v; break; case 'fetchmode': $obj->SetFetchMode($v); break; #ado case 'charpage': $obj->charPage = $v; break; #mysql, mysqli case 'clientflags': $obj->clientFlags = $v; break; #mysql, mysqli, postgres case 'port': $obj->port = $v; break; #mysqli case 'socket': $obj->socket = $v; break; #oci8 case 'nls_date_format': $obj->NLS_DATE_FORMAT = $v; break; case 'cachesecs': $obj->cacheSecs = $v; break; case 'memcache': $varr = explode(':',$v); $vlen = sizeof($varr); if ($vlen == 0) { break; } $obj->memCache = true; $obj->memCacheHost = explode(',',$varr[0]); if ($vlen == 1) { break; } $obj->memCachePort = $varr[1]; if ($vlen == 2) { break; } $obj->memCacheCompress = $varr[2] ? true : false; break; } } if (empty($persist)) { $ok = $obj->Connect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']); } else if (empty($nconnect)) { $ok = $obj->PConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']); } else { $ok = $obj->NConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']); } if (!$ok) { return false; } } } return $obj; } // $perf == true means called by NewPerfMonitor(), otherwise for data dictionary function _adodb_getdriver($provider,$drivername,$perf=false) { switch ($provider) { case 'odbtp': if (strncmp('odbtp_',$drivername,6)==0) { return substr($drivername,6); } case 'odbc' : if (strncmp('odbc_',$drivername,5)==0) { return substr($drivername,5); } case 'ado' : if (strncmp('ado_',$drivername,4)==0) { return substr($drivername,4); } case 'native': break; default: return $provider; } switch($drivername) { case 'mysqlt': case 'mysqli': $drivername='mysql'; break; case 'postgres7': case 'postgres8': $drivername = 'postgres'; break; case 'firebird15': $drivername = 'firebird'; break; case 'oracle': $drivername = 'oci8'; break; case 'access': if ($perf) { $drivername = ''; } break; case 'db2' : case 'sapdb' : break; default: $drivername = 'generic'; break; } return $drivername; } function NewPerfMonitor(&$conn) { $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType,true); if (!$drivername || $drivername == 'generic') { return false; } include_once(ADODB_DIR.'/adodb-perf.inc.php'); @include_once(ADODB_DIR."/perf/perf-$drivername.inc.php"); $class = "Perf_$drivername"; if (!class_exists($class)) { return false; }
< $perf = new $class($conn);
< return $perf;
> return new $class($conn);
}
< function NewDataDictionary(&$conn,$drivername=false) {
> /** > * Get a new Data Dictionary object for the connection. > * > * @param ADOConnection $conn > * @param string $drivername > * > * @return ADODB_DataDict|false > */ > function newDataDictionary(&$conn, $drivername='') {
if (!$drivername) { $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType); } include_once(ADODB_DIR.'/adodb-lib.inc.php'); include_once(ADODB_DIR.'/adodb-datadict.inc.php'); $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php"; if (!file_exists($path)) { ADOConnection::outp("Dictionary driver '$path' not available"); return false; } include_once($path); $class = "ADODB2_$drivername";
> /** @var ADODB_DataDict $dict */
$dict = new $class(); $dict->dataProvider = $conn->dataProvider; $dict->connection = $conn; $dict->upperName = strtoupper($drivername); $dict->quote = $conn->nameQuote; if (!empty($conn->_connectionID)) { $dict->serverInfo = $conn->ServerInfo(); } return $dict; }
< < < /* < Perform a print_r, with pre tags for better formatting.
> /** > * Perform a print_r, with pre tags for better formatting.
*/ function adodb_pr($var,$as_string=false) { if ($as_string) { ob_start(); } if (isset($_SERVER['HTTP_USER_AGENT'])) { echo " <pre>\n";print_r($var);echo "</pre>\n"; } else { print_r($var); } if ($as_string) { $s = ob_get_contents(); ob_end_clean(); return $s; } }
< /* < Perform a stack-crawl and pretty print it. < < @param printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then). < @param levels Number of levels to display
> /** > * Perform a stack-crawl and pretty print it. > * > * @param bool $printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then). > * @param int $levels Number of levels to display > * @param mixed $ishtml > * > * @return string
*/ function adodb_backtrace($printOrArr=true,$levels=9999,$ishtml=null) { global $ADODB_INCLUDED_LIB; if (empty($ADODB_INCLUDED_LIB)) {
< include(ADODB_DIR.'/adodb-lib.inc.php');
> include_once(ADODB_DIR.'/adodb-lib.inc.php');
} return _adodb_backtrace($printOrArr,$levels,0,$ishtml); } }