0,0 → 1,4007 |
<?php |
/* |
* Set tabs to 4 for best viewing. |
* |
* Latest version is available at http://adodb.sourceforge.net |
* |
* This is the main include file for ADOdb. |
* Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php |
* |
* 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 V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved. |
|
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. |
|
Latest Download at http://adodb.sourceforge.net/ |
|
*/ |
|
if (!defined('_ADODB_LAYER')) { |
define('_ADODB_LAYER',1); |
|
//============================================================================================== |
// 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_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... |
|
//============================================================================================== |
// 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. |
*/ |
define('ADODB_FORCE_IGNORE',0); |
define('ADODB_FORCE_NULL',1); |
define('ADODB_FORCE_EMPTY',2); |
define('ADODB_FORCE_VALUE',3); |
//********************************************************// |
|
|
if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) { |
|
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); |
|
|
/* |
Controls ADODB_FETCH_ASSOC field-name case. Default is 2, use native case-names. |
This currently works only with mssql, odbc, oci8po and ibase derived drivers. |
|
0 = assoc lowercase field names. $rs->fields['orderid'] |
1 = assoc uppercase field names. $rs->fields['ORDERID'] |
2 = use native-case field names. $rs->fields['OrderID'] |
*/ |
|
define('ADODB_FETCH_DEFAULT',0); |
define('ADODB_FETCH_NUM',1); |
define('ADODB_FETCH_ASSOC',2); |
define('ADODB_FETCH_BOTH',3); |
|
if (!defined('TIMESTAMP_FIRST_YEAR')) define('TIMESTAMP_FIRST_YEAR',100); |
|
// PHP's version scheme makes converting to numbers difficult - workaround |
$_adodb_ver = (float) PHP_VERSION; |
if ($_adodb_ver >= 5.0) { |
define('ADODB_PHPVER',0x5000); |
} else if ($_adodb_ver > 4.299999) { # 4.3 |
define('ADODB_PHPVER',0x4300); |
} else if ($_adodb_ver > 4.199999) { # 4.2 |
define('ADODB_PHPVER',0x4200); |
} else if (strnatcmp(PHP_VERSION,'4.0.5')>=0) { |
define('ADODB_PHPVER',0x4050); |
} else { |
define('ADODB_PHPVER',0x4000); |
} |
} |
|
//if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2); |
|
|
/** |
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_FORCE_TYPE; |
|
$ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT; |
$ADODB_FORCE_TYPE = ADODB_FORCE_VALUE; |
|
|
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://"); |
} |
|
|
// Initialize random number generator for randomizing cache flushes |
srand(((double)microtime())*1000000); |
|
/** |
* ADODB version as a string. |
*/ |
$ADODB_vers = 'V4.80 8 Mar 2006 (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved. Released BSD & LGPL.'; |
|
/** |
* 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 |
*/ |
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_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); |
} |
} |
|
//============================================================================================== |
// CLASS ADOConnection |
//============================================================================================== |
|
/** |
* Connection object. For connecting to databases, and executing queries. |
*/ |
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 $host = ''; /// The hostname 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 $charSet=false; /// character set to use - only for interbase, postgres and oci8 |
var $metaDatabasesSQL = ''; |
var $metaTablesSQL = ''; |
var $uniqueOrderBy = false; /// All order by columns have to be unique |
var $emptyDate = ' '; |
var $emptyTimeStamp = ' '; |
var $lastInsID = false; |
//-- |
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 |
var $hasLimit = false; /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10 |
var $readOnly = false; /// this is a readonly database - used by phpLens |
var $hasMoveFirst = false; /// has ability to run MoveFirst(), scrolling backwards |
var $hasGenID = false; /// can generate sequences using GenID(); |
var $hasTransactions = true; /// has transactions |
//-- |
var $genID = 0; /// sequence id used by GenID(); |
var $raiseErrorFn = false; /// error function to call |
var $isoDates = false; /// accepts dates in ISO format |
var $cacheSecs = 3600; /// cache for 1 hour |
var $sysDate = false; /// name of function that returns the current date |
var $sysTimeStamp = false; /// name of function that returns the current timestamp |
var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets |
|
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 $fnExecute = false; |
var $fnCacheExecute = false; |
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; |
// |
// PRIVATE VARS |
// |
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 $_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; |
var $_affected = false; |
var $_logsql = false; |
|
/** |
* Constructor |
*/ |
function ADOConnection() |
{ |
die('Virtual Class -- cannot instantiate'); |
} |
|
function Version() |
{ |
global $ADODB_vers; |
|
return (float) substr($ADODB_vers,1); |
} |
|
/** |
Get server version info... |
|
@returns An array with 2 elements: $arr['string'] is the description string, |
and $arr[version] is the version (also a string). |
*/ |
function ServerInfo() |
{ |
return array('description' => '', 'version' => ''); |
} |
|
function IsConnected() |
{ |
return !empty($this->_connectionID); |
} |
|
function _findvers($str) |
{ |
if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) return $arr[1]; |
else return ''; |
} |
|
/** |
* All error messages go through this bottleneck function. |
* You can define your own handler by defining the function name in ADODB_OUTP. |
*/ |
function outp($msg,$newline=true) |
{ |
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); |
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() |
{ |
$rs =& $this->_Execute("select $this->sysTimeStamp"); |
if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields)); |
|
return false; |
} |
|
/** |
* 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 |
* |
* @return true or false |
*/ |
function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) |
{ |
if ($argHostname != "") $this->host = $argHostname; |
if ($argUsername != "") $this->user = $argUsername; |
if ($argPassword != "") $this->password = $argPassword; // not stored for security reasons |
if ($argDatabaseName != "") $this->database = $argDatabaseName; |
|
$this->_isPersistentConnection = false; |
if ($forceNew) { |
if ($rez=$this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true; |
} else { |
if ($rez=$this->_connect($this->host, $this->user, $this->password, $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; |
} |
if ($fn = $this->raiseErrorFn) |
$fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this); |
|
|
$this->_connectionID = false; |
if ($this->debug) ADOConnection::outp( $this->host.': '.$err); |
return $ret; |
} |
|
function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) |
{ |
return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName); |
} |
|
|
/** |
* Always force a new connection to database - currently only works with oracle |
* |
* @param [argHostname] Host to connect to |
* @param [argUsername] Userid to login |
* @param [argPassword] Associated password |
* @param [argDatabaseName] database |
* |
* @return true or false |
*/ |
function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") |
{ |
return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true); |
} |
|
/** |
* Establish persistent connect to database |
* |
* @param [argHostname] Host to connect to |
* @param [argUsername] Userid to login |
* @param [argPassword] Associated password |
* @param [argDatabaseName] database |
* |
* @return return true or false |
*/ |
function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") |
{ |
if (defined('ADODB_NEVER_PERSIST')) |
return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName); |
|
if ($argHostname != "") $this->host = $argHostname; |
if ($argUsername != "") $this->user = $argUsername; |
if ($argPassword != "") $this->password = $argPassword; |
if ($argDatabaseName != "") $this->database = $argDatabaseName; |
|
$this->_isPersistentConnection = true; |
if ($rez = $this->_pconnect($this->host, $this->user, $this->password, $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; |
} |
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; |
} |
|
// Format date column in sql string given an input format that understands Y M D |
function SQLDate($fmt, $col=false) |
{ |
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'); |
* |
* @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. |
* |
*/ |
function Prepare($sql) |
{ |
return $sql; |
} |
|
/** |
* Some databases, eg. mssql require a different function for preparing |
* stored procedures. So we cannot use Prepare(). |
* |
* 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 |
* |
* @return return FALSE, or the prepared statement, or the original sql if |
* if the database does not support prepare. |
* |
*/ |
function PrepareSP($sql,$param=true) |
{ |
return $this->Prepare($sql,$param); |
} |
|
/** |
* PEAR DB Compat |
*/ |
function Quote($s) |
{ |
return $this->qstr($s,false); |
} |
|
/** |
Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de> |
*/ |
function QMagic($s) |
{ |
return $this->qstr($s,get_magic_quotes_gpc()); |
} |
|
function q(&$s) |
{ |
$s = $this->qstr($s,false); |
} |
|
/** |
* PEAR DB Compat - do not use internally. |
*/ |
function ErrorNative() |
{ |
return $this->ErrorNo(); |
} |
|
|
/** |
* PEAR DB Compat - do not use internally. |
*/ |
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 |
* |
* @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 |
*/ |
function RowLock($table,$where) |
{ |
return false; |
} |
|
function CommitLock($table) |
{ |
return $this->CommitTrans(); |
} |
|
function RollbackLock($table) |
{ |
return $this->RollbackTrans(); |
} |
|
/** |
* 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 |
*/ |
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. |
*/ |
function &Query($sql, $inputarr=false) |
{ |
$rs = &$this->Execute($sql, $inputarr); |
if (!$rs && defined('ADODB_PEAR')) 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 placeholder for parameter, eg. |
$DB->Param('a') |
|
will return ':a' for Oracle, and '?' for most other databases... |
|
For databases that require positioned params, eg $1, $2, $3 for postgresql, |
pass in Param(false) before setting the first parameter. |
*/ |
function Param($name,$type='C') |
{ |
return '?'; |
} |
|
/* |
InParameter and OutParameter are self-documenting versions of Parameter(). |
*/ |
function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) |
{ |
return $this->Parameter($stmt,$var,$name,false,$maxLen,$type); |
} |
|
/* |
*/ |
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. |
|
*/ |
function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) |
{ |
return false; |
} |
|
/** |
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; |
} |
|
$this->_oldRaiseFn = $this->raiseErrorFn; |
$this->raiseErrorFn = $errfn; |
$this->_transOK = true; |
|
if ($this->debug && $this->transCnt > 0) ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans"); |
$this->BeginTrans(); |
$this->transOff = 1; |
} |
|
|
/** |
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. |
*/ |
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"); |
} |
|
return $this->_transOK; |
} |
|
/* |
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. |
*/ |
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 |
*/ |
function &Execute($sql,$inputarr=false) |
{ |
if ($this->fnExecute) { |
$fn = $this->fnExecute; |
$ret =& $fn($this,$sql,$inputarr); |
if (isset($ret)) return $ret; |
} |
if ($inputarr) { |
if (!is_array($inputarr)) $inputarr = array($inputarr); |
|
$element0 = reset($inputarr); |
# is_object check because oci8 descriptors can be passed in |
$array_2d = is_array($element0) && !is_object(reset($element0)); |
//remove extra memory copy of input -mikefedyk |
unset($element0); |
|
if (!is_array($sql) && !$this->_bindInputArray) { |
$sqlarr = explode('?',$sql); |
|
if (!$array_2d) $inputarr = array($inputarr); |
foreach($inputarr as $arr) { |
$sql = ''; $i = 0; |
//Use each() instead of foreach to reduce memory usage -mikefedyk |
while(list(, $v) = each($arr)) { |
$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 ($v === null) |
$sql .= 'NULL'; |
else |
$sql .= $v; |
$i += 1; |
} |
if (isset($sqlarr[$i])) { |
$sql .= $sqlarr[$i]; |
if ($i+1 != sizeof($sqlarr)) ADOConnection::outp( "Input Array does not match ?: ".htmlspecialchars($sql)); |
} else if ($i != sizeof($sqlarr)) |
ADOConnection::outp( "Input array does not match ?: ".htmlspecialchars($sql)); |
|
$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) |
{ |
if ($this->debug) { |
global $ADODB_INCLUDED_LIB; |
if (empty($ADODB_INCLUDED_LIB)) 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 |
*************************/ |
|
if ($this->_queryID === false) { // error handling if query fails |
if ($this->debug == 99) adodb_backtrace(true,5); |
$fn = $this->raiseErrorFn; |
if ($fn) { |
$fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this); |
} |
$false = false; |
return $false; |
} |
|
if ($this->_queryID === true) { // return simplified recordset for inserts/updates/deletes with lower overhead |
$rs =& new ADORecordSet_empty(); |
return $rs; |
} |
|
// return real recordset from select statement |
$rsclass = $this->rsPrefix.$this->databaseType; |
$rs = new $rsclass($this->_queryID,$this->fetchMode); |
$rs->connection = &$this; // Pablo suggestion |
$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; |
* 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 |
*/ |
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. |
*/ |
function Insert_ID($table='',$column='') |
{ |
if ($this->_logsql && $this->lastInsID) return $this->lastInsID; |
if ($this->hasInsertID) return $this->_insertid($table,$column); |
if ($this->debug) { |
ADOConnection::outp( '<p>Insert_ID error</p>'); |
adodb_backtrace(); |
} |
return false; |
} |
|
|
/** |
* Portable Insert ID. Pablo Roca <pabloroca#mvps.org> |
* |
* @return the last inserted ID. All databases support this. But aware possible |
* problems in multiuser environments. Heavy test this before deploying. |
*/ |
function PO_Insert_ID($table="", $id="") |
{ |
if ($this->hasInsertID){ |
return $this->Insert_ID($table,$id); |
} else { |
return $this->GetOne("SELECT MAX($id) FROM $table"); |
} |
} |
|
/** |
* @return # rows affected by UPDATE/DELETE |
*/ |
function Affected_Rows() |
{ |
if ($this->hasAffectedRows) { |
if ($this->fnExecute === 'adodb_log_sql') { |
if ($this->_logsql && $this->_affected !== false) return $this->_affected; |
} |
$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 |
*/ |
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. |
*/ |
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 |
*/ |
function MetaForeignKeys($table, $owner=false, $upper=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 |
*/ |
function SelectDB($dbName) |
{return false;} |
|
|
/** |
* 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') |
*/ |
function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) |
{ |
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.' '.((integer)$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.' '.((integer)$nrows).' ',$sql); |
} else { |
$sql = preg_replace( |
'/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql); |
} |
} else { |
$nn = $nrows + $offset; |
if ($isaccess || $ismssql) { |
$sql = preg_replace( |
'/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql); |
} else { |
$sql = preg_replace( |
'/(^\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; |
|
$savec = $ADODB_COUNTRECS; |
$ADODB_COUNTRECS = false; |
|
if ($offset>0){ |
if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr); |
else $rs = &$this->Execute($sql,$inputarr); |
} else { |
if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr); |
else $rs = &$this->Execute($sql,$inputarr); |
} |
$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 |
*/ |
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 |
*/ |
function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true) |
{ |
if (! $rs) { |
$false = false; |
return $false; |
} |
$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->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 |
*/ |
function &GetAll($sql, $inputarr=false) |
{ |
$arr =& $this->GetArray($sql,$inputarr); |
return $arr; |
} |
|
function &GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false) |
{ |
$rs =& $this->Execute($sql, $inputarr); |
if (!$rs) { |
$false = false; |
return $false; |
} |
$arr =& $rs->GetAssoc($force_array,$first2cols); |
return $arr; |
} |
|
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) { |
$false = false; |
return $false; |
} |
$arr =& $rs->GetAssoc($force_array,$first2cols); |
return $arr; |
} |
|
/** |
* Return first element of first row of sql statement. Recordset is disposed |
* for you. |
* |
* @param sql SQL statement |
* @param [inputarr] input bind array |
*/ |
function GetOne($sql,$inputarr=false) |
{ |
global $ADODB_COUNTRECS; |
$crecs = $ADODB_COUNTRECS; |
$ADODB_COUNTRECS = false; |
|
$ret = false; |
$rs = &$this->Execute($sql,$inputarr); |
if ($rs) { |
if (!$rs->EOF) $ret = reset($rs->fields); |
$rs->Close(); |
} |
$ADODB_COUNTRECS = $crecs; |
return $ret; |
} |
|
function CacheGetOne($secs2cache,$sql=false,$inputarr=false) |
{ |
$ret = false; |
$rs = &$this->CacheExecute($secs2cache,$sql,$inputarr); |
if ($rs) { |
if (!$rs->EOF) $ret = reset($rs->fields); |
$rs->Close(); |
} |
|
return $ret; |
} |
|
function GetCol($sql, $inputarr = false, $trim = false) |
{ |
$rv = false; |
$rs = &$this->Execute($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(); |
} |
return $rv; |
} |
|
function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false) |
{ |
$rv = false; |
$rs = &$this->CacheExecute($secs, $sql, $inputarr); |
if ($rs) { |
if ($trim) { |
while (!$rs->EOF) { |
$rv[] = trim(reset($rs->fields)); |
$rs->MoveNext(); |
} |
} else { |
while (!$rs->EOF) { |
$rv[] = reset($rs->fields); |
$rs->MoveNext(); |
} |
} |
$rs->Close(); |
} |
return $rv; |
} |
|
/* |
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. |
*/ |
function OffsetDate($dayFraction,$date=false) |
{ |
if (!$date) $date = $this->sysDate; |
return '('.$date.'+'.$dayFraction.')'; |
} |
|
|
/** |
* |
* @param sql SQL statement |
* @param [inputarr] input bind array |
*/ |
function &GetArray($sql,$inputarr=false) |
{ |
global $ADODB_COUNTRECS; |
|
$savec = $ADODB_COUNTRECS; |
$ADODB_COUNTRECS = false; |
$rs =& $this->Execute($sql,$inputarr); |
$ADODB_COUNTRECS = $savec; |
if (!$rs) |
if (defined('ADODB_PEAR')) { |
$cls = ADODB_PEAR_Error(); |
return $cls; |
} else { |
$false = false; |
return $false; |
} |
$arr =& $rs->GetArray(); |
$rs->Close(); |
return $arr; |
} |
|
function &CacheGetAll($secs2cache,$sql=false,$inputarr=false) |
{ |
return $this->CacheGetArray($secs2cache,$sql,$inputarr); |
} |
|
function &CacheGetArray($secs2cache,$sql=false,$inputarr=false) |
{ |
global $ADODB_COUNTRECS; |
|
$savec = $ADODB_COUNTRECS; |
$ADODB_COUNTRECS = false; |
$rs =& $this->CacheExecute($secs2cache,$sql,$inputarr); |
$ADODB_COUNTRECS = $savec; |
|
if (!$rs) |
if (defined('ADODB_PEAR')) { |
$cls = ADODB_PEAR_Error(); |
return $cls; |
} else { |
$false = false; |
return $false; |
} |
$arr =& $rs->GetArray(); |
$rs->Close(); |
return $arr; |
} |
|
|
|
/** |
* Return one row of sql statement. Recordset is disposed for you. |
* |
* @param sql SQL statement |
* @param [inputarr] input bind array |
*/ |
function &GetRow($sql,$inputarr=false) |
{ |
global $ADODB_COUNTRECS; |
$crecs = $ADODB_COUNTRECS; |
$ADODB_COUNTRECS = false; |
|
$rs =& $this->Execute($sql,$inputarr); |
|
$ADODB_COUNTRECS = $crecs; |
if ($rs) { |
if (!$rs->EOF) $arr = $rs->fields; |
else $arr = array(); |
$rs->Close(); |
return $arr; |
} |
|
$false = false; |
return $false; |
} |
|
function &CacheGetRow($secs2cache,$sql=false,$inputarr=false) |
{ |
$rs =& $this->CacheExecute($secs2cache,$sql,$inputarr); |
if ($rs) { |
$arr = false; |
if (!$rs->EOF) $arr = $rs->fields; |
$rs->Close(); |
return $arr; |
} |
$false = false; |
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 |
* 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_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') |
*/ |
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) ADOConnection::outp( "Warning: \$sql missing from 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. |
*/ |
|
/** |
* 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; |
|
if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) { |
/*if (strncmp(PHP_OS,'WIN',3) === 0) |
$dir = str_replace('/', '\\', $ADODB_CACHE_DIR); |
else */ |
$dir = $ADODB_CACHE_DIR; |
|
if ($this->debug) { |
ADOConnection::outp( "CacheFlush: $dir<br><pre>\n", $this->_dirFlush($dir),"</pre>"); |
} else { |
$this->_dirFlush($dir); |
} |
return; |
} |
|
global $ADODB_INCLUDED_CSV; |
if (empty($ADODB_INCLUDED_CSV)) include_once(ADODB_DIR.'/adodb-csvlib.inc.php'); |
|
$f = $this->_gencachename($sql.serialize($inputarr),false); |
adodb_write_file($f,''); // is adodb_write_file needed? |
if (!@unlink($f)) { |
if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f"); |
} |
} |
|
/** |
* 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; |
|
if (!@unlink($dir.'/'.$obj)) |
$this->_dirFlush($dir.'/'.$obj, true); |
} |
if ($kill_top_level === true) |
@rmdir($dir); |
return true; |
} |
|
|
function xCacheFlush($sql=false,$inputarr=false) |
{ |
global $ADODB_CACHE_DIR; |
|
if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) { |
if (strncmp(PHP_OS,'WIN',3) === 0) { |
$cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache'; |
} else { |
//$cmd = 'find "'.$ADODB_CACHE_DIR.'" -type f -maxdepth 1 -print0 | xargs -0 rm -f'; |
$cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/[0-9a-f][0-9a-f]/'; |
// old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`'; |
} |
if ($this->debug) { |
ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>"); |
} else { |
exec($cmd); |
} |
return; |
} |
|
global $ADODB_INCLUDED_CSV; |
if (empty($ADODB_INCLUDED_CSV)) include_once(ADODB_DIR.'/adodb-csvlib.inc.php'); |
|
$f = $this->_gencachename($sql.serialize($inputarr),false); |
adodb_write_file($f,''); // is adodb_write_file needed? |
if (!@unlink($f)) { |
if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f"); |
} |
} |
|
/** |
* 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). |
* 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_DIR; |
static $notSafeMode; |
|
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 (!isset($notSafeMode)) $notSafeMode = !ini_get('safe_mode'); |
$dir = ($notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($m,0,2) : $ADODB_CACHE_DIR; |
|
if ($createdir && $notSafeMode && !file_exists($dir)) { |
$oldu = umask(0); |
if (!mkdir($dir,0771)) |
if ($this->debug) ADOConnection::outp( "Unable to mkdir $dir for $sql"); |
umask($oldu); |
} |
return $dir.'/adodb_'.$m.'.cache'; |
} |
|
|
/** |
* Execute SQL, caching recordsets. |
* |
* @param [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 |
*/ |
function &CacheExecute($secs2cache,$sql=false,$inputarr=false) |
{ |
|
|
if (!is_numeric($secs2cache)) { |
$inputarr = $sql; |
$sql = $secs2cache; |
$secs2cache = $this->cacheSecs; |
} |
|
if (is_array($sql)) { |
$sqlparam = $sql; |
$sql = $sql[0]; |
} else |
$sqlparam = $sql; |
|
global $ADODB_INCLUDED_CSV; |
if (empty($ADODB_INCLUDED_CSV)) include_once(ADODB_DIR.'/adodb-csvlib.inc.php'); |
|
$md5file = $this->_gencachename($sql.serialize($inputarr),true); |
$err = ''; |
|
if ($secs2cache > 0){ |
$rs = &csv2rs($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()) { |
ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :("); |
} |
if ($this->debug !== -1) ADOConnection::outp( " $md5file cache failure: $err (see sql below)"); |
} |
|
$rs = &$this->Execute($sqlparam,$inputarr); |
|
if ($rs) { |
$eof = $rs->EOF; |
$rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately |
$txt = _rs2serialize($rs,false,$sql); // serialize |
|
if (!adodb_write_file($md5file,$txt,$this->debug)) { |
if ($fn = $this->raiseErrorFn) { |
$fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this); |
} |
if ($this->debug) ADOConnection::outp( " Cache write error"); |
} |
if ($rs->EOF && !$eof) { |
$rs->MoveFirst(); |
//$rs = &csv2rs($md5file,$err); |
$rs->connection = &$this; // Pablo suggestion |
} |
|
} else |
@unlink($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){ |
|
$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. |
*/ |
function& AutoExecute($table, $fields_values, $mode = 'INSERT', $where = FALSE, $forceUpdate=true, $magicq=false) |
{ |
$sql = 'SELECT * FROM '.$table; |
if ($where!==FALSE) $sql .= ' WHERE '.$where; |
else if ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) { |
ADOConnection::outp('AutoExecute: Illegal mode=UPDATE with empty WHERE clause'); |
return false; |
} |
|
$rs =& $this->SelectLimit($sql,1); |
if (!$rs) return false; // table does not exist |
$rs->tableName = $table; |
|
switch((string) $mode) { |
case 'UPDATE': |
case '2': |
$sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq); |
break; |
case 'INSERT': |
case '1': |
$sql = $this->GetInsertSQL($rs, $fields_values, $magicq); |
break; |
default: |
ADOConnection::outp("AutoExecute: Unknown mode=$mode"); |
return false; |
} |
$ret = false; |
if ($sql) $ret = $this->Execute($sql); |
if ($ret) $ret = true; |
return $ret; |
} |
|
|
/** |
* 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 |
* |
* "Jonathan Younger" <jyounger@unilab.com> |
*/ |
function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null) |
{ |
global $ADODB_INCLUDED_LIB; |
|
//********************************************************// |
//This is here to maintain compatibility |
//with older adodb versions. Sets force type to force nulls if $forcenulls is set. |
if (!isset($force)) { |
global $ADODB_FORCE_TYPE; |
$force = $ADODB_FORCE_TYPE; |
} |
//********************************************************// |
|
if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php'); |
return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$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. |
*/ |
function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null) |
{ |
global $ADODB_INCLUDED_LIB; |
if (!isset($force)) { |
global $ADODB_FORCE_TYPE; |
$force = $ADODB_FORCE_TYPE; |
|
} |
if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php'); |
return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$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. |
* |
* Usage to update a $blobvalue which has a primary key blob_id=1 into a |
* field blobtable.blobcolumn: |
* |
* UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1'); |
* |
* Insert example: |
* |
* $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); |
* $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1'); |
*/ |
|
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'); |
* |
* $blobtype supports 'BLOB' and 'CLOB' |
* |
* $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); |
* $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1'); |
*/ |
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 SetCharSet($charset) |
{ |
return false; |
} |
|
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; |
} |
|
function GetCharSet() |
{ |
return false; |
} |
|
/** |
* 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 '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; |
} |
} |
|
function &GetActiveRecordsClass($class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false) |
{ |
global $_ADODB_ACTIVE_DBS; |
|
$save = $this->SetFetchMode(ADODB_FETCH_NUM); |
if (empty($whereOrderBy)) $whereOrderBy = '1=1'; |
$rows = $this->GetAll("select * from ".$table.' WHERE '.$whereOrderBy,$bindarr); |
$this->SetFetchMode($save); |
|
$false = false; |
|
if ($rows === false) { |
return $false; |
} |
|
|
if (!isset($_ADODB_ACTIVE_DBS)) { |
include_once(ADODB_DIR.'/adodb-active-record.inc.php'); |
} |
if (!class_exists($class)) { |
ADOConnection::outp("Unknown class $class in GetActiveRcordsClass()"); |
return $false; |
} |
$arr = array(); |
foreach($rows as $row) { |
|
$obj =& new $class($table,$primkeyArr,$this); |
if ($obj->ErrorMsg()){ |
$this->_errorMsg = $obj->ErrorMsg(); |
return $false; |
} |
$obj->Set($row); |
$arr[] =& $obj; |
} |
return $arr; |
} |
|
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->_connectionID = false; |
return $rez; |
} |
|
/** |
* Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans(). |
* |
* @return true if succeeded or false if database does not support transactions |
*/ |
function BeginTrans() {return false;} |
|
|
/** |
* If database does not support transactions, always return true as data always commited |
* |
* @param $ok set to false to rollback transaction, true to commit |
* |
* @return true/false. |
*/ |
function CommitTrans($ok=true) |
{ return true;} |
|
|
/** |
* If database does not support transactions, rollbacks always fail, so return false |
* |
* @return true/false. |
*/ |
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. |
*/ |
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; |
} |
|
|
/** |
* @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; |
|
|
$false = false; |
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; |
|
$false = false; |
|
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) |
{ |
$false = 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) |
{ |
$objarr =& $this->MetaColumns($table); |
if (!is_array($objarr)) { |
$false = false; |
return $false; |
} |
$arr = array(); |
if ($numIndexes) { |
$i = 0; |
foreach($objarr as $v) $arr[$i++] = $v->name; |
} else |
foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name; |
|
return $arr; |
} |
|
/** |
* 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 |
*/ |
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. |
* |
* @return date string in database date format |
*/ |
function DBDate($d) |
{ |
if (empty($d) && $d !== 0) return 'null'; |
|
if (is_string($d) && !is_numeric($d)) { |
if ($d === 'null' || strncmp($d,"'",1) === 0) return $d; |
if ($this->isoDates) return "'$d'"; |
$d = ADOConnection::UnixDate($d); |
} |
|
return adodb_date($this->fmtDate,$d); |
} |
|
|
/** |
* Converts a timestamp "ts" to a string that the database can understand. |
* |
* @param ts a timestamp in Unix date time format. |
* |
* @return timestamp string in database timestamp format |
*/ |
function DBTimeStamp($ts) |
{ |
if (empty($ts) && $ts !== 0) return 'null'; |
|
# 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) 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 |
* |
* @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format |
*/ |
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 |
* |
* @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format |
*/ |
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() |
* |
* @return a date formated as user desires |
*/ |
|
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); |
|
} |
|
/** |
* |
* @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() |
* |
* @return a timestamp formated as user desires |
*/ |
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) |
{ |
return $this->addq($s,$magic_quotes); |
} |
|
/** |
* Quotes a string, without prefixing nor appending quotes. |
*/ |
function addq($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 == "\\'") // ' 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()); |
* |
* @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. |
* |
* @return quoted string to be sent back to database |
*/ |
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 == "\\'") // ' 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)."'"; |
} |
} |
|
|
/** |
* 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 readme.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(). |
* |
*/ |
function &PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0) |
{ |
global $ADODB_INCLUDED_LIB; |
if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php'); |
if ($this->pageExecuteCountRows) $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') |
*/ |
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; |
} |
|
} // end class ADOConnection |
|
|
|
//============================================================================================== |
// CLASS ADOFetchObj |
//============================================================================================== |
|
/** |
* Internal placeholder for record objects. Used by ADORecordSet->FetchObj(). |
*/ |
class ADOFetchObj { |
}; |
|
//============================================================================================== |
// CLASS ADORecordSet_empty |
//============================================================================================== |
|
/** |
* Lightweight recordset when there are no records to be returned |
*/ |
class ADORecordSet_empty |
{ |
var $dataProvider = 'empty'; |
var $databaseType = false; |
var $EOF = true; |
var $_numOfRows = 0; |
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() {} |
} |
|
//============================================================================================== |
// DATE AND TIME FUNCTIONS |
//============================================================================================== |
include_once(ADODB_DIR.'/adodb-time.inc.php'); |
|
//============================================================================================== |
// CLASS ADORecordSet |
//============================================================================================== |
|
if (PHP_VERSION < 5) include_once(ADODB_DIR.'/adodb-php4.inc.php'); |
else include_once(ADODB_DIR.'/adodb-iterator.inc.php'); |
/** |
* 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 extends ADODB_BASE_RS { |
/* |
* public variables |
*/ |
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 |
/// in other words, we use a text area for editing. |
var $canSeek = false; /// indicates that seek is supported |
var $sql; /// sql text |
var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object. |
|
var $emptyTimeStamp = ' '; /// what to display when $time==0 |
var $emptyDate = ' '; /// 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 |
/* |
* 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 $_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; |
|
/** |
* Constructor |
* |
* @param queryID this is the queryID returned by ADOConnection->_query() |
* |
*/ |
function ADORecordSet($queryID) |
{ |
$this->_queryID = $queryID; |
} |
|
|
|
function Init() |
{ |
if ($this->_inited) return; |
$this->_inited = true; |
if ($this->_queryID) @$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; |
} |
} |
|
|
/** |
* Generate a SELECT tag string from a recordset, and return the string. |
* If the recordset has 2 cols, we treat the 1st col as the containing |
* the text to display to the user, and 2nd col as the return value. Default |
* strings are compared with the FIRST column. |
* |
* @param name name of SELECT tag |
* @param [defstr] the value to hilite. Use an array for multiple hilites for listbox. |
* @param [blank1stItem] true to leave the 1st item in list empty |
* @param [multiple] true for listbox, false for popup |
* @param [size] #rows to show for listbox. not used by popup |
* @param [selectAttr] additional attributes to defined for SELECT tag. |
* useful for holding javascript onChange='...' handlers. |
& @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with |
* column 0 (1st col) if this is true. This is not documented. |
* |
* @return HTML |
* |
* changes by glen.davies@cce.ac.nz to support multiple hilited items |
*/ |
function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false, |
$size=0, $selectAttr='',$compareFields0=true) |
{ |
global $ADODB_INCLUDED_LIB; |
if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php'); |
return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple, |
$size, $selectAttr,$compareFields0); |
} |
|
|
|
/** |
* Generate a SELECT tag string from a recordset, and return the string. |
* If the recordset has 2 cols, we treat the 1st col as the containing |
* the text to display to the user, and 2nd col as the return value. Default |
* strings are compared with the SECOND column. |
* |
*/ |
function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='') |
{ |
return $this->GetMenu($name,$defstr,$blank1stItem,$multiple, |
$size, $selectAttr,false); |
} |
|
/* |
Grouped Menu |
*/ |
function GetMenu3($name,$defstr='',$blank1stItem=true,$multiple=false, |
$size=0, $selectAttr='') |
{ |
global $ADODB_INCLUDED_LIB; |
if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php'); |
return _adodb_getmenu_gp($this, $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. |
* |
* @return an 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; |
} |
|
/* |
* Some databases allow multiple recordsets to be returned. This function |
* will return true if there is a next recordset, or false if no more. |
*/ |
function NextRecordSet() |
{ |
return false; |
} |
|
/** |
* 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 |
* |
* @return an array indexed by the rows (0-based) from the recordset |
*/ |
function &GetArrayLimit($nrows,$offset=-1) |
{ |
if ($offset <= 0) { |
$arr =& $this->GetArray($nrows); |
return $arr; |
} |
|
$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. |
* |
* @return an array indexed by the rows (0-based) from the recordset |
*/ |
function &GetRows($nRows = -1) |
{ |
$arr =& $this->GetArray($nRows); |
return $arr; |
} |
|
/** |
* 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. |
* |
* @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, |
* 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 |
* |
* @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) { |
$false = false; |
return $false; |
} |
$numIndex = isset($this->fields[0]); |
$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) { |
$results[trim(reset($this->fields))] = array_slice($this->fields, 1); |
adodb_movenext($this); |
} |
} |
} else { |
if ($numIndex) { |
while (!$this->EOF) { |
$results[trim($this->fields[0])] = array_slice($this->fields, 1); |
$this->MoveNext(); |
} |
} else { |
while (!$this->EOF) { |
$results[trim(reset($this->fields))] = array_slice($this->fields, 1); |
$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 { |
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(); |
} |
} |
} |
} |
|
$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() |
* |
* @return 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() |
* |
* @return a date formated 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 |
* |
* @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format |
*/ |
function UnixDate($v) |
{ |
return ADOConnection::UnixDate($v); |
} |
|
|
/** |
* @param $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 |
*/ |
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 |
*/ |
function NumRows() |
{ |
return $this->_numOfRows; |
} |
|
|
/** |
* PEAR DB compat, number of cols |
*/ |
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 |
*/ |
function &FetchRow() |
{ |
if ($this->EOF) { |
$false = false; |
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 |
*/ |
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 |
*/ |
function MoveFirst() |
{ |
if ($this->_currentRow == 0) return true; |
return $this->Move(0); |
} |
|
|
/** |
* Move to the last row in the recordset. |
* |
* @return 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). |
*/ |
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) |
* |
* @return 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 ($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; |
} |
|
|
/** |
* Get the value of a field in the current row by column name. |
* Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM. |
* |
* @param colname is the field to access |
* |
* @return the value of $colname column |
*/ |
function Fields($colname) |
{ |
return $this->fields[$colname]; |
} |
|
function GetAssocKeys($upper=true) |
{ |
$this->bind = array(); |
for ($i=0; $i < $this->_numOfFields; $i++) { |
$o = $this->FetchField($i); |
if ($upper === 2) $this->bind[$o->name] = $i; |
else $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $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 |
* |
* If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC |
* before you execute your SQL statement, and access $rs->fields['col'] directly. |
* |
* $upper 0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField |
*/ |
function &GetRowAssoc($upper=1) |
{ |
$record = array(); |
// if (!$this->fields) return $record; |
|
if (!$this->bind) { |
$this->GetAssocKeys($upper); |
} |
|
foreach($this->bind as $k => $v) { |
$record[$k] = $this->fields[$v]; |
} |
|
return $record; |
} |
|
|
/** |
* Clean up recordset |
* |
* @return true or false |
*/ |
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 |
* |
* @return the number of rows or -1 if this is not supported |
*/ |
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. |
*/ |
function MaxRecordCount() |
{ |
return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount(); |
} |
|
/** |
* synonyms RecordCount and RowCount |
* |
* @return the number of rows or -1 if this is not supported |
*/ |
function RowCount() {return $this->_numOfRows;} |
|
|
/** |
* Portable RecordCount. Pablo Roca <pabloroca@mvps.org> |
* |
* @return the number of records from a previous SELECT. All databases support this. |
* |
* But aware possible problems in multiuser environments. For better speed the table |
* must be indexed by the condition. Heavy test this before deploying. |
*/ |
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. |
* |
* @param fieldoffset is the column position to access(0-based). |
* |
* @return the ADOFieldObject for that column, or false. |
*/ |
function &FetchField($fieldoffset) |
{ |
// must be defined by child class |
} |
|
/** |
* Get the ADOFieldObjects of all columns in an array. |
* |
*/ |
function& FieldTypesArray() |
{ |
$arr = array(); |
for ($i=0, $max=$this->_numOfFields; $i < $max; $i++) |
$arr[] = $this->FetchField($i); |
return $arr; |
} |
|
/** |
* 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 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 |
* |
* @return the object with the properties set to the fields of the current row |
*/ |
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) $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 |
* |
* Fixed bug reported by tim@orotech.net |
*/ |
function &FetchNextObj() |
{ |
$o =& $this->FetchNextObject(false); |
return $o; |
} |
|
|
/** |
* 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 |
* |
* @return the object with the properties set to the fields of the current row, |
* or false if EOF |
* |
* Fixed bug reported by tim@orotech.net |
*/ |
function &FetchNextObject($isupper=true) |
{ |
$o = false; |
if ($this->_numOfRows != 0 && !$this->EOF) { |
$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 |
* |
* |
*/ |
function MetaType($t,$len=-1,$fieldobj=false) |
{ |
if (is_object($t)) { |
$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 |
## |
'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', |
## |
'TIME' => 'T', |
'TIMESTAMP' => 'T', |
'DATETIME' => 'T', |
'TIMESTAMPTZ' => 'T', |
'T' => 'T', |
## |
'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' |
); |
|
$tmap = false; |
$t = strtoupper($t); |
$tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N'; |
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)) return 'R'; |
return 'I'; |
|
case false: |
return 'N'; |
|
case 'B': |
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; |
} |
} |
|
function _close() {} |
|
/** |
* set/returns the current recordset page when paginating |
*/ |
function AbsolutePage($page=-1) |
{ |
if ($page != -1) $this->_currentPage = $page; |
return $this->_currentPage; |
} |
|
/** |
* set/returns the status of the atFirstPage flag when paginating |
*/ |
function AtFirstPage($status=false) |
{ |
if ($status != false) $this->_atFirstPage = $status; |
return $this->_atFirstPage; |
} |
|
function LastPageNo($page = false) |
{ |
if ($page != false) $this->_lastPageNo = $page; |
return $this->_lastPageNo; |
} |
|
/** |
* set/returns the status of the atLastPage flag when paginating |
*/ |
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 $_fieldarr; // holds array of field objects |
var $canSeek = true; |
var $affectedrows = false; |
var $insertid = false; |
var $sql = ''; |
var $compat = false; |
/** |
* Constructor |
* |
*/ |
function ADORecordSet_array($fakeid=1) |
{ |
global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH; |
|
// fetch() on EOF does not delete $this->fields |
$this->compat = !empty($ADODB_COMPAT_FETCH); |
$this->ADORecordSet($fakeid); // fake queryID |
$this->fetchMode = $ADODB_FETCH_MODE; |
} |
|
|
/** |
* 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. |
* @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 |
* $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. |
* The first row should hold the column names |
* unless paramter $colnames is used. |
* @param fieldarr holds an 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) |
{ |
if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) { |
return $this->_array; |
} else { |
$arr =& ADORecordSet::GetArray($nRows); |
return $arr; |
} |
} |
|
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 */ |
function Fields($colname) |
{ |
$mode = isset($this->adodbFetchMode) ? $this->adodbFetchMode : $this->fetchMode; |
|
if ($mode & ADODB_FETCH_ASSOC) { |
if (!isset($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) |
{ |
if (isset($this->_fieldobjects)) { |
return $this->_fieldobjects[$fieldOffset]; |
} |
$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) |
{ |
if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) { |
$this->_currentRow = $row; |
if ($this->_skiprow1) $row += 1; |
$this->fields = $this->_array[$row]; |
return true; |
} |
return false; |
} |
|
function MoveNext() |
{ |
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() |
{ |
$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 'postgres': |
case 'postgres8': |
case 'pgsql': $class = $db = 'postgres7'; break; |
default: |
$class = $db; break; |
} |
|
$file = ADODB_DIR."/drivers/adodb-".$db.".inc.php"; |
@include_once($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 |
*/ |
function &NewADOConnection($db='') |
{ |
$tmp =& ADONewConnection($db); |
return $tmp; |
} |
|
/** |
* Instantiate a new Connection class for a specific database driver. |
* |
* @param [db] is the 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. |
*/ |
function &ADONewConnection($db='') |
{ |
GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB; |
|
if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2); |
$errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false; |
$false = false; |
if ($at = strpos($db,'://')) { |
$origdsn = $db; |
if (PHP_VERSION < 5) $dsna = @parse_url($db); |
else { |
$fakedsn = 'fake'.substr($db,$at); |
$dsna = @parse_url($fakedsn); |
$dsna['scheme'] = substr($db,0,$at); |
|
if (strncmp($db,'pdo',3) == 0) { |
$sch = explode('_',$dsna['scheme']); |
if (sizeof($sch)>1) { |
$dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : ''; |
$dsna['host'] = rawurlencode($sch[1].':host='.rawurldecode($dsna['host'])); |
$dsna['scheme'] = 'pdo'; |
} |
} |
} |
|
if (!$dsna) { |
// special handling of oracle, which might not have host |
$db = str_replace('@/','@adodb-fakehost/',$db); |
$dsna = parse_url($db); |
if (!$dsna) return $false; |
$dsna['host'] = ''; |
} |
$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 (isset($dsna['query'])) { |
$opt1 = explode('&',$dsna['query']); |
foreach($opt1 as $k => $v) { |
$arr = explode('=',$v); |
$opt[$arr[0]] = isset($arr[1]) ? rawurldecode($arr[1]) : 1; |
} |
} 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); |
|
} else { |
|
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; |
} |
} |
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' : break; |
case 'sapdb' : break; |
default: |
$drivername = 'generic'; |
break; |
} |
return $drivername; |
} |
|
function &NewPerfMonitor(&$conn) |
{ |
$false = false; |
$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; |
} |
|
function &NewDataDictionary(&$conn,$drivername=false) |
{ |
$false = false; |
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("Database driver '$path' not available"); |
return $false; |
} |
include_once($path); |
$class = "ADODB2_$drivername"; |
$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. |
*/ |
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 |
*/ |
function adodb_backtrace($printOrArr=true,$levels=9999) |
{ |
global $ADODB_INCLUDED_LIB; |
if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php'); |
return _adodb_backtrace($printOrArr,$levels); |
} |
|
|
} |
?> |