Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;
');
define('ADODB_FETCH_DEFAULT',0);
define('ADODB_FETCH_NUM',1);
define('ADODB_FETCH_ASSOC',2);
define('ADODB_FETCH_BOTH',3);
// allow [ ] @ and . in table names
define('ADODB_TABLE_REGEX','([]0-9a-z_\.\@\[-]*)');
if (!defined('ADODB_PREFETCH_ROWS')) define('ADODB_PREFETCH_ROWS',10);
/**
* 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_Database, // last database driver used
$ADODB_COUNTRECS, // count number of records returned - slows down query
$ADODB_CACHE_DIR, // directory to cache recordsets
$ADODB_FETCH_MODE; // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...
//==============================================================================
// GLOBAL SETUP
//==============================================================================
$ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
if (!isset($ADODB_CACHE_DIR)) {
$ADODB_CACHE_DIR = '/tmp';
} else {
// do not accept url based paths, eg. http:/ or ftp:/
if (strpos($ADODB_CACHE_DIR,':/') !== false)
die("Illegal \$ADODB_CACHE_DIR");
}
//==============================================================================
// CHANGE NOTHING BELOW UNLESS YOU ARE CODING
//==============================================================================
// Initialize random number generator for randomizing cache flushes
srand(((double)microtime())*1000000);
/**
* Name of last database driver loaded into memory. Set by ADOLoadCode().
*/
$ADODB_Database = '';
/**
* ADODB version as a string.
*/
$ADODB_vers = 'V1.71 18 Jan 2001 (c) 2000, 2001 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...
*/
$ADODB_COUNTRECS = true;
//==============================================================================
// 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.
}
//==============================================================================
// 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
var $debug = false; // if set to true will output sql statements
var $maxblobsize = 8000; // maximum size of blobs or large text fields -- some databases die otherwise like foxpro
var $concat_operator = '+'; // default concat operator -- change to || for Oracle/Interbase
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 $hasInsertID = false; // supports autoincrement ID?
var $hasAffectedRows = false; // supports affected rows for update/delete?
var $autoCommit = true;
var $charSet=false; // character set to use - only for interbase
var $metaTablesSQL = '';
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 $genID = 0; // sequence id used by GenID();
var $raiseErrorFn = false; // error function to call
var $upperCase = false; // uppercase function to call for searching/where
var $isoDates = false; // accepts dates in ISO format
/*
* PRIVATE VARS
*/
var $_connectionID = false; // The returned link identifier whenever a successful database connection is made. */
var $_errorMsg = ''; // A variable which was used to keep the returned last error message. The value will
//then returned by the errorMsg() function
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.
/**
* Constructor
*/
function ADOConnection()
{
die('Virtual Class -- cannot instantiate');
}
/**
* Connect to database
*
* @param [argHostname] Host to connect to
* @param [argUsername] Userid to login
* @param [argPassword] Associated password
* @param [argDatabaseName] database
*
* @return true or false
*/
function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {
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 ($fn = $this->raiseErrorFn) {
if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
$err = $this->ErrorMsg();
if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
$fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database);
} else
if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
if ($this->debug) print $this->host.': '.$this->ErrorMsg().' ';
return false;
}
/**
* 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 ($argHostname != "") $this->host = $argHostname;
if ($argUsername != "") $this->user = $argUsername;
if ($argPassword != "") $this->password = $argPassword;
if ($argDatabaseName != "") $this->database = $argDatabaseName;
$this->_isPersistentConnection = true;
if ($fn = $this->raiseErrorFn) {
if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
$err = $this->ErrorMsg();
if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
$fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database);
} else
if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
if ($this->debug) print $this->host.': '.$this->ErrorMsg().' ';
return false;
}
/**
* 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 TRUE or FALSE, or the $sql.
*
*/
function Prepare($sql)
{
return $sql;
}
/**
* PEAR DB Compat - do not use internally.
*/
function Quote($s)
{
return $this->qstr($s);
}
/**
* 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);
}
/**
* PEAR DB Compat - do not use internally.
*
* Appears that the fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB
* are the same numeric values!
*/
function SetFetchMode($mode)
{
global $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = $mode;
}
/**
* 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)
{
$rs = &$this->SelectLimit($sql, $count, $offset); // swap
if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
return $rs;
}
/**
* PEAR DB Compat - do not use internally
*/
function Disconnect()
{
return $this->Close();
}
/**
* Execute SQL
*
* @param sql SQL statement to execute
* @param [inputarr] holds the input data to bind to. Null elements will be set to null.
* @param [arg3] reserved for john lim for future use
* @return RecordSet or false
*/
function &Execute($sql,$inputarr=false,$arg3=false)
{
if (!$this->_bindInputArray && $inputarr) {
$sqlarr = explode('?',$sql);
$sql = '';
$i = 0;
foreach($inputarr as $v) {
$sql .= $sqlarr[$i];
// from Ron Baldwin
// Only quote string types
if (gettype($v) == 'string')
$sql .= "'".$v."'";
else if ($v === null)
$sql .= 'NULL';
else
$sql .= $v;
$i += 1;
}
$sql .= $sqlarr[$i];
if ($i+1 != sizeof($sqlarr))
print "Input Array does not match ?: ".htmlspecialchars($sql);
$inputarr = false;
}
if ($this->debug) {
$ss = '';
if ($inputarr) {
foreach ($inputarr as $kk => $vv) {
if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
$ss .= "($kk=>'$vv') ";
}
$ss = "[ $ss ]";
}
print "($this->databaseType): ".htmlspecialchars($sql)." $ss";
$this->_queryID = $this->_query($sql,$inputarr,$arg3);
if ($this->databaseType == 'mssql') { // ErrorNo is a slow function call in mssql, and not reliable
if($this->ErrorMsg()) {
$err = $this->ErrorNo();
if ($err) print $err.': '.$this->ErrorMsg().' ';
}
} else
if (!$this->_queryID) print $this->ErrorNo().': '.$this->ErrorMsg().' ';
} else
$this->_queryID =@$this->_query($sql,$inputarr,$arg3);
if ($this->_queryID === false) {
if ($fn = $this->raiseErrorFn) {
$fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr);
}
return false;
} else if ($this->_queryID === true){
$rs = new ADORecordSet_empty();
return $rs;
}
$rsclass = "ADORecordSet_".$this->databaseType;
$rs = new $rsclass($this->_queryID); // &new not supported by older PHP versions
$rs->connection = &$this; // Pablo suggestion
$rs->Init();
//$this->_insertQuery(&$rs); PHP4 handles closing automatically
if (is_string($sql)) $rs->sql = $sql;
return $rs;
}
/**
* Generates a sequence id and stores it in $this->genID;
* GenID is only available if $this->hasGenID = true;
*
* @seqname name of sequence to use
* @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);
$rs = @$this->Execute($getnext);
if (!$rs) {
$u = strtoupper($seqname);
$createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
$rs = $this->Execute($getnext);
}
if ($rs && !$rs->EOF) $this->genID = (integer) reset($rs->fields);
else $this->genID = 0; // false
if ($rs) $rs->Close();
return $this->genID;
}
/**
* @return the last inserted ID. Not all databases support this.
*/
function Insert_ID()
{
if ($this->hasInsertID) return $this->_insertid();
if ($this->debug) print '
Insert_ID error
';
return false;
}
/**
* Portable Insert ID. Pablo Roca
*
* @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();
} else {
return $this->GetOne("SELECT MAX($id) FROM $table");
}
}
/**
* @return # rows affected by UPDATE/DELETE
*/
function Affected_Rows()
{
if ($this->hasAffectedRows) {
$val = $this->_affectedrows();
return ($val < 0) ? false : $val;
}
if ($this->debug) print '
Affected_Rows error
';
return false;
}
/**
* @return the last error message
*/
function ErrorMsg()
{
return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
}
/**
* @return the last error number. Normally 0 means no error.
*/
function ErrorNo()
{
return ($this->_errorMsg) ? -1 : 0;
}
/**
* @returns an array with the primary key columns in it.
*/
function MetaPrimaryKeys($table)
{
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, and FIRST_ROWS CBO hint for Oracle 8+
* 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 [rows] is the number of rows to get
* @param [inputarr] array of bind variables
* @param [arg3] is a private parameter only used by jlim
* @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,$arg3=false,$secs2cache=0)
{
if ($this->hasTop && $nrows > 0) {
// suggested by Reinhard Balling. Access requires top after distinct
if ($offset <= 0) {
$sql = preg_replace(
'/(^select[\\t\\n ]*(distinctrow|distinct)?)/i','\\1 top '.$nrows.' ',$sql);
if ($secs2cache>0) return $this->CacheExecute($secs2cache, $sql,$inputarr,$arg3);
else return $this->Execute($sql,$inputarr,$arg3);
} else {
$nrows += $offset;
$sql = preg_replace(
'/(^select[\\t\\n ]*(distinctrow|distinct)?)/i','\\1 top '.$nrows.' ',$sql);
$nrows = -1;
}
}
if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr,$arg3);
else $rs = &$this->Execute($sql,$inputarr,$arg3);
if ($rs && !$rs->EOF) {
return $this->_rs2rs($rs,$nrows,$offset);
}
//print_r($rs);
return $rs;
}
/**
* Convert 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)
{
$arr = &$rs->GetArrayLimit($nrows,$offset);
$flds = array();
for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++)
$flds[] = &$rs->FetchField($i);
$rs->Close();
$rs2 = new ADORecordSet_array();
$rs2->connection = &$this;
$rs2->InitArrayFields($arr,$flds);
return $rs2;
}
/**
* 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)
{
$ret = false;
$rs = $this->Execute($sql,$inputarr);
if ($rs) {
if (!$rs->EOF) $ret = reset($rs->fields);
$rs->Close();
}
return $ret;
}
/**
* Return all rows. Compat with PEAR DB
*
* @param sql SQL statement
* @param [inputarr] input bind array
*/
function &GetAll($sql,$inputarr=false)
{
$rs = $this->Execute($sql,$inputarr);
if (!$rs)
if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
else return false;
return $rs->GetArray();
}
/**
* 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)
{
$rs = $this->Execute($sql,$inputarr);
if ($rs) {
$arr = false;
if (!$rs->EOF) $arr = $rs->fields;
$rs->Close();
return $arr;
}
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.
* 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
* @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 [arg3] is a private parameter only used by jlim
* @return the recordset ($rs->databaseType == 'array')
*/
function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false)
{
return $this->SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
}
function CacheFlush($sql)
{
$f = $this->_gencachename($sql);
adodb_write_file($f,''); // is adodb_write_file needed?
@unlink($f);
}
function _gencachename($sql)
{
global $ADODB_CACHE_DIR;
return $ADODB_CACHE_DIR.'/adodb_'.md5($sql.$this->databaseType.$this->database.$this->user).'.cache';
}
/**
* Execute SQL, caching recordsets.
*
* @param secs2cache seconds to cache data, set to 0 to force query
* @param sql SQL statement to execute
* @param [inputarr] holds the input data to bind to
* @param [arg3] reserved for john lim for future use
* @return RecordSet or false
*/
function &CacheExecute($secs2cache,$sql,$inputarr=false,$arg3=false)
{
include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
// cannot cache if $inputarr set
if ($inputarr) return $this->Execute($sql, $inputarr, $arg3);
$md5file = $this->_gencachename($sql);
$err = '';
if ($secs2cache > 0)$rs = &csv2rs($md5file,$err,$secs2cache);
else {
$err='Timeout 1';
$rs = false;
}
if (!$rs) {
// no cached rs found
if ($this->debug) print " $md5file cache failure: $err ";
$rs = &$this->Execute($sql,$inputarr,$arg3);
if ($rs) {
$eof = $rs->EOF;
$rs = &$this->_rs2rs($rs);
$txt = &rs2csv($rs,false,$sql);
if (!adodb_write_file($md5file,$txt,$this->debug) && $this->debug) print ' Cache write error ';
if ($rs->EOF && !$eof) {
$rs = &csv2rs($md5file,$err);
$rs->connection = &$this; // Pablo suggestion
}
} else
@unlink($md5file);
} else {
// ok, set cached object found
$rs->connection = &$this; // Pablo suggestion
if ($this->debug){
$ttl = $rs->timeCreated + $secs2cache - time();
print " $md5file success ttl=$ttl ";
}
}
return $rs;
}
/**
* 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.
*
* "Jonathan Younger"
*/
function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false)
{
include_once(ADODB_DIR.'/adodb-lib.inc.php');
return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq);
}
/**
* 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)
{
include_once(ADODB_DIR.'/adodb-lib.inc.php');
return _adodb_getinsertsql($this,$rs,$arrFields,$magicq);
}
/**
* Usage:
* UpdateBlob('TABLE', 'COLUMN', $var, 'ID=1', 'BLOB');
*
* $blobtype supports 'BLOB' and 'CLOB'
*
* $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')
{
$sql = "UPDATE $table SET $column=".$this->qstr($val)." where $where";
$rs = $this->Execute($sql);
$rez = !empty($rs);
if ($rez) $rs->Close();
return $rez;
}
/**
* Usage:
* UpdateBlob('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 used - will probably remove in future
*/
function BlankRecordSet($id=false)
{
$rsclass = "ADORecordSet_".$this->databaseType;
return new $rsclass($id);
}
/**
* @meta contains the desired type, which could be...
* C for character. You will have to define the precision yourself.
* X for teXt. For unlimited character lengths.
* B for Binary
* F for floating point, with no need to define scale and precision
* N for decimal numbers, you will have to define the (scale, precision) yourself
* D for date
* T for timestamp
* L for logical/Boolean
* I for integer
* R for autoincrement counter/integer
* and if you want to use double-byte, add a 2 to the end, like C2 or X2.
*
*
* @return the actual type of the data or false if no such type available
*/
function ActualType($meta)
{
switch($meta) {
case 'C':
case 'X':
return 'VARCHAR';
case 'B':
case 'D':
case 'T':
case 'L':
case 'R':
case 'I':
case 'N':
return false;
}
}
/*
* Maximum size of C field
*/
function CharMax()
{
return 255; // make it conservative if not defined
}
/*
* Maximum size of X field
*/
function TextMax()
{
return 4000; // make it conservative if not defined
}
/**
* Close Connection
*/
function Close()
{
return $this->_close();
// "Simon Lee" reports that persistent connections need
// to be closed too!
//if ($this->_isPersistentConnection != true) return $this->_close();
//else return true;
}
/**
* 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
*
* @return true/false.
*/
function CommitTrans()
{ 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()
{return false;}
/**
* @return array of tables for current database.
*/
function &MetaTables()
{
if ($this->metaTablesSQL) {
$rs = $this->Execute($this->metaTablesSQL);
if ($rs === false) return false;
$arr = $rs->GetArray();
$arr2 = array();
for ($i=0; $i < sizeof($arr); $i++) {
$arr2[] = $arr[$i][0];
}
$rs->Close();
return $arr2;
}
return false;
}
/**
* List columns in a database as an array of ADOFieldObjects.
* See top of file for definition of object.
*
* @params table table name to query
*
* @return array of ADOFieldObjects for current table.
*/
function &MetaColumns($table)
{
global $ADODB_FETCH_MODE;
if (!empty($this->metaColumnsSQL)) {
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
$rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
$ADODB_FETCH_MODE = $save;
if ($rs === false) return false;
$retarr = array();
while (!$rs->EOF) { //print_r($rs->fields);
$fld = new ADOFieldObject();
$fld->name = $rs->fields[0];
$fld->type = $rs->fields[1];
$fld->max_length = $rs->fields[2];
$retarr[strtoupper($fld->name)] = $fld;
$rs->MoveNext();
}
$rs->Close();
return $retarr;
}
return false;
}
/**
* 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)
{
// note that we are limited to 1970 to 2038
if (empty($d) && $d !== 0) return 'null';
if (is_string($d))
if ($this->isoDates) return "'$d'";
else $d = ADORecordSet::UnixDate($d);
return 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';
if (is_string($ts))
if ($this->isoDates) return "'$ts'";
else $ts = ADORecordSet::UnixTimeStamp($ts);
return date($this->fmtTimeStamp,$ts);
}
/**
* Converts a timestamp "ts" to a string that the database can understand.
* 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)
{
$nofixquotes=false;
if (!$magic_quotes) {
if ($this->replaceQuote[0] == '\\'){
$s = 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 [arg3] is a private parameter only used by jlim
* @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, $arg3=false, $secs2cache=0)
{
include_once(ADODB_DIR.'/adodb-lib.inc.php');
return _adodb_pageexecute($this, $sql, $nrows, $page, $inputarr, $arg3, $secs2cache);
}
/**
* 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
* @param [arg3] is a private parameter only used by jlim
* @return the recordset ($rs->databaseType == 'array')
*/
function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false, $arg3=false) {
include_once(ADODB_DIR.'/adodb-lib.inc.php');
return _adodb_pageexecute($this, $sql, $nrows, $page, $inputarr, $arg3,$secs2cache);
}
} // 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 $EOF = true;
var $_numOfRows = 0;
var $fields = false;
var $connection = false;
function RowCount() {return 0;}
function RecordCount() {return 0;}
function Close(){return true;}
}
//==============================================================================
// CLASS ADORecordSet
//==============================================================================
/**
* 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 {
/*
* public variables
*/
var $dataProvider = "native";
var $fields = false; // holds the current row data
var $blobSize = 64; // any varchar/char field this size or greater is treated as a blob
// in other words, we use a text area for editting.
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;
var $_numOfFields = -1;
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;
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 */
/**
* 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;
$this->EOF = ($this->_fetch() === false);
} else
$this->EOF = true;
}
/**
* Generate a