diff --git a/lib/adodb/adodb-connection.inc.php b/lib/adodb/adodb-connection.inc.php
index 321aadac904..2cdf250feee 100644
--- a/lib/adodb/adodb-connection.inc.php
+++ b/lib/adodb/adodb-connection.inc.php
@@ -1,1787 +1,1787 @@
-_transOK = false;
- if ($thisConnection->_oldRaiseFn) {
- $fn = $thisConnection->_oldRaiseFn;
- $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
- }
- }
-
-
- /**
- * 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 = 256000; /// 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 $charSet=false; /// character set to use - only for interbase
- var $metaTablesSQL = '';
- //--
- 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 $upperCase = false; /// uppercase function to call for searching/where
- 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 $dbxDriver = 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 = ''; /// 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.
- 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;
-
- /**
- * Constructor
- */
- function ADOConnection()
- {
- die('Virtual Class -- cannot instantiate');
- }
-
- /**
- 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 _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 $HTTP_SERVER_VARS;
-
- if (defined('ADODB_OUTP')) {
- $fn = ADODB_OUTP;
- $fn($msg,$newline);
- return;
- }
-
- if ($newline) $msg .= " Insert_ID error Affected_Rows error Error=".$this->ErrorNo().' ';
- $first = true;
- foreach($fieldArray as $k => $v) {
- if ($has_autoinc && in_array($k,$keyCol)) continue; // skip autoinc col
-
- if ($first) {
- $first = false;
- $iCols = "$k";
- $iVals = "$v";
- } else {
- $iCols .= ",$k";
- $iVals .= ",$v";
- }
- }
- $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)";
- $rs = $this->Execute($insert);
- return ($rs) ? 2 : 0;
- }
-
-
- /**
- * 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
- * @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)
- {
- if (!is_numeric($secs2cache)) {
- if ($sql === false) $sql = -1;
- if ($offset == -1) $offset = false;
- // sql, nrows, offset,inputarr,arg3
- return $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$inputarr,$this->cacheSecs);
- } else {
- if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()");
- return $this->SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
- }
- }
-
- /**
- * 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 (strpos(strtoupper(PHP_OS),'WIN') !== false) {
- $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
- } else {
- $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/??/adodb_*.cache';
- // old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`';
- }
- if ($this->debug) {
- ADOConnection::outp( "CacheFlush: $cmd Insert_ID error Affected_Rows error Error=".$this->ErrorNo().' '; */
+ $first = true;
+ foreach($fieldArray as $k => $v) {
+ if ($has_autoinc && in_array($k,$keyCol)) continue; /* skip autoinc col */
+
+ if ($first) {
+ $first = false;
+ $iCols = "$k";
+ $iVals = "$v";
+ } else {
+ $iCols .= ",$k";
+ $iVals .= ",$v";
+ }
+ }
+ $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)";
+ $rs = $this->Execute($insert);
+ return ($rs) ? 2 : 0;
+ }
+
+
+ /**
+ * 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
+ * @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)
+ {
+ if (!is_numeric($secs2cache)) {
+ if ($sql === false) $sql = -1;
+ if ($offset == -1) $offset = false;
+ /* sql, nrows, offset,inputarr,arg3 */
+ return $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$inputarr,$this->cacheSecs);
+ } else {
+ if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()");
+ return $this->SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
+ }
+ }
+
+ /**
+ * 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 (strpos(strtoupper(PHP_OS),'WIN') !== false) {
+ $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
+ } else {
+ $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/??/adodb_*.cache';
+ /* old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`'; */
+ }
+ if ($this->debug) {
+ ADOConnection::outp( "CacheFlush: $cmd \$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']} Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().' \$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']} \$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']} Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().' \$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}
\n";
-
- if (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT'])) echo $msg;
- else echo strip_tags($msg);
- flush();
- }
-
- /**
- * 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 ($fn = $this->raiseErrorFn) {
- if ($forceNew) {
- if ($this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
- } else {
- 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,$this);
- } else {
- if ($forceNew) {
- if ($this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
- } else {
- if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
- }
- }
- if ($this->debug) ADOConnection::outp( $this->host.': '.$this->ErrorMsg());
-
- return false;
- }
-
- 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 ($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,$this);
- } else
- if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
-
- if ($this->debug) ADOConnection::outp( $this->host.': '.$this->ErrorMsg());
-
- return false;
- }
-
- // 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)
- {
- return $this->Prepare($sql);
- }
-
- /**
- * PEAR DB Compat
- */
- function Quote($s)
- {
- return $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)
- {
- $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();
- }
-
- /*
- 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.
- b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.
- 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) $this->CommitTrans();
- else $this->RollbackTrans();
-
- return $this->_transOK;
- }
-
- /*
- At the end of a StartTrans/CompleteTrans block, perform a rollback.
- */
- function FailTrans()
- {
- if ($this->debug && $this->transOff == 0) {
- ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
- }
- $this->_transOK = 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.
- * @param [arg3] reserved for john lim for future use
- * @return RecordSet or false
- */
- function &Execute($sql,$inputarr=false,$arg3=false)
- {
- if ($this->fnExecute) {
- $fn = $this->fnExecute;
- $fn($this,$sql,$inputarr);
- }
- if (!$this->_bindInputArray && $inputarr) {
- $sqlarr = explode('?',$sql);
- $sql = '';
- $i = 0;
- foreach($inputarr as $v) {
-
- $sql .= $sqlarr[$i];
- // from Ron Baldwin
\n($this->databaseType): ".htmlspecialchars($sqlTxt)." $ss\n
\n",false);
- else
- ADOConnection::outp( "=----\n($this->databaseType): ".($sqlTxt)." \n-----\n",false);
- flush();
-
- $this->_queryID = $this->_query($sql,$inputarr,$arg3);
-
- /*
- Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
- because ErrorNo() calls Execute('SELECT @ERROR'), causing recure
- */
- if ($this->databaseType == 'mssql') {
- // ErrorNo is a slow function call in mssql, and not reliable
- // in PHP 4.0.6
- if($emsg = $this->ErrorMsg()) {
- $err = $this->ErrorNo();
- if ($err) {
- ADOConnection::outp($err.': '.$emsg);
- flush();
- }
- }
- } else
- if (!$this->_queryID) {
- $e = $this->ErrorNo();
- $m = $this->ErrorMsg();
- ADOConnection::outp($e .': '. $m );
- flush();
- }
- } else {
- // non-debug version of query
-
- $this->_queryID =@$this->_query($sql,$inputarr,$arg3);
-
- }
- // error handling if query fails
- if ($this->_queryID === false) {
- $fn = $this->raiseErrorFn;
- if ($fn) {
- $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
- }
- return false;
- } else if ($this->_queryID === true) {
- // return simplified empty recordset for inserts/updates/deletes with lower overhead
- $rs = new ADORecordSet_empty();
- return $rs;
- }
-
- // return real recordset from select statement
- $rsclass = "ADORecordSet_".$this->databaseType;
- $rs = new $rsclass($this->_queryID,$this->fetchMode); // &new not supported by older PHP versions
- $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)
- {
- 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);
- $rs = @$this->Execute($getnext);
- if (!$rs) {
- $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;
- }
-
- /**
- * @return the last inserted ID. Not all databases support this.
- */
- function Insert_ID()
- {
- if ($this->hasInsertID) return $this->_insertid();
- if ($this->debug) ADOConnection::outp( '\n", system($cmd),"
");
- } else {
- exec($cmd);
- }
- return;
- }
- $f = $this->_gencachename($sql.serialize($inputarr),false);
- adodb_write_file($f,''); // is adodb_write_file needed?
- @unlink($f);
- }
-
- /**
- * Private function to generate filename for caching.
- * Filename is generated based on:
- *
- * - sql statement
- * - database type (oci8, ibase, ifx, etc)
- * - database name
- * - userid
- *
- * 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;
-
- $m = md5($sql.$this->databaseType.$this->database.$this->user);
- $dir = $ADODB_CACHE_DIR.'/'.substr($m,0,2);
- if ($createdir && !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
- * @param [arg3] reserved for john lim for future use
- * @return RecordSet or false
- */
- function &CacheExecute($secs2cache,$sql=false,$inputarr=false,$arg3=false)
- {
- if (!is_numeric($secs2cache)) {
- $arg3 = $inputarr;
- $inputarr = $sql;
- $sql = $secs2cache;
- $secs2cache = $this->cacheSecs;
- }
- 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->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 :(");
- }
- ADOConnection::outp( " $md5file cache failure: $err (see sql below)");
- }
- $rs = &$this->Execute($sql,$inputarr,$arg3);
- 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 {
- if ($this->fnCacheExecute) {
- $fn = $this->fnCacheExecute;
- $fn($this, $secs2cache, $sql, $inputarr);
- }
- // ok, set cached object found
- $rs->connection = &$this; // Pablo suggestion
- if ($this->debug){
- global $HTTP_SERVER_VARS;
-
- $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
- $ttl = $rs->timeCreated + $secs2cache - time();
- $s = is_array($sql) ? $sql[0] : $sql;
- if ($inBrowser) $s = ''.htmlspecialchars($s).'';
-
- ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
- }
- }
- 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 and sql should only
- * be a simple select stmt with no groupby/orderby/limit
- *
- * "Jonathan Younger"
\n";
+
+ if (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT'])) echo $msg;
+ else echo strip_tags($msg);
+ flush();
+ }
+
+ /**
+ * 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 ($fn = $this->raiseErrorFn) {
+ if ($forceNew) {
+ if ($this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
+ } else {
+ 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,$this);
+ } else {
+ if ($forceNew) {
+ if ($this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
+ } else {
+ if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
+ }
+ }
+ if ($this->debug) ADOConnection::outp( $this->host.': '.$this->ErrorMsg());
+
+ return false;
+ }
+
+ 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 ($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,$this);
+ } else
+ if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
+
+ if ($this->debug) ADOConnection::outp( $this->host.': '.$this->ErrorMsg());
+
+ return false;
+ }
+
+ /* 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)
+ {
+ return $this->Prepare($sql);
+ }
+
+ /**
+ * PEAR DB Compat
+ */
+ function Quote($s)
+ {
+ return $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)
+ {
+ $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();
+ }
+
+ /*
+ 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.
+ b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.
+ 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) $this->CommitTrans();
+ else $this->RollbackTrans();
+
+ return $this->_transOK;
+ }
+
+ /*
+ At the end of a StartTrans/CompleteTrans block, perform a rollback.
+ */
+ function FailTrans()
+ {
+ if ($this->debug && $this->transOff == 0) {
+ ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
+ }
+ $this->_transOK = 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.
+ * @param [arg3] reserved for john lim for future use
+ * @return RecordSet or false
+ */
+ function &Execute($sql,$inputarr=false,$arg3=false)
+ {
+ if ($this->fnExecute) {
+ $fn = $this->fnExecute;
+ $fn($this,$sql,$inputarr);
+ }
+ if (!$this->_bindInputArray && $inputarr) {
+ $sqlarr = explode('?',$sql);
+ $sql = '';
+ $i = 0;
+ foreach($inputarr as $v) {
+
+ $sql .= $sqlarr[$i];
+ /* from Ron Baldwin
\n($this->databaseType): ".htmlspecialchars($sqlTxt)." $ss\n
\n",false);
+ else
+ ADOConnection::outp( "=----\n($this->databaseType): ".($sqlTxt)." \n-----\n",false);
+ flush();
+
+ $this->_queryID = $this->_query($sql,$inputarr,$arg3);
+
+ /*
+ Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
+ because ErrorNo() calls Execute('SELECT @ERROR'), causing recure
+ */
+ if ($this->databaseType == 'mssql') {
+ /* ErrorNo is a slow function call in mssql, and not reliable */
+ /* in PHP 4.0.6 */
+ if($emsg = $this->ErrorMsg()) {
+ $err = $this->ErrorNo();
+ if ($err) {
+ ADOConnection::outp($err.': '.$emsg);
+ flush();
+ }
+ }
+ } else
+ if (!$this->_queryID) {
+ $e = $this->ErrorNo();
+ $m = $this->ErrorMsg();
+ ADOConnection::outp($e .': '. $m );
+ flush();
+ }
+ } else {
+ /* non-debug version of query */
+
+ $this->_queryID =@$this->_query($sql,$inputarr,$arg3);
+
+ }
+ /* error handling if query fails */
+ if ($this->_queryID === false) {
+ $fn = $this->raiseErrorFn;
+ if ($fn) {
+ $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
+ }
+ return false;
+ } else if ($this->_queryID === true) {
+ /* return simplified empty recordset for inserts/updates/deletes with lower overhead */
+ $rs = new ADORecordSet_empty();
+ return $rs;
+ }
+
+ /* return real recordset from select statement */
+ $rsclass = "ADORecordSet_".$this->databaseType;
+ $rs = new $rsclass($this->_queryID,$this->fetchMode); /* &new not supported by older PHP versions */
+ $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)
+ {
+ 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);
+ $rs = @$this->Execute($getnext);
+ if (!$rs) {
+ $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;
+ }
+
+ /**
+ * @return the last inserted ID. Not all databases support this.
+ */
+ function Insert_ID()
+ {
+ if ($this->hasInsertID) return $this->_insertid();
+ if ($this->debug) ADOConnection::outp( '\n", system($cmd),"
");
+ } else {
+ exec($cmd);
+ }
+ return;
+ }
+ $f = $this->_gencachename($sql.serialize($inputarr),false);
+ adodb_write_file($f,''); /* is adodb_write_file needed? */
+ @unlink($f);
+ }
+
+ /**
+ * Private function to generate filename for caching.
+ * Filename is generated based on:
+ *
+ * - sql statement
+ * - database type (oci8, ibase, ifx, etc)
+ * - database name
+ * - userid
+ *
+ * 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;
+
+ $m = md5($sql.$this->databaseType.$this->database.$this->user);
+ $dir = $ADODB_CACHE_DIR.'/'.substr($m,0,2);
+ if ($createdir && !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
+ * @param [arg3] reserved for john lim for future use
+ * @return RecordSet or false
+ */
+ function &CacheExecute($secs2cache,$sql=false,$inputarr=false,$arg3=false)
+ {
+ if (!is_numeric($secs2cache)) {
+ $arg3 = $inputarr;
+ $inputarr = $sql;
+ $sql = $secs2cache;
+ $secs2cache = $this->cacheSecs;
+ }
+ 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->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 :(");
+ }
+ ADOConnection::outp( " $md5file cache failure: $err (see sql below)");
+ }
+ $rs = &$this->Execute($sql,$inputarr,$arg3);
+ 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 {
+ if ($this->fnCacheExecute) {
+ $fn = $this->fnCacheExecute;
+ $fn($this, $secs2cache, $sql, $inputarr);
+ }
+ /* ok, set cached object found */
+ $rs->connection = &$this; /* Pablo suggestion */
+ if ($this->debug){
+ global $HTTP_SERVER_VARS;
+
+ $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
+ $ttl = $rs->timeCreated + $secs2cache - time();
+ $s = is_array($sql) ? $sql[0] : $sql;
+ if ($inBrowser) $s = ''.htmlspecialchars($s).'';
+
+ ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
+ }
+ }
+ 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 and sql should only
+ * be a simple select stmt with no groupby/orderby/limit
+ *
+ * "Jonathan Younger" Session Error: PHP.INI setting session.gc_maxlifetimenot set: $ADODB_SESS_LIFE
";
- $ADODB_SESS_LIFE=1440;
-}
-
-function adodb_sess_open($save_path, $session_name)
-{
-GLOBAL $ADODB_SESSION_CONNECT,
- $ADODB_SESSION_DRIVER,
- $ADODB_SESSION_USER,
- $ADODB_SESSION_PWD,
- $ADODB_SESSION_DB,
- $ADODB_SESS_CONN,
- $ADODB_SESS_DEBUG;
-
- $ADODB_SESS_INSERT = false;
-
- if (isset($ADODB_SESS_CONN)) return true;
-
- $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);
- if (!empty($ADODB_SESS_DEBUG)) {
- $ADODB_SESS_CONN->debug = true;
- print" conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ";
- }
- return $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,
- $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
-
-}
-
-function adodb_sess_close()
-{
-global $ADODB_SESS_CONN;
-
- if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();
- return true;
-}
-
-function adodb_sess_read($key)
-{
-$Crypt = new MD5Crypt;
-global $ADODB_SESS_CONN,$ADODB_SESS_INSERT,$ADODB_SESSION_TBL;
- $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());
- if ($rs) {
- if ($rs->EOF) {
- $ADODB_SESS_INSERT = true;
- $v = '';
- } else {
- // Decrypt session data
- $v = rawurldecode($Crypt->Decrypt(reset($rs->fields), ADODB_Session_Key()));
- }
- $rs->Close();
- return $v;
- }
- else $ADODB_SESS_INSERT = true;
-
- return '';
-}
-
-function adodb_sess_write($key, $val)
-{
-$Crypt = new MD5Crypt;
- global $ADODB_SESS_INSERT,$ADODB_SESS_CONN, $ADODB_SESS_LIFE, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
-
- $expiry = time() + $ADODB_SESS_LIFE;
-
- // encrypt session data..
- $val = $Crypt->Encrypt(rawurlencode($val), ADODB_Session_Key());
-
- $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);
- if ($ADODB_SESSION_EXPIRE_NOTIFY) {
- $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);
- global $$var;
- $arr['expireref'] = $$var;
- }
- $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,
- $arr,
- 'sesskey',$autoQuote = true);
-
- if (!$rs) {
- ADOConnection::outp( 'Session Error: PHP.INI setting session.gc_maxlifetimenot set: $ADODB_SESS_LIFE
"; */
+ $ADODB_SESS_LIFE=1440;
+}
+
+function adodb_sess_open($save_path, $session_name)
+{
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_DEBUG;
+
+ $ADODB_SESS_INSERT = false;
+
+ if (isset($ADODB_SESS_CONN)) return true;
+
+ $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);
+ if (!empty($ADODB_SESS_DEBUG)) {
+ $ADODB_SESS_CONN->debug = true;
+ print" conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ";
+ }
+ return $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+
+}
+
+function adodb_sess_close()
+{
+global $ADODB_SESS_CONN;
+
+ if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();
+ return true;
+}
+
+function adodb_sess_read($key)
+{
+$Crypt = new MD5Crypt;
+global $ADODB_SESS_CONN,$ADODB_SESS_INSERT,$ADODB_SESSION_TBL;
+ $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());
+ if ($rs) {
+ if ($rs->EOF) {
+ $ADODB_SESS_INSERT = true;
+ $v = '';
+ } else {
+ /* Decrypt session data */
+ $v = rawurldecode($Crypt->Decrypt(reset($rs->fields), ADODB_Session_Key()));
+ }
+ $rs->Close();
+ return $v;
+ }
+ else $ADODB_SESS_INSERT = true;
+
+ return '';
+}
+
+function adodb_sess_write($key, $val)
+{
+$Crypt = new MD5Crypt;
+ global $ADODB_SESS_INSERT,$ADODB_SESS_CONN, $ADODB_SESS_LIFE, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ $expiry = time() + $ADODB_SESS_LIFE;
+
+ /* encrypt session data.. */
+ $val = $Crypt->Encrypt(rawurlencode($val), ADODB_Session_Key());
+
+ $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ global $$var;
+ $arr['expireref'] = $$var;
+ }
+ $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,
+ $arr,
+ 'sesskey',$autoQuote = true);
+
+ if (!$rs) {
+ ADOConnection::outp( '
";
- //print_r($text);
- //if (strlen($text) == 0) $arr = array();
- //else
- $arr = unserialize($text);
- //print_r($arr);
- if (!is_array($arr)) {
- $err = "Recordset had unexpected EOF (in serialized recordset)";
- if (get_magic_quotes_runtime()) $err .= ". Magic Quotes Runtime should be disabled!";
- return false;
- }
- $rs = new ADORecordSet_array();
- $rs->timeCreated = $ttl;
- $rs->InitArrayFields($arr,$flds);
- return $rs;
- }
-
+FieldCount() : 0;
+
+ if ($sql) $sql = urlencode($sql);
+ /* metadata setup */
+
+ if ($max <= 0 || $rs->dataProvider == 'empty') { /* is insert/update/delete */
+ if (is_object($conn)) {
+ $sql .= ','.$conn->Affected_Rows();
+ $sql .= ','.$conn->Insert_ID();
+ } else
+ $sql .= ',,';
+
+ $text = "====-1,0,$sql\n";
+ return $text;
+ } else {
+ $tt = ($rs->timeCreated) ? $rs->timeCreated : time();
+ $line = "====0,$tt,$sql\n";
+ }
+ /* column definitions */
+ for($i=0; $i < $max; $i++) {
+ $o = $rs->FetchField($i);
+ $line .= urlencode($o->name).':'.$rs->MetaType($o->type,$o->max_length).":$o->max_length,";
+ }
+ $text = substr($line,0,strlen($line)-1)."\n";
+
+
+ /* get data */
+ if ($rs->databaseType == 'array') {
+ $text .= serialize($rs->_array);
+ } else {
+ $rows = array();
+ while (!$rs->EOF) {
+ $rows[] = $rs->fields;
+ $rs->MoveNext();
+ }
+ $text .= serialize($rows);
+ }
+ $rs->MoveFirst();
+ return $text;
+ }
+
+
+/**
+* Open CSV file and convert it into Data.
+*
+* @param url file/ftp/http url
+* @param err returns the error message
+* @param timeout dispose if recordset has been alive for $timeout secs
+*
+* @return recordset, or false if error occured. If no
+* error occurred in sql INSERT/UPDATE/DELETE,
+* empty recordset is returned
+*/
+ function &csv2rs($url,&$err,$timeout=0)
+ {
+ $fp = @fopen($url,'r');
+ $err = false;
+ if (!$fp) {
+ $err = $url.'file/URL not found';
+ return false;
+ }
+ flock($fp, LOCK_SH);
+ $arr = array();
+ $ttl = 0;
+
+ if ($meta = fgetcsv ($fp, 32000, ",")) {
+ /* check if error message */
+ if (substr($meta[0],0,4) === '****') {
+ $err = trim(substr($meta[0],4,1024));
+ fclose($fp);
+ return false;
+ }
+ /* check for meta data */
+ /* $meta[0] is -1 means return an empty recordset */
+ /* $meta[1] contains a time */
+
+ if (substr($meta[0],0,4) === '====') {
+
+ if ($meta[0] == "====-1") {
+ if (sizeof($meta) < 5) {
+ $err = "Corrupt first line for format -1";
+ fclose($fp);
+ return false;
+ }
+ fclose($fp);
+
+ if ($timeout > 0) {
+ $err = " Illegal Timeout $timeout ";
+ return false;
+ }
+ $rs->fields = array();
+ $rs->timeCreated = $meta[1];
+ $rs = new ADORecordSet($val=true);
+ $rs->EOF = true;
+ $rs->_numOfFields=0;
+ $rs->sql = urldecode($meta[2]);
+ $rs->affectedrows = (integer)$meta[3];
+ $rs->insertid = $meta[4];
+ return $rs;
+ }
+ # Under high volume loads, we want only 1 thread/process to _write_file
+ # so that we don't have 50 processes queueing to write the same data.
+ # Would require probabilistic blocking write
+ #
+ # -2 sec before timeout, give processes 1/16 chance of writing to file with blocking io
+ # -1 sec after timeout give processes 1/4 chance of writing with blocking
+ # +0 sec after timeout, give processes 100% chance writing with blocking
+ if (sizeof($meta) > 1) {
+ if($timeout >0){
+ $tdiff = $meta[1]+$timeout - time();
+ if ($tdiff <= 2) {
+ switch($tdiff) {
+ case 2:
+ if ((rand() & 15) == 0) {
+ fclose($fp);
+ $err = "Timeout 2";
+ return false;
+ }
+ break;
+ case 1:
+ if ((rand() & 3) == 0) {
+ fclose($fp);
+ $err = "Timeout 1";
+ return false;
+ }
+ break;
+ default:
+ fclose($fp);
+ $err = "Timeout 0";
+ return false;
+ } /* switch */
+
+ } /* if check flush cache */
+ }/* (timeout>0) */
+ $ttl = $meta[1];
+ }
+ $meta = false;
+ $meta = fgetcsv($fp, 16000, ",");
+ if (!$meta) {
+ fclose($fp);
+ $err = "Unexpected EOF 1";
+ return false;
+ }
+ }
+
+ /* Get Column definitions */
+ $flds = array();
+ foreach($meta as $o) {
+ $o2 = explode(':',$o);
+ if (sizeof($o2)!=3) {
+ $arr[] = $meta;
+ $flds = false;
+ break;
+ }
+ $fld = new ADOFieldObject();
+ $fld->name = urldecode($o2[0]);
+ $fld->type = $o2[1];
+ $fld->max_length = $o2[2];
+ $flds[] = $fld;
+ }
+ } else {
+ fclose($fp);
+ $err = "Recordset had unexpected EOF 2";
+ return false;
+ }
+
+ /* slurp in the data */
+ $MAXSIZE = 128000;
+ $text = fread($fp,$MAXSIZE);
+ $cnt = 1;
+ while (strlen($text) == $MAXSIZE*$cnt) {
+ $text .= fread($fp,$MAXSIZE);
+ $cnt += 1;
+ }
+
+ fclose($fp);
+ $arr = @unserialize($text);
+
+ /* var_dump($arr); */
+ if (!is_array($arr)) {
+ $err = "Recordset had unexpected EOF (in serialized recordset)";
+ if (get_magic_quotes_runtime()) $err .= ". Magic Quotes Runtime should be disabled!";
+ return false;
+ }
+ $rs = new ADORecordSet_array();
+ $rs->timeCreated = $ttl;
+ $rs->InitArrayFields($arr,$flds);
+ return $rs;
+ }
?>
\ No newline at end of file
diff --git a/lib/adodb/adodb-datadict.inc.php b/lib/adodb/adodb-datadict.inc.php
index 2ddf79d3071..c5a19df5c61 100644
--- a/lib/adodb/adodb-datadict.inc.php
+++ b/lib/adodb/adodb-datadict.inc.php
@@ -1,332 +1,582 @@
-connection->MetaTables();
- }
-
- function MetaColumns($tab)
- {
- return $this->connection->MetaColumns($tab);
- }
-
- function MetaPrimaryKeys($tab,$owner=false,$intkey=false)
- {
- return $this->connection->MetaPrimaryKeys($tab.$owner,$intkey);
- }
-
- function MetaType($t,$len=-1,$fieldobj=false)
- {
- return ADORecordSet::MetaType($t,$len,$fieldobj);
- }
-
- // Executes the sql array returned by GetTableSQL and GetIndexSQL
- function ExecuteSQLArray($sql, $continueOnError = true)
- {
- $rez = 2;
- $conn = &$this->connection;
- foreach($sql as $line) {
- $ok = $conn->Execute($line);
- if (!$ok) {
- if ($this->debug) ADOConnection::outp($conn->ErrorMsg());
- if (!$continueOnError) return 0;
- $rez = 1;
- }
- }
- return 2;
- }
-
- /*
- Returns the actual type given a character code.
-
- C: varchar
- X: CLOB (character large object) or largest varchar size if CLOB is not supported
- C2: Multibyte varchar
- X2: Multibyte CLOB
-
- B: BLOB (binary large object)
-
- D: Date
- T: Date-time
- L: Integer field suitable for storing booleans (0 or 1)
- I: Integer
- F: Floating point number
- N: Numeric or decimal number
- */
-
- function ActualType($meta)
- {
- return $meta;
- }
-
- function CreateDatabase($dbname,$options=false)
- {
- $options = $this->_Options($options);
- $s = 'CREATE DATABASE '.$dbname;
- if (isset($options[$this->upperName])) $s .= ' '.$options[$this->upperName];
- $sql[] = $s;
- return $sql;
- }
-
- /*
- Generates the SQL to create index. Returns an array of sql strings.
- */
- function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false)
- {
- if ($this->schema) $tabname = $this->schema.'.'.$tabname;
- return $this->_IndexSQL($idxname, $tabname, $flds, $this->_Options($idxoptions));
- }
-
- function SetSchema($schema)
- {
- $this->schema = $schema;
- }
-
- function AddColumnSQL($tabname, $flds)
- {
- if ($this->schema) $tabname = $this->schema.'.'.$tabname;
- $sql = array();
- list($lines,$pkey) = $this->_GenFields($flds);
- foreach($lines as $v) {
- $sql[] = "ALTER TABLE $tabname $this->addCol $v";
- }
- return $sql;
- }
-
- function AlterColumnSQL($tabname, $flds)
- {
- if ($this->schema) $tabname = $this->schema.'.'.$tabname;
- $sql = array();
- list($lines,$pkey) = $this->_GenFields($flds);
-
- foreach($lines as $v) {
- $sql[] = "ALTER TABLE $tabname $this->alterCol $v";
- }
- return $sql;
- }
-
- function DropColumnSQL($tabname, $flds)
- {
- if ($this->schema) $tabname = $this->schema.'.'.$tabname;
- if (!is_array($flds)) $flds = explode(',',$flds);
- $sql = array();
- foreach($flds as $v) {
- $sql[] = "ALTER TABLE $tabname $this->dropCol $v";
- }
- return $sql;
- }
-
- function DropTableSQL($tabname)
- {
- if ($this->schema) $tabname = $this->schema.'.'.$tabname;
- $sql[] = sprintf($this->dropTable,$tabname);
- return $sql;
- }
-
- /*
- Generate the SQL to create table. Returns an array of sql strings.
- */
- function CreateTableSQL($tabname, $flds, $tableoptions=false)
- {
- if (!$tableoptions) $tableoptions = array();
-
- list($lines,$pkey) = $this->_GenFields($flds);
-
- $taboptions = $this->_Options($tableoptions);
- if ($this->schema) $tabname = $this->schema.'.'.$tabname;
- $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
-
- $tsql = $this->_Triggers($tabname,$taboptions);
- foreach($tsql as $s) $sql[] = $s;
-
- return $sql;
- }
-
- function _GenFields($flds)
- {
- $lines = array();
- $pkey = array();
- foreach($flds as $fld) {
- $fld = _array_change_key_case($fld);
-
- $fname = false;
- $fdefault = false;
- $fautoinc = false;
- $ftype = false;
- $fsize = false;
- $fprec = false;
- $fprimary = false;
- $fnoquote = false;
- $fdefts = false;
- $fdefdate = false;
- $fconstraint = false;
- $fnotnull = false;
- //-----------------
- // Parse attributes
- foreach($fld as $attr => $v) {
- if ($attr == 2 && is_numeric($v)) $attr = 'SIZE';
- else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr = strtoupper($v);
-
- switch($attr) {
- case '0':
- case 'NAME': $fname = $v; break;
- case '1':
- case 'TYPE': $ty = $v; $ftype = $this->ActualType(strtoupper($v)); break;
- case 'SIZE': $dotat = strpos($v,'.');
- if ($dotat === false) $fsize = $v;
- else {
- $fsize = substr($v,0,$dotat);
- $fprec = substr($v,$dotat+1);
- }
- break;
- case 'AUTOINCREMENT':
- case 'AUTO': $fautoinc = true; $fnotnull = true; break;
- case 'KEY':
- case 'PRIMARY': $fprimary = $v; $fnotnull = true; break;
- case 'DEFAULT': $fdefault = $v; break;
- case 'NOTNULL': $fnotnull = $v; break;
- case 'NOQUOTE': $fnoquote = $v; break;
- case 'DEFDATE': $fdefdate = $v; break;
- case 'DEFTIMESTAMP': $fdefts = $v; break;
- case 'CONSTRAINT': $fconstraint = $v; break;
- } //switch
- } // foreach $fld
-
- //--------------------
- // VALIDATE FIELD INFO
- if (!strlen($fname)) {
- if ($this->debug) ADOConnection::outp("Undefined NAME");
- return false;
- }
-
- if (!strlen($ftype)) {
- if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'");
- return false;
- } else
- $ftype = strtoupper($ftype);
-
- $ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);
-
- if ($fprimary) $pkey[] = $fname;
-
- // some databases do not allow blobs to have defaults
- if ($ty == 'X') $fdefault = false;
-
- //--------------------
- // CONSTRUCT FIELD SQL
- if ($fdefts) {
- if (substr($this->connection->databaseType,0,5) == 'mysql') {
- $ftype = 'TIMESTAMP';
- } else {
- $fdefault = $this->connection->sysTimeStamp;
- }
- } else if ($fdefdate) {
- if (substr($this->connection->databaseType,0,5) == 'mysql') {
- $ftype = 'TIMESTAMP';
- } else {
- $fdefault = $this->connection->sysDate;
- }
- } else if (strlen($fdefault) && !$fnoquote)
- if ($ty == 'C' or $ty == 'X' or
- ( substr($fdefault,0,1) != "'" && !is_numeric($fdefault)))
- if (substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ')
- $fdefault = trim($fdefault);
- else
- $fdefault = $this->connection->qstr($fdefault);
- $suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint);
-
- $fname = str_pad($fname,16);
- $lines[] = "$fname $ftype$suffix";
-
- } // foreach $flds
-
-
- return array($lines,$pkey);
- }
- /*
- GENERATE THE SIZE PART OF THE DATATYPE
- $ftype is the actual type
- $ty is the type defined originally in the DDL
- */
- function _GetSize($ftype, $ty, $fsize, $fprec)
- {
- if (strlen($fsize) && $ty != 'X' && $ty != 'B') {
- $ftype .= "(".$fsize;
- if ($fprec) $ftype .= ",".$fprec;
- $ftype .= ')';
- }
- return $ftype;
- }
-
-
- function _TableSQL($tabname,$lines,$pkey,$tableoptions)
- {
- $sql = array();
-
- if (isset($tableoptions['REPLACE'])) $sql[] = sprintf($this->dropTable,$tabname);
- $s = "CREATE TABLE $tabname (\n";
- $s .= implode(",\n", $lines);
- if (sizeof($pkey)>0) {
- $s .= ",\n PRIMARY KEY (";
- $s .= implode(", ",$pkey).")";
- }
- if (isset($tableoptions['CONSTRAINTS']))
- $s .= "\n".$tableoptions['CONSTRAINTS'];
-
- if (isset($tableoptions[$this->upperName.'_CONSTRAINTS']))
- $s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
-
- $s .= "\n)";
- if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName];
- $sql[] = $s;
-
- return $sql;
- }
-
- /*
- GENERATE TRIGGERS IF NEEDED
- used when table has auto-incrementing field that is emulated using triggers
- */
- function _Triggers($tabname,$taboptions)
- {
- return array();
- }
-
- /*
- Sanitize options, so that array elements with no keys are promoted to keys
- */
- function _Options($opts)
- {
- if (!is_array($opts)) return array();
- $newopts = array();
- foreach($opts as $k => $v) {
- if (is_numeric($k)) $newopts[strtoupper($v)] = $v;
- else $newopts[strtoupper($k)] = $v;
- }
- return $newopts;
- }
-}
+$str
"; +print_r($a); +print ""; +} +/* Lens_ParseTest(); */ + +/** + Parse arguments, treat "text" (text) and 'text' as quotation marks. + To escape, use "" or '' or )) + + @param endstmtchar Character that indicates end of statement + @param tokenchars Include the following characters in tokens apart from A-Z and 0-9 + @returns 2 dimensional array containing parsed tokens. +*/ +function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-') +{ + $pos = 0; + $intoken = false; + $stmtno = 0; + $endquote = false; + $tokens = array(); + $tokens[$stmtno] = array(); + $max = strlen($args); + $quoted = false; + + while ($pos < $max) { + $ch = substr($args,$pos,1); + switch($ch) { + case ' ': + case "\t": + case "\n": + case "\r": + if (!$quoted) { + if ($intoken) { + $intoken = false; + $tokens[$stmtno][] = implode('',$tokarr); + } + break; + } + + $tokarr[] = $ch; + break; + + case '(': + case ')': + case '"': + case "'": + + if ($intoken) { + if (empty($endquote)) { + $tokens[$stmtno][] = implode('',$tokarr); + if ($ch == '(') $endquote = ')'; + else $endquote = $ch; + $quoted = true; + $intoken = true; + $tokarr = array(); + } else if ($endquote == $ch) { + $ch2 = substr($args,$pos+1,1); + if ($ch2 == $endquote) { + $pos += 1; + $tokarr[] = $ch2; + } else { + $quoted = false; + $intoken = false; + $tokens[$stmtno][] = implode('',$tokarr); + $endquote = ''; + } + } else + $tokarr[] = $ch; + + }else { + + if ($ch == '(') $endquote = ')'; + else $endquote = $ch; + $quoted = true; + $intoken = true; + $tokarr = array(); + } + break; + + default: + + if (!$intoken) { + if ($ch == $endstmtchar) { + $stmtno += 1; + $tokens[$stmtno] = array(); + break; + } + + $intoken = true; + $quoted = false; + $endquote = false; + $tokarr = array(); + + } + + if ($quoted) $tokarr[] = $ch; + else if (ctype_alnum($ch) || strpos($tokenchars,$ch) !== false) $tokarr[] = $ch; + else { + if ($ch == $endstmtchar) { + $tokens[$stmtno][] = implode('',$tokarr); + $stmtno += 1; + $tokens[$stmtno] = array(); + $intoken = false; + $tokarr = array(); + break; + } + $tokens[$stmtno][] = implode('',$tokarr); + $tokens[$stmtno][] = $ch; + $intoken = false; + } + } + $pos += 1; + } + + return $tokens; +} + + +class ADODB_DataDict { + var $connection; + var $debug = false; + var $dropTable = "DROP TABLE %s"; + var $addCol = ' ADD'; + var $alterCol = ' ALTER COLUMN'; + var $dropCol = ' DROP COLUMN'; + var $schema = false; + var $serverInfo = array(); + var $autoIncrement = false; + var $dataProvider; + 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 editting. */ + + function GetCommentSQL($table,$col) + { + return false; + } + + function SetCommentSQL($table,$col,$cmt) + { + return false; + } + + function &MetaTables() + { + return $this->connection->MetaTables(); + } + + function &MetaColumns($tab) + { + return $this->connection->MetaColumns($tab); + } + + function &MetaPrimaryKeys($tab,$owner=false,$intkey=false) + { + return $this->connection->MetaPrimaryKeys($tab.$owner,$intkey); + } + + function MetaType($t,$len=-1,$fieldobj=false) + { + return ADORecordSet::MetaType($t,$len,$fieldobj); + } + + /* Executes the sql array returned by GetTableSQL and GetIndexSQL */ + function ExecuteSQLArray($sql, $continueOnError = true) + { + $rez = 2; + $conn = &$this->connection; + $saved = $conn->debug; + foreach($sql as $line) { + + if ($this->debug) $conn->debug = true; + $ok = $conn->Execute($line); + $conn->debug = $saved; + if (!$ok) { + if ($this->debug) ADOConnection::outp($conn->ErrorMsg()); + if (!$continueOnError) return 0; + $rez = 1; + } + } + return 2; + } + + /* + Returns the actual type given a character code. + + C: varchar + X: CLOB (character large object) or largest varchar size if CLOB is not supported + C2: Multibyte varchar + X2: Multibyte CLOB + + B: BLOB (binary large object) + + D: Date + T: Date-time + L: Integer field suitable for storing booleans (0 or 1) + I: Integer + F: Floating point number + N: Numeric or decimal number + */ + + function ActualType($meta) + { + return $meta; + } + + function CreateDatabase($dbname,$options=false) + { + $options = $this->_Options($options); + $s = 'CREATE DATABASE '.$dbname; + if (isset($options[$this->upperName])) $s .= ' '.$options[$this->upperName]; + $sql[] = $s; + return $sql; + } + + /* + Generates the SQL to create index. Returns an array of sql strings. + */ + function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false) + { + if ($this->schema) $tabname = $this->schema.'.'.$tabname; + return $this->_IndexSQL($idxname, $tabname, $flds, $this->_Options($idxoptions)); + } + + function SetSchema($schema) + { + $this->schema = $schema; + } + + function AddColumnSQL($tabname, $flds) + { + if ($this->schema) $tabname = $this->schema.'.'.$tabname; + $sql = array(); + list($lines,$pkey) = $this->_GenFields($flds); + foreach($lines as $v) { + $sql[] = "ALTER TABLE $tabname $this->addCol $v"; + } + return $sql; + } + + function AlterColumnSQL($tabname, $flds) + { + if ($this->schema) $tabname = $this->schema.'.'.$tabname; + $sql = array(); + list($lines,$pkey) = $this->_GenFields($flds); + + foreach($lines as $v) { + $sql[] = "ALTER TABLE $tabname $this->alterCol $v"; + } + return $sql; + } + + function DropColumnSQL($tabname, $flds) + { + if ($this->schema) $tabname = $this->schema.'.'.$tabname; + if (!is_array($flds)) $flds = explode(',',$flds); + $sql = array(); + foreach($flds as $v) { + $sql[] = "ALTER TABLE $tabname $this->dropCol $v"; + } + return $sql; + } + + function DropTableSQL($tabname) + { + if ($this->schema) $tabname = $this->schema.'.'.$tabname; + $sql[] = sprintf($this->dropTable,$tabname); + return $sql; + } + + /* + Generate the SQL to create table. Returns an array of sql strings. + */ + function CreateTableSQL($tabname, $flds, $tableoptions=false) + { + if (!$tableoptions) $tableoptions = array(); + + list($lines,$pkey) = $this->_GenFields($flds); + + $taboptions = $this->_Options($tableoptions); + if ($this->schema) $tabname = $this->schema.'.'.$tabname; + $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions); + + $tsql = $this->_Triggers($tabname,$taboptions); + foreach($tsql as $s) $sql[] = $s; + + return $sql; + } + + function _GenFields($flds) + { + if (is_string($flds)) { + $padding = ' '; + $txt = $flds.$padding; + $flds = array(); + $flds0 = Lens_ParseArgs($txt,','); + $hasparam = false; + foreach($flds0 as $f0) { + $f1 = array(); + foreach($f0 as $token) { + switch (strtoupper($token)) { + case 'CONSTRAINT': + case 'DEFAULT': + $hasparam = $token; + break; + default: + if ($hasparam) $f1[$hasparam] = $token; + else $f1[] = $token; + $hasparam = false; + break; + } + } + $flds[] = $f1; + + } + } + $this->autoIncrement = false; + $lines = array(); + $pkey = array(); + foreach($flds as $fld) { + $fld = _array_change_key_case($fld); + + $fname = false; + $fdefault = false; + $fautoinc = false; + $ftype = false; + $fsize = false; + $fprec = false; + $fprimary = false; + $fnoquote = false; + $fdefts = false; + $fdefdate = false; + $fconstraint = false; + $fnotnull = false; + $funsigned = false; + + /* ----------------- */ + /* Parse attributes */ + foreach($fld as $attr => $v) { + if ($attr == 2 && is_numeric($v)) $attr = 'SIZE'; + else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr = strtoupper($v); + + switch($attr) { + case '0': + case 'NAME': $fname = $v; break; + case '1': + case 'TYPE': $ty = $v; $ftype = $this->ActualType(strtoupper($v)); break; + case 'SIZE': $dotat = strpos($v,'.'); + if ($dotat === false) $fsize = $v; + else { + $fsize = substr($v,0,$dotat); + $fprec = substr($v,$dotat+1); + } + break; + case 'UNSIGNED': $funsigned = true; break; + case 'AUTOINCREMENT': + case 'AUTO': $fautoinc = true; $fnotnull = true; break; + case 'KEY': + case 'PRIMARY': $fprimary = $v; $fnotnull = true; break; + case 'DEF': + case 'DEFAULT': $fdefault = $v; break; + case 'NOTNULL': $fnotnull = $v; break; + case 'NOQUOTE': $fnoquote = $v; break; + case 'DEFDATE': $fdefdate = $v; break; + case 'DEFTIMESTAMP': $fdefts = $v; break; + case 'CONSTRAINT': $fconstraint = $v; break; + } /* switch */ + } /* foreach $fld */ + + /* -------------------- */ + /* VALIDATE FIELD INFO */ + if (!strlen($fname)) { + if ($this->debug) ADOConnection::outp("Undefined NAME"); + return false; + } + + if (!strlen($ftype)) { + if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'"); + return false; + } else { + $ftype = strtoupper($ftype); + } + + $ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec); + + if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull = false; /* some blob types do not accept nulls */ + + if ($fprimary) $pkey[] = $fname; + + /* some databases do not allow blobs to have defaults */ + if ($ty == 'X') $fdefault = false; + + /* -------------------- */ + /* CONSTRUCT FIELD SQL */ + if ($fdefts) { + if (substr($this->connection->databaseType,0,5) == 'mysql') { + $ftype = 'TIMESTAMP'; + } else { + $fdefault = $this->connection->sysTimeStamp; + } + } else if ($fdefdate) { + if (substr($this->connection->databaseType,0,5) == 'mysql') { + $ftype = 'TIMESTAMP'; + } else { + $fdefault = $this->connection->sysDate; + } + } else if (strlen($fdefault) && !$fnoquote) + if ($ty == 'C' or $ty == 'X' or + ( substr($fdefault,0,1) != "'" && !is_numeric($fdefault))) + if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ') + $fdefault = trim($fdefault); + else if (strtolower($fdefault) != 'null') + $fdefault = $this->connection->qstr($fdefault); + $suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned); + + $fname = str_pad($fname,16); + $lines[] = "$fname $ftype$suffix"; + + if ($fautoinc) $this->autoIncrement = true; + } /* foreach $flds */ + + + return array($lines,$pkey); + } + /* + GENERATE THE SIZE PART OF THE DATATYPE + $ftype is the actual type + $ty is the type defined originally in the DDL + */ + function _GetSize($ftype, $ty, $fsize, $fprec) + { + if (strlen($fsize) && $ty != 'X' && $ty != 'B' && strpos($ftype,'(') === false) { + $ftype .= "(".$fsize; + if ($fprec) $ftype .= ",".$fprec; + $ftype .= ')'; + } + return $ftype; + } + + + /* return string must begin with space */ + function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint) + { + $suffix = ''; + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fnotnull) $suffix .= ' NOT NULL'; + if ($fconstraint) $suffix .= ' '.$fconstraint; + return $suffix; + } + + function _IndexSQL($idxname, $tabname, $flds, $idxoptions) + { + if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX $idxname"; + if (isset($idxoptions['UNIQUE'])) $unique = ' UNIQUE'; + else $unique = ''; + + if (is_array($flds)) $flds = implode(', ',$flds); + $s = "CREATE$unique INDEX $idxname ON $tabname "; + if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName]; + $s .= "($flds)"; + $sql[] = $s; + + return $sql; + } + + function _DropAutoIncrement($tabname) + { + return false; + } + + function _TableSQL($tabname,$lines,$pkey,$tableoptions) + { + $sql = array(); + + if (isset($tableoptions['REPLACE'])) { + $sql[] = sprintf($this->dropTable,$tabname); + if ($this->autoIncrement) { + $sInc = $this->_DropAutoIncrement($tabname); + if ($sInc) $sql[] = $sInc; + } + } + $s = "CREATE TABLE $tabname (\n"; + $s .= implode(",\n", $lines); + if (sizeof($pkey)>0) { + $s .= ",\n PRIMARY KEY ("; + $s .= implode(", ",$pkey).")"; + } + if (isset($tableoptions['CONSTRAINTS'])) + $s .= "\n".$tableoptions['CONSTRAINTS']; + + if (isset($tableoptions[$this->upperName.'_CONSTRAINTS'])) + $s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS']; + + $s .= "\n)"; + if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName]; + $sql[] = $s; + + return $sql; + } + + /* + GENERATE TRIGGERS IF NEEDED + used when table has auto-incrementing field that is emulated using triggers + */ + function _Triggers($tabname,$taboptions) + { + return array(); + } + + /* + Sanitize options, so that array elements with no keys are promoted to keys + */ + function _Options($opts) + { + if (!is_array($opts)) return array(); + $newopts = array(); + foreach($opts as $k => $v) { + if (is_numeric($k)) $newopts[strtoupper($v)] = $v; + else $newopts[strtoupper($k)] = $v; + } + return $newopts; + } + + +/* +"Florian Buzin [ easywe ]"
|<';
- var $prev = '<<';
- var $next = '>>';
- var $last = '>|';
- var $moreLinks = '...';
- var $startLinks = '...';
- var $gridHeader = false;
- var $htmlSpecialChars = true;
- var $page = 'Page';
- var $linkSelectedColor = 'red';
- var $cache = 0; #secs to cache with CachePageExecute()
-
- //----------------------------------------------
- // constructor
- //
- // $db adodb connection object
- // $sql sql statement
- // $id optional id to identify which pager,
- // if you have multiple on 1 page.
- // $id should be only be [a-z0-9]*
- //
- function ADODB_Pager(&$db,$sql,$id = 'adodb', $showPageLinks = false)
- {
- global $HTTP_SERVER_VARS,$PHP_SELF,$HTTP_SESSION_VARS,$HTTP_GET_VARS;
-
- $curr_page = $id.'_curr_page';
- if (empty($PHP_SELF)) $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
-
- $this->sql = $sql;
- $this->id = $id;
- $this->db = $db;
- $this->showPageLinks = $showPageLinks;
-
- $next_page = $id.'_next_page';
-
- if (isset($HTTP_GET_VARS[$next_page])) {
- $HTTP_SESSION_VARS[$curr_page] = $HTTP_GET_VARS[$next_page];
- }
- if (empty($HTTP_SESSION_VARS[$curr_page])) $HTTP_SESSION_VARS[$curr_page] = 1; ## at first page
-
- $this->curr_page = $HTTP_SESSION_VARS[$curr_page];
-
- }
-
- //---------------------------
- // Display link to first page
- function Render_First($anchor=true)
- {
- global $PHP_SELF;
- if ($anchor) {
- ?>
- first;?>
- first ";
- }
- }
-
- //--------------------------
- // Display link to next page
- function render_next($anchor=true)
- {
- global $PHP_SELF;
-
- if ($anchor) {
- ?>
- next;?>
- next ";
- }
- }
-
- //------------------
- // Link to last page
- //
- // for better performance with large recordsets, you can set
- // $this->db->pageExecuteCountRows = false, which disables
- // last page counting.
- function render_last($anchor=true)
- {
- global $PHP_SELF;
-
- if (!$this->db->pageExecuteCountRows) return;
-
- if ($anchor) {
- ?>
- last;?>
- last ";
- }
- }
-
- //---------------------------------------------------
- // original code by "Pablo Costa" | ", - $header, - " |
| ", - $grid, - " |
| ", - $footer, - " |
|<';
+ var $prev = '<<';
+ var $next = '>>';
+ var $last = '>|';
+ var $moreLinks = '...';
+ var $startLinks = '...';
+ var $gridHeader = false;
+ var $htmlSpecialChars = true;
+ var $page = 'Page';
+ var $linkSelectedColor = 'red';
+ var $cache = 0; #secs to cache with CachePageExecute()
+
+ /* ---------------------------------------------- */
+ /* constructor */
+ /* */
+ /* $db adodb connection object */
+ /* $sql sql statement */
+ /* $id optional id to identify which pager, */
+ /* if you have multiple on 1 page. */
+ /* $id should be only be [a-z0-9]* */
+ /* */
+ function ADODB_Pager(&$db,$sql,$id = 'adodb', $showPageLinks = false)
+ {
+ global $HTTP_SERVER_VARS,$PHP_SELF,$HTTP_SESSION_VARS,$HTTP_GET_VARS;
+
+ $curr_page = $id.'_curr_page';
+ if (empty($PHP_SELF)) $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
+
+ $this->sql = $sql;
+ $this->id = $id;
+ $this->db = $db;
+ $this->showPageLinks = $showPageLinks;
+
+ $next_page = $id.'_next_page';
+
+ if (isset($HTTP_GET_VARS[$next_page])) {
+ $HTTP_SESSION_VARS[$curr_page] = $HTTP_GET_VARS[$next_page];
+ }
+ if (empty($HTTP_SESSION_VARS[$curr_page])) $HTTP_SESSION_VARS[$curr_page] = 1; ## at first page
+
+ $this->curr_page = $HTTP_SESSION_VARS[$curr_page];
+
+ }
+
+ /* --------------------------- */
+ /* Display link to first page */
+ function Render_First($anchor=true)
+ {
+ global $PHP_SELF;
+ if ($anchor) {
+ ?>
+ first;?>
+ first ";
+ }
+ }
+
+ /* -------------------------- */
+ /* Display link to next page */
+ function render_next($anchor=true)
+ {
+ global $PHP_SELF;
+
+ if ($anchor) {
+ ?>
+ next;?>
+ next ";
+ }
+ }
+
+ /* ------------------ */
+ /* Link to last page */
+ /* */
+ /* for better performance with large recordsets, you can set */
+ /* $this->db->pageExecuteCountRows = false, which disables */
+ /* last page counting. */
+ function render_last($anchor=true)
+ {
+ global $PHP_SELF;
+
+ if (!$this->db->pageExecuteCountRows) return;
+
+ if ($anchor) {
+ ?>
+ last;?>
+ last ";
+ }
+ }
+
+ /* --------------------------------------------------- */
+ /* original code by "Pablo Costa" | ", + $header, + " |
| ", + $grid, + " |
| ", + $footer, + " |
\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}
"; + + + Installation + ============ + 1. Create this table in your database (syntax might vary depending on your db): + + create table sessions ( + SESSKEY char(32) not null, + EXPIRY int(11) unsigned not null, + EXPIREREF varchar(64), + DATA CLOB, + primary key (sesskey) + ); + + + 2. Then define the following parameters in this file: + $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase'; + $ADODB_SESSION_CONNECT='server to connect to'; + $ADODB_SESSION_USER ='user'; + $ADODB_SESSION_PWD ='password'; + $ADODB_SESSION_DB ='database'; + $ADODB_SESSION_TBL = 'sessions' + $ADODB_SESSION_USE_LOBS = false; (or, if you wanna use CLOBS (= 'CLOB') or ( = 'BLOB') + + 3. Recommended is PHP 4.0.6 or later. There are documented + session bugs in earlier versions of PHP. + + 4. If you want to receive notifications when a session expires, then + you can tag a session with an EXPIREREF, and before the session + record is deleted, we can call a function that will pass the EXPIREREF + as the first parameter, and the session key as the second parameter. + + To do this, define a notification function, say NotifyFn: + + function NotifyFn($expireref, $sesskey) + { + } + + Then define a global variable, with the first parameter being the + global variable you would like to store in the EXPIREREF field, and + the second is the function name. + + In this example, we want to be notified when a user's session + has expired, so we store the user id in $USERID, and make this + the value stored in the EXPIREREF field: + + $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn'); +*/ + +if (!defined('_ADODB_LAYER')) { + include (dirname(__FILE__).'/adodb.inc.php'); +} + +if (!defined('ADODB_SESSION')) { + + define('ADODB_SESSION',1); + + /* if database time and system time is difference is greater than this, then give warning */ + define('ADODB_SESSION_SYNCH_SECS',60); + +/****************************************************************************************\ + Global definitions +\****************************************************************************************/ +GLOBAL $ADODB_SESSION_CONNECT, + $ADODB_SESSION_DRIVER, + $ADODB_SESSION_USER, + $ADODB_SESSION_PWD, + $ADODB_SESSION_DB, + $ADODB_SESS_CONN, + $ADODB_SESS_LIFE, + $ADODB_SESS_DEBUG, + $ADODB_SESSION_EXPIRE_NOTIFY, + $ADODB_SESSION_CRC; + $ADODB_SESSION_USE_LOBS; + + + $ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime'); + if ($ADODB_SESS_LIFE <= 1) { + /* bug in PHP 4.0.3 pl 1 -- how about other versions? */ + /* print "Session: connection failed
",false); +} + +/****************************************************************************************\ + Close the connection +\****************************************************************************************/ +function adodb_sess_close() +{ +global $ADODB_SESS_CONN; + + if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close(); + return true; +} + +/****************************************************************************************\ + Slurp in the session variables and return the serialized string +\****************************************************************************************/ +function adodb_sess_read($key) +{ +global $ADODB_SESS_CONN,$ADODB_SESSION_TBL,$ADODB_SESSION_CRC; + + $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time()); + if ($rs) { + if ($rs->EOF) { + $v = ''; + } else + $v = rawurldecode(reset($rs->fields)); + + $rs->Close(); + + /* new optimization adodb 2.1 */ + $ADODB_SESSION_CRC = strlen($v).crc32($v); + + return $v; + } + + return ''; /* thx to Jorma Tuomainen, webmaster#wizactive.com */ +} + +/****************************************************************************************\ + Write the serialized data to a database. + + If the data has not been modified since adodb_sess_read(), we do not write. +\****************************************************************************************/ +function adodb_sess_write($key, $val) +{ + global + $ADODB_SESS_CONN, + $ADODB_SESS_LIFE, + $ADODB_SESSION_TBL, + $ADODB_SESS_DEBUG, + $ADODB_SESSION_CRC, + $ADODB_SESSION_EXPIRE_NOTIFY, + $ADODB_SESSION_DRIVER, /* added */ + $ADODB_SESSION_USE_LOBS; /* added */ + + $expiry = time() + $ADODB_SESS_LIFE; + + /* crc32 optimization since adodb 2.1 */ + /* now we only update expiry date, thx to sebastian thom in adodb 2.32 */ + if ($ADODB_SESSION_CRC !== false && $ADODB_SESSION_CRC == strlen($val).crc32($val)) { + if ($ADODB_SESS_DEBUG) echo "Session: Only updating date - crc32 not changed
"; + $qry = "UPDATE $ADODB_SESSION_TBL SET expiry=$expiry WHERE sesskey='$key' AND expiry >= " . time(); + $rs = $ADODB_SESS_CONN->Execute($qry); + return true; + } + $val = rawurlencode($val); + + $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val); + if ($ADODB_SESSION_EXPIRE_NOTIFY) { + $var = reset($ADODB_SESSION_EXPIRE_NOTIFY); + global $$var; + $arr['expireref'] = $$var; + } + + + if ($ADODB_SESSION_USE_LOBS === false) { /* no lobs, simply use replace() */ + $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,$arr, 'sesskey',$autoQuote = true); + if (!$rs) { + $err = $ADODB_SESS_CONN->ErrorMsg(); + } + } else { + /* what value shall we insert/update for lob row? */ + switch ($ADODB_SESSION_DRIVER) { + /* empty_clob or empty_lob for oracle dbs */ + case "oracle": + case "oci8": + case "oci8po": + case "oci805": + $lob_value = sprintf("empty_%s()", strtolower($ADODB_SESSION_USE_LOBS)); + break; + + /* null for all other */ + default: + $lob_value = "null"; + break; + } + + /* do we insert or update? => as for sesskey */ + $res = $ADODB_SESS_CONN->Execute("select count(*) as cnt from $ADODB_SESSION_TBL where sesskey = '$key'"); + if ($res && ($res->fields["CNT"] > 0)) { + $qry = sprintf("update %s set expiry = %d, data = %s where sesskey = '%s'", $ADODB_SESSION_TBL, $expiry, $lob_value, $key); + } else { + /* insert */ + $qry = sprintf("insert into %s (sesskey, expiry, data) values ('%s', %d, %s)", $ADODB_SESSION_TBL, $key, $expiry, $lob_value); + } + + $err = ""; + $rs1 = $ADODB_SESS_CONN->Execute($qry); + if (!$rs1) { + $err .= $ADODB_SESS_CONN->ErrorMsg()."\n"; + } + $rs2 = $ADODB_SESS_CONN->UpdateBlob($ADODB_SESSION_TBL, 'data', $val, "sesskey='$key'", strtoupper($ADODB_SESSION_USE_LOBS)); + if (!$rs2) { + $err .= $ADODB_SESS_CONN->ErrorMsg()."\n"; + } + $rs = ($rs1 && $rs2) ? true : false; + } + + if (!$rs) { + ADOConnection::outp( 'Session Replace: '.nl2br($err).'
',false); + } else { + /* bug in access driver (could be odbc?) means that info is not commited */ + /* properly unless select statement executed in Win2000 */ + if ($ADODB_SESS_CONN->databaseType == 'access') + $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'"); + } + return !empty($rs); +} + +function adodb_sess_destroy($key) +{ + global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY; + + if ($ADODB_SESSION_EXPIRE_NOTIFY) { + reset($ADODB_SESSION_EXPIRE_NOTIFY); + $fn = next($ADODB_SESSION_EXPIRE_NOTIFY); + $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM); + $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'"); + $ADODB_SESS_CONN->SetFetchMode($savem); + if ($rs) { + $ADODB_SESS_CONN->BeginTrans(); + while (!$rs->EOF) { + $ref = $rs->fields[0]; + $key = $rs->fields[1]; + $fn($ref,$key); + $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'"); + $rs->MoveNext(); + } + $ADODB_SESS_CONN->CommitTrans(); + } + } else { + $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'"; + $rs = $ADODB_SESS_CONN->Execute($qry); + } + return $rs ? true : false; +} + +function adodb_sess_gc($maxlifetime) +{ + global $ADODB_SESS_DEBUG, $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY; + + if ($ADODB_SESSION_EXPIRE_NOTIFY) { + reset($ADODB_SESSION_EXPIRE_NOTIFY); + $fn = next($ADODB_SESSION_EXPIRE_NOTIFY); + $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM); + $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < " . time()); + $ADODB_SESS_CONN->SetFetchMode($savem); + if ($rs) { + $ADODB_SESS_CONN->BeginTrans(); + while (!$rs->EOF) { + $ref = $rs->fields[0]; + $key = $rs->fields[1]; + $fn($ref,$key); + $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'"); + $rs->MoveNext(); + } + $ADODB_SESS_CONN->CommitTrans(); + } + } else { + $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time(); + $ADODB_SESS_CONN->Execute($qry); + + if ($ADODB_SESS_DEBUG) ADOConnection::outp("Garbage Collection: $qry
"); + } + /* suggested by Cameron, "GaM3R"$msg
"); + } + } + + return true; +} + +session_module_name('user'); +session_set_save_handler( + "adodb_sess_open", + "adodb_sess_close", + "adodb_sess_read", + "adodb_sess_write", + "adodb_sess_destroy", + "adodb_sess_gc"); +} + +/* TEST SCRIPT -- UNCOMMENT */ + +if (0) { +GLOBAL $HTTP_SESSION_VARS; + + session_start(); + session_register('AVAR'); + $HTTP_SESSION_VARS['AVAR'] += 1; + ADOConnection::outp( "\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}
",false); +} + +?> diff --git a/lib/adodb/adodb-session.php b/lib/adodb/adodb-session.php index 67b61e7583e..d808b06d7c2 100644 --- a/lib/adodb/adodb-session.php +++ b/lib/adodb/adodb-session.php @@ -1,379 +1,379 @@ -\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}"; - -To force non-persistent connections, call adodb_session_open first before session_start(): - - GLOBAL $HTTP_SESSION_VARS; - include('adodb.inc.php'); - include('adodb-session.php'); - adodb_session_open(false,false,false); - session_start(); - session_register('AVAR'); - $HTTP_SESSION_VARS['AVAR'] += 1; - print "\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}
"; - - - Installation - ============ - 1. Create this table in your database (syntax might vary depending on your db): - - create table sessions ( - SESSKEY char(32) not null, - EXPIRY int(11) unsigned not null, - EXPIREREF varchar(64), - DATA text not null, - primary key (sesskey) - ); - - - 2. Then define the following parameters in this file: - $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase'; - $ADODB_SESSION_CONNECT='server to connect to'; - $ADODB_SESSION_USER ='user'; - $ADODB_SESSION_PWD ='password'; - $ADODB_SESSION_DB ='database'; - $ADODB_SESSION_TBL = 'sessions' - - 3. Recommended is PHP 4.0.6 or later. There are documented - session bugs in earlier versions of PHP. - - 4. If you want to receive notifications when a session expires, then - you can tag a session with an EXPIREREF, and before the session - record is deleted, we can call a function that will pass the EXPIREREF - as the first parameter, and the session key as the second parameter. - - To do this, define a notification function, say NotifyFn: - - function NotifyFn($expireref, $sesskey) - { - } - - Then define a global variable, with the first parameter being the - global variable you would like to store in the EXPIREREF field, and - the second is the function name. - - In this example, we want to be notified when a user's session - has expired, so we store the user id in $USERID, and make this - the value stored in the EXPIREREF field: - - $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn'); -*/ - -if (!defined('_ADODB_LAYER')) { - include (dirname(__FILE__).'/adodb.inc.php'); -} - -if (!defined('ADODB_SESSION')) { - - define('ADODB_SESSION',1); - - /* if database time and system time is difference is greater than this, then give warning */ - define('ADODB_SESSION_SYNCH_SECS',60); - -/****************************************************************************************\ - Global definitions -\****************************************************************************************/ -GLOBAL $ADODB_SESSION_CONNECT, - $ADODB_SESSION_DRIVER, - $ADODB_SESSION_USER, - $ADODB_SESSION_PWD, - $ADODB_SESSION_DB, - $ADODB_SESS_CONN, - $ADODB_SESS_LIFE, - $ADODB_SESS_DEBUG, - $ADODB_SESSION_EXPIRE_NOTIFY, - $ADODB_SESSION_CRC; - - - $ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime'); - if ($ADODB_SESS_LIFE <= 1) { - // bug in PHP 4.0.3 pl 1 -- how about other versions? - //print "Session: connection failed
",false); -} - -/****************************************************************************************\ - Close the connection -\****************************************************************************************/ -function adodb_sess_close() -{ -global $ADODB_SESS_CONN; - - if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close(); - return true; -} - -/****************************************************************************************\ - Slurp in the session variables and return the serialized string -\****************************************************************************************/ -function adodb_sess_read($key) -{ -global $ADODB_SESS_CONN,$ADODB_SESSION_TBL,$ADODB_SESSION_CRC; - - $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time()); - if ($rs) { - if ($rs->EOF) { - $v = ''; - } else - $v = rawurldecode(reset($rs->fields)); - - $rs->Close(); - - // new optimization adodb 2.1 - $ADODB_SESSION_CRC = strlen($v).crc32($v); - - return $v; - } - - return ''; // thx to Jorma Tuomainen, webmaster#wizactive.com -} - -/****************************************************************************************\ - Write the serialized data to a database. - - If the data has not been modified since adodb_sess_read(), we do not write. -\****************************************************************************************/ -function adodb_sess_write($key, $val) -{ - global - $ADODB_SESS_CONN, - $ADODB_SESS_LIFE, - $ADODB_SESSION_TBL, - $ADODB_SESS_DEBUG, - $ADODB_SESSION_CRC, - $ADODB_SESSION_EXPIRE_NOTIFY; - - $expiry = time() + $ADODB_SESS_LIFE; - - // crc32 optimization since adodb 2.1 - // now we only update expiry date, thx to sebastian thom in adodb 2.32 - if ($ADODB_SESSION_CRC !== false && $ADODB_SESSION_CRC == strlen($val).crc32($val)) { - if ($ADODB_SESS_DEBUG) echo "Session: Only updating date - crc32 not changed
"; - $qry = "UPDATE $ADODB_SESSION_TBL SET expiry=$expiry WHERE sesskey='$key' AND expiry >= " . time(); - $rs = $ADODB_SESS_CONN->Execute($qry); - return true; - } - $val = rawurlencode($val); - - $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val); - if ($ADODB_SESSION_EXPIRE_NOTIFY) { - $var = reset($ADODB_SESSION_EXPIRE_NOTIFY); - global $$var; - $arr['expireref'] = $$var; - } - $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,$arr, - 'sesskey',$autoQuote = true); - - if (!$rs) { - ADOConnection::outp( 'Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().'
',false); - } else { - // bug in access driver (could be odbc?) means that info is not commited - // properly unless select statement executed in Win2000 - if ($ADODB_SESS_CONN->databaseType == 'access') - $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'"); - } - return !empty($rs); -} - -function adodb_sess_destroy($key) -{ - global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY; - - if ($ADODB_SESSION_EXPIRE_NOTIFY) { - reset($ADODB_SESSION_EXPIRE_NOTIFY); - $fn = next($ADODB_SESSION_EXPIRE_NOTIFY); - $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM); - $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'"); - $ADODB_SESS_CONN->SetFetchMode($savem); - if ($rs) { - $ADODB_SESS_CONN->BeginTrans(); - while (!$rs->EOF) { - $ref = $rs->fields[0]; - $key = $rs->fields[1]; - $fn($ref,$key); - $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'"); - $rs->MoveNext(); - } - $ADODB_SESS_CONN->CommitTrans(); - } - } else { - $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'"; - $rs = $ADODB_SESS_CONN->Execute($qry); - } - return $rs ? true : false; -} - -function adodb_sess_gc($maxlifetime) -{ - global $ADODB_SESS_DEBUG, $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY; - - if ($ADODB_SESSION_EXPIRE_NOTIFY) { - reset($ADODB_SESSION_EXPIRE_NOTIFY); - $fn = next($ADODB_SESSION_EXPIRE_NOTIFY); - $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM); - $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < " . time()); - $ADODB_SESS_CONN->SetFetchMode($savem); - if ($rs) { - $ADODB_SESS_CONN->BeginTrans(); - while (!$rs->EOF) { - $ref = $rs->fields[0]; - $key = $rs->fields[1]; - $fn($ref,$key); - $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'"); - $rs->MoveNext(); - } - $ADODB_SESS_CONN->CommitTrans(); - } - } else { - $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time(); - $ADODB_SESS_CONN->Execute($qry); - - if ($ADODB_SESS_DEBUG) ADOConnection::outp("Garbage Collection: $qry
"); - } - // suggested by Cameron, "GaM3R"$msg
"); - } - } - - return true; -} - -session_module_name('user'); -session_set_save_handler( - "adodb_sess_open", - "adodb_sess_close", - "adodb_sess_read", - "adodb_sess_write", - "adodb_sess_destroy", - "adodb_sess_gc"); -} - -/* TEST SCRIPT -- UNCOMMENT */ - -if (0) { -GLOBAL $HTTP_SESSION_VARS; - - session_start(); - session_register('AVAR'); - $HTTP_SESSION_VARS['AVAR'] += 1; - ADOConnection::outp( "\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}
",false); -} - +\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}"; + +To force non-persistent connections, call adodb_session_open first before session_start(): + + GLOBAL $HTTP_SESSION_VARS; + include('adodb.inc.php'); + include('adodb-session.php'); + adodb_sess_open(false,false,false); + session_start(); + session_register('AVAR'); + $HTTP_SESSION_VARS['AVAR'] += 1; + print "\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}
"; + + + Installation + ============ + 1. Create this table in your database (syntax might vary depending on your db): + + create table sessions ( + SESSKEY char(32) not null, + EXPIRY int(11) unsigned not null, + EXPIREREF varchar(64), + DATA text not null, + primary key (sesskey) + ); + + + 2. Then define the following parameters in this file: + $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase'; + $ADODB_SESSION_CONNECT='server to connect to'; + $ADODB_SESSION_USER ='user'; + $ADODB_SESSION_PWD ='password'; + $ADODB_SESSION_DB ='database'; + $ADODB_SESSION_TBL = 'sessions' + + 3. Recommended is PHP 4.0.6 or later. There are documented + session bugs in earlier versions of PHP. + + 4. If you want to receive notifications when a session expires, then + you can tag a session with an EXPIREREF, and before the session + record is deleted, we can call a function that will pass the EXPIREREF + as the first parameter, and the session key as the second parameter. + + To do this, define a notification function, say NotifyFn: + + function NotifyFn($expireref, $sesskey) + { + } + + Then define a global variable, with the first parameter being the + global variable you would like to store in the EXPIREREF field, and + the second is the function name. + + In this example, we want to be notified when a user's session + has expired, so we store the user id in $USERID, and make this + the value stored in the EXPIREREF field: + + $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn'); +*/ + +if (!defined('_ADODB_LAYER')) { + include (dirname(__FILE__).'/adodb.inc.php'); +} + +if (!defined('ADODB_SESSION')) { + + define('ADODB_SESSION',1); + + /* if database time and system time is difference is greater than this, then give warning */ + define('ADODB_SESSION_SYNCH_SECS',60); + +/****************************************************************************************\ + Global definitions +\****************************************************************************************/ +GLOBAL $ADODB_SESSION_CONNECT, + $ADODB_SESSION_DRIVER, + $ADODB_SESSION_USER, + $ADODB_SESSION_PWD, + $ADODB_SESSION_DB, + $ADODB_SESS_CONN, + $ADODB_SESS_LIFE, + $ADODB_SESS_DEBUG, + $ADODB_SESSION_EXPIRE_NOTIFY, + $ADODB_SESSION_CRC; + + + $ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime'); + if ($ADODB_SESS_LIFE <= 1) { + /* bug in PHP 4.0.3 pl 1 -- how about other versions? */ + /* print "Session: connection failed
",false); +} + +/****************************************************************************************\ + Close the connection +\****************************************************************************************/ +function adodb_sess_close() +{ +global $ADODB_SESS_CONN; + + if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close(); + return true; +} + +/****************************************************************************************\ + Slurp in the session variables and return the serialized string +\****************************************************************************************/ +function adodb_sess_read($key) +{ +global $ADODB_SESS_CONN,$ADODB_SESSION_TBL,$ADODB_SESSION_CRC; + + $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time()); + if ($rs) { + if ($rs->EOF) { + $v = ''; + } else + $v = rawurldecode(reset($rs->fields)); + + $rs->Close(); + + /* new optimization adodb 2.1 */ + $ADODB_SESSION_CRC = strlen($v).crc32($v); + + return $v; + } + + return ''; /* thx to Jorma Tuomainen, webmaster#wizactive.com */ +} + +/****************************************************************************************\ + Write the serialized data to a database. + + If the data has not been modified since adodb_sess_read(), we do not write. +\****************************************************************************************/ +function adodb_sess_write($key, $val) +{ + global + $ADODB_SESS_CONN, + $ADODB_SESS_LIFE, + $ADODB_SESSION_TBL, + $ADODB_SESS_DEBUG, + $ADODB_SESSION_CRC, + $ADODB_SESSION_EXPIRE_NOTIFY; + + $expiry = time() + $ADODB_SESS_LIFE; + + /* crc32 optimization since adodb 2.1 */ + /* now we only update expiry date, thx to sebastian thom in adodb 2.32 */ + if ($ADODB_SESSION_CRC !== false && $ADODB_SESSION_CRC == strlen($val).crc32($val)) { + if ($ADODB_SESS_DEBUG) echo "Session: Only updating date - crc32 not changed
"; + $qry = "UPDATE $ADODB_SESSION_TBL SET expiry=$expiry WHERE sesskey='$key' AND expiry >= " . time(); + $rs = $ADODB_SESS_CONN->Execute($qry); + return true; + } + $val = rawurlencode($val); + + $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val); + if ($ADODB_SESSION_EXPIRE_NOTIFY) { + $var = reset($ADODB_SESSION_EXPIRE_NOTIFY); + global $$var; + $arr['expireref'] = $$var; + } + $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,$arr, + 'sesskey',$autoQuote = true); + + if (!$rs) { + ADOConnection::outp( 'Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().'
',false); + } else { + /* bug in access driver (could be odbc?) means that info is not commited */ + /* properly unless select statement executed in Win2000 */ + if ($ADODB_SESS_CONN->databaseType == 'access') + $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'"); + } + return !empty($rs); +} + +function adodb_sess_destroy($key) +{ + global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY; + + if ($ADODB_SESSION_EXPIRE_NOTIFY) { + reset($ADODB_SESSION_EXPIRE_NOTIFY); + $fn = next($ADODB_SESSION_EXPIRE_NOTIFY); + $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM); + $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'"); + $ADODB_SESS_CONN->SetFetchMode($savem); + if ($rs) { + $ADODB_SESS_CONN->BeginTrans(); + while (!$rs->EOF) { + $ref = $rs->fields[0]; + $key = $rs->fields[1]; + $fn($ref,$key); + $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'"); + $rs->MoveNext(); + } + $ADODB_SESS_CONN->CommitTrans(); + } + } else { + $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'"; + $rs = $ADODB_SESS_CONN->Execute($qry); + } + return $rs ? true : false; +} + +function adodb_sess_gc($maxlifetime) +{ + global $ADODB_SESS_DEBUG, $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY; + + if ($ADODB_SESSION_EXPIRE_NOTIFY) { + reset($ADODB_SESSION_EXPIRE_NOTIFY); + $fn = next($ADODB_SESSION_EXPIRE_NOTIFY); + $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM); + $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < " . time()); + $ADODB_SESS_CONN->SetFetchMode($savem); + if ($rs) { + $ADODB_SESS_CONN->BeginTrans(); + while (!$rs->EOF) { + $ref = $rs->fields[0]; + $key = $rs->fields[1]; + $fn($ref,$key); + $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'"); + $rs->MoveNext(); + } + $ADODB_SESS_CONN->CommitTrans(); + } + } else { + $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time(); + $ADODB_SESS_CONN->Execute($qry); + + if ($ADODB_SESS_DEBUG) ADOConnection::outp("Garbage Collection: $qry
"); + } + /* suggested by Cameron, "GaM3R"$msg
"); + } + } + + return true; +} + +session_module_name('user'); +session_set_save_handler( + "adodb_sess_open", + "adodb_sess_close", + "adodb_sess_read", + "adodb_sess_write", + "adodb_sess_destroy", + "adodb_sess_gc"); +} + +/* TEST SCRIPT -- UNCOMMENT */ + +if (0) { +GLOBAL $HTTP_SESSION_VARS; + + session_start(); + session_register('AVAR'); + $HTTP_SESSION_VARS['AVAR'] += 1; + ADOConnection::outp( "\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}
",false); +} + ?> \ No newline at end of file diff --git a/lib/adodb/adodb-time.inc.php b/lib/adodb/adodb-time.inc.php index 97faaf801fd..5a0f6cac369 100644 --- a/lib/adodb/adodb-time.inc.php +++ b/lib/adodb/adodb-time.inc.php @@ -1,5 +1,4 @@ $y1 errorTesting gregorian <=> julian conversion
";
$t = adodb_mktime(0,0,0,10,11,1492);
- //http://www.holidayorigins.com/html/columbus_day.html - Friday check
+ /* http://www.holidayorigins.com/html/columbus_day.html - Friday check */
if (!(adodb_date('D Y-m-d',$t) == 'Fri 1492-10-11')) print 'Error in Columbus landing
';
$t = adodb_mktime(0,0,0,2,29,1500);
@@ -303,7 +302,7 @@ function adodb_date_test()
if (adodb_year_digit_check(50) != 1950) print "Err 2-digit 1950
";
if (adodb_year_digit_check(90) != 1990) print "Err 2-digit 1990
";
- // Test string formating
+ /* Test string formating */
print "
Testing date formating
"; $fmt = '\d\a\t\e T Y-m-d H:i:s a A d D F g G h H i j l L m M n O \R\F\C822 r s t U w y Y z Z 2003'; $s1 = date($fmt,0); @@ -317,7 +316,7 @@ function adodb_date_test() $ts = 3600.0*((rand()%60000)+(rand()%60000))+(rand()%60000); $s1 = date($fmt,$ts); $s2 = adodb_date($fmt,$ts); - //print "$s1";
+ /* print "$s1
$s2
"; */ $pos = strcmp($s1,$s2); if (($s1) != ($s2)) { @@ -346,7 +345,7 @@ function adodb_date_test() } } - // Test generation of dates outside 1901-2038 + /* Test generation of dates outside 1901-2038 */ print "
Testing random dates between 100 and 4000
"; adodb_date_test_date(100,1); for ($i=100; --$i >= 0;) { @@ -365,8 +364,8 @@ function adodb_date_test() $max = 365*$yrs*86400; $lastyear = 0; - // we generate a timestamp, convert it to a date, and convert it back to a timestamp - // and check if the roundtrip broke the original timestamp value. + /* we generate a timestamp, convert it to a date, and convert it back to a timestamp */ + /* and check if the roundtrip broke the original timestamp value. */ print "Testing $start to ".($start+$yrs).", or $max seconds, offset=$offset: "; for ($max += $i; $i < $max; $i += $offset) { @@ -437,7 +436,7 @@ function _adodb_is_leap_year($year) if ($year % 400 == 0) { return true; - // if gregorian calendar (>1582), century not-divisible by 400 is not leap + /* if gregorian calendar (>1582), century not-divisible by 400 is not leap */ } else if ($year > 1582 && $year % 100 == 0 ) { return false; } @@ -472,8 +471,8 @@ function adodb_year_digit_check($y) $c0 = $century - 1; } $c1 *= 100; - // if 2-digit year is less than 30 years in future, set it to this century - // otherwise if more than 30 years in future, then we set 2-digit year to the prev century. + /* if 2-digit year is less than 30 years in future, set it to this century */ + /* otherwise if more than 30 years in future, then we set 2-digit year to the prev century. */ if (($y + $c1) < $yr+30) $y = $y + $c1; else $y = $y + $c0*100; } @@ -499,8 +498,8 @@ function adodb_getdate($d=false,$fast=false) { if ($d === false) return getdate(); if (!defined('ADODB_TEST_DATES')) { - if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range - if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer + if ((abs($d) <= 0x7FFFFFFF)) { /* check if number in 32-bit signed range */ + if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) /* if windows, must be +ve integer */ return @getdate($d); } } @@ -520,15 +519,15 @@ function _adodb_getdate($origd=false,$fast=false,$is_gmt=false) $_hour_power = 3600; $_min_power = 60; - if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction + if ($d < -12219321600) $d -= 86400*10; /* if 15 Oct 1582 or earlier, gregorian correction */ $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); if ($d < 0) { $origd = $d; - // The valid range of a 32bit signed timestamp is typically from - // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT + /* The valid range of a 32bit signed timestamp is typically from */ + /* Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT */ for ($a = 1970 ; --$a >= 0;) { $lastd = $d; @@ -642,8 +641,8 @@ function adodb_date($fmt,$d=false,$is_gmt=false) { if ($d === false) return date($fmt); if (!defined('ADODB_TEST_DATES')) { - if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range - if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer + if ((abs($d) <= 0x7FFFFFFF)) { /* check if number in 32-bit signed range */ + if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) /* if windows, must be +ve integer */ return @date($fmt,$d); } } @@ -666,10 +665,10 @@ function adodb_date($fmt,$d=false,$is_gmt=false) */ for ($i=0; $i < $max; $i++) { switch($fmt[$i]) { - case 'T': $dates .= date('T',100000);break; - // YEAR + case 'T': $dates .= date('T');break; + /* YEAR */ case 'L': $dates .= $arr['leap'] ? '1' : '0'; break; - case 'r': // Thu, 21 Dec 2000 16:01:07 +0200 + case 'r': /* Thu, 21 Dec 2000 16:01:07 +0200 */ $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', ' . ($day<10?' '.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' '; @@ -685,12 +684,12 @@ function adodb_date($fmt,$d=false,$is_gmt=false) case 'Y': $dates .= $year; break; case 'y': $dates .= substr($year,strlen($year)-2,2); break; - // MONTH + /* MONTH */ case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break; case 'n': $dates .= $month; break; case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break; case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break; - // DAY + /* DAY */ case 't': $dates .= $arr['ndays']; break; case 'z': $dates .= $arr['yday']; break; case 'w': $dates .= adodb_dow($year,$month,$day); break; @@ -706,7 +705,7 @@ function adodb_date($fmt,$d=false,$is_gmt=false) else $dates .= 'th'; break; - // HOUR + /* HOUR */ case 'Z': $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_different(); break; case 'O': @@ -740,13 +739,13 @@ function adodb_date($fmt,$d=false,$is_gmt=false) } $dates .= $hh; break; - // MINUTES + /* MINUTES */ case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break; - // SECONDS + /* SECONDS */ case 'U': $dates .= $d; break; case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break; - // AM/PM - // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM + /* AM/PM */ + /* Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM */ case 'a': if ($hour>=12) $dates .= 'pm'; else $dates .= 'am'; @@ -757,7 +756,7 @@ function adodb_date($fmt,$d=false,$is_gmt=false) break; default: $dates .= $fmt[$i]; break; - // ESCAPE + /* ESCAPE */ case "\\": $i++; if ($i < $max) $dates .= $fmt[$i]; @@ -781,9 +780,10 @@ function adodb_gmmktime($hr,$min,$sec,$mon,$day,$year,$is_dst=false) Note that $is_dst is not implemented and is ignored. */ function adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst=false,$is_gmt=false) -{ if (!defined('ADODB_TEST_DATES')) { - // for windows, we don't check 1970 because with timezone differences, - // 1 Jan 1970 could generate negative timestamp, which is illegal +{ + if (!defined('ADODB_TEST_DATES')) { + /* for windows, we don't check 1970 because with timezone differences, */ + /* 1 Jan 1970 could generate negative timestamp, which is illegal */ if (!defined('ADODB_NO_NEGATIVE_TS') || ($year >= 1971)) if (1901 < $year && $year < 2038) return @mktime($hr,$min,$sec,$mon,$day,$year); @@ -858,10 +858,10 @@ function adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst=false,$is_gmt=false) $_day_time = $hr * $_hour_power + $min * $_min_power + $sec; $_day_time = $_day_power - $_day_time; $ret = -( $_total_date * $_day_power + $_day_time - $gmt_different); - if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction - else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582. + if ($ret < -12220185600) $ret += 10*86400; /* if earlier than 5 Oct 1582 - gregorian correction */ + else if ($ret < -12219321600) $ret = -12219321600; /* if in limbo, reset to 15 Oct 1582. */ } - //print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret; + /* print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret; */ return $ret; } diff --git a/lib/adodb/adodb-xmlschema.inc.php b/lib/adodb/adodb-xmlschema.inc.php new file mode 100644 index 00000000000..9debc392e91 --- /dev/null +++ b/lib/adodb/adodb-xmlschema.inc.php @@ -0,0 +1,722 @@ +tableName = $name; + } + + /** + * Adds a field to a table object + * + * $name is the name of the table to which the field should be added. + * $type is an ADODB datadict field type. The following field types + * are supported as of ADODB 3.40: + * - C: varchar + * - X: CLOB (character large object) or largest varchar size + * if CLOB is not supported + * - C2: Multibyte varchar + * - X2: Multibyte CLOB + * - B: BLOB (binary large object) + * - D: Date (some databases do not support this, and we return a datetime type) + * - T: Datetime or Timestamp + * - L: Integer field suitable for storing booleans (0 or 1) + * - I: Integer (mapped to I4) + * - I1: 1-byte integer + * - I2: 2-byte integer + * - I4: 4-byte integer + * - I8: 8-byte integer + * - F: Floating point number + * - N: Numeric or decimal number + * + * @param string $name Name of the table to which the field will be added. + * @param string $type ADODB datadict field type. + * @param string $size Field size + * @param array $opts Field options array + * @return array Field specifier array + */ + function addField( $name, $type, $size = NULL, $opts = NULL ) { + + /* Set the field index so we know where we are */ + $this->currentField = $name; + + /* Set the field type (required) */ + $this->fieldSpec[$name]['TYPE'] = $type; + + /* Set the field size (optional) */ + if( isset( $size ) ) { + $this->fieldSpec[$name]['SIZE'] = $size; + } + + /* Set the field options */ + if( isset( $opts ) ) $this->fieldSpec[$name]['OPTS'] = $opts; + + /* Return array containing field specifier */ + return $this->fieldSpec; + } + + /** + * Adds a field option to the current field specifier + * + * This method adds a field option allowed by the ADOdb datadict + * and appends it to the given field. + * + * @param string $field Field name + * @param string $opt ADOdb field option + * @param mixed $value Field option value + * @return array Field specifier array + */ + function addFieldOpt( $field, $opt, $value = NULL ) { + + /* Add the option to the field specifier */ + if( $value === NULL ) { /* No value, so add only the option */ + $this->fieldSpec[$field]['OPTS'][] = $opt; + } else { /* Add the option and value */ + $this->fieldSpec[$field]['OPTS'][] = array( "$opt" => "$value" ); + } + + /* Return array containing field specifier */ + return $this->fieldSpec; + } + + /** + * Adds an option to the table + * + *This method takes a comma-separated list of table-level options + * and appends them to the table object. + * + * @param string $opt Table option + * @return string Option list + */ + function addTableOpt( $opt ) { + + $optlist = &$this->tableOpts; + $optlist ? $optlist .= ", $opt" : $optlist = $opt; + + /* Return the options list */ + return $optlist; + } + + /** + * Generates the SQL that will create the table in the database + * + * Returns SQL that will create the table represented by the object. + * + * @param object $dict ADOdb data dictionary + * @return array Array containing table creation SQL + */ + function create( $dict ) { + + /* Loop through the field specifier array, building the associative array for the field options */ + $fldarray = array(); + $i = 0; + + foreach( $this->fieldSpec as $field => $finfo ) { + $i++; + + /* Set an empty size if it isn't supplied */ + if( !isset( $finfo['SIZE'] ) ) $finfo['SIZE'] = ''; + + /* Initialize the field array with the type and size */ + $fldarray[$i] = array( $field, $finfo['TYPE'], $finfo['SIZE'] ); + + /* Loop through the options array and add the field options. */ + $opts = $finfo['OPTS']; + if( $opts ) { + foreach( $finfo['OPTS'] as $opt ) { + + if( is_array( $opt ) ) { /* Option has an argument. */ + $key = key( $opt ); + $value = $opt[key( $opt ) ]; + $fldarray[$i][$key] = $value; + } else { /* Option doesn't have arguments */ + array_push( $fldarray[$i], $opt ); + } + } + } + } + + /* Build table array */ + $sqlArray = $dict->CreateTableSQL( $this->tableName, $fldarray, $this->tableOpts ); + + /* Return the array containing the SQL to create the table */ + return $sqlArray; + } + + /** + * Destructor + */ + function destroy() { + unset( $this ); + } +} + +/** +* Creates an index object in ADOdb's datadict format +* +* This class stores information about a database index. As charactaristics +* of the index are loaded from the external source, methods and properties +* of this class are used to build up the index description in ADOdb's +* datadict format. +* +* @package xmlschema +* @access private +*/ +class dbIndex { + + /** + * @var string Index name + */ + var $indexName; + + /** + * @var string Name of the table this index is attached to + */ + var $tableName; + + /** + * @var array Indexed fields: Table columns included in this index + */ + var $fields; + + /** + * Constructor. Initialize the index and table names. + * + * @param string $name Index name + * @param string $table Name of indexed table + */ + function dbIndex( $name, $table ) { + $this->indexName = $name; + $this->tableName = $table; + } + + /** + * Adds a field to the index + * + * This method adds the specified column to an index. + * + * @param string $name Field name + * @return string Field list + */ + function addField( $name ) { + $fieldlist = &$this->fields; + $fieldlist ? $fieldlist .=" , $name" : $fieldlist = $name; + + /* Return the field list */ + return $fieldlist; + } + + /** + * Generates the SQL that will create the index in the database + * + * Returns SQL that will create the index represented by the object. + * + * @param object $dict ADOdb data dictionary object + * @return array Array containing index creation SQL + */ + function create( $dict ) { + + /* Build table array */ + $sqlArray = $dict->CreateIndexSQL( $this->indexName, $this->tableName, $this->fields ); + + /* Return the array containing the SQL to create the table */ + return $sqlArray; + } + + /** + * Destructor + */ + function destroy() { + unset( $this ); + } +} + +/** +* Creates the SQL to execute a list of provided SQL queries +* +* This class compiles a list of SQL queries specified in the external file. +* +* @package xmlschema +* @access private +*/ +class dbQuerySet { + + /** + * @var array List of SQL queries + */ + var $querySet; + + /** + * @var string String used to build of a query line by line + */ + var $query; + + /** + * Constructor. Initializes the queries array + */ + function dbQuerySet() { + $this->querySet = array(); + $this->query = ''; + } + + /** + * Appends a line to a query that is being built line by line + * + * $param string $data Line of SQL data or NULL to initialize a new query + */ + function buildQuery( $data = NULL ) { + isset( $data ) ? $this->query .= " " . trim( $data ) : $this->query = ''; + } + + /** + * Adds a completed query to the query list + * + * @return string SQL of added query + */ + function addQuery() { + + /* Push the query onto the query set array */ + $finishedQuery = $this->query; + array_push( $this->querySet, $finishedQuery ); + + /* Return the query set array */ + return $finishedQuery; + } + + /** + * Creates and returns the current query set + * + * @return array Query set + */ + function create() { + return $this->querySet; + } + + /** + * Destructor + */ + function destroy() { + unset( $this ); + } +} + + +/** +* Loads and parses an XML file, creating an array of "ready-to-run" SQL statements +* +* This class is used to load and parse the XML file, to create an array of SQL statements +* that can be used to build a database, and to build the database using the SQL array. +* +* @package xmlschema +*/ +class adoSchema { + + /** + * @var array Array containing SQL queries to generate all objects + */ + var $sqlArray; + + /** + * @var object XML Parser object + */ + var $xmlParser; + + /** + * @var object ADOdb connection object + */ + var $dbconn; + + /** + * @var string Database type (platform) + */ + var $dbType; + + /** + * @var object ADOdb Data Dictionary + */ + var $dict; + + /** + * @var object Temporary dbTable object + * @access private + */ + var $table; + + /** + * @var object Temporary dbIndex object + * @access private + */ + var $index; + + /** + * @var object Temporary dbQuerySet object + * @access private + */ + var $querySet; + + /** + * @var string Current XML element + * @access private + */ + var $currentElement; + + /** + * @var long Original Magic Quotes Runtime value + * @access private + */ + var $mgq; + + /** + * Constructor. Initializes the xmlschema object + * + * @param object $dbconn ADOdb connection object + */ + function adoSchema( $dbconn ) { + + /* Initialize the environment */ + $this->mgq = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + + $this->dbconn = &$dbconn; + $this->dbType = $dbconn->databaseType; + $this->sqlArray = array(); + + /* Create an ADOdb dictionary object */ + $this->dict = NewDataDictionary( $dbconn ); + } + + /** + * Loads and parses an XML file + * + * This method accepts a path to an xmlschema-compliant XML file, + * loads it, parses it, and uses it to create the SQL to generate the objects + * described by the XML file. + * + * @param string $file XML file + * @return array Array of SQL queries, ready to execute + */ + function ParseSchema( $file ) { + + /* Create the parser */ + $this->xmlParser = &$xmlParser; + $xmlParser = xml_parser_create(); + xml_set_object( $xmlParser, &$this ); + + /* Initialize the XML callback functions */ + xml_set_element_handler( $xmlParser, "_xmlcb_startElement", "_xmlcb_endElement" ); + xml_set_character_data_handler( $xmlParser, "_xmlcb_cData" ); + + /* Open the file */ + if( !( $fp = fopen( $file, "r" ) ) ) { + die( "Unable to open file" ); + } + + /* Process the file */ + while( $data = fread( $fp, 4096 ) ) { + if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) { + die( sprint( "XML error: %s at line %d", + xml_error_string( xml_get_error_code( $xmlParser ) ), + xml_get_current_line_number( $xmlParser ) ) ); + } + } + + /* Return the array of queries */ + return $this->sqlArray; + } + + /** + * Loads a schema into the database + * + * Accepts an array of SQL queries generated by the parser + * and executes them. + * + * @param array $sqlArray Array of SQL statements + * @param boolean $continueOnErr Don't fail out if an error is encountered + * @return integer 0 if failed, 1 if errors, 2 if successful + */ + function ExecuteSchema( $sqlArray, $continueOnErr = TRUE ) { + $err = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr ); + + /* Return the success code */ + return $err; + } + + /** + * XML Callback to process start elements + * + * @access private + */ + function _xmlcb_startElement( $parser, $name, $attrs ) { + + $dbType = $this->dbType; + if( isset( $this->table ) ) $table = &$this->table; + if( isset( $this->index ) ) $index = &$this->index; + if( isset( $this->querySet ) ) $querySet = &$this->querySet; + $this->currentElement = $name; + + /* Process the element. Ignore unimportant elements. */ + if( in_array( trim( $name ), array( "SCHEMA", "DESCR", "COL", "CONSTRAINT" ) ) ) { + return FALSE; + } + + switch( $name ) { + + case "TABLE": /* Table element */ + if( $this->supportedPlatform( $attrs['PLATFORM'] ) ) { + $this->table = new dbTable( $attrs['NAME'] ); + } else { + unset( $this->table ); + } + break; + + case "FIELD": /* Table field */ + if( isset( $this->table ) ) { + $fieldName = $attrs['NAME']; + $fieldType = $attrs['TYPE']; + isset( $attrs['SIZE'] ) ? $fieldSize = $attrs['SIZE'] : $fieldSize = NULL; + isset( $attrs['OPTS'] ) ? $fieldOpts = $attrs['OPTS'] : $fieldOpts = NULL; + $this->table->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts ); + } + break; + + case "KEY": /* Table field option */ + if( isset( $this->table ) ) { + $this->table->addFieldOpt( $this->table->currentField, 'KEY' ); + } + break; + + case "NOTNULL": /* Table field option */ + if( isset( $this->table ) ) { + $this->table->addFieldOpt( $this->table->currentField, 'NOTNULL' ); + } + break; + + case "AUTOINCREMENT": /* Table field option */ + if( isset( $this->table ) ) { + $this->table->addFieldOpt( $this->table->currentField, 'AUTOINCREMENT' ); + } + break; + + case "DEFAULT": /* Table field option */ + if( isset( $this->table ) ) { + $this->table->addFieldOpt( $this->table->currentField, 'DEFAULT', $attrs['VALUE'] ); + } + break; + + case "INDEX": /* Table index */ + if( $this->supportedPlatform( $attrs['PLATFORM'] ) ) { + $this->index = new dbIndex( $attrs['NAME'], $attrs['TABLE'] ); + } else { + if( isset( $this->index ) ) unset( $this->index ); + } + break; + + case "SQL": /* Freeform SQL queryset */ + if( $this->supportedPlatform( $attrs['PLATFORM'] ) ) { + $this->querySet = new dbQuerySet( $attrs ); + } else { + if( isset( $this->querySet ) ) unset( $this->querySet ); + } + break; + + case "QUERY": /* Queryset SQL query */ + if( isset( $this->querySet ) ) { + /* Ignore this query set if a platform is specified and it's different than the */ + /* current connection platform. */ + if( $this->supportedPlatform( $attrs['PLATFORM'] ) ) { + $this->querySet->buildQuery(); + } else { + if( isset( $this->querySet->query ) ) unset( $this->querySet->query ); + } + } + break; + + default: + print "OPENING ELEMENT '$name'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); - - /* - 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'] - */ - if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2); - - // 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__)); - - define('TIMESTAMP_FIRST_YEAR',100); - - //============================================================================================== - // 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_EXTENSION, // ADODB extension installed - $ADODB_COMPAT_PATCH, // 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 - //============================================================================================== - - if (strnatcmp(PHP_VERSION,'4.3.0')>=0) { - define('ADODB_PHPVER',0x4300); - } else if (strnatcmp(PHP_VERSION,'4.2.0')>=0) { - define('ADODB_PHPVER',0x4200); - } else if (strnatcmp(PHP_VERSION,'4.0.5')>=0) { - define('ADODB_PHPVER',0x4050); - } else { - define('ADODB_PHPVER',0x4000); - } - $ADODB_EXTENSION = defined('ADODB_EXTENSION'); - //if (extension_loaded('dbx')) define('ADODB_DBX',1); - - /** - 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_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; - - $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 path http:// or ftp://"); - } - - - // 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 = 'V3.40 7 April 2003 (c) 2000-2003 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; - } - - - //============================================================================================== - // CHANGE NOTHING BELOW UNLESS YOU ARE CODING - //============================================================================================== - - 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. - } - - - //============================================================================================== - // CLASS ADOConnection - //============================================================================================== - - include_once(ADODB_DIR.'/adodb-connection.inc.php'); - - - - //============================================================================================== - // 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;} - } - - //============================================================================================== - // DATE AND TIME FUNCTIONS - //============================================================================================== - include_once(ADODB_DIR.'/adodb-time.inc.php'); - - //============================================================================================== - // CLASS ADORecordSet - //============================================================================================== - include_once(ADODB_DIR.'/adodb-recordset.inc.php'); - - //============================================================================================== - // 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. Later we will have XML-Data and CSV handlers - * - * @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->_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 { - return ADORecordSet::GetArray($nRows); - } - } - - function _initrs() - { - $this->_numOfRows = sizeof($this->_array); - if ($this->_skiprow1) $this->_numOfRows -= 1; - - $this->_numOfFields =(isset($this->_fieldobjects)) ? - sizeof($this->_fieldobjects):sizeof($this->_types); - } - - /* Use associative array to get fields array */ - function Fields($colname) - { - if ($this->fetchMode & ADODB_FETCH_ASSOC) 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) && $row < $this->_numOfRows) { - $this->fields = $this->_array[$row]; - return true; - } - return false; - } - - function MoveNext() - { - if (!$this->EOF) { - $this->_currentRow++; - - $pos = $this->_currentRow; - if ($this->_skiprow1) $pos += 1; - - if ($this->_numOfRows <= $pos) { - if (!$this->compat) $this->fields = false; - } else { - $this->fields = $this->_array[$pos]; - return true; - } - $this->EOF = true; - } - - return false; - } - - function _fetch() - { - $pos = $this->_currentRow; - if ($this->_skiprow1) $pos += 1; - - if ($this->_numOfRows <= $pos) { - if (!$this->compat) $this->fields = false; - return false; - } - - $this->fields = $this->_array[$pos]; - return true; - } - - function _close() - { - return true; - } - - } // ADORecordSet_array - - //============================================================================================== - // HELPER FUNCTIONS - //============================================================================================== - - /** - * Synonym for ADOLoadCode. - * - * @deprecated - */ - function ADOLoadDB($dbType) - { - return ADOLoadCode($dbType); - } - - /** - * Load the code for a specific database driver - */ - function ADOLoadCode($dbType) - { - GLOBAL $ADODB_Database; - - if (!$dbType) return false; - $ADODB_Database = strtolower($dbType); - switch ($ADODB_Database) { - case 'maxsql': $ADODB_Database = 'mysqlt'; break; - case 'postgres': - case 'pgsql': $ADODB_Database = 'postgres7'; break; - } - // Karsten KrausADONewConnection: Unable to load database driver '$db'
",false); - - return false; - } - - $cls = 'ADODB_'.$ADODB_Database; - $obj = new $cls(); - if ($errorfn) { - $obj->raiseErrorFn = $errorfn; - } - return $obj; - } - - function &NewDataDictionary(&$conn) - { - $provider = $conn->dataProvider; - if ($provider !== 'native' && $provider != 'odbc' && $provider != 'ado') - $drivername = $conn->dataProvider; - else { - $drivername = $conn->databaseType; - if (substr($drivername,0,5) == 'odbc_') $drivername = substr($drivername,5); - else if (substr($drivername,0,4) == 'ado_') $drivername = substr($drivername,4); - else if ($drivername == 'oracle') $drivername = 'oci8'; - } - 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->connection = &$conn; - $dict->upperName = strtoupper($drivername); - if (is_resource($conn->_connectionID)) - $dict->serverInfo = $conn->ServerInfo(); - - return $dict; - } - - - /** - * Save a file $filename and its $contents (normally for caching) with file locking - */ - function adodb_write_file($filename, $contents,$debug=false) - { - # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows - # So to simulate locking, we assume that rename is an atomic operation. - # First we delete $filename, then we create a $tempfile write to it and - # rename to the desired $filename. If the rename works, then we successfully - # modified the file exclusively. - # What a stupid need - having to simulate locking. - # Risks: - # 1. $tempfile name is not unique -- very very low - # 2. unlink($filename) fails -- ok, rename will fail - # 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs - # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and cache updated - if (strpos(strtoupper(PHP_OS),'WIN') !== false) { - // skip the decimal place - $mtime = substr(str_replace(' ','_',microtime()),2); - // unlink will let some latencies develop, so uniqid() is more random - @unlink($filename); - // getmypid() actually returns 0 on Win98 - never mind! - $tmpname = $filename.uniqid($mtime).getmypid(); - if (!($fd = fopen($tmpname,'a'))) return false; - $ok = ftruncate($fd,0); - if (!fwrite($fd,$contents)) $ok = false; - fclose($fd); - chmod($tmpname,0644); - if (!@rename($tmpname,$filename)) { - unlink($tmpname); - $ok = false; - } - if (!$ok) { - if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed')); - } - return $ok; - } - if (!($fd = fopen($filename, 'a'))) return false; - if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) { - $ok = fwrite( $fd, $contents ); - fclose($fd); - chmod($filename,0644); - }else { - fclose($fd); - if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename';
- $traceArr = debug_backtrace();
- array_shift($traceArr);
- $tabs = sizeof($traceArr)-1;
- foreach ($traceArr as $arr) {
- for ($i=0; $i < $tabs; $i++) $s .= ' ';
- $tabs -= 1;
- $s .= '';
- if (isset($arr['class'])) $s .= $arr['class'].'.';
- foreach($arr['args'] as $v) {
- if (is_null($v)) $args[] = 'null';
- else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
- else if (is_object($v)) $args[] = 'Object:'.get_class($v);
- else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
- else {
- $v = (string) @$v;
- $str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
- if (strlen($v) > $MAXSTRLEN) $str .= '...';
- $args[] = $str;
- }
- }
-
- $s .= $arr['function'].'('.implode(', ',$args).')';
- $s .= sprintf(" # line %4d, file: %s",
- $arr['line'],$arr['file'],$arr['file']);
- $s .= "\n";
- }
- $s .= '';
- if ($print) print $s;
- }
- return $s;
- }
-
-} // defined
-?>
\ No newline at end of file
+
+ Manual is at http://php.weblogs.com/adodb_manual
+
+ */
+
+ if (!defined('_ADODB_LAYER')) {
+ define('_ADODB_LAYER',1);
+
+ /* ============================================================================================== */
+ /* CONSTANT DEFINITIONS */
+ /* ============================================================================================== */
+
+ define('ADODB_BAD_RS','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); + + /* + 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'] + */ + if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2); + + /* 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__)); + + if (!defined('TIMESTAMP_FIRST_YEAR')) define('TIMESTAMP_FIRST_YEAR',100); + + /* ============================================================================================== */ + /* 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_EXTENSION, /* ADODB extension installed */ + $ADODB_COMPAT_PATCH, /* 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 */ + /* ============================================================================================== */ + + if (strnatcmp(PHP_VERSION,'4.3.0')>=0) { + define('ADODB_PHPVER',0x4300); + } else if (strnatcmp(PHP_VERSION,'4.2.0')>=0) { + define('ADODB_PHPVER',0x4200); + } else if (strnatcmp(PHP_VERSION,'4.0.5')>=0) { + define('ADODB_PHPVER',0x4050); + } else { + define('ADODB_PHPVER',0x4000); + } + $ADODB_EXTENSION = defined('ADODB_EXTENSION'); + /* if (extension_loaded('dbx')) define('ADODB_DBX',1); */ + + /** + 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_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; + + $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 path http:/* or ftp://"); + } + + + /* 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 = 'V3.60 16 June 2003 (c) 2000-2003 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; + } + + + /* ============================================================================================== */ + /* CHANGE NOTHING BELOW UNLESS YOU ARE CODING */ + /* ============================================================================================== */ + + 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 = 256000; /* / 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 $charSet=false; /* / character set to use - only for interbase */ + var $metaDatabasesSQL = ''; + var $metaTablesSQL = ''; + var $uniqueOrderBy = false; /* / All order by columns have to be unique */ + var $emptyDate = ' '; + /* -- */ + 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 $upperCase = false; /* / uppercase function to call for searching/where */ + 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 $dbxDriver = 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 = ''; /* / 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. */ + 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; + + /** + * Constructor + */ + function ADOConnection() + { + die('Virtual Class -- cannot instantiate'); + } + + /** + 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 _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 $HTTP_SERVER_VARS; + + if (defined('ADODB_OUTP')) { + $fn = ADODB_OUTP; + $fn($msg,$newline); + return; + } + + if ($newline) $msg .= "$ss\nInsert_ID error
'); + return false; + } + + + /** + * Portable Insert ID. Pablo RocaAffected_Rows error
',false); + 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; + } + + 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; + 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 [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 */ + /* Informix requires first before distinct - F Riosa */ + $ismssql = (strpos($this->databaseType,'mssql') !== false); + if ($ismssql) $isaccess = false; + else $isaccess = (strpos($this->databaseType,'access') !== false); + + if ($offset <= 0) { + + /* access includes ties in result */ + if ($isaccess) { + $sql = preg_replace( + '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql); + + if ($secs2cache>0) return $this->CacheExecute($secs2cache, $sql,$inputarr,$arg3); + else return $this->Execute($sql,$inputarr,$arg3); + } else if ($ismssql){ + $sql = preg_replace( + '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql); + } else { + $sql = preg_replace( + '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql); + } + } else { + $nn = $nrows + $offset; + if ($isaccess || $ismssql) { + $sql = preg_replace( + '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql); + } 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,$arg3); + else $rs = &$this->Execute($sql,$inputarr,$arg3); + } else { + if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr,$arg3); + else $rs = &$this->Execute($sql,$inputarr,$arg3); + } + $ADODB_COUNTRECS = $savec; + if ($rs && !$rs->EOF) { + return $this->_rs2rs($rs,$nrows,$offset); + } + /* print_r($rs); */ + return $rs; + } + + + /** + * 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) 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); + return $rs2; + } + + + function &GetArray($sql, $inputarr=false) + { + return $this->GetAll($sql,$inputarr); + } + + /** + * 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) { + 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.')'; + } + + + /** + * Return all rows. Compat with PEAR DB + * + * @param sql SQL statement + * @param [inputarr] input bind array + */ + function &GetAll($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')) return ADODB_PEAR_Error(); + else return false; + $arr =& $rs->GetArray(); + $rs->Close(); + return $arr; + } + + function &CacheGetAll($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')) return ADODB_PEAR_Error(); + else 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) { + $arr = array(); + if (!$rs->EOF) $arr = $rs->fields; + $rs->Close(); + return $arr; + } + + 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; + } + 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) + { + if (count($fieldArray) == 0) return 0; + $first = true; + $uSet = ''; + + if (!is_array($keyCol)) { + $keyCol = array($keyCol); + } + foreach($fieldArray as $k => $v) { + if ($autoQuote && !is_numeric($v) and substr($v,0,1) != "'" and strcasecmp($v,'null')!=0) { + $v = $this->qstr($v); + $fieldArray[$k] = $v; + } + if (in_array($k,$keyCol)) continue; /* skip UPDATE if is key */ + + if ($first) { + $first = false; + $uSet = "$k=$v"; + } else + $uSet .= ",$k=$v"; + } + + $first = true; + foreach ($keyCol as $v) { + if ($first) { + $first = false; + $where = "$v=$fieldArray[$v]"; + } else { + $where .= " and $v=$fieldArray[$v]"; + } + } + + if ($uSet) { + $update = "UPDATE $table SET $uSet WHERE $where"; + + $rs = $this->Execute($update); + if ($rs) { + if ($this->poorAffectedRows) { + /* + The Select count(*) wipes out any errors that the update would have returned. + http://phplens.com/lens/lensforum/msgs.php?id=5696 + */ + if ($this->ErrorNo()<>0) return 0; + + # affected_rows == 0 if update field values identical to old values + # for mysql - which is silly. + + $cnt = $this->GetOne("select count(*) from $table where $where"); + if ($cnt > 0) return 1; /* record already exists */ + } else + if (($this->Affected_Rows()>0)) return 1; + } + + } + /* print "Error=".$this->ErrorNo().'
'; */
+ $first = true;
+ foreach($fieldArray as $k => $v) {
+ if ($has_autoinc && in_array($k,$keyCol)) continue; /* skip autoinc col */
+
+ if ($first) {
+ $first = false;
+ $iCols = "$k";
+ $iVals = "$v";
+ } else {
+ $iCols .= ",$k";
+ $iVals .= ",$v";
+ }
+ }
+ $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)";
+ $rs = $this->Execute($insert);
+ return ($rs) ? 2 : 0;
+ }
+
+
+ /**
+ * 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
+ * @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)
+ {
+ if (!is_numeric($secs2cache)) {
+ if ($sql === false) $sql = -1;
+ if ($offset == -1) $offset = false;
+ /* sql, nrows, offset,inputarr,arg3 */
+ return $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$inputarr,$this->cacheSecs);
+ } else {
+ if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()");
+ return $this->SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
+ }
+ }
+
+ /**
+ * 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 (strpos(strtoupper(PHP_OS),'WIN') !== false) {
+ $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
+ } else {
+ $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/??/adodb_*.cache';
+ /* old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`'; */
+ }
+ if ($this->debug) {
+ ADOConnection::outp( "CacheFlush: $cmd
\n", system($cmd),""); + } else { + exec($cmd); + } + return; + } + $f = $this->_gencachename($sql.serialize($inputarr),false); + adodb_write_file($f,''); /* is adodb_write_file needed? */ + @unlink($f); + } + + /** + * Private function to generate filename for caching. + * Filename is generated based on: + * + * - sql statement + * - database type (oci8, ibase, ifx, etc) + * - database name + * - userid + * + * 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; + + $m = md5($sql.$this->databaseType.$this->database.$this->user); + $dir = $ADODB_CACHE_DIR.'/'.substr($m,0,2); + if ($createdir && !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 + * @param [arg3] reserved for john lim for future use + * @return RecordSet or false + */ + function &CacheExecute($secs2cache,$sql=false,$inputarr=false,$arg3=false) + { + if (!is_numeric($secs2cache)) { + $arg3 = $inputarr; + $inputarr = $sql; + $sql = $secs2cache; + $secs2cache = $this->cacheSecs; + } + 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->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 :("); + } + ADOConnection::outp( " $md5file cache failure: $err (see sql below)"); + } + $rs = &$this->Execute($sql,$inputarr,$arg3); + 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 { + if ($this->fnCacheExecute) { + $fn = $this->fnCacheExecute; + $fn($this, $secs2cache, $sql, $inputarr); + } + /* ok, set cached object found */ + $rs->connection = &$this; /* Pablo suggestion */ + if ($this->debug){ + global $HTTP_SERVER_VARS; + + $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']); + $ttl = $rs->timeCreated + $secs2cache - time(); + $s = is_array($sql) ? $sql[0] : $sql; + if ($inBrowser) $s = ''.htmlspecialchars($s).''; + + ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]"); + } + } + 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 and sql should only + * be a simple select stmt with no groupby/orderby/limit + * + * "Jonathan Younger"
ADONewConnection: Unable to load database driver '$db'
",false); + + return false; + } + + $cls = 'ADODB_'.$ADODB_Database; + $obj =& new $cls(); + if ($errorfn) $obj->raiseErrorFn = $errorfn; + + return $obj; + } + + function &NewDataDictionary(&$conn) + { + $provider = $conn->dataProvider; + $drivername = $conn->databaseType; + if ($provider !== 'native' && $provider != 'odbc' && $provider != 'ado') + $drivername = $conn->dataProvider; + else { + if (substr($drivername,0,5) == 'odbc_') $drivername = substr($drivername,5); + else if (substr($drivername,0,4) == 'ado_') $drivername = substr($drivername,4); + else + switch($drivername) { + case 'oracle': $drivername = 'oci8';break; + case 'sybase': $drivername = 'mssql';break; + case 'access': + case 'db2': + break; + default: + $drivername = 'generic'; + break; + } + } + 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); + if (is_resource($conn->_connectionID)) + $dict->serverInfo = $conn->ServerInfo(); + + return $dict; + } + + + /** + * Save a file $filename and its $contents (normally for caching) with file locking + */ + function adodb_write_file($filename, $contents,$debug=false) + { + # http:/* www.php.net/bugs.php?id=9203 Bug that flock fails on Windows */ + # So to simulate locking, we assume that rename is an atomic operation. + # First we delete $filename, then we create a $tempfile write to it and + # rename to the desired $filename. If the rename works, then we successfully + # modified the file exclusively. + # What a stupid need - having to simulate locking. + # Risks: + # 1. $tempfile name is not unique -- very very low + # 2. unlink($filename) fails -- ok, rename will fail + # 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs + # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and cache updated + if (strpos(strtoupper(PHP_OS),'WIN') !== false) { + /* skip the decimal place */ + $mtime = substr(str_replace(' ','_',microtime()),2); + /* unlink will let some latencies develop, so uniqid() is more random */ + @unlink($filename); + /* getmypid() actually returns 0 on Win98 - never mind! */ + $tmpname = $filename.uniqid($mtime).getmypid(); + if (!($fd = fopen($tmpname,'a'))) return false; + $ok = ftruncate($fd,0); + if (!fwrite($fd,$contents)) $ok = false; + fclose($fd); + chmod($tmpname,0644); + if (!@rename($tmpname,$filename)) { + unlink($tmpname); + $ok = false; + } + if (!$ok) { + if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed')); + } + return $ok; + } + if (!($fd = fopen($filename, 'a'))) return false; + if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) { + $ok = fwrite( $fd, $contents ); + fclose($fd); + chmod($filename,0644); + }else { + fclose($fd); + if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename';
+ $traceArr = debug_backtrace();
+ array_shift($traceArr);
+ $tabs = sizeof($traceArr)-1;
+
+ foreach ($traceArr as $arr) {
+ $args = array();
+ for ($i=0; $i < $tabs; $i++) $s .= ' ';
+ $tabs -= 1;
+ $s .= '';
+ if (isset($arr['class'])) $s .= $arr['class'].'.';
+ if (isset($arr['args']))
+ foreach($arr['args'] as $v) {
+ if (is_null($v)) $args[] = 'null';
+ else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
+ else if (is_object($v)) $args[] = 'Object:'.get_class($v);
+ else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
+ else {
+ $v = (string) @$v;
+ $str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
+ if (strlen($v) > $MAXSTRLEN) $str .= '...';
+ $args[] = $str;
+ }
+ }
+ $s .= $arr['function'].'('.implode(', ',$args).')';
+ $s .= @sprintf(" # line %4d, file: %s",
+ $arr['line'],$arr['file'],$arr['file']);
+ $s .= "\n";
+ }
+ $s .= '';
+ if ($print) print $s;
+ }
+ return $s;
+ }
+
+} /* defined */
+?>
diff --git a/lib/adodb/crypt.inc.php b/lib/adodb/crypt.inc.php
index 7266ab619df..57e8894fa90 100644
--- a/lib/adodb/crypt.inc.php
+++ b/lib/adodb/crypt.inc.php
@@ -1,64 +1,64 @@
-
-class MD5Crypt{
- function keyED($txt,$encrypt_key)
- {
- $encrypt_key = md5($encrypt_key);
- $ctr=0;
- $tmp = "";
- for ($i=0;$iV3.60 16 June 2003 (c) 2000-2003 John Lim (jlim#natsoft.com.my)
+This software is dual licensed using BSD-Style and LGPL. Where + there is any discrepancy, the BSD-Style license will take precedence. This + means you can use it in proprietary and commercial products.
+Introduction
+ Unique Features
+ How People are using ADOdb
+ Feature Requests and Bug Reports
+ Installation
+ Initializing Code ADONewConnection
+ NewADOConnection
+ Supported Databases
+ Tutorial
+ Example 1: Select
+ Example 2: Advanced Select
+ Example 3: Insert
+ Example 4: Debugging rs2html
+ example
+ Example 5: MySQL and Menus
+ Example 6: Connecting to Multiple Databases at once
+ Example 7: Generating Update and Insert SQL
+ Example 8: Implementing Scrolling with Next and Previous
+ Example 9: Exporting in CSV or Tab-Delimited Format
+ Example 10: Custom filters
+ Example 11: Smart Transactions
+
+ Using Custom Error Handlers and PEAR_Error
+ Data Source Names
+ Caching
+ Pivot Tables
+
Variables: $ADODB_COUNTRECS
+ $ADODB_CACHE_DIR $ADODB_FETCH_MODE $ADODB_LANG
+ Constants: ADODB_ASSOC_CASE
+
+ ADOConnection
+ Connections: Connect PConnect
+ NConnect
+ Executing SQL: Execute CacheExecute
+ SelectLimit CacheSelectLimit
+ Prepare PrepareSP Parameter
+
+ GetOne CacheGetOne
+ GetRow CacheGetRow
+ GetAll CacheGetAll
+ GetCol CacheGetCol
+ Replace
+ ExecuteCursor
+ (oci8 only)
+ Generates SQL: GetUpdateSQL GetInsertSQL
+ Blobs: UpdateBlob UpdateClob
+ UpdateBlobFile BlobEncode
+ BlobDecode
+ Paging/Scrolling: PageExecute CachePageExecute
+ Cleanup: CacheFlush Close
+ Transactions: BeginTrans CommitTrans
+ RollbackTrans StartTrans CompleteTrans
+ Fetching Data: SetFetchMode
+ Strings: concat qstr quote
+ Dates: DBDate DBTimeStamp
+ UnixDate UnixTimeStamp
+ OffsetDate SQLDate
+ Rows Management: Affected_Rows Insert_ID
+ GenID CreateSequence DropSequence
+
+ Error Handling: ErrorMsg ErrorNo
+ MetaError MetaErrorMsg
+ Data Dictionary (metadata): MetaDatabases MetaTables
+ MetaColumns MetaColumnNames
+ MetaPrimaryKeys ServerInfo
+
+ Statistics and Query-Rewriting: fnExecute and fnCacheExecute
+ Deprecated: Bind BlankRecordSet
+
+ ADORecordSet
+ Returns one row:FetchRow FetchInto
+ FetchObject FetchNextObject
+ FetchObj FetchNextObj
+ Returns all rows:GetArray GetRows
+ GetAssoc
+ Scrolling:Move MoveNext MoveFirst
+ MoveLast AbsolutePosition CurrentRow
+ AtFirstPage AtLastPage
+ AbsolutePage
+ Menu generation:GetMenu GetMenu2
+ Dates:UserDate UserTimeStamp
+ UnixDate UnixTimeStamp
+ Recordset Info:RecordCount PO_RecordSet
+ NextRecordSet
+ Field Info:FieldCount FetchField
+ MetaType
+ Cleanup: Close
+ Deprecated: GetRowAssoc Fields
+
rs2html example
+ Differences between ADOdb and ADO
+ Database Driver Guide
+ Change Log
+
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. PHP 4.0.5 or later + is now required (because we use array-based str_replace).
+We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, Informix, + PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access, ADO and ODBC. We have had successful reports of connecting + to Progress and DB2 via ODBC. We hope more people + will contribute drivers to support other databases.
+PHP4 supports session variables. You can store your session information using + ADOdb for true portability and scalability. See adodb-session.php for more information.
+Also read http://php.weblogs.com/portable_sql + (also available as tips_portable_sql.htm in the release) for tips on writing + portable SQL.
++ +
+ +
+ +
+ +
+ +
+ +
Feature requests and bug reports can be emailed to jlim#natsoft.com.my + or posted to the ADOdb Help forums at http://phplens.com/lens/lensforum/topics.php?id=4.
+Make sure you are running PHP 4.0.4 or later. + Unpack all the files into a directory accessible by your webserver.
+To test, try modifying some of the tutorial examples. Make sure you customize + the connection settings correctly. You can debug using:
+<?php
+ include('adodb/adodb.inc.php');
+ $db = ADONewConnection($dbdriver); # eg 'mysql' or 'postgres'
+ $db->debug = true;
+ $db->Connect($server, $user, $password, $database);
+ $rs = $db->Execute('select * from some_small_table');
+ print "<pre>";
+ print_r($rs->GetRows());
+ print "</pre>";
+?>
+When running ADOdb, at least two files are loaded. First is adodb/adodb.inc.php, + which contains all functions used by all database classes. The code specific + to a particular database is in the adodb/driver/adodb-????.inc.php file.
+For example, to connect to a mysql database:
+
+include('/path/to/set/here/adodb.inc.php');
+$conn = &ADONewConnection('mysql');
+
+Whenever you need to connect to a database, you create a Connection object + using the ADONewConnection($driver) function. + NewADOConnection($driver) is an alternative name for the same function.
+At this point, you are not connected to the database.
+You will use $conn->Connect() or
+$conn->PConnect() to perform the actual connection.
See the examples below in the Tutorial.
+ +| Name | +Tested | +Database | +RecordCount() usable | +Prerequisites | +Operating Systems | +
| access | +B | +Microsoft Access/Jet. You need to create an ODBC DSN. | +Y/N | +ODBC | +Windows only | +
| ado | +B | +Generic ADO, not tuned for specific databases. Allows + DSN-less connections. For best performance, use an OLEDB provider. + This is the base class for all ado drivers. +You can set $db->codePage before connecting. |
+ ? depends on database | +ADO or OLEDB provider | +Windows only | +
| ado_access | +B | +Microsoft Access/Jet using ADO. Allows DSN-less connections. + For best performance, use an OLEDB provider. | +Y/N | +ADO or OLEDB provider | +Windows only | +
| ado_mssql | +B | +Microsoft SQL Server using ADO. Allows DSN-less connections. + For best performance, use an OLEDB provider. | +Y/N | +ADO or OLEDB provider | +Windows only | +
| db2 | +A | +DB2. Should work reliably as based on ODBC + driver. | +Y/N | +DB2 CLI/ODBC interface | +
+ Unix and Windows. Unix + install hints. + |
+
| vfp | +A | +Microsoft Visual FoxPro. You need to create an ODBC DSN. | +Y/N | +ODBC | +Windows only | +
| fbsql | +C | +FrontBase. | +Y | +? | +
+ Unix and Windows + |
+
| ibase | +B | +Interbase 6 or earlier. Some users report you might need
+ to use this + $db->PConnect('localhost:c:/ibase/employee.gdb', "sysdba", "masterkey") + to connect. Lacks Affected_Rows currently. + + You can set $db->dialect, $db->buffers and $db->charSet before + connecting. |
+ Y/N | +Interbase client | +Unix and Windows | +
| firebird | +C | +Firebird version of interbase. | +Y/N | +Interbase client | +Unix and Windows | +
| borland_ibase | +C | +Borland version of Interbase 6.5 or later. Very sad that + the forks differ. | +Y/N | +Interbase client | +Unix and Windows | +
| informix72 | +C | +Informix databases before Informix 7.3 that do no support + SELECT FIRST. | +Y/N | +Informix client | +Unix and Windows | +
| informix | +C | +Generic informix driver. | +Y/N | +Informix client | +Unix and Windows | +
| mssql | +A | +
+ Microsoft SQL Server 7 and later. Works with Microsoft SQL Server + 2000 also. Note that date formating is problematic with this driver. For + example, the PHP mssql extension does not return the seconds for datetime! + |
+ Y/N | +Mssql client | +
+ Unix and Windows. |
+
| mssqlpo | +A | +
+ Portable mssql driver. Identical to above mssql driver, + except that '||', the concatenation operator, is converted to '+'. Useful + for porting scripts from most other sql variants that use ||. + |
+ Y/N | +Mssql client | +
+ Unix and Windows. |
+
| mysql | +A | +MySQL without transaction support. You can also set + $db->clientFlags before connecting. | +Y/N | +MySQL client | +Unix and Windows | +
| mysqlt or maxsql | +A | +
+ MySQL with transaction support. We recommend using ||
+ as the concat operator for best portability. This can be done by running
+ MySQL using: |
+ Y/N | +MySQL client | +Unix and Windows | +
| oci8 | +A | +Oracle 8/9. Has more functionality than oracle driver
+ (eg. Affected_Rows). You might have to putenv('ORACLE_HOME=...') before
+ Connect/PConnect.
+ There are 2 ways of connecting - with server IP
+ and service name: Since 2.31, we support Oracle REF cursor variables directly + (see ExecuteCursor). + |
+ Y/N | +Oracle client | +Unix and Windows | +
| oci805 | +C | +Supports reduced Oracle functionality for Oracle 8.0.5. + SelectLimit is not as efficient as in the oci8 or oci8po drivers. | +Y/N | +Oracle client | +Unix and Windows | +
| oci8po | +A | +Oracle 8/9 portable driver. This is nearly identical with
+ the oci8 driver except (a) bind variables in Prepare() use the ? convention,
+ instead of :bindvar, (b) field names use the more common PHP convention
+ of lowercase names.
+ Use this driver if porting from other databases is important. + Otherwise the oci8 driver offers better performance. + |
+ Y/N | +Oracle client | +Unix and Windows | +
| odbc | +A | +Generic ODBC, not tuned for specific databases. To connect,
+ use + PConnect('DSN','user','pwd'). This is the base class for all odbc + derived drivers. |
+ ? depends on database | +ODBC | +Unix and Windows. Unix + hints. | +
| odbc_mssql | +C | +Uses ODBC to connect to MSSQL | +Y/N | +ODBC | +Unix and Windows. | +
| odbc_oracle | +C | +Uses ODBC to connect to Oracle | +Y/N | +ODBC | +Unix and Windows. | +
| oracle | +C | +Implements old Oracle 7 client API. Use oci8 + driver if possible for better performance. | +Y/N | +Oracle client | +Unix and Windows | +
| postgres | +A | +Generic PostgreSQL driver. Currently identical to postgres7 + driver. | +Y | +PostgreSQL client | +Unix and Windows. | +
| postgres64 | +A | +For PostgreSQL 6.4 and earlier which does not support LIMIT + internally. | +Y | +PostgreSQL client | +Unix and Windows. | +
| postgres7 | +A | +PostgreSQL which supports LIMIT and other version 7 functionality. | +Y | +PostgreSQL client | +Unix and Windows. | +
| sqlanywhere | +C | +Sybase SQL Anywhere. Should work reliably as based on ODBC + driver. | +Y/N | +SQL Anywhere ODBC client | +
+ ? + |
+
| sybase | +C | +Sybase. | +Y/N | +Sybase client | +
+ Unix and Windows. + |
+
The "Tested" column indicates how extensively the code has been tested
+ and used.
+ A = well tested and used by many people
+ B = tested and usable, but some features might not be implemented
+ C = user contributed or experimental driver. Might not fully support all of
+ the latest features of ADOdb.
The column "RecordCount() usable" indicates whether RecordCount() + return the number of rows, or returns -1 when a SELECT statement is executed. + If this column displays Y/N then the RecordCount() is emulated when the global + variable $ADODB_COUNTRECS=true (this is the default). Note that for large + recordsets, it might be better to disable RecordCount() emulation because + substantial amounts of memory are required to cache the recordset for counting. Also + there is a speed penalty of 40-50% if emulation is required. This is emulated in + most databases except for PostgreSQL and MySQL. + This variable is checked every time a query is executed, so you can selectively + choose which recordsets to count.
++ +
Task: Connect to the Access Northwind DSN, display the first 2 columns + of each row.
+In this example, we create a ADOConnection object, which represents the connection + to the database. The connection is initiated with PConnect, + which is a persistent connection. Whenever we want to query the database, we + call the ADOConnection.Execute() + function. This returns an ADORecordSet object which is actually a cursor that + holds the current row in the array fields[]. + We use MoveNext() + to move from row to row.
+NB: A useful function that is not used in this example is +SelectLimit, which +allows us to limit the number of rows shown. +
+<?
+include('adodb.inc.php'); # load code common to ADOdb
+$conn = &ADONewConnection('access'); # create a connection
+$conn->PConnect('northwind'); # connect to MS-Access, northwind DSN
+$recordSet = &$conn->Execute('select * from products');
+if (!$recordSet)
+ print $conn->ErrorMsg();
+else
+while (!$recordSet->EOF) {
+ print $recordSet->fields[0].' '.$recordSet->fields[1].'<BR>';
+ $recordSet->MoveNext();
+}
+
+$recordSet->Close(); # optional
+$conn->Close(); # optional
+
+?>
+
+The $recordSet returned stores + the current row in the $recordSet->fields + array, indexed by column number (starting from zero). We use the MoveNext() + function to move to the next row. The EOF + property is set to true when end-of-file is reached. If an error occurs in Execute(), + we return false instead of a recordset.
+The $recordSet->fields[] array is generated by the PHP database
+ extension. Some database extensions only index by number and do not index
+ the array by field name. To force indexing by name - that is associative arrays
+ - use the SetFetchMode function. Each recordset saves and uses whatever fetch
+ mode was set when the recordset was created in Execute() or SelectLimit().
+
+ $db->SetFetchMode(ADODB_FETCH_NUM);
+ $rs1 = $db->Execute('select * from table');
+ $db->SetFetchMode(ADODB_FETCH_ASSOC);
+ $rs2 = $db->Execute('select * from table');
+ print_r($rs1->fields); # shows array([0]=>'v0',[1] =>'v1')
+ print_r($rs2->fields); # shows array(['col1']=>'v0',['col2'] =>'v1')
+
++
+To get the number of rows in the select statement, you can use $recordSet->RecordCount(). + Note that it can return -1 if the number of rows returned cannot be determined.
+Select a table, display the first two columns. If the second column is a date or timestamp, reformat the date to US format.
+
+<?
+include('adodb.inc.php'); # load code common to ADOdb
+$conn = &ADONewConnection('access'); # create a connection
+$conn->PConnect('northwind'); # connect to MS-Access, northwind dsn
+$recordSet = &$conn->Execute('select CustomerID,OrderDate from Orders');
+if (!$recordSet)
+ print $conn->ErrorMsg();
+else
+while (!$recordSet->EOF) {
+ $fld = $recordSet->FetchField(1);
+ $type = $recordSet->MetaType($fld->type);
+
+ if ( $type == 'D' || $type == 'T')
+ print $recordSet->fields[0].' '.
+ $recordSet->UserDate($recordSet->fields[1],'m/d/Y').'<BR>';
+ else
+ print $recordSet->fields[0].' '.$recordSet->fields[1].'<BR>';
+
+ $recordSet->MoveNext();
+}
+$recordSet->Close(); # optional
+$conn->Close(); # optional
+
+?>
+
+In this example, we check the field type of the second column using FetchField(). + This returns an object with at least 3 fields.
+We then use MetaType() + to translate the native type to a generic type. Currently the following + generic types are defined:
+If the metatype is of type date or timestamp, then we print it using the user + defined date format with UserDate(), + which converts the PHP SQL date string format to a user defined one. Another + use for MetaType() + is data validation before doing an SQL insert or update.
+Insert a row to the Orders table containing dates and strings that need to be quoted before they can be accepted by the database, eg: the single-quote in the word John's.
+
+<?
+include('adodb.inc.php'); # load code common to ADOdb
+$conn = &ADONewConnection('access'); # create a connection
+
+$conn->PConnect('northwind'); # connect to MS-Access, northwind dsn
+$shipto = $conn->qstr("John's Old Shoppe");
+
+$sql = "insert into orders (customerID,EmployeeID,OrderDate,ShipName) ";
+$sql .= "values ('ANATR',2,".$conn->DBDate(time()).",$shipto)";
+
+if ($conn->Execute($sql) === false) {
+ print 'error inserting: '.$conn->ErrorMsg().'<BR>';
+}
+?>
+
+In this example, we see the advanced date and quote handling facilities of + ADOdb. The unix timestamp (which is a long integer) is appropriately formated + for Access with DBDate(), + and the right escape character is used for quoting the John's Old Shoppe, + which is John''s Old Shoppe and not PHP's default John's + Old Shoppe with qstr(). +
+Observe the error-handling of the Execute statement. False is returned by + Execute() if an error occured. The error message + for the last error that occurred is displayed in ErrorMsg(). + Note: php_track_errors might have to be enabled for error messages to + be saved.
+<?
+include('adodb.inc.php'); # load code common to ADOdb
+$conn = &ADONewConnection('access'); # create a connection
+$conn->PConnect('northwind'); # connect to MS-Access, northwind dsn
+$shipto = $conn->qstr("John's Old Shoppe");
+$sql = "insert into orders (customerID,EmployeeID,OrderDate,ShipName) ";
+$sql .= "values ('ANATR',2,".$conn->FormatDate(time()).",$shipto)";
+$conn->debug = true;
+if ($conn->Execute($sql) === false) print 'error inserting';
+?>
+
+In the above example, we have turned on debugging by setting debug = true. + This will display the SQL statement before execution, and also show any error + messages. There is no need to call ErrorMsg() + in this case. For displaying the recordset, see the rs2html() + example.
+Also see the section on Custom Error Handlers.
+Connect to MySQL database agora, and generate a <select> menu + from an SQL statement where the <option> captions are in the 1st column, + and the value to send back to the server is in the 2nd column.
+<?
+include('adodb.inc.php'); # load code common to ADOdb
+$conn = &ADONewConnection('mysql'); # create a connection
+$conn->PConnect('localhost','userid','','agora');# connect to MySQL, agora db
+$sql = 'select CustomerName, CustomerID from customers';
+$rs = $conn->Execute($sql);
+print $rs->GetMenu('GetCust','Mary Rosli');
+?>
+Here we define a menu named GetCust, with the menu option 'Mary Rosli' selected. + See GetMenu(). + We also have functions that return the recordset as an array: GetArray(), + and as an associative array with the key being the first column: GetAssoc().
+<?
+include('adodb.inc.php'); # load code common to ADOdb
+$conn1 = &ADONewConnection('mysql'); # create a mysql connection
+$conn2 = &ADONewConnection('oracle'); # create a oracle connection
+
+$conn1->PConnect($server, $userid, $password, $database);
+$conn2->PConnect(false, $ora_userid, $ora_pwd, $oraname);
+
+$conn1->Execute('insert ...');
+$conn2->Execute('update ...');
+?>
++ +
+We show how the functions can be used when +accessing a table with the following fields: (ID, FirstName, LastName, Created). +
+Before these functions can be called, you need to initialize the recordset by +performing a select on the table. Idea and code by Jonathan Younger jyounger#unilab.com. +
+
<?
+#==============================================
+# SAMPLE GetUpdateSQL() and GetInsertSQL() code
+#==============================================
+include('adodb.inc.php');
+include('tohtml.inc.php');
+
+#==========================
+# This code tests an insert
+
+$sql = "SELECT * FROM ADOXYZ WHERE id = -1";
+# Select an empty record from the database
+
+$conn = &ADONewConnection("mysql"); # create a connection
+$conn->debug=1;
+$conn->PConnect("localhost", "admin", "", "test"); # connect to MySQL, testdb
+$rs = $conn->Execute($sql); # Execute the query and get the empty recordset
+
+$record = array(); # Initialize an array to hold the record data to insert
+
+# Set the values for the fields in the record
+# Note that field names are case-insensitive
+$record["firstname"] = "Bob";
+$record["lastNamE"] = "Smith";
+$record["creaTed"] = time();
+
+# Pass the empty recordset and the array containing the data to insert
+# into the GetInsertSQL function. The function will process the data and return
+# a fully formatted insert sql statement.
+$insertSQL = $conn->GetInsertSQL($rs, $record);
+
+$conn->Execute($insertSQL); # Insert the record into the database
+
+#==========================
+# This code tests an update
+
+$sql = "SELECT * FROM ADOXYZ WHERE id = 1";
+# Select a record to update
+
+$rs = $conn->Execute($sql); # Execute the query and get the existing record to update
+
+$record = array(); # Initialize an array to hold the record data to update
+
+# Set the values for the fields in the record
+# Note that field names are case-insensitive
+$record["firstname"] = "Caroline";
+$record["LasTnAme"] = "Smith"; # Update Caroline's lastname from Miranda to Smith
+
+# Pass the single record recordset and the array containing the data to update
+# into the GetUpdateSQL function. The function will process the data and return
+# a fully formatted update sql statement with the correct WHERE clause.
+# If the data has not changed, no recordset is returned
+$updateSQL = $conn->GetUpdateSQL($rs, $record);
+
+$conn->Execute($updateSQL); # Update the record in the database
+$conn->Close();
+?>
+
+The following code creates a very simple recordset pager, where you can scroll + from page to page of a recordset.
+ +
+include_once('../adodb.inc.php');
+include_once('../adodb-pager.inc.php');
+session_start();
+
+$db = NewADOConnection('mysql');
+
+$db->Connect('localhost','root','','xphplens');
+
+$sql = "select * from adoxyz ";
+
+$pager = new ADODB_Pager($db,$sql);
+$pager->Render($rows_per_page=5);
+This will create a basic record pager that looks like this: +
+
|< <<
+ >> >|
+ |
+ ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| Page 8/10 |
The number of rows to display at one time is controled by the Render($rows) + method. If you do not pass any value to Render(), ADODB_Pager will default to + 10 records per page. +
You can control the column titles by modifying your SQL (supported by most + databases): +
$sql = 'select id as "ID", firstname as "First Name", + lastname as "Last Name", created as "Date Created"+
from adoxyz';
The above code can be found in the adodb/tests/testpaging.php example + included with this release, and the class ADODB_Pager in adodb/adodb-pager.inc.php. + The ADODB_Pager code can be adapted by a programmer so that the text links can + be replaced by images, and the dull white background be replaced with more interesting + colors. +
You can also allow display of html by setting $pager->htmlSpecialChars = false. +
Some of the code used here was contributed by Iván Oliva and Cornel + G.
+We provide some helper functions to export in comma-separated-value (CSV) and + tab-delimited formats:
+include_once('/path/to/adodb/toexport.inc.php');
include_once('/path/to/adodb/adodb.inc.php');
+$db = &NewADOConnection('mysql');
$db->Connect($server, $userid, $password, $database);
$rs = $db->Execute('select fname as "First Name", surname as "Surname" from table');
+
+print "<pre>";
print rs2csv($rs); # return a string, CSV formatprint '<hr>';
+
$rs->MoveFirst(); # note, some databases do not support MoveFirst
print rs2tab($rs,false); # return a string, tab-delimited
+ # false == suppress field names in first line
print '<hr>';
$rs->MoveFirst();
rs2tabout($rs); # send to stdout directly (there is also an rs2csvout function)
+print "</pre>";
+
+$rs->MoveFirst();
$fp = fopen($path, "w");
+if ($fp) {
rs2csvfile($rs, $fp); # write to file (there is also an rs2tabfile function)
+ fclose($fp);
}
+
+Carriage-returns or newlines are converted to spaces. Field names are returned + in the first line of text. Strings containing the delimiter character are quoted + with double-quotes. Double-quotes are double-quoted again. This conforms to + Excel import and export guide-lines. +
All the above functions take as an optional last parameter, $addtitles which
+ defaults to true. When set to false field names in the first line
+ are suppressed.
+
Sometimes we want to pre-process all rows in a recordset before we use it. For example, +we want to ucwords all text in recordset. +
+include_once('adodb/rsfilter.inc.php');
+include_once('adodb/adodb.inc.php');
+
+// ucwords() every element in the recordset
+function do_ucwords(&$arr,$rs)
+{
+ foreach($arr as $k => $v) {
+ $arr[$k] = ucwords($v);
+ }
+}
+
+$db = NewADOConnection('mysql');
+$db->PConnect('server','user','pwd','db');
+
+$rs = $db->Execute('select ... from table');
+$rs = RSFilter($rs,'do_ucwords');
+
+The RSFilter function takes 2 parameters, the recordset, and the name + of the filter function. It returns the processed recordset scrolled + to the first record. The filter function takes two parameters, the + current row as an array, and the recordset object. For future compatibility, + you should not use the original recordset object.
++$conn->BeginTrans(); +$ok = $conn->Execute($sql); +if ($ok) $ok = $conn->Execute($sql2); +if (!$ok) $conn->RollbackTrans(); +else $conn->CommitTrans(); ++This is very complicated for large projects because you have to track the error +status. Smart Transactions is much simpler. You start a smart transaction by calling StartTrans(): +
+$conn->StartTrans(); +$conn->Execute($sql); +$conn->Execute($Sql2); +$conn->CompleteTrans(); ++ +CompleteTrans() detects when an SQL error occurs, and +will Rollback/Commit as appropriate. + +To specificly force a rollback even if no error occured, +use FailTrans(). Note that the rollback is done in +CompleteTrans(), and not in FailTrans(). + +
+$conn->StartTrans(); +$conn->Execute($sql); +if (!CheckRecords()) $conn->FailTrans(); +$conn->Execute($Sql2); +$conn->CompleteTrans(); ++Lastly, StartTrans/CompleteTrans is nestable, and only the outermost block is +executed. In contrast, BeginTrans/CommitTrans/RollbackTrans is NOT nestable. +
+$conn->StartTrans(); +$conn->Execute($sql); + $conn->StartTrans(); # ignored + if (!CheckRecords()) $conn->FailTrans(); + $conn->CompleteTrans(); # ignored +$conn->Execute($Sql2); +$conn->CompleteTrans(); ++
Note: Savepoints +are currently not supported. +
+ADOdb provides two custom handlers which you can modify for your needs. +The first one is in the adodb-errorhandler.inc.php file. This makes +use of the standard PHP functions error_reporting +to control what error messages types to display, +and trigger_error which invokes the default +PHP error handler. +
+Including the above file will cause trigger_error($errorstring,E_USER_ERROR)
+to be called when
+(a) Connect() or PConnect() fails, or
+(b) a function that executes SQL statements such as Execute() or SelectLimit() has an error.
+(c) GenID() appears to go into an infinite loop.
+
+The $errorstring is generated by ADOdb and will contain useful debugging information similar +to the error.log data generated below. +This file adodb-errorhandler.inc.php should be included before you create any ADOConnection objects. +
+ If you define error_reporting(0), no errors will be shown. + If you set error_reporting(E_ALL), all errors will be displayed on the screen. +
+<?php
+error_reporting(E_ALL); # show any error messages triggered
+include('adodb-errorhandler.inc.php');
+include('adodb.inc.php');
+include('tohtml.inc.php');
+$c = NewADOConnection('mysql');
+$c->PConnect('localhost','root','','northwind');
+$rs=$c->Execute('select * from productsz'); #invalid table productsz');
+if ($rs) $rs2html($rs);
+?>
+
+ + If you want to log the error message, you can do so by defining the following optional + constants ADODB_ERROR_LOG_TYPE and ADODB_ERROR_LOG_DEST. ADODB_ERROR_LOG_TYPE is + the error log message type (see error_log + in the PHP manual). In this case we set + it to 3, which means log to the file defined by the constant ADODB_ERROR_LOG_DEST. + +
+<?php
+error_reporting(0); # do not echo any errors
+define('ADODB_ERROR_LOG_TYPE',3);
+define('ADODB_ERROR_LOG_DEST','C:/errors.log');
+include('adodb-errorhandler.inc.php');
+include('adodb.inc.php');
+include('tohtml.inc.php');
+
+$c = NewADOConnection('mysql');
+$c->PConnect('localhost','root','','northwind');
+$rs=$c->Execute('select * from productsz'); ## invalid table productsz
+if ($rs) $rs2html($rs);
+?>
+
+The following message will be logged in the error.log file:
+
+(2001-10-28 14:20:38) mysql error: [1146: Table 'northwind.productsz' doesn't exist] in
+ EXECUTE("select * from productsz")
+
+The second error handler is adodb-errorpear.inc.php. This will create a
+PEAR_Error derived object whenever an error occurs. The last PEAR_Error object
+created can be retrieved using ADODB_Pear_Error().
+
+<?php
+include('adodb-errorpear.inc.php');
+include('adodb.inc.php');
+include('tohtml.inc.php');
+$c = NewADOConnection('mysql');
+$c->PConnect('localhost','root','','northwind');
+$rs=$c->Execute('select * from productsz'); #invalid table productsz');
+if ($rs) $rs2html($rs);
+else {
+ $e = ADODB_Pear_Error();
+ echo '<p>',$e->message,'</p>';
+}
+?>
+
++You can use a PEAR_Error derived class by defining the constant ADODB_PEAR_ERROR_CLASS +before the adodb-errorpear.inc.php file is included. For easy debugging, you can +set the default error handler in the beginning of the PHP script to PEAR_ERROR_DIE, +which will cause an error message to be printed, then halt script execution: +
+include('PEAR.php');
+PEAR::setErrorHandling('PEAR_ERROR_DIE');
+
+Note that we do not explicitly return a PEAR_Error object to you when an error + occurs. We return false instead. You have to call ADODB_Pear_Error() to get + the last error or use the PEAR_ERROR_DIE technique. +
Error messages are outputted using the static method ADOConnnection::outp($msg,$newline=true). + By default, it sends the messages to the client. You can override this to + perform error-logging. +
We now support connecting using PEAR style DSN's. A DSN is a connection string + of the form:
+$dsn = "$driver://$username:$password@$hostname/$databasename";
+You pass the DSN to the static class function DB::Connect. An example:
+ include_once('../adodb/adodb-pear.inc.php');
+ $username = 'root';
+ $password = '';
+ $hostname = 'localhost';
+ $databasename = 'xphplens';
+ $driver = 'mysql';
+ $dsn = "$driver://$username:$password@$hostname/$databasename";
+$db = DB::Connect($dsn);+
$rs = $db->Execute('select firstname,lastname from adoxyz'); + $cnt = 0; + while ($arr = $rs->FetchRow()) { + print_r($arr); print "<br>"; + }
This requires PEAR to be installed and in the default include path in php.ini.
+ADOdb now supports caching of recordsets using the CacheExecute( ), +CachePageExecute( ) and CacheSelectLimit( ) functions. There are similar to the +non-cache functions, except that they take a new first parameter, $secs2cache. +
An example: +
+include('adodb.inc.php'); # load code common to ADOdb
+$ADODB_CACHE_DIR = '/usr/ADODB_cache';
+$conn = &ADONewConnection('mysql'); # create a connection
+$conn->PConnect('localhost','userid','','agora');# connect to MySQL, agora db
+$sql = 'select CustomerName, CustomerID from customers';
+$rs = $conn->CacheExecute(15,$sql);
+The first parameter is the number of seconds to cache + the query. Subsequent calls to that query will used the cached version stored + in $ADODB_CACHE_DIR. To force a query to execute and flush the cache, call CacheExecute() + with the first parameter set to zero. Alternatively, use the CacheFlush($sql) + call.
+For the sake of security, we recommend you set register_globals=off + in php.ini if you are using $ADODB_CACHE_DIR.
+In ADOdb 1.80 onwards, the secs2cache parameter is optional in CacheSelectLimit() and +CacheExecute(). If you leave it out, it will use the $connection->cacheSecs parameter, which defaults +to 60 minutes. +
+ $conn->Connect(...);
+ $conn->cacheSecs = 3600*24; # cache 24 hours
+ $rs = $conn->CacheExecute('select * from table');
+
+Please note that magic_quotes_runtime should be turned off. More info.
+
+Pivot Tables
+
+
Since ADOdb 2.30, we support the generation of SQL to + create pivot tables, also known as cross-tabulations. For further explanation + read this DevShed Cross-Tabulation + tutorial. We assume that your database supports the SQL case-when expression. +
+ +In this example, we will use the Northwind database from Microsoft. In the + database, we have a products table, and we want to analyze this table by suppliers + versus product categories. We will place the suppliers on each row, and + pivot on categories. So from the table on the left, we generate the pivot-table on the right:
+ +
+
|
+ --> | +
+
|
+
The following code will generate the SQL for a cross-tabulation: +
+# Query the main "product" table +# Set the rows to CompanyName +# and the columns to the values of Categories +# and define the joins to link to lookup tables +# "categories" and "suppliers" +# + include "adodb/pivottable.php"; + $sql = PivotTableSQL( + $gDB, # adodb connection + 'products p ,categories c ,suppliers s', # tables + 'CompanyName', # rows (multiple fields allowed) + 'CategoryName', # column to pivot on + 'p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID' # joins/where +); ++ +
This will generate the following SQL:
+SELECT CompanyName,
+ SUM(CASE WHEN CategoryName='Beverages' THEN 1 ELSE 0 END) AS "Beverages",
+
+ SUM(CASE WHEN CategoryName='Condiments' THEN 1 ELSE 0 END) AS "Condiments",
+
+ SUM(CASE WHEN CategoryName='Confections' THEN 1 ELSE 0 END) AS "Confections",
+
+ SUM(CASE WHEN CategoryName='Dairy Products' THEN 1 ELSE 0 END) AS "Dairy
+ Products",
+ SUM(CASE WHEN CategoryName='Grains/Cereals' THEN 1 ELSE 0 END) AS "Grains/Cereals",
+
+ SUM(CASE WHEN CategoryName='Meat/Poultry' THEN 1 ELSE 0 END) AS "Meat/Poultry",
+
+ SUM(CASE WHEN CategoryName='Produce' THEN 1 ELSE 0 END) AS "Produce",
+
+ SUM(CASE WHEN CategoryName='Seafood' THEN 1 ELSE 0 END) AS "Seafood",
+
+ SUM(1) as Total
+ FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID
+ and s.SupplierID= p.SupplierID
+ GROUP BY CompanyName
You can also pivot on numerical columns and generate totals + by using ranges. This code was revised in ADODB 2.41 + and is not backward compatible. The second example shows this:
++ $sql = PivotTableSQL( + $gDB, # adodb connection + 'products p ,categories c ,suppliers s', # tables + 'CompanyName', # rows (multiple fields allowed) + array( # column ranges + ' 0 ' => 'UnitsInStock <= 0', + "1 to 5" => '0 < UnitsInStock and UnitsInStock <= 5', + "6 to 10" => '5 < UnitsInStock and UnitsInStock <= 10', + "11 to 15" => '10 < UnitsInStock and UnitsInStock <= 15', + "16+" => '15 < UnitsInStock' + ), + ' p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID', # joins/where + 'UnitsInStock', # sum this field + 'Sum ' # sum label prefix +); ++
Which generates:
+ SELECT CompanyName,
+ SUM(CASE WHEN UnitsInStock <= 0 THEN UnitsInStock ELSE 0 END) AS "Sum
+ 0 ",
+ SUM(CASE WHEN 0 < UnitsInStock and UnitsInStock <= 5 THEN UnitsInStock
+ ELSE 0 END) AS "Sum 1 to 5",
+ SUM(CASE WHEN 5 < UnitsInStock and UnitsInStock <= 10 THEN UnitsInStock
+ ELSE 0 END) AS "Sum 6 to 10",
+ SUM(CASE WHEN 10 < UnitsInStock and UnitsInStock <= 15 THEN UnitsInStock
+ ELSE 0 END) AS "Sum 11 to 15",
+ SUM(CASE WHEN 15 < UnitsInStock THEN UnitsInStock ELSE 0 END) AS "Sum
+ 16+",
+ SUM(UnitsInStock) AS "Sum UnitsInStock",
+ SUM(1) as Total,
+ FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID
+ and s.SupplierID= p.SupplierID
+ GROUP BY CompanyName
+
Function parameters with [ ] around them are optional.
+ +If the database driver API does not support counting the number of records + returned in a SELECT statement, the function RecordCount() is emulated when + the global variable $ADODB_COUNTRECS is set to true, which is the default. + We emulate this by buffering the records, which can take up large amounts + of memory for big recordsets. Set this variable to false for the best performance. + This variable is checked every time a query is executed, so you can selectively + choose which recordsets to count.
+If you are using recordset caching, this is the directory to save your recordsets + in. Define this before you call any caching functions such as CacheExecute( + ). We recommend setting register_globals=off in php.ini if you use this + feature for security reasons.
+If you are using Unix and apache, you might need to set your cache directory + permissions to something similar to the following:
+ +chown -R apache /path/to/adodb/cache
+ chgrp -R apache /path/to/adodb/cache
Determines the language used in MetaErrorMsg(). The default is 'en', for English. +To find out what languages are supported, see the files +in adodb/lang/adodb-$lang.inc.php, where $lang is the supported langauge. +
This is a global variable that determines how arrays are retrieved by recordsets. + The recordset saves this value on creation (eg. in Execute( ) or SelectLimit( + )), and any subsequent changes to $ADODB_FETCH_MODE have no affect on existing + recordsets, only on recordsets created in the future.
+The following constants are defined:
+ +define('ADODB_FETCH_DEFAULT',0);
+ define('ADODB_FETCH_NUM',1);
+ define('ADODB_FETCH_ASSOC',2);
+ define('ADODB_FETCH_BOTH',3);
An example: +
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $rs1 = $db->Execute('select * from table');
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $rs2 = $db->Execute('select * from table');
+ print_r($rs1->fields); # shows array([0]=>'v0',[1] =>'v1')
+ print_r($rs2->fields); # shows array(['col1']=>'v0',['col2'] =>'v1')
+
+As you can see in the above example, both recordsets store and use different + fetch modes based on the $ADODB_FETCH_MODE setting when the recordset was + created by Execute().
+If no fetch mode is predefined, the fetch mode defaults to ADODB_FETCH_DEFAULT. + The behaviour of this default mode varies from driver to driver, so do not + rely on ADODB_FETCH_DEFAULT. For portability, we recommend sticking to ADODB_FETCH_NUM + or ADODB_FETCH_ASSOC. Many drivers do not support ADODB_FETCH_BOTH.
+SetFetchMode Function
+Some programmers prefer to use a more object-oriented solution, where the fetch + mode is set by a object function, SetFetchMode. + Once this function is called for a connection object, that connection object + will ignore the global variable $ADODB_FETCH_MODE and will use the internal + fetchMode property exclusively.
+
+ $db->SetFetchMode(ADODB_FETCH_NUM);
+ $rs1 = $db->Execute('select * from table');
+ $db->SetFetchMode(ADODB_FETCH_ASSOC);
+ $rs2 = $db->Execute('select * from table');
+ print_r($rs1->fields); # shows array([0]=>'v0',[1] =>'v1')
+ print_r($rs2->fields); # shows array(['col1']=>'v0',['col2'] =>'v1')
+To retrieve the previous fetch mode, you can use check the $db->fetchMode + property, or use the return value of SetFetchMode( ). +
+You can control the associative fetch case for certain drivers which behave + differently. For the sybase, oci8po, mssql, odbc and ibase drivers and all + drivers derived from them, ADODB_ASSOC_CASE will by default generate recordsets + where the field name keys are lower-cased. Use the constant ADODB_ASSOC_CASE + to change the case of the keys. There are 3 possible values:
+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'] -- this is the
+ default since ADOdb 2.90
To use it, declare it before you incldue adodb.inc.php.
+define('ADODB_ASSOC_CASE', 2); # use native-case for ADODB_FETCH_ASSOC
+ include('adodb.inc.php');
Object that performs the connection to the database, executes SQL statements + and has a set of utility functions for standardising the format of SQL statements + for issues such as concatenation and date formats.
+databaseType: Name of the database system we are connecting to. Eg. + odbc or mssql or mysql.
+dataProvider: The underlying mechanism used to connect to the database. + Normally set to native, unless using odbc or ado.
+host: Name of server or data source name (DSN) to connect to.
+database: Name of the database or to connect to. If ado is used, it + will hold the ado data provider.
+user: Login id to connect to database. Password is not saved for security + reasons.
+raiseErrorFn: Allows you to define an error handling function. See adodb-errorhandler.inc.php + for an example.
+debug: Set to true to make debug statements to appear.
+concat_operator: Set to '+' or '||' normally. The operator used to concatenate + strings in SQL. Used by the Concat function.
+fmtDate: The format used by the DBDate + function to send dates to the database. is '#Y-m-d#' for Microsoft Access, + and ''Y-m-d'' for MySQL.
+fmtTimeStamp: The format used by the DBTimeStamp + function to send timestamps to the database.
+true: The value used to represent true.Eg. '.T.'. for Foxpro, '1' for + Microsoft SQL.
+false: The value used to represent false. Eg. '.F.'. for Foxpro, '0' + for Microsoft SQL.
+replaceQuote: The string used to escape quotes. Eg. double single-quotes + for Microsoft SQL, and backslash-quote for MySQL. Used by qstr.
+autoCommit: indicates whether automatic commit is enabled. Default is + true.
+charSet: set the default charset to use. Currently only interbase supports + this.
+dialect: set the default sql dialect to use. Currently only interbase + supports this.
+metaTablesSQL: SQL statement to return a list of available tables. Eg. + SHOW TABLES in MySQL.
+genID: The latest id generated by GenID() if supported by the database.
+cacheSecs: The number of seconds to cache recordsets if CacheExecute() + or CacheSelectLimit() omit the $secs2cache parameter. Defaults to 60 minutes.
+sysDate: String that holds the name of the database function to call + to get the current date. Useful for inserts and updates.
+sysTimeStamp: String that holds the name of the database function to + call to get the current timestamp/datetime value.
+leftOuter: String that holds operator for left outer join, if known. + Otherwise set to false.
+rightOuter: String that holds operator for left outer join, if known. + Otherwise set to false.
+ansiOuter: Boolean that if true indicates that ANSI style outer joins + are permitted. Eg. select * from table1 left join table2 on p1=p2.
+connectSID: Boolean that indicates whether to treat the $database parameter + in connects as the SID for the oci8 driver. Defaults to false. Useful for + Oracle 8.0.5 and earlier.
+autoRollback: Persistent connections are auto-rollbacked in PConnect( + ) if this is set to true. Default is false.
+ADOConnection( )
+Constructor function. Do not call this directly. Use ADONewConnection( ) instead.
+Connect($host,[$user],[$password],[$database])
+Non-persistent connect to data source or server $host, using userid + $user and password $password. If the server supports multiple + databases, connect to database $database.
+Returns true/false depending on connection.
+ADO Note: If you are using a Microsoft ADO and not OLEDB, you can set the $database + parameter to the OLEDB data provider you are using.
+PostgreSQL: An alternative way of connecting to the database is to pass the + standard PostgreSQL connection string in the first parameter $host, and the + other parameters will be ignored.
+For Oracle and Oci8, there are two ways to connect. First is to use the TNS + name defined in your local tnsnames.ora (or ONAMES or HOSTNAMES). Place the + name in the $database field, and set the $host field to false. Alternatively, + set $host to the server, and $database to the database SID, this bypassed + tnsnames.ora. +
Examples: +
# $oraname in tnsnames.ora/ONAMES/HOSTNAMES
+ $conn->Connect(false, 'scott', 'tiger', $oraname);
+ $conn->Connect('server:1521', 'scott', 'tiger', 'ServiceName'); # bypass tnsnames.ora
+There are many examples of connecting to a database at php.weblogs.com/ADOdb, + and in the testdatabases.inc.php file included in the release.
+PConnect($host,[$user],[$password],[$database])
+Persistent connect to data source or server $host, using userid $user + and password $password. If the server supports multiple databases, + connect to database $database.
+We now perform a rollback on persistent connection for selected databases since + 2.21, as advised in the PHP manual. See change log or source code for which + databases are affected. +
Returns true/false depending on connection. See Connect( ) above for more info.
+Since ADOdb 2.21, we also support autoRollback. If you set:
+ + $conn = &NewADOConnection('mysql');
+ $conn->autoRollback = true; # default is false
+ $conn->PConnect(...); # rollback here
+Then when doing a persistent connection with PConnect( ), ADOdb will + perform a rollback first. This is because it is documented that PHP is + not guaranteed to rollback existing failed transactions when + persistent connections are used. This is implemented in Oracle, + MySQL, PgSQL, MSSQL, ODBC currently. +
Since ADOdb 3.11, you can force non-persistent +connections even if PConnect is called by defining the constant +ADODB_NEVER_PERSIST before you call PConnect. +
NConnect($host,[$user],[$password],[$database])
+Always force a new connection. In contrast, PHP sometimes reuses connections
+ when you use Connect() or PConnect(). Currently works only on mysql (PHP 4.3.0
+ or later) and oci8-derived drivers. For other drivers, NConnect() works like
+ Connect().
+
+
+ Execute SQL statement $sql and return derived class of ADORecordSet
+ if successful. Note that a record set is always returned on success, even
+ if we are executing an insert or update statement. Returns derived class of ADORecordSet. Eg. if connecting via mysql, then ADORecordSet_mysql
+ would be returned. False is returned if there was an error in executing the
+ sql. The $inputarr parameter can be used for binding variables to parameters. Below
+ is an Oracle example: Another example, using ODBC,which uses the ? convention: Variable binding in the odbc and oci8po drivers.
+ CacheExecute([$secs2cache,]$sql,$inputarr=false) Similar to Execute, except that the recordset is cached for $secs2cache seconds
+ in the $ADODB_CACHE_DIR directory. If CacheExecute() is called again with
+ the same parameters, same database, same userid, same password, and the cached
+ recordset has not expired, the cached recordset is returned.
+ Alternatively, since ADOdb 1.80, the $secs2cache parameter is optional: Performance note: I have done some benchmarks and found that they vary so greatly
+ that it's better to talk about when caching is of benefit. When your database
+ server is much slower than your Web server or the database is very
+ overloaded then ADOdb's caching is good because it reduces the load on
+ your database server. If your database server is lightly loaded or much faster
+ than your Web server, then caching could actually reduce performance. ExecuteCursor($sql,$cursorName='rs',$parameters=false) Execute an Oracle stored procedure, and returns an Oracle REF cursor variable as
+ a regular ADOdb recordset. Does not work with any other database except oci8.
+ Thanks to Robert Tuttle for the design.
+ ExecuteCursor() is a helper function that does the following internally:
+ SelectLimit($sql,$numrows=-1,$offset=-1,$inputarr=false) Returns a recordset if successful. Returns false otherwise. Performs a select
+ statement, simulating PostgreSQL's SELECT statement, LIMIT $numrows OFFSET
+ $offset clause. In PostgreSQL, SELECT * FROM TABLE LIMIT 3 will return the first 3 records
+ only. The equivalent is And SELECT * FROM TABLE LIMIT 3 OFFSET 2 will return records 3, 4 and 5 (eg.
+ after record 2, return 3 rows). The equivalent in ADOdb is Note that this is the opposite of MySQL's LIMIT clause. You can also
+ set The last parameter $inputarr is for databases that support variable binding
+ such as Oracle oci8. This substantially reduces SQL compilation overhead.
+ Below is an Oracle example: The oci8po driver (oracle portable driver) uses the more standard bind variable
+ of ?:
+
+ Ron Wilson reports that SelectLimit does not work with UNIONs.
+ CacheSelectLimit([$secs2cache,] $sql, $numrows=-1,$offset=-1,$inputarr=false) Similar to SelectLimit, except that the recordset returned is cached for $secs2cache
+ seconds in the $ADODB_CACHE_DIR directory. Since 1.80, $secs2cache has been optional, and you can define the caching time
+ in $connection->cacheSecs.
+ $conn->Execute("SELECT * FROM TABLE WHERE COND=:val", array('val'=> $val));
+
+
+ $conn->Execute("SELECT * FROM TABLE WHERE COND=?", array($val));
+
+Binding variables
+Variable binding speeds the compilation and caching of SQL statements, leading
+to higher performance. Currently Oracle and ODBC support variable binding. ODBC
+style ? binding is emulated in databases that do not support binding.
+
+$rs = $db->Execute('select * from table where val=?', array('10'));
+
+Variable binding in the oci8 driver.
+
+$rs = $db->Execute('select name from table where val=:key',
+ array('key' => 10));
+
+
+ include('adodb.inc.php');
+ include('tohtml.inc.php');
+ $ADODB_CACHE_DIR = '/usr/local/ADOdbcache';
+ $conn = &ADONewConnection('mysql');
+ $conn->PConnect('localhost','userid','password','database');
+ $rs = $conn->CacheExecute(15, 'select * from table'); # cache 15 secs
+ rs2html($rs); /* recordset to html table */
+
+
+ $conn->Connect(...);
+ $conn->cacheSecs = 3600*24; // cache 24 hours
+ $rs = $conn->CacheExecute('select * from table');
+
+Note that the $secs2cache parameter is optional. If omitted, we use the value
+in $connection->cacheSecs (default is 3600 seconds, or 1 hour). Use CacheExecute()
+only with SELECT statements.
+
+ $db = ADONewConnection("oci8");
+ $db->Connect("foo.com:1521", "uid", "pwd", "FOO");
+ $rs = $db->ExecuteCursor("begin :cursorvar := getdata(:param1); end;",
+ 'cursorvar',
+ array('param1'=>10));
+ # $rs is now just like any other ADOdb recordset object
+
rs2html($rs);
+ $stmt = $db->Prepare("BEGIN :RS := SP_FOO(); END;");
+ $db->Parameter($stmt, $cur, 'RS', false, -1, OCI_B_CURSOR);
+ $rs = $db->Execute($stmt);
+$connection->SelectLimit('SELECT * FROM TABLE',3).
+ This functionality is simulated for databases that do not possess this feature.$connection->SelectLimit('SELECT
+ * FROM TABLE',3,2).$connection->SelectLimit('SELECT * FROM TABLE',-1,10) to
+ get rows 11 to the last row.
+ $conn->SelectLimit("SELECT * FROM TABLE WHERE COND=:val", 100,-1,array('val'=> $val));
+
+
+ $conn->SelectLimit("SELECT * FROM TABLE WHERE COND=?", 100,-1,array('val'=> $val));
+
+
$conn->Connect(...);
+ $conn->cacheSecs = 3600*24; // cache 24 hours
+ $rs = $conn->CacheSelectLimit('select * from table',10);
+
+CacheFlush($sql=false,$inputarr=false)
+Flush (delete) any cached recordsets for the SQL statement $sql in $ADODB_CACHE_DIR. +
If no parameter is passed in, then all adodb_*.cache files are deleted. +
If you want to flush all cached recordsets manually, execute the following
+ PHP code (works only under Unix):
+ system("rm -f `find ".$ADODB_CACHE_DIR." -name
+ adodb_*.cache`");
For general cleanup of all expired files, you should use crontab
+ on Unix, or at.exe on Windows, and a shell script similar to the following:
+ #------------------------------------------------------
+ # This particular example deletes files in the TMPPATH
+ # directory with the string ".cache" in their name that
+ # are more than 7 days old.
+ #------------------------------------------------------
+ AGED=7
+ find ${TMPPATH} -mtime +$AGED | grep "\.cache" | xargs rm -f
+
Returns a virtualized error number, based on PEAR DB's error number system. You might +need to include adodb-error.inc.php before you call this function. The parameter $errno +is the native error number you want to convert. If you do not pass any parameter, MetaError +will call ErrorNo() for you and convert it. If the error number cannot be virtualized, MetaError +will return -1 (DB_ERROR).
+ + +Pass the error number returned by MetaError() for the equivalent textual error message.
+ +Returns the last status or error message. This can return a string even if + no error occurs. In general you do not need to call this function unless an + ADOdb function returns false on an error.
+Note: If debug is enabled, the SQL error message is always displayed + when the Execute function is called.
+ +Returns the last error number. Note that old versions of PHP (pre 4.0.6) do + not support error number for ODBC. In general you do not need to call this + function unless an ADOdb function returns false on an error.
+ + +Sets the current fetch mode for the connection and stores + it in $db->fetchMode. Legal modes are ADODB_FETCH_ASSOC and ADODB_FETCH_NUM. + For more info, see $ADODB_FETCH_MODE.
+Returns the previous fetch mode, which could be false + if SetFetchMode( ) has not been called before.
+ +CreateSequence($seqName = 'adodbseq',$startID=1)
+Create a sequence. The next time GenID( ) is called, the value returned will + be $startID. Added in 2.60. +
DropSequenceD($seqName = 'adodbseq')
+Delete a sequence. Added in 2.60. +
GenID($seqName = 'adodbseq',$startID=1)
+Generate a sequence number . Works for interbase, + mysql, postgresql, oci8, oci8po, mssql, ODBC based (access,vfp,db2,etc) drivers + currently. Uses $seqName as the name of the sequence. GenID() will automatically + create the sequence for you if it does not exist (provided the userid has + permission to do so). Otherwise you will have to create the sequence yourself. +
If your database driver emulates sequences, the name of the table is the sequence + name. The table has one column, "id" which should be of type integer, or if + you need something larger - numeric(16). +
For ODBC and databases that do not support sequences natively (eg mssql, mysql), + we create a table for each sequence. If the sequence has not been defined + earlier, it is created with the starting value set in $startID.
+Note that the mssql driver's GenID() before 1.90 used to generate 16 byte GUID's.
+UpdateBlob($table,$column,$val,$where)
+Allows you to store a blob (in $val) into $table into $column in a row at $where. +Usage: +
+
+ # for oracle
+ $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, empty_blob())');
+ $conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1');
+
+ # non oracle databases
+ $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+ $conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1');
+
+Returns true if succesful, false otherwise. Supported by MySQL, PostgreSQL, + Oci8, Oci8po and Interbase drivers. Other drivers might work, depending on + the state of development.
+Note that when an Interbase blob is retrieved using SELECT, it still needs + to be decoded using $connection->DecodeBlob($blob); to derive the original + value in versions of PHP before 4.1.0. +
For PostgreSQL, you can store your blob using blob oid's or as a bytea field.
+ You can use bytea fields but not blob oid's currently with UpdateBlob( ).
+ Conversely UpdateBlobFile( ) supports oid's, but not bytea data.
+
+ If you do not pass in an oid, then UpdateBlob() assumes that you are storing
+ in bytea fields.
+
UpdateClob($table,$column,$val,$where)
+Allows you to store a clob (in $val) into $table into $column in a row at $where. +Similar to UpdateBlob (see above), but for Character Large OBjects. +Usage: +
+ # for oracle
+ $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, empty_clob())');
+ $conn->UpdateBlob('clobtable','clobcol',$clobvalue,'id=1');
+
+ # non oracle databases
+ $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
+ $conn->UpdateBlob('clobtable','clobcol',$clobvalue,'id=1');
+
+UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
+Similar to UpdateBlob, except that we pass in a file path to where the blob + resides. +
For PostgreSQL, if you are using blob oid's, use this interface. This interface + does not support bytea fields. +
Returns true if successful, false otherwise. +
Some databases require blob's to be encoded manually before upload. Note if + you use UpdateBlob( ) or UpdateBlobFile( ) the conversion is done automatically + for you and you do not have to call this function. For PostgreSQL, currently, + BlobEncode() can only be used for bytea fields. +
Returns the encoded blob value. +
Note that there is a connection property called blobEncodeType which + has 3 legal values: +
false - no need to perform encoding or decoding.
+ 'I' - blob encoding required, and returned encoded blob is a numeric value
+ (no need to quote).
+ 'C' - blob encoding required, and returned encoded blob is a character value
+ (requires quoting).
+
This is purely for documentation purposes, so that programs that accept multiple + database drivers know what is the right thing to do when processing blobs. +
Some databases require blob's to be decoded manually after doing a select statement. + If the database does not require decoding, then this function will return + the blob unchanged. Currently BlobDecode is only required for one database, + PostgreSQL, and only if you are using blob oid's (if you are using bytea fields, + we auto-decode for you).
+$rs = $db->Execute("select bloboid from postgres_table where id=$key");
+$blob = $db->BlobDecode( reset($rs->fields) );
+Replace($table, $arrFields, $keyCols,$autoQuote=false)
+Try to update a record, and if the record is not found, an insert statement + is generated and executed. Returns 0 on failure, 1 if update statement worked, + 2 if no record was found and the insert was executed successfully. This differs + from MySQL's replace which deletes the record and inserts a new record. This + also means you cannot update the primary key. The only exception to this is + Interbase and its derivitives, which uses delete and insert because of some + Interbase API limitations. +
The parameters are $table which is the table name, the $keyCols which is an + associative array where the keys are the field names, and keyCols is the name + of the primary key, or an array of field names if it is a compound key. If + $autoQuote is set to true, then Replace() will quote all values that are non-numeric; + auto-quoting will not quote nulls. Note that auto-quoting will not work if + you use SQL functions or operators. +
Examples: +
+# single field primary key
+$ret = $db->Replace('atable',
+ array('id'=>1000,'firstname'=>'Harun','lastname'=>'Al-Rashid'),
+ 'id',
+ 'firstname',$autoquote = true);
+# generates UPDATE atable SET firstname='Harun',lastname='Al-Rashid' WHERE id=1000
+# or INSERT INTO atable (id,firstname,lastname) VALUES (1000,'Harun','Al-Rashid')
+
+# compound key
+$ret = $db->Replace('atable2',
+ array('firstname'=>'Harun','lastname'=>'Al-Rashid', 'age' => 33, 'birthday' => 'null'),
+ array('lastname','firstname'),
+ 'firstname',$autoquote = true);
+
+# no auto-quoting
+$ret = $db->Replace('atable2',
+ array('firstname'=>"'Harun'",'lastname'=>"'Al-Rashid'", 'age' => 'null'),
+ array('lastname','firstname'),
+ 'firstname');
+
+
+GetUpdateSQL(&$rs, $arrFields, $forceUpdate=false,$magicq=false)
+Generate SQL to update a table given a recordset $rs, and the modified fields + of the array $arrFields (which must be an associative array holding the column + names and the new values) are compared with the current recordset. If $forceUpdate + is true, then we also generate the SQL even if $arrFields is identical to + $rs->fields. Requires the recordset to be associative. $magicq is used + to indicate whether magic quotes are enabled (see qstr()). The field names in the array + are case-insensitive.
+GetInsertSQL(&$rs, $arrFields,$magicq=false)
+Generate SQL to insert into a table given a recordset $rs. Requires the query + to be associative. $magicq is used to indicate whether magic quotes are enabled + (for qstr()). The field names in the array are case-insensitive.
+PageExecute($sql, $nrows, $page, $inputarr=false) +Used for pagination of recordset. $page is 1-based. See Example + 8.
+ +CachePageExecute($secs2cache, + $sql, $nrows, $page, $inputarr=false)
+Used for pagination of recordset. $page is 1-based. See + Example 8. Caching version of PageExecute.
+ + + +Close the database connection. PHP4 proudly states that we no longer have to + clean up at the end of the connection because the reference counting mechanism + of PHP4 will automatically clean up for us.
+ +Start a monitored transaction. As SQL statements are executed, ADOdb will monitor + for SQL errors, and if any are detected, when CompleteTrans() is called, we auto-rollback. +
+
To understand why StartTrans() is superior to BeginTrans(), + let us examine a few ways of using BeginTrans(). + The following is the wrong way to use transactions: +
+$DB->BeginTrans();
+$DB->Execute("update table1 set val=$val1 where id=$id");
+$DB->Execute("update table2 set val=$val2 where id=$id");
+$DB->CommitTrans();
+
+because you perform no error checking. It is possible to update table1 and + for the update on table2 to fail. Here is a better way: +
+$DB->BeginTrans();
+$ok = $DB->Execute("update table1 set val=$val1 where id=$id");
+if ($ok) $ok = $DB->Execute("update table2 set val=$val2 where id=$id");
+if ($ok) $DB->CommitTrans();
+else $DB->RollbackTrans();
+
+Another way is (since ADOdb 2.0): +
+$DB->BeginTrans();
+$ok = $DB->Execute("update table1 set val=$val1 where id=$id");
+if ($ok) $ok = $DB->Execute("update table2 set val=$val2 where id=$id");
+$DB->CommitTrans($ok);
+
+Now it is a headache monitoring $ok all over the place. StartTrans() is an +improvement because it monitors all SQL errors for you. This is particularly +useful if you are calling black-box functions in which SQL queries might be executed. + Also all BeginTrans, CommitTrans and RollbackTrans calls inside a StartTrans block + will be disabled, so even if the black box function does a commit, it will be ignored. +
+$DB->StartTrans();
+CallBlackBox();
+$DB->Execute("update table1 set val=$val1 where id=$id");
+$DB->Execute("update table2 set val=$val2 where id=$id");
+$DB->CompleteTrans($ok);
+
+Note that a StartTrans blocks are nestable, the inner blocks are ignored. +
CompleteTrans($autoComplete=true)
+Complete a transaction called with StartTrans(). This function monitors + for SQL errors, and will commit if no errors have occured, otherwise it will rollback. + Returns true on commit, false on rollback. If the parameter $autoComplete is true + monitor sql errors and commit and rollback as appropriate. Set $autoComplete to false + to force rollback even if no SQL error detected. +
+Begin a transaction. Turns off autoCommit. Returns true if successful. Some + databases will always return false if transaction support is not available. + Any open transactions will be rolled back when the connection is closed. Among the + databases that support transactions are Oracle, PostgreSQL, Interbase, MSSQL, certain + versions of MySQL, DB2, Informix, Sybase, etc.
+Note that StartTrans() and CompleteTrans() is a superior method of + handling transactions, available since ADOdb 3.40. For a explanation, see the StartTrans() documentation. + +
You can also use the ADOdb error handler to die + and rollback your transactions for you transparently. Some buggy database extensions + are known to commit all outstanding tranasactions, so you might want to explicitly + do a $DB->RollbackTrans() in your error handler for safety. +
Since ADOdb 2.50, you are able to detect when you are inside a transaction. Check + that $connection->transCnt > 0. This variable is incremented whenever BeginTrans() is called, + and decremented whenever RollbackTrans() or CommitTrans() is called. +
+End a transaction successfully. Returns true if successful. If the database + does not support transactions, will return true also as data is always committed. +
+If you pass the parameter $ok=false, the data is rolled back. See example in + BeginTrans().
+ +End a transaction, rollback all changes. Returns true if successful. If the + database does not support transactions, will return false as data is never rollbacked. +
+ +Executes the SQL and returns the first field of the first row. The recordset + and remaining rows are discarded for you automatically. If an error occur, false + is returned.
+ +Executes the SQL and returns the first row as an array. The recordset and remaining + rows are discarded for you automatically. If an error occurs, false is returned.
+ + +Executes the SQL and returns the all the rows as a 2-dimensional + array. The recordset is discarded for you automatically. If an error occurs, + false is returned.
+GetCol($sql,$inputarr=false,$trim=false)
+ +Executes the SQL and returns all elements of the first column as a +1-dimensional array. The recordset is discarded for you automatically. If an error occurs, + false is returned.
+CacheGetOne([$secs2cache,] + $sql,$inputarr=false), CacheGetRow([$secs2cache,] $sql,$inputarr=false), CacheGetAll([$secs2cache,] + $sql,$inputarr=false), CacheGetCol([$secs2cache,] + $sql,$inputarr=false,$trim=false)
+ +Similar to above Get* functions, except that the recordset is serialized and + cached in the $ADODB_CACHE_DIR directory for $secs2cache seconds. Good for speeding + up queries on rarely changing data. Note that the $secs2cache parameter is optional. + If omitted, we use the value in $connection->cacheSecs (default is 3600 seconds, + or 1 hour).
+ + +Prepares an SQL query for repeated execution. Only supported + internally by interbase, oci8 and selected ODBC-based drivers, otherwise it + is emulated. There is no performance advantage to using Prepare() with emulation. +
+Returns an array containing the original sql statement + in the first array element; the remaining elements of the array are driver dependent. + If there is an error, or we are emulating Prepare( ), we return the original + $sql string. This is because all error-handling has been centralized in Execute( + ).
+Example:
+$stmt = $DB->Prepare('insert into table (col1,col2) values (?,?)');
+for ($i=0; $i < $max; $i++)
$DB->Execute($stmt,array((string) rand(), $i));
+
++Important: Due to limitations or bugs in PHP, if you are getting errors when you using prepared queries, try +setting $ADODB_COUNTRECS = false before preparing. This behaviour has been observed with ODBC. +
+In the mssql driver, preparing stored procedures requires a special function + call, mssql_init( ), which is called by this function. PrepareSP( ) is available + in all other drivers, and is emulated by calling Prepare( ). For examples of + usage, see Parameter( ) below.
+Returns the same array or $sql string as Prepare( ) above.
+Parameter($stmt, $var, $name, $isOutput=false, + $maxLen = 4000, $type = false )
+Adds a bind parameter in a fashion that is compatible with Microsoft SQL Server
+ and Oracle oci8. The parameters are:
+
+ $stmt Statement returned by Prepare() or PrepareSP().
+ $var PHP variable to bind to. Make sure you pre-initialize it!
+ $name Name of stored procedure variable name to bind to.
+ [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT
+ 2= IN/OUT. This is ignored in oci8 as this driver auto-detects the direction.
+ [$maxLen] Maximum length of the parameter variable.
+ [$type] Consult mssql_bind and ocibindbyname
+ docs at php.net for more info on legal values for type.
In mssql, $opt can hold the following elements: array('type' => integer, + maxLen =>integer). Example:
+ +# @RETVAL = SP_RUNSOMETHING @myid,@group+
$stmt = $db->PrepareSP('SP_RUNSOMETHING');
# note that the parameter name does not have @ in front!
$db->Parameter($stmt,$id,'myid');
$db->Parameter($stmt,$group,'group',false,64);
# return value in mssql - RETVAL is hard-coded name
$db->Parameter($stmt,$ret,'RETVAL',true);
$db->Execute($stmt);
An oci8 example:
+ +# For oracle, Prepare and PrepareSP are identical +$stmt = $db->PrepareSP( + "declare RETVAL integer;+
begin
:RETVAL := SP_RUNSOMETHING(:myid,:group);
end;");
$db->Parameter($stmt,$id,'myid');
$db->Parameter($stmt,$group,'group',false,64); +$db->Parameter($stmt,$ret,'RETVAL',true);
$db->Execute($stmt); +
Note that the only difference between the oci8 and mssql implementations is + the syntax of $sql.
+If $type parameter is set to false, in mssql, $type will be dynamicly determined +based on the type of the PHP variable passed (string +=> SQLCHAR, boolean =>SQLINT1, integer =>SQLINT4 or float/double=>SQLFLT8). +In oci8, $type can be set to OCI_B_FILE (Binary-File), OCI_B_CFILE (Character-File), +OCI_B_CLOB (Character-LOB), OCI_B_BLOB (Binary-LOB) and OCI_B_ROWID (ROWID). To +pass in a null, use $db->Parameter($stmt, +$null=null, 'param'). +Lastly, in oci8, bind parameters can be reused without calling PrepareSP( ) + or Parameters again. This is not possible with mssql. An oci8 example:
+$id = 0; $i = 0;
+$stmt = $db->PrepareSP( "update table set val=:i where id=:id");
+$db->Parameter($stmt,$id,'id');
+$db->Parameter($stmt,$i, 'i');
+for ($cnt=0; $cnt < 1000; $cnt++) {
+ $id = $cnt;
$i = $cnt * $cnt; # works with oci8!
+ $db->Execute($stmt);
}
+Bind($stmt, $var, $size=4001, $type=false, $name=false)
+ +This is a low-level function supported only by the oci8 + driver. Avoid using unless you only want to support Oracle. The Parameter( + ) function is the recommended way to go with bind variables.
+Bind( ) allows you to use bind variables in your sql + statement. This binds a PHP variable to a name defined in an Oracle sql statement + that was previously prepared using Prepare(). Oracle named variables begin with + a colon, and ADOdb requires the named variables be called :0, :1, :2, :3, etc. + The first invocation of Bind() will match :0, the second invocation will match + :1, etc. Binding can provide 100% speedups for insert, select and update statements. +
+The other variables, $size sets the buffer size for data storage, $type is the optional +descriptor type OCI_B_FILE (Binary-File), OCI_B_CFILE (Character-File), OCI_B_CLOB (Character-LOB), OCI_B_BLOB (Binary-LOB) and OCI_B_ROWID (ROWID). +Lastly, instead of using the default :0, :1, etc names, you can define your own bind-name using +$name. +
The following example shows 3 bind variables being used: + p1, p2 and p3. These variables are bound to :0, :1 and :2.
+$stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)");
+$DB->Bind($stmt, $p1);
+$DB->Bind($stmt, $p2);
+$DB->Bind($stmt, $p3);
+for ($i = 0; $i < $max; $i++) {
+ $p1 = ?; $p2 = ?; $p3 = ?;
+ $DB->Execute($stmt);
+}
+You can also use named variables:
+
+$stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:name0, :name1, :name2)");
+$DB->Bind($stmt, $p1, "name0");
+$DB->Bind($stmt, $p2, "name1");
+$DB->Bind($stmt, $p3, "name2");
+for ($i = 0; $i < $max; $i++) {
+ $p1 = ?; $p2 = ?; $p3 = ?;
+ $DB->Execute($stmt);
+}
+
+fnExecute and fnCacheExecute properties
+These two properties allow you to define bottleneck functions for all sql statements + processed by ADOdb. This allows you to perform statistical analysis and query-rewriting + of your sql. For example, to count all cached queries and non-cached queries, + you can do this:
+# $db is the connection object
+function CountExecs($db, $sql, $inputarray)
+{
global $EXECS; $EXECS++;
+}
+
+# $db is the connection object
+function CountCachedExecs($db, $secs2cache, $sql, $inputarray)
+{
global $CACHED; $CACHED++;
+}
+
$db = NewADOConnection('mysql');
+$db->Connect(...);
+$db->fnExecute = 'CountExecs';
+$db->fnCacheExecute = 'CountCachedExecs';
+ :
+ :
# After many sql statements:`
+printf("<p>Total queries=%d; total cached=%d</p>",$EXECS+$CACHED, $CACHED);
+The fnExecute function is called before the sql is parsed and executed, so + you can perform a query rewrite. If you are passing in a prepared statement, + then $sql is an array (see Prepare). The fnCacheExecute + function is only called if the recordset returned was cached. + The function parameters match the Execute and CacheExecute functions respectively, + except that $this (the connection object) is passed as the first parameter.
+ +No longer available - removed since 1.99.
+ +Generates the sql string used to concatenate $s1, $s2, etc together. Uses the + string in the concat_operator field to generate the concatenation. Override + this function if a concatenation operator is not used, eg. MySQL.
+Returns the concatenated string.
+ +Format the $date in the format the database accepts; this can be a Unix + integer timestamp or an ISO format Y-m-d. Uses the fmtDate field, which holds + the format to use. If null or false or '' is passed in, it will be converted + to an SQL null.
+Returns the date as a quoted string.
+ +Format the timestamp $ts in the format the database accepts; this can + be a Unix integer timestamp or an ISO format Y-m-d H:i:s. Uses the fmtTimeStamp + field, which holds the format to use. If null or false or '' is passed in, + it will be converted to an SQL null.
+Returns the timestamp as a quoted string.
+qstr($s,[$magic_quotes_enabled=false])
+Quotes a string to be sent to the database. The $magic_quotes_enabled + parameter may look funny, but the idea is if you are quoting a string extracted + from a POST/GET variable, then pass get_magic_quotes_gpc() as the second parameter. + This will ensure that the variable is not quoted twice, once by qstr + and once by the magic_quotes_gpc.
+Eg. $s = $db->qstr(HTTP_GET_VARS['name'],get_magic_quotes_gpc());
+Returns the quoted string.
+ +Quotes the string, automatically checking get_magic_quotes_gpc() first. If + get_magic_quotes_gpc() is set, then we do not quote the string. +
+Returns the number of rows affected by a update or delete statement. Returns + false if function not supported.
+Not supported by interbase/firebird currently.
+ +Returns the last autonumbering ID inserted. Returns false if function not supported. +
+Only supported by databases that support auto-increment or object id's, such + as PostgreSQL, MySQL and MSSQL currently. PostgreSQL returns the OID, which + can change on a database reload.
+ +Returns a list of databases available on the server as an array. You have to + connect to the server first. Only available for ODBC, MySQL and ADO.
+ +Returns an array of tables and views for the current database as an array. + The array should exclude system catalog tables if possible.
+ +Returns an array of ADOFieldObject's, one field object for every column of + $table. Currently Sybase does not recognise date types, and ADO cannot identify + the correct data type (so we default to varchar)..
+ +Returns an array of column names for $table. +
+Returns an array containing column names that are the + primary keys of $table. Only supported by mysql, postgres, oci8 currently. + +
Returns an array of containing two elements 'description'
+ and 'version'. The 'description' element contains the string description of
+ the database. The 'version' naturally holds the version number (which is also
+ a string).
+ When an SQL statement successfully is executed by ADOConnection->Execute($sql),an
+ ADORecordSet object is returned. This object contains a virtual cursor so
+ we can move from row to row, functions to obtain information about the columns
+ and column types, and helper functions to deal with formating the results
+ to show to the user. fields: Array containing the current row. This is not associative, but
+ is an indexed array from 0 to columns-1. See also the function Fields,
+ which behaves like an associative array. dataProvider: The underlying mechanism used to connect to the database.
+ Normally set to native, unless using odbc or ado. blobSize: Maximum size of a char, string or varchar object before it
+ is treated as a Blob (Blob's should be shown with textarea's). See the MetaType
+ function. sql: Holds the sql statement used to generate this record set. canSeek: Set to true if Move( ) function works. EOF: True if we have scrolled the cursor past the last record. ADORecordSet( ) Constructer. Normally you never call this function yourself. Generates an associative array from the recordset if the number of columns
+ is greater than 2. The array is generated from the current cursor position
+ till EOF. The first column of the recordset becomes the key to the rest of
+ the array. If the columns is equal to two, then the key directly maps to the
+ value unless $force_array is set to true, when an array is created for each
+ key. Inspired by PEAR's getAssoc. Example: We have the following data in a recordset: row1: Apple, Fruit, Edible GetAssoc will generate the following associative array: Apple => [Fruit, Edible] Returns: The associative array, or false if an error occurs. Generate a 2-dimensional array of records from the current cursor position,
+ indexed from 0 to $number_of_rows - 1. If $number_of_rows is undefined, till
+ EOF. GetMenu($name, [$default_str=''], [$blank1stItem=true],
+ [$multiple_select=false], [$size=0], [$moreAttr='']) Generate a HTML menu (<select><option><option></select>).
+ The first column of the recordset (fields[0]) will hold the string to display
+ in the option tags. If the recordset has more than 1 column, the second column
+ (fields[1]) is the value to send back to the web server.. The menu will be
+ given the name $name.
+ If $default_str is defined, then if $default_str == fields[0],
+ that field is selected. If $blank1stItem is true, the first option
+ is empty. You can also set the first option strings by setting $blank1stItem
+ = "$value:$text". $Default_str can be array for a multiple select listbox. To get a listbox, set the $size to a non-zero value (or pass $default_str
+ as an array). If $multiple_select is true then a listbox will be generated
+ with $size items (or if $size==0, then 5 items) visible, and we will
+ return an array to a server. Lastly use $moreAttr to add additional
+ attributes such as javascript or styles. Menu Example 1: Menu Example 2: For the same data, GetMenu2($name, [$default_str=''], [$blank1stItem=true],
+ [$multiple_select=false], [$size=0], [$moreAttr='']) This is nearly identical to GetMenu, except that the $default_str is
+ matched to fields[1] (the option values). Menu Example 3: Given the data in menu example 2, Converts the date string $str to another format.UserDate calls UnixDate
+ to parse $str, and $fmt defaults to Y-m-d if not defined. Converts the timestamp string $str to another format. The timestamp
+ format is Y-m-d H:i:s, as in '2002-02-28 23:00:12'. UserTimeStamp calls UnixTimeStamp
+ to parse $str, and $fmt defaults to Y-m-d H:i:s if not defined.
+ Parses the date string $str and returns it in unix mktime format (eg.
+ a number indicating the seconds after January 1st, 1970). Expects the date
+ to be in Y-m-d H:i:s format, except for Sybase and Microsoft SQL Server, where
+ M d Y is also accepted (the 3 letter month strings are controlled by a global
+ array, which might need localisation). This function is available in both ADORecordSet and ADOConnection since 1.91. Parses the timestamp string $str and returns it in unix mktime format
+ (eg. a number indicating the seconds after January 1st, 1970). Expects the
+ date to be in Y-m-d H:i:s format, except for Sybase and Microsoft SQL Server,
+ where M d Y h:i:sA is also accepted (the 3 letter month strings are controlled
+ by a global array, which might need localisation).
+ADORecordSet
+ADORecordSet Fields
+ADORecordSet Functions
+
+ row2: Cactus, Plant, Inedible
+ row3: Rose, Flower, Edible
+ Cactus => [Plant, Inedible]
+ Rose => [Flower,Edible]GetMenu('menu1','A',true) will generate a menu:
+
+ for the data (A,1), (B,2), (C,3). Also see example 5.GetMenu('menu1',array('A','B'),false)
+ will generate a menu with both A and B selected:
+
+GetMenu2('menu1',array('1','2'),false)
+ will generate a menu with both A and B selected in menu example 2, but this
+ time the selection is based on the 2nd column, which holds the values to return
+ to the Web server.
+
This function is available in both ADORecordSet and ADOConnection + since 1.91.
+OffsetDate($dayFraction, + $basedate=false)
+Allows you to calculate future and past dates based on + $basedate in a portable fashion. If $basedate is not defined, then the current + date (at 12 midnight) is used. Returns the SQL string that performs the calculation + when passed to Execute().
+For example, in Oracle, to find the date and time that + is 2.5 days from today, you can use:
+# get date one week from now +$fld = $conn->OffsetDate(7); // returns "(trunc(sysdate)+7")+
# get date and time that is 60 hours from current date and time
+$fld = $conn->OffsetDate(2.5, $conn->sysTimeStamp); // returns "(sysdate+2.5)"
+
+$conn->Execute("UPDATE TABLE SET dodate=$fld WHERE ID=$id");
+This function is available for mysql, mssql, oracle, oci8 and postgresql drivers + since 2.13. It might work with other drivers provided + they allow performing numeric day arithmetic on dates.
+ +SQLDate($dateFormat, + $basedate=false)
+ Use the native SQL functions to format a date or date column $basedate, + using a case-sensitive $dateFormat, which supports: ++ Y: 4-digit Year + Q: Quarter (1-4) + m: Month (01-12) + d: Day (01-31) + H: Hour (00-23) + h: Hour (1-12) + i: Minute (00-59) + s: Second (00-60) + A: AM/PM indicator+
All other characters are treated as strings. You can also use \ to escape characters. Available + on selected databases, including mysql, postgresql, mssql, oci8 and DB2. +
This is useful in writing portable sql statements that GROUP BY on dates. For example to display + total cost of goods sold broken by quarter (dates are stored in a field called postdate): +
+ $sqlfn = $db->SQLDate('Y-\QQ','postdate'); # get sql that formats postdate to output 2002-Q1
+ $sql = "SELECT $sqlfn,SUM(cogs) FROM table GROUP BY $sqlfn ORDER BY 1 desc";
+
+
+Move the internal cursor to the next row. The $this->fields array is automatically + updated. Return false if unable to do so (normally because EOF has been reached), otherwise true. + If EOF is reached, then the $this->fields array is set to false (this was only implemented consistently + in ADOdb 3.30). + Note that if false is returned, then the previous array in $this->fields is preserved.
+Example:
+$rs = $db->Execute($sql);
+if ($rs)
+ while (!$rs->EOF) {
+ ProcessArray($rs->fields);
+ $rs->MoveNext();
+ }
+
+Moves the internal cursor to a specific row $to. Rows are zero-based + eg. 0 is the first row. The fields array is automatically updated. For + databases that do not support scrolling internally, ADOdb will simulate forward + scrolling. Some databases do not support backward scrolling. If the $to + position is after the EOF, $to will move to the end of the RecordSet + for most databases. Some obscure databases using odbc might not behave this + way.
+Note: This function uses absolute positioning, unlike Microsoft's ADO.
+Returns true or false. If false, the internal cursor is not moved in most implementations, + so AbsolutePosition( ) will return the last cursor position before the Move( + ).
+ +Internally calls Move(0). Note that some databases do not support this function.
+ +Internally calls Move(RecordCount()-1). Note that some databases do not support + this function.
+ +The above function is no longer the prefered way of getting associative arrays. + Use the $ADODB_FETCH_MODE variable instead.
+Returns an associative array containing the current row. The keys to the array + are the column names. The column names are upper-cased for easy access. To get + the next row, you will still need to call MoveNext().
+For example:
+ Array ( [ID] => 1 [FIRSTNAME] => Caroline [LASTNAME] => Miranda [CREATED] =>
+ 2001-07-05 )
Note: do not use GetRowAssoc() with $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC. + Because they have the same functionality, they will interfere with each other.
+ + +Returns the current page. Requires PageExecute()/CachePageExecute() to be called. See Example 8.
+ +AtFirstPage($status='')
+Returns true if at first page (1-based). Requires PageExecute()/CachePageExecute() + to be called. See Example 8.
+AtLastPage($status='')
+Returns true if at last page (1-based). Requires PageExecute()/CachePageExecute() + to be called. See Example 8.
+ +This function is deprecated. Use $ADODB_FETCH_MODE + instead.
+Some database extensions (eg. MySQL) return arrays that are both associative + and indexed if you use the native extensions. GetRowAssoc() does not return + arrays that combine associative and indexed elements. Returns the value of the + associated column $colname for the current row. The column name is case-insensitive.
+ + +Returns array containing current row, or false if EOF. + FetchRow( ) internally moves to the next record after returning the current + row.
+Warning: Do not mix using FetchRow() with MoveNext().
+Usage:
+$rs = $db->Execute($sql);
+if ($rs)
+ while ($arr = $rs->FetchRow()) {
+ # process $arr
+ }
+
+Sets $array to the current row. Returns PEAR_Error object + if EOF, 1 if ok (DB_OK constant). If PEAR is undefined, false is returned when + EOF. FetchInto( ) internally moves to the next + record after returning the current row.
+FetchRow() is easier to use. See above.
+ + +Returns an object containing the name, type and max_length + of the associated field. If the max_length cannot be determined reliably, + it will be set to -1. The column numbers are zero-based. See example + 2.
+ +Returns the number of fields (columns) in the record set.
+ +Returns the number of rows in the record set. If the number of records returned + cannot be determined from the database driver API, we will buffer all rows + and return a count of the rows after all the records have been retrieved. + This buffering can be disabled (for performance reasons) by setting the global + variable $ADODB_COUNTRECS = false. When disabled, RecordCount( ) will return + -1 for certain databases. See the supported databases list above for more + details.
+RowCount is a synonym for RecordCount.
+PO_RecordCount($table, $where)
+Returns the number of rows in the record set. If the database does not support + this, it will perform a SELECT COUNT(*) on the table $table, with the given + $where condition to return an estimate of the recordset size.
+$numrows = $rs->PO_RecordCount("articles_table", "group=$group");
+ NextRecordSet() +For databases that allow multiple recordsets to be returned in one query, this + function allows you to switch to the next recordset. Currently only supported + by mssql driver.
+
+$rs = $db->Execute('execute return_multiple_rs');
+$arr1 = $rs->GetArray();
+$rs->NextRecordSet();
+$arr2 = $rs->GetArray();
+
+Returns the current row as an object. If you set $toupper to true, then the + object fields are set to upper-case. Note: The newer FetchNextObject() is + the recommended way of accessing rows as objects. See below.
+FetchNextObject($toupper=true)
+Gets the current row as an object and moves to the next row automatically. + Returns false if at end-of-file. If you set $toupper to true, then the object + fields are set to upper-case.
+
+$rs = $db->Execute('select firstname,lastname from table');
+if ($rs) {
+ while ($o = $rs->FetchNextObject()) {
+ print "$o->FIRSTNAME, $o->LASTNAME<BR>";
+ }
+}
+
+There is some trade-off in speed in using FetchNextObject(). If performance
+ is important, you should access rows with the fields[] array.
+FetchObj()
+
Returns the current record as an object. Fields are not upper-cased, unlike + FetchObject. +
+ +Returns the current record as an object and moves to + the next record. If EOF, false is returned. Fields are not upper-cased, unlike + FetctNextObject.
+ + +Returns the current row of the record set. 0 is the first row.
+ +Synonym for CurrentRow for compatibility with ADO. Returns the current + row of the record set. 0 is the first row.
+MetaType($nativeDBType[,$field_max_length],[$fieldobj])
+Determine what generic meta type a database field type is given its + native type $nativeDBType as a string and the length of the field $field_max_length. + Note that field_max_length can be -1 if it is not known. The field object + returned by the database driver can be passed in $fieldobj. This is + useful for databases such as mysql which has additional properties + in the field object such as primary_key.
+Uses the field blobSize and compares it with $field_max_length + to determine whether the character field is actually a blob.
+For example, $db->MetaType('char') will return 'C'. +Returns:
+Since ADOdb 3.0, MetaType accepts $fieldobj as the first + parameter, instead of $nativeDBType.
+ + +Close the recordset.
+This is a standalone function (rs2html = recordset to html) that is similar + to PHP's odbc_result_all function, it prints a ADORecordSet, $adorecordset + as a HTML table. $tableheader_attributes allow you to control the table + cellpadding, cellspacing and border attributes. Lastly + you can replace the database column names with your own column titles with + the array $col_titles. This is designed more as a quick debugging mechanism, + not a production table recordset viewer.
+You will need to include the file tohtml.inc.php.
+ +<?
+include('tohtml.inc.php'); # load code common to ADOdb
+include('adodb.inc.php'); # load code common to ADOdb
+$conn = &ADONewConnection('mysql'); # create a connection
+$conn->PConnect('localhost','userid','','agora');# connect to MySQL, agora db
+$sql = 'select CustomerName, CustomerID from customers';
+$rs = $conn->Execute($sql);
+rs2html($rs,'border=2 cellpadding=3',array('Customer Name','Customer ID'));
+?>
+This describes how to create a class to connect to a new database. To ensure + there is no duplication of work, kindly email me at jlim#natsoft.com.my if + you decide to create such a class.
+First decide on a name in lower case to call the database type. Let's say we + call it xbase.
+Then we need to create two classes ADODB_xbase and ADORecordSet_xbase + in the file adodb-xbase.inc.php.
+The simplest form of database driver is an adaptation of an existing ODBC driver. + Then we just need to create the class ADODB_xbase extends ADODB_odbc + to support the new date and timestamp formats, the concatenation + operator used, true and false. For the ADORecordSet_xbase + extends ADORecordSet_odbc we need to change the MetaType function. + See adodb-vfp.inc.php as an example.
+More complicated is a totally new database driver that connects to a new PHP + extension. Then you will need to implement several functions. Fortunately, + you do not have to modify most of the complex code. You only need to override + a few stub functions. See adodb-mysql.inc.php for example.
+The default date format of ADOdb internally is YYYY-MM-DD (Ansi-92). All dates + should be converted to that format when passing to an ADOdb date function. + See Oracle for an example how we use ALTER SESSION to change the default date + format in _pconnect _connect.
+ADOConnection Functions to Override
+Defining a constructor for your ADOConnection derived function is optional. + There is no need to call the base class constructor.
+_connect: Low level implementation of Connect. Returns true or false. + Should set the _connectionID.
+_pconnect: Low level implemention of PConnect. Returns true or false. + Should set the _connectionID.
+_query: Execute a query. Returns the queryID, or false.
+_close: Close the connection -- PHP should clean up all recordsets. +
+ErrorMsg: Stores the error message in the private variable _errorMsg. +
+ADOConnection Fields to Set
+_bindInputArray: Set to true if binding of parameters for SQL inserts + and updates is allowed using ?, eg. as with ODBC.
+fmtDate
+fmtTimeStamp
+true
+false
+concat_operator
+replaceQuote
+hasLimit support SELECT * FROM TABLE LIMIT 10 of MySQL.
+hasTop support Microsoft style SELECT TOP 10 * FROM TABLE.
+ADORecordSet Functions to Override
+You will need to define a constructor for your ADORecordSet derived class that + calls the parent class constructor.
+FetchField: as documented above in ADORecordSet
+_initrs: low level initialization of the recordset: setup the _numOfRows + and _numOfFields fields -- called by the constructor.
+_seek: seek to a particular row. Do not load the data into the fields + array. This is done by _fetch. Returns true or false. Note that some implementations + such as Interbase do not support seek. Set canSeek to false.
+_fetch: fetch a row using the database extension function and then move + to the next row. Sets the fields array. If the parameter $ignore_fields + is true then there is no need to populate the fields array, just move + to the next row. then Returns true or false.
+_close: close the recordset
+Fields: If the array row returned by the PHP extension is not an associative + one, you will have to override this. See adodb-odbc.inc.php for an example. + For databases such as MySQL and MSSQL where an associative array is returned, + there is no need to override this function.
+ADOConnection Fields to Set
+canSeek: Set to true if the _seek function works.
+See the RoadMap article.
+Also see the ADOdb proxy article + for bridging Windows and Unix databases using http remote procedure calls. + For your education, visit palslib.com for + database info, and read this article on Optimizing + PHP.
+ +3.60 16 June 2003 + +
We now SET CONCAT_NULL_YIELDS_NULL OFF for odbc_mssql driver to be compat with mssql driver. + +
The property $emptyDate missing from connection class. Also changed 1903 to constant (TIMESTAMP_FIRST_YEAR=100). +Thx to Sebastiaan van Stijn. +
ADOdb speedup optimization - we now return all arrays by reference. +
Now DBDate() and DBTimeStamp() now accepts the string 'null' as a parameter. Suggested by vincent. +
Added GetArray() to connection class. +
Added not_null check in informix metacolumns(). +
Connection parameters for postgresql did not work correctly when port was defined. +
DB2 is now a tested driver, making adodb 100% compatible. +Extensive changes to odbc driver for DB2, including implementing serverinfo() and SQLDate(), +switching to SQL_CUR_USE_ODBC as the cursor mode, +and lastAffectedRows and SelectLimit() fixes. +
The odbc driver's FetchField() field names did not obey ADODB_ASSOC_CASE. Fixed. +
Some bugs in adodb_backtrace() fixed. +
Added "INT IDENTITY" type to adorecordset::MetaType() to support odbc_mssql properly. +
MetaColumns() for oci8, mssql, odbc revised to support scale. Also minor revisions to odbc +MetaColumns() for vfp and db2 compat. +
Added unsigned support to mysql datadict class. Thx to iamsure. +
Infinite loop in mssql MoveNext() fixed when ADODB_FETCH_ASSOC used. Thx to Josh R, Night_Wulfe#hotmail.com. +
ChangeTableSQL contributed by Florian Buzin. +
The odbc_mssql driver now sets CONCAT_NULL_YIELDS_NULL OFF for compat with mssql driver. +
3.50 19 May 2003
+Fixed mssql compat with FreeTDS. FreeTDS does not implement mssql_fetch_assoc(). +
Merged back connection and recordset code into adodb.inc.php. +
ADOdb sessions using oracle clobs contributed by achim.gosse#ddd.de. See adodb-session-clob.php. +
Added /s modifier to preg_match everywhere, which ensures that regex does not stop at /n. Thx Pao-Hsi Huang. +
Fixed error in metacolumns() for mssql. +
Added time format support for SQLDate. +
Image => B added to metatype. +
MetaType now checks empty($this->blobSize) instead of empty($this). +
Datadict has beta support for informix, sybase (mapped to mssql), db2 and generic (which is a fudge). +
BlobEncode for postgresql uses pg_escape_bytea, if available. Needed for compat with 7.3. +
Added $ADODB_LANG, to support multiple languages in MetaErrorMsg(). +
Datadict can now parse table definition as declarative text. +
For DataDict, oci8 autoincrement trigger missing semi-colon. Fixed. +
For DataDict, when REPLACE flag enabled, drop sequence in datadict for autoincrement field in postgres and oci8.s +
Postgresql defaults to template1 database if no database defined in connect/pconnect. +
We now clear _resultid in postgresql if query fails. +
3.40 19 May 2003
+Added insert_id for odbc_mssql. +
Modified postgresql UpdateBlobFile() because it did not work in safe mode. +
Now connection object is passed to raiseErrorFn as last parameter. Needed by StartTrans(). +
Added StartTrans() and CompleteTrans(). It is recommended that you do not modify transOff, but +use the above functions. +
oci8po now obeys ADODB_ASSOC_CASE settings. +
Added virtualized error codes, using PEAR DB equivalents. Requires you to manually include + adodb-error.inc.php yourself, with MetaError() and MetaErrorMsg($errno). +
GetRowAssoc for mysql and pgsql were flawed. Fix by Ross Smith. +
Added to datadict types I1, I2, I4 and I8. Changed datadict type 'T' to map to +timestamp instead of datetime for postgresql. +
Error handling in ExecuteSQLArray(), adodb-datadict.inc.php did not work. +
We now auto-quote postgresql connection parameters when building connection string. +
Added session expiry notification. +
We now test with odbc mysql - made some changes to odbc recordset constructor. +
MetaColumns now special cases access and other databases for odbc. +
3.31 17 March 2003
+Added row checking for _fetch in postgres. +
Added Interval type to MetaType for postgres. +
Remapped postgres driver to call postgres7 driver internally. +
Adorecordset_array::getarray() did not return array when nRows >= 0. +
Postgresql: at times, no error message returned by pg_result_error() + but error message returned in pg_last_error(). Recoded again. +
Interbase blob's now use chunking for updateblob. +
Move() did not set EOF correctly. Reported by Jorma T. +
We properly support mysql timestamp fields when we are creating mysql + tables using the data-dict interface. +
Table regex includes backticks character now. +
3.30 3 March 2003
+Added $ADODB_EXTENSION and $ADODB_COMPAT_FETCH constant. +
Made blank1stItem configurable using syntax "value:text" in GetMenu/GetMenu2. Thx to Gabriel Birke. +
Previously ADOdb differed from the Microsoft standard because it did not define + what to set $this->fields when EOF was reached. Now at EOF, ADOdb sets $this->fields + to false for all databases, which is consist with Microsoft's implementation. + Postgresql and mysql have always worked this way (in 3.11 and earlier). If + you are experiencing compatibility problems (and you are not using postgresql + nor mysql) on upgrading to 3.30, try setting the global variables $ADODB_COUNTRECS + = true (which is the default) and $ADODB_FETCH_COMPAT = true (this is a new + global variable). +
We now check both pg_result_error and pg_last_error as sometimes pg_result_error does not display anything. + Iman Mayes +
+We no longer check for magic quotes gpc in Quote(). +
+Misc fixes for table creation in adodb-datadict.inc.php. Thx to iamsure. +
+Time calculations use adodb_time library for all negative timestamps +due to problems in Red Hat 7.3 or later. Formerly, only did this for +Windows. +
+In mssqlpo, we now check if $sql in _query is a string before we change || to +. This is +to support prepared stmts. +
+Move() and MoveLast() internals changed to support to support EOF and $this->fields change. +
+Added ADODB_FETCH_BOTH support to mssql. Thx to Angel Fradejas afradejas#mediafusion.es +
+We now check if link resource exists before we run mysql_escape_string in qstr(). +
+Before we flock in csv code, we check that it is not a http url. +
3.20 17 Feb 2003
+Added new Data Dictionary classes for creating tables and indexes. Warning - this is very much alpha quality code. +The API can still change. See adodb/tests/test-datadict.php for more info. +
We now ignore $ADODB_COUNTRECS for mysql, because PHP truncates incomplete recordsets + when mysql_unbuffered_query() is called a second time. +
Now postgresql works correctly when $ADODB_COUNTRECS = false. +
Changed _adodb_getcount to properly support SELECT DISTINCT. +
Discovered that $ADODB_COUNTRECS=true has some problems with prepared queries - suspect +PHP bug. +
Now GetOne and GetRow run in $ADODB_COUNTRECS=false mode for better performance. +
Added support for mysql_real_escape_string() and pg_escape_string() in qstr(). +
Added an intermediate variable for mysql _fetch() and MoveNext() to store fields, to prevent +overwriting field array with boolean when mysql_fetch_array() returns false. +
Made arrays for getinsertsql and getupdatesql case-insensitive. Suggested by Tim Uckun" tim#diligence.com +
3.11 11 Feb 2003
+Added check for ADODB_NEVER_PERSIST constant in PConnect(). +If defined, then PConnect() will actually call non-persistent Connect(). +
Modified interbase to properly work with Prepare(). +
Added $this->ibase_timefmt to allow you to change the date and time format. +
Added support for $input_array parameter in CacheFlush(). +
Added experimental support for dbx, which was then removed when i found that +it was slower than using native calls. +
Added MetaPrimaryKeys for mssql and ibase/firebird. +
Added new $trim parameter to GetCol and CacheGetCol +
Uses updated adodb-time.inc.php 0.06. +
3.10 27 Jan 2003 +
Added adodb_date(), adodb_getdate(), adodb_mktime() and adodb-time.inc.php. +
For interbase, added code to handle unlimited number of bind parameters. +From Daniel Hasan daniel#hasan.cl. +
Added BlobDecode and UpdateBlob for informix. Thx to Fernando Ortiz. +
Added constant ADODB_WINDOWS. If defined, means that running on Windows. +
Added constant ADODB_PHPVER which stores php version as a hex num. Removed $ADODB_PHPVER variable. +
Felho Bacsi reported a minor white-space regular expression problem in GetInsertSQL. +
Modified ADO to use variant to store _affectedRows +
Changed ibase to use base class Replace(). Modified base class Replace() to support ibase. +
Changed odbc to auto-detect when 0 records returned is wrong due to bad odbc drivers. +
Changed mssql to use datetimeconvert ini setting only when 4.30 or later (does not work in 4.23). +
ExecuteCursor($stmt, $cursorname, $params) now accepts a new $params array of additional bind +parameters -- William Lovaton walovaton#yahoo.com.mx. +
Added support for sybase_unbuffered_query if ADODB_COUNTRECS == false. Thx to chuck may. +
Fixed FetchNextObj() bug. Thx to Jorma Tuomainen. +
We now use SCOPE_IDENTITY() instead of @@IDENTITY for mssql - thx to marchesini#eside.it +
Changed postgresql movenext logic to prevent illegal row number from being passed to pg_fetch_array(). +
Postgresql initrs bug found by "Bogdan RIPA" bripa#interakt.ro $f1 accidentally named $f +
3.00 6 Jan 2003 +
Fixed adodb-pear.inc.php syntax error. +
Improved _adodb_getcount() to use SELECT COUNT(*) FROM ($sql) for languages that +accept it. +
Fixed _adodb_getcount() caching error. +
Added sql to retrive table and column info for odbc_mssql. +
2.91 3 Jan 2003 +
Revised PHP version checking to use $ADODB_PHPVER with legal values 0x4000, 0x4050, 0x4200, 0x4300. +
Added support for bytea fields and oid blobs in postgres by allowing BlobDecode() + to detect and convert non-oid fields. Also added BlobEncode to postgres when + you want to encode oid blobs. +
Added blobEncodeType property for connections to inform phpLens what encoding +method to use for blobs. +
Added BlobDecode() and BlobEncode() to base ADOConnection class. +
Added umask() to _gencachename() when creating directories. +
Added charPage for ado drivers, so you can set the code page. +
+$conn->charPage = CP_UTF8; +$conn->Connect($dsn); ++
Modified _seek in mysql to check for num rows=0. +
Added to metatypes new informix types for IDS 9.30. Thx Fernando Ortiz. +
_maxrecordcount returned in CachePageExecute $rsreturn +
Fixed sybase cacheselectlimit( ) problems +
MetaColumns() max_length should use precision for types X and C for ms access. Fixed. +
Speedup of odbc non-SELECT sql statements. +
Added support in MetaColumns for Wide Char types for ODBC. We halve max_length + if unicode/wide char. +
Added 'B' to types handled by GetUpdateSQL/GetInsertSQL. +
Fixed warning message in oci8 driver with $persist variable when using PConnect. +
2.90 11 Dec 2002 +
Mssql and mssqlpo and oci8po now support ADODB_ASSOC_CASE. +
Now MetaType() can accept a field object as the first parameter. +
New $arr = $db->ServerInfo( ) function. Returns $arr['description'] which + is the string description, and $arr['version']. +
PostgreSQL and MSSQL speedups for insert/updates. +
Implemented new SetFetchMode() that removes the need to use $ADODB_FETCH_MODE. + Each connection has independant fetchMode. +
ADODB_ASSOC_CASE now defaults to 2, use native defaults. This is because we would +break backward compat for too many applications otherwise. +
Patched encrypted sessions to use replace() +
The qstr function supports quoting of nulls when escape character is \ +
Rewrote bits and pieces of session code to check for time synch and improve reliability. +
Added property ADOConnection::hasTransactions = true/false; +
Added CreateSequence and DropSequence functions +
Found misplaced MoveNext() in adodb-postgres.inc.php. Fixed. +
Sybase SelectLimit not reliable because 'set rowcount' not cached - fixed. +
Moved ADOConnection to adodb-connection.inc.php and ADORecordSet to adodb-recordset.inc.php. +This allows us to use doxygen to generate documentation. Doxygen doesn't like the classes +in the main adodb.inc.php file for some mysterious reason. +
2.50, 14 Nov 2002 +
Added transOff and transCnt properties for disabling (transOff = true) +and tracking transaction status (transCnt>0). +
Added inputarray handling into _adodb_pageexecute_all_rows - "Ross Smith" RossSmith#bnw.com. +
Fixed postgresql inconsistencies in date handling. +
Added support for mssql_fetch_assoc. +
Fixed $ADODB_FETCH_MODE bug in odbc MetaTables() and MetaPrimaryKeys(). +
Accidentally declared UnixDate() twice, making adodb incompatible with php 4.3.0. Fixed. +
Fixed pager problems with some databases that returned -1 for _currentRow on MoveLast() by +switching to MoveNext() in adodb-lib.inc.php. +
Also fixed uninited $discard in adodb-lib.inc.php. +
2.43, 25 Oct 2002
+Added ADODB_ASSOC_CASE constant to better support ibase and odbc field names. +Added support for NConnect() for oracle OCINLogin. +
Fixed NumCols() bug. +
Changed session handler to use Replace() on write. +
Fixed oci8 SelectLimit aggregate function bug again. +
Rewrote pivoting code. +
2.42, 4 Oct 2002
+Fixed ibase_fetch() problem with nulls. Also interbase now does automatic blob decoding, +and is backward compatible. Suggested by Heinz Hombergs heinz#hhombergs.de. +
Fixed postgresql MoveNext() problems when called repeatedly after EOF. +Also suggested by Heinz Hombergs. +
PageExecute() does not rewrite queries if SELECT DISTINCT is used. Requested by hans#velum.net +
Added additional fixes to oci8 SelectLimit handling with aggregate functions - thx to Christian Bugge +for reporting the problem. +
2.41, 2 Oct 2002
+Fixed ADODB_COUNTRECS bug in odbc. Thx to Joshua Zoshi jzoshi#hotmail.com. +
Increased buffers for adodb-csvlib.inc.php for extremely long sql from 8192 to 32000. +
Revised pivottable.inc.php code. Added better support for aggregate fields. +
Fixed mysql text/blob types problem in MetaTypes base class - thx to horacio degiorgi. +
Added SQLDate($fmt,$date) function, which allows an sql date format string to be generated - +useful for group by's. +
Fixed bug in oci8 SelectLimit when offset>100. +
2.40 4 Sept 2002
+Added new NLS_DATE_FORMAT property to oci8. Suggested by Laurent NAVARRO ln#altidev.com +
Now use bind parameters in oci8 selectlimit for better performance. +
Fixed interbase replaceQuote for dialect != 1. Thx to +"BEGUIN Pierre-Henri - INFOCOB" phb#infocob.com. +
Added white-space check to QA. +
Changed unixtimestamp to support fractional seconds (we always round down/floor the seconds). + Thanks to beezly#beezly.org.uk. +
Now you can set the trigger_error type your own user-defined type in adodb-errorhandler.inc.php. +Suggested by Claudio Bustos clbustos#entelchile.net. +
Added recordset filters with rsfilter.inc.php. +
$conn->_rs2rs does not create a new recordset when it detects it is of type array. Some +trickery there as there seems to be a bug in Zend Engine +
Added render_pagelinks to adodb-pager.inc.php. Code by "Pablo Costa" pablo#cbsp.com.br. +
MetaType() speedup in adodb.inc.php by using hashing instead of switch. Best performance +if constant arrays are supported, as they are in PHP5. +
adodb-session.php now updates only the expiry date if the crc32 check indicates + that the data has not been modified.
0.10 Sept 9 2000 First release +
+
+ + diff --git a/lib/adodb/docs-datadict.htm b/lib/adodb/docs-datadict.htm new file mode 100644 index 00000000000..fe0a45c1fb1 --- /dev/null +++ b/lib/adodb/docs-datadict.htm @@ -0,0 +1,293 @@ + +
+V3.60 16 June 2003 (c) 2000-2003 John Lim (jlim#natsoft.com.my)
+This software is dual licensed using BSD-Style and LGPL. +Where there is any discrepancy, the BSD-Style license will take precedence. +This means you can use it in proprietary and commercial products.
+ +This documentation describes a class library to automate the creation of tables, + indexes and foreign key constraints portably for multiple databases. Download + from http://php.weblogs.com/adodb +
Currently the following databases are supported: +
Well-tested: PostgreSQL, MySQL, Oracle, MSSQL.
+Beta-quality: DB2, Informix, Sybase, Interbase, Firebird.
+Alpha-quality: MS Access (does not support DEFAULT values) and generic ODBC.
include_once('adodb.inc.php');
+
+# First create a normal connection
+$db->NewADOConnection('mysql');
+$db->Connect(...);
+
+# Then create a data dictionary object, using this connection
+$dict = NewDataDictionary($db);
+
+# We have a portable declarative data dictionary format in ADOdb 3.50, similar to SQL.
+# Field types use 1 character codes, and fields are separated by commas.
+# The following example creates three fields: "col1", "col2" and "col3":
+$flds = "
+ col1 C(32) NOTNULL DEFAULT 'abc',
+ col2 I DEFAULT 0,
+ col3 N(12.2)
+";
+# We demonstrate creating tables and indexes
+$sqlarray = $dict->CreateTableSQL($tabname, $flds, $taboptarray);
+$dict->ExecuteSQLArray($sqlarray);
+$idxflds = 'co11, col2';
+$sqlarray = $dict->CreateIndexSQL($idxname, $tabname, $idxflds);
+$dict->ExecuteSQLArray($sqlarray);
+
+function CreateDatabase($dbname, $optionsarray=false) +
Create a database with the name $dbname; +
function CreateTableSQL($tabname, $fldarray, $taboptarray=false) +
+ RETURNS: an array of strings, the sql to be executed, or false + $tabname: name of table + $fldarray: string (or array) containing field info + $taboptarray: array containing table options ++
+ The new format of $fldarray uses a free text format, where each field is comma-delimited. + The first token for each field is the field name, followed by the type and optional + field size. Then optional keywords in $otheroptions: +
"$fieldname $type $colsize $otheroptions"+
The older (and still supported) format of $fldarray is a 2-dimensional array, where each row in the + 1st dimension represents one field. Each row has this format: +
array($fieldname, $type, [,$colsize] [,$otheroptions]*)+ The first 2 fields must be the field name and the field type. The field type + can be a portable type codes or the actual type for that database. +
+ Legal portable type codes include: +
+C: varchar +X: Largest varchar size +XL: For Oracle, returns CLOB, otherwise same as 'X' above + +C2: Multibyte varchar +X2: Multibyte varchar (largest size) + +B: BLOB (binary large object)+
+D: Date (some databases do not support this, and we return a datetime type) +T: Datetime or Timestamp +L: Integer field suitable for storing booleans (0 or 1) +I: Integer (mapped to I4) +I1: 1-byte integer +I2: 2-byte integer +I4: 4-byte integer +I8: 8-byte integer +F: Floating point number +N: Numeric or decimal number +
The $colsize field represents the size of the field. If a decimal number is + used, then it is assumed that the number following the dot is the precision, + so 6.2 means a number of size 6 digits and 2 decimal places. It is + recommended that the default for number types be represented as a string to + avoid any rounding errors. +
+ The $otheroptions include the following keywords (case-insensitive): +
+AUTO For autoincrement number. Emulated with triggers if not available. + Sets NOTNULL also. +AUTOINCREMENT Same as auto. +KEY Primary key field. Sets NOTNULL also. Compound keys are supported. +PRIMARY Same as KEY. +DEF Synonym for DEFAULT for lazy typists. +DEFAULT The default value. Character strings are auto-quoted unless + the string begins and ends with spaces, eg ' SYSDATE '. +NOTNULL If field is not null. +DEFDATE Set default value to call function to get today's date. +DEFTIMESTAMP Set default to call function to get today's datetime. +NOQUOTE Prevents autoquoting of default string values. +CONSTRAINTS Additional constraints defined at the end of the field + definition. ++
The Data Dictonary accepts two formats, the older array specification:
+
+$flds = array(
+ array('COLNAME', 'DECIMAL', '8.4', 'DEFAULT' => 0, 'NotNull'),
+ array('ID', 'I' , 'AUTO'),
+ array('MYDATE', 'D' , 'DEFDATE'),
+ array('NAME', 'C' ,'32',
+ 'CONSTRAINTS' => 'FOREIGN KEY REFERENCES reftable')
+);
+Or the simpler declarative format:
+$flds = " + COLNAME DECIMAL(8.4) DEFAULT 0 NotNull, + ID I AUTO, + MYDATE D DEFDATE, + NAME C(32) CONSTRAINTS 'FOREIGN KEY REFERENCES reftable' +"; ++
+ The $taboptarray is the 3rd parameter of the CreateTableSQL function. + This contains table specific settings. Legal keywords include: + +
Database specific table options can be defined also using the name of the + database type as the array key. In the following example, create the table + as ISAM with MySQL, and store the table in the "users" tablespace + if using Oracle. And if the table already exists, drop the table first. +
$taboptarray = array('mysql' => 'TYPE=ISAM', 'oci8' => 'tablespace users', 'REPLACE');
++ You can also define foreignkey constraints. The following is syntax for + postgresql:
+ $taboptarray = array('constraints' =>
+ ', FOREIGN KEY (col1) REFERENCES reftable (refcol)');
+
+function ChangeTableSQL($tabname, $flds) +
Checks to see if table exists, if table does not exist, behaves like CreateTableSQL. + If table exists, generates appropriate ALTER TABLE MODIFY COLUMN commands if + field already exists, or ALTER TABLE ADD $column if field does not exist. +
The class must be connected to the database for ChangeTableSQL to detect the + existance of the table. Idea and code contributed by Florian Buzin. +
function CreateIndexSQL($idxname, $tabname, $flds, $idxoptarray=false) +
+ RETURNS: an array of strings, the sql to be executed, or false +
+ $idxname: name of index + $tabname: name of table + $flds: list of fields as a comma delimited string or an array of strings + $idxoptarray: array of index creation options ++
$idxoptarray is similar to $taboptarray in that index specific information can + be embedded in the array. Other options include: +
+ CLUSTERED Create clustered index (only mssql) + BITMAP Create bitmap index (only oci8) + UNIQUE Make unique index + FULLTEXT Make fulltext index (only mysql) + HASH Create hash index (only postgres) ++
function AddColumnSQL($tabname, $flds) +
Add one or more columns. Not guaranteed to work under all situations. +
function AlterColumnSQL($tabname, $flds) +
Warning, not all databases support this feature. +
function DropColumnSQL($tabname, $flds) +
Drop 1 or more columns. +
function ExecuteSQLArray($sqlarray, $contOnError = true) +
+ RETURNS: 0 if failed, 1 if executed all but with errors, 2 if executed successfully + $sqlarray: an array of strings with sql code (no semicolon at the end of string) + $contOnError: if true, then continue executing even if error occurs ++
Executes an array of SQL strings returned by CreateTableSQL or CreateIndexSQL. +
First, create an XML database schema. Let's call it "schema.xml:"
+<?xml version="1.0"?> +<schema> + <table name="mytable"> + <field name="row1" type="I"> + <descr>An integer row that's a primary key and autoincrements</descr> + <KEY/> + <AUTOINCREMENT/> + </field> + <field name="row2" type="C" size="16"> + <descr>A 16 character varchar row that can't be null</descr> + <NOTNULL/> + </field> + </table> + <index name="myindex" table="mytable"> + <col>row1</col> + <col>row2</col> + </index> + <sql> + <descr>SQL to be executed only on specific platforms</descr> + <query platform="postgres|postgres7"> + insert into mytable ( row1, row2 ) values ( 12, 'stuff' ) + </query> + <query platform="mysql"> + insert into mytable ( row1, row2 ) values ( 12, 'different stuff' ) + </query> + </sql> +</schema> +
Create a new database using the appropriate tool for your platform. +Executing the following PHP code will create the a mytable and myindex +in the database and insert one row into mytable if the platform is postgres or mysql.
+include_once('/path/to/adodb.inc.php');
+include_once('/path/to/adodb-xmlschema.inc.php');
+
+// To build the schema, start by creating a normal ADOdb connection:
+$db->NewADOConnection( 'mysql' );
+$db->Connect( ... );
+
+// Create the schema object and build the query array.
+$schema = new adoSchema( $db );
+
+// Build the SQL array
+$sql = $schema->ParseSchema( "schema.xml" );
+
+// Execute the SQL on the database
+$result = $schema->ExecuteSchema( $sql );
+
+// Finally, clean up after the XML parser
+// (PHP won't do this for you!)
+$schema->Destroy();
+
+
+(See ADOdb_schema.dtd for the full specification)
++<?xml version="1.0"?> +<schema> + <table name="tablename" platform="platform1|platform2|..."> + <descr>Optional description</descr> + <field name="fieldname" type="datadict_type" size="size"> + <KEY/> + <NOTNULL/> + <AUTOINCREMENT/> + <DEFAULT value="value"/> + </field> + ... more fields + </table> + ... more tables + + <index name="indexname" platform="platform1|platform2|..."> + <descr>Optional description</descr> + <col>fieldname</col> + ... more columns + </index> + ... more indices + + <sql platform="platform1|platform2|..."> + <descr>Optional description</descr> + <query platform="platform1|platform2|...">SQL query</query> + ... more queries + </sql> + ... more SQL + </schema> ++
+V3.60 16 June 2003 (c) 2000-2003 John Lim (jlim#natsoft.com.my) +
+This software is dual licensed using BSD-Style and LGPL. Where there is any discrepancy, the BSD-Style license will take precedence. This means you can use it in proprietary and commercial products. + +
PHP is packed with good features. One of the most popular is session variables. +These are variables that persist throughout a session, as the user moves from page to page. Session variables are great holders of state information and other useful stuff. +
+To use session variables, call session_start() at the beginning of your web page, +before your HTTP headers are sent. Then for every variable you want to keep alive +for the duration of the session, call session_register($variable_name). By default, +the session handler will keep track of the session by using a cookie. You can save objects + or arrays in session variables also. +
The default method of storing sessions is to store it in a file. However if you have multiple web servers, +or need to do special processing of each session, or require notification when a session expires, you +need to override the default session storage behaviour. +
The ADOdb session handler provides you with the above additional capabilities by storing +the session information as records in a database table that can be shared by multiple servers. +
There are 3 session management files that you can use: +
+adodb-session.inc.php : The default
+adodb-session-clob.inc.php : Use this if you are storing DATA in clobs
+adodb-cryptsession.inc.php : Use this if you want to store encrypted session data in the database
+
+Examples
+
+ GLOBAL $HTTP_SESSION_VARS;
+ include('adodb.inc.php');
+ include('adodb-session.php');
+ session_start();
+ session_register('AVAR');
+ $HTTP_SESSION_VARS['AVAR'] += 1;
+ print "\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}
";
+
+To force non-persistent connections, call adodb_session_open first before session_start():
+
+ GLOBAL $HTTP_SESSION_VARS;
+ include('adodb.inc.php');
+ include('adodb-session.php');
+ adodb_sess_open(false,false,false);
+ session_start();
+ session_register('AVAR');
+ $HTTP_SESSION_VARS['AVAR'] += 1;
+ print "\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}
";
+
+To use a encrypted sessions, simply replace the file:
+
+ GLOBAL $HTTP_SESSION_VARS;
+ include('adodb.inc.php');
+ include('adodb-cryptsession.php');
+ session_start();
+
+And the same technique for adodb-session-clob.inc.php:
+
+ GLOBAL $HTTP_SESSION_VARS;
+ include('adodb.inc.php');
+ include('adodb-session-clob.php');
+ session_start();
+
+ Installation
+ 1. Create this table in your database (syntax might vary depending on your db):
+
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY int(11) unsigned not null,
+ EXPIREREF varchar(64),
+ DATA text not null,
+ primary key (sesskey)
+ );
+
+ For the adodb-session-clob.inc.php version, create this:
+
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY int(11) unsigned not null,
+ EXPIREREF varchar(64),
+ DATA CLOB,
+ primary key (sesskey)
+ );
+
+ 2. Then define the following parameters in this file:
+ $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';
+ $ADODB_SESSION_CONNECT='server to connect to';
+ $ADODB_SESSION_USER ='user';
+ $ADODB_SESSION_PWD ='password';
+ $ADODB_SESSION_DB ='database';
+ $ADODB_SESSION_TBL = 'sessions'
+
+ 3. Recommended is PHP 4.0.6 or later. There are documented
+ session bugs in earlier versions of PHP.
+
+ 4. If you want to receive notifications when a session expires, then
+ you can tag a session with an EXPIREREF, and before the session
+ record is deleted, we can call a function that will pass the EXPIREREF
+ as the first parameter, and the session key as the second parameter.
+
+ To do this, define a notification function, say NotifyFn:
+
+ function NotifyFn($expireref, $sesskey)
+ {
+ }
+
+ Then define a global variable, with the first parameter being the
+ global variable you would like to store in the EXPIREREF field, and
+ the second is the function name.
+
+ In this example, we want to be notified when a user's session
+ has expired, so we store the user id in $USERID, and make this
+ the value stored in the EXPIREREF field:
+
+ $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');
+
+
+Also see the core ADOdb documentation.
+
+
\ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-access.inc.php b/lib/adodb/drivers/adodb-access.inc.php
index fa4aa4ae076..e154ba57e4f 100644
--- a/lib/adodb/drivers/adodb-access.inc.php
+++ b/lib/adodb/drivers/adodb-access.inc.php
@@ -1,74 +1,74 @@
-ADODB_odbc();
- }
-
- function BeginTrans() { return false;}
-
- function &MetaTables()
- {
- global $ADODB_FETCH_MODE;
-
- $savem = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
- $qid = odbc_tables($this->_connectionID);
- $rs = new ADORecordSet_odbc($qid);
- $ADODB_FETCH_MODE = $savem;
- if (!$rs) return false;
-
- $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
-
- $arr = &$rs->GetArray();
- //print_pre($arr);
- $arr2 = array();
- for ($i=0; $i < sizeof($arr); $i++) {
- if ($arr[$i][2] && $arr[$i][3] != 'SYSTEM TABLE')
- $arr2[] = $arr[$i][2];
- }
- return $arr2;
- }
-}
-
-
-class ADORecordSet_access extends ADORecordSet_odbc {
-
- var $databaseType = "access";
-
- function ADORecordSet_access($id,$mode=false)
- {
- return $this->ADORecordSet_odbc($id,$mode);
- }
-}// class
-}
+ADODB_odbc();
+ }
+
+ function BeginTrans() { return false;}
+
+ function &MetaTables()
+ {
+ global $ADODB_FETCH_MODE;
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $qid = odbc_tables($this->_connectionID);
+ $rs = new ADORecordSet_odbc($qid);
+ $ADODB_FETCH_MODE = $savem;
+ if (!$rs) return false;
+
+ $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+
+ $arr = &$rs->GetArray();
+ /* print_pre($arr); */
+ $arr2 = array();
+ for ($i=0; $i < sizeof($arr); $i++) {
+ if ($arr[$i][2] && $arr[$i][3] != 'SYSTEM TABLE')
+ $arr2[] = $arr[$i][2];
+ }
+ return $arr2;
+ }
+}
+
+
+class ADORecordSet_access extends ADORecordSet_odbc {
+
+ var $databaseType = "access";
+
+ function ADORecordSet_access($id,$mode=false)
+ {
+ return $this->ADORecordSet_odbc($id,$mode);
+ }
+}/* class */
+}
?>
\ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-ado.inc.php b/lib/adodb/drivers/adodb-ado.inc.php
index 9d195d31702..98271168e3a 100644
--- a/lib/adodb/drivers/adodb-ado.inc.php
+++ b/lib/adodb/drivers/adodb-ado.inc.php
@@ -1,589 +1,589 @@
-_affectedRows = new VARIANT;
- }
-
- function ServerInfo()
- {
- if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider;
- return array('description' => $desc, 'version' => '');
- }
-
- function _affectedrows()
- {
- return $this->_affectedRows->value;
- }
-
- // you can also pass a connection string like this:
- //
- // $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB');
- function _connect($argHostname, $argUsername, $argPassword, $argProvider= 'MSDASQL')
- {
- $u = 'UID';
- $p = 'PWD';
-
- if (!empty($this->charPage))
- $dbc = new COM('ADODB.Connection',null,$this->charPage);
- else
- $dbc = new COM('ADODB.Connection');
-
- if (! $dbc) return false;
-
- /* special support if provider is mssql or access */
- if ($argProvider=='mssql') {
- $u = 'User Id'; //User parameter name for OLEDB
- $p = 'Password';
- $argProvider = "SQLOLEDB"; // SQL Server Provider
-
- // not yet
- //if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename";
-
- //use trusted conection for SQL if username not specified
- if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes";
- } else if ($argProvider=='access')
- $argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider
-
- if ($argProvider) $dbc->Provider = $argProvider;
-
- if ($argUsername) $argHostname .= ";$u=$argUsername";
- if ($argPassword)$argHostname .= ";$p=$argPassword";
-
- if ($this->debug) ADOConnection::outp( "Host=".$argHostname." Connect: 1st argument should be left blank for $this->databaseType Connect: 1st argument should be left blank for $this->databaseType Connect: 1st argument should be left blank for $this->databaseType PConnect: 1st argument should be left blank for $this->databaseType Connect: 1st argument should be left blank for $this->databaseType PConnect: 1st argument should be left blank for $this->databaseType V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim#natsoft.com.my) This software is dual licensed using BSD-Style and LGPL.
-Where there is any discrepancy, the BSD-Style license will take precedence.
-This means you can use it in proprietary and commercial products. Introduction Variables: $ADODB_COUNTRECS
- $ADODB_CACHE_DIR $ADODB_FETCH_MODE rs2html example 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. PHP 4.0.5 or later
- is now required (because we use array-based str_replace). We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, Informix,
- PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access, ADO and ODBC. We have had successful reports of connecting
- to Progress and DB2 via ODBC. We hope more people
- will contribute drivers to support other databases. PHP4 supports session variables. You can store your session information using
- ADOdb for true portability and scalability. See adodb-session.php for more information. Also read http://php.weblogs.com/portable_sql
- (also available as tips_portable_sql.htm in the release) for tips on writing
- portable SQL. ADOdb is a suite of database libraries that allow you to connect to multiple
+ databases in a portable manner. The ADOdb documentation has moved to docs-adodb.htm
+ This allows you to query, update and insert records using a portable API.
+ The ADOdb data dictionary docs are at docs-datadict.htm.
+ This allows you to create database tables and indexes in a portable manner.
+
+
+To test, try modifying some of the tutorial examples. Make sure you customize the connection settings correctly. You can debug using:
+
-
-
-
-
-
-
-
-
-
-
-
- Feature requests and bug reports can be emailed to jlim#natsoft.com.my
- or posted to the ADOdb Help forums at http://phplens.com/lens/lensforum/topics.php?id=4. Make sure you are running PHP4.01pl2 or later (it uses require_once and include_once).
- Unpack all the files into a directory accessible by your webserver. To test, try modifying some of the tutorial examples. Make sure you customize
- the connection settings correctly. You can debug using: When running ADOdb, at least two files are loaded. First is adodb/adodb.inc.php,
- which contains all functions used by all database classes. The code specific
- to a particular database is in the adodb/driver/adodb-????.inc.php file. For example, to connect to a mysql database: Whenever you need to connect to a database, you create a Connection object
- using the ADONewConnection($driver) function.
- NewADOConnection($driver) is an alternative name for the same function. At this point, you are not connected to the database.
-You will use See the examples below in the Tutorial. Generic ADO, not tuned for specific databases. Allows
- DSN-less connections. For best performance, use an OLEDB provider.
- This is the base class for all ado drivers. You can set $db->codePage before connecting. Unix and Windows. Unix
- install hints. Unix and Windows Microsoft SQL Server 7 and later. Works with Microsoft SQL Server
- 2000 also. Note that date formating is problematic with this driver. For
- example, the PHP mssql extension does not return the seconds for datetime! Unix and Windows. Portable mssql driver. Identical to above mssql driver,
- except that '||', the concatenation operator, is converted to '+'. Useful
- for porting scripts from most other sql variants that use ||. Unix and Windows. MySQL with transaction support. We recommend using ||
- as the concat operator for best portability. This can be done by running
- MySQL using: There are 2 ways of connecting - with server IP
- and service name: Since 2.31, we support Oracle REF cursor variables directly
- (see ExecuteCursor).
- Use this driver if porting from other databases is important.
- Otherwise the oci8 driver offers better performance.
- ? Unix and Windows.
- The "Tested" column indicates how extensively the code has been tested
- and used. The column "RecordCount() usable" indicates whether RecordCount()
- return the number of rows, or returns -1 when a SELECT statement is executed.
- If this column displays Y/N then the RecordCount() is emulated when the global
- variable $ADODB_COUNTRECS=true (this is the default). Note that for large
- recordsets, it might be better to disable RecordCount() emulation because
- substantial amounts of memory are required to cache the recordset for counting. Also
- there is a speed penalty of 40-50% if emulation is required. This is emulated in
- most databases except for PostgreSQL and MySQL.
- This variable is checked every time a query is executed, so you can selectively
- choose which recordsets to count.
-
- Task: Connect to the Access Northwind DSN, display the first 2 columns
- of each row. In this example, we create a ADOConnection object, which represents the connection
- to the database. The connection is initiated with PConnect,
- which is a persistent connection. Whenever we want to query the database, we
- call the ADOConnection.Execute()
- function. This returns an ADORecordSet object which is actually a cursor that
- holds the current row in the array fields[].
- We use MoveNext()
- to move from row to row. NB: A useful function that is not used in this example is
-SelectLimit, which
-allows us to limit the number of rows shown.
- The $recordSet returned stores
- the current row in the $recordSet->fields
- array, indexed by column number (starting from zero). We use the MoveNext()
- function to move to the next row. The EOF
- property is set to true when end-of-file is reached. If an error occurs in Execute(),
- we return false instead of a recordset. The
- To get the number of rows in the select statement, you can use $recordSet->RecordCount().
- Note that it can return -1 if the number of rows returned cannot be determined. Select a table, display the first two columns. If the second column is a date or timestamp, reformat the date to US format. In this example, we check the field type of the second column using FetchField().
- This returns an object with at least 3 fields. We then use MetaType()
- to translate the native type to a generic type. Currently the following
- generic types are defined: If the metatype is of type date or timestamp, then we print it using the user
- defined date format with UserDate(),
- which converts the PHP SQL date string format to a user defined one. Another
- use for MetaType()
- is data validation before doing an SQL insert or update. Insert a row to the Orders table containing dates and strings that need to be quoted before they can be accepted by the database, eg: the single-quote in the word John's. In this example, we see the advanced date and quote handling facilities of
- ADOdb. The unix timestamp (which is a long integer) is appropriately formated
- for Access with DBDate(),
- and the right escape character is used for quoting the John's Old Shoppe,
- which is John''s Old Shoppe and not PHP's default John's
- Old Shoppe with qstr().
- Observe the error-handling of the Execute statement. False is returned by
- Execute() if an error occured. The error message
- for the last error that occurred is displayed in ErrorMsg().
- Note: php_track_errors might have to be enabled for error messages to
- be saved. In the above example, we have turned on debugging by setting debug = true.
- This will display the SQL statement before execution, and also show any error
- messages. There is no need to call ErrorMsg()
- in this case. For displaying the recordset, see the rs2html()
- example. Also see the section on Custom Error Handlers. Connect to MySQL database agora, and generate a <select> menu
- from an SQL statement where the <option> captions are in the 1st column,
- and the value to send back to the server is in the 2nd column. Here we define a menu named GetCust, with the menu option 'Mary Rosli' selected.
- See GetMenu().
- We also have functions that return the recordset as an array: GetArray(),
- and as an associative array with the key being the first column: GetAssoc().
-
-
-We show how the functions can be used when
-accessing a table with the following fields: (ID, FirstName, LastName, Created).
-
-Before these functions can be called, you need to initialize the recordset by
-performing a select on the table. Idea and code by Jonathan Younger jyounger#unilab.com.
-
- The following code creates a very simple recordset pager, where you can scroll
- from page to page of a recordset. This will create a basic record pager that looks like this:
-
- The number of rows to display at one time is controled by the Render($rows)
- method. If you do not pass any value to Render(), ADODB_Pager will default to
- 10 records per page.
- You can control the column titles by modifying your SQL (supported by most
- databases):
- The above code can be found in the adodb/tests/testpaging.php example
- included with this release, and the class ADODB_Pager in adodb/adodb-pager.inc.php.
- The ADODB_Pager code can be adapted by a programmer so that the text links can
- be replaced by images, and the dull white background be replaced with more interesting
- colors.
- You can also allow display of html by setting $pager->htmlSpecialChars = false.
- Some of the code used here was contributed by Iván Oliva and Cornel
- G. We provide some helper functions to export in comma-separated-value (CSV) and
- tab-delimited formats: print '<hr>';
- Carriage-returns or newlines are converted to spaces. Field names are returned
- in the first line of text. Strings containing the delimiter character are quoted
- with double-quotes. Double-quotes are double-quoted again. This conforms to
- Excel import and export guide-lines.
- All the above functions take as an optional last parameter, $addtitles which
- defaults to true. When set to false field names in the first line
- are suppressed. Sometimes we want to pre-process all rows in a recordset before we use it. For example,
-we want to ucwords all text in recordset.
- The RSFilter function takes 2 parameters, the recordset, and the name of the filter
-function. It returns the processed recordset scrolled to the first record. The filter function takes two parameters,
-the current row as an array, and the recordset object. For future compatibility,
-you should not use the original recordset object.
-
-ADOdb provides two custom handlers which you can modify for your needs.
-The first one is in the adodb-errorhandler.inc.php file. This makes
-use of the standard PHP functions error_reporting
-to control what error messages types to display,
-and trigger_error which invokes the default
-PHP error handler.
-
-Including the above file will cause trigger_error($errorstring,E_USER_ERROR)
-to be called when
-The $errorstring is generated by ADOdb and will contain useful debugging information similar
-to the error.log data generated below.
-This file adodb-errorhandler.inc.php should be included before you create any ADOConnection objects.
-
- If you define error_reporting(0), no errors will be shown.
- If you set error_reporting(E_ALL), all errors will be displayed on the screen.
-
- If you want to log the error message, you can do so by defining the following optional
- constants ADODB_ERROR_LOG_TYPE and ADODB_ERROR_LOG_DEST. ADODB_ERROR_LOG_TYPE is
- the error log message type (see error_log
- in the PHP manual). In this case we set
- it to 3, which means log to the file defined by the constant ADODB_ERROR_LOG_DEST.
-
-
-You can use a PEAR_Error derived class by defining the constant ADODB_PEAR_ERROR_CLASS
-before the adodb-errorpear.inc.php file is included. For easy debugging, you can
-set the default error handler in the beginning of the PHP script to PEAR_ERROR_DIE,
-which will cause an error message to be printed, then halt script execution:
- Note that we do not explicitly return a PEAR_Error object to you when an error
- occurs. We return false instead. You have to call ADODB_Pear_Error() to get
- the last error or use the PEAR_ERROR_DIE technique.
- Error messages are outputted using the static method ADOConnnection::outp($msg,$newline=true).
- By default, it sends the messages to the client. You can override this to
- perform error-logging.
- We now support connecting using PEAR style DSN's. A DSN is a connection string
- of the form: $dsn = "$driver://$username:$password@$hostname/$databasename"; You pass the DSN to the static class function DB::Connect. An example: This requires PEAR to be installed and in the default include path in php.ini. ADOdb now supports caching of recordsets using the CacheExecute( ),
-CachePageExecute( ) and CacheSelectLimit( ) functions. There are similar to the
-non-cache functions, except that they take a new first parameter, $secs2cache.
- An example:
- The first parameter is the number of seconds to cache
- the query. Subsequent calls to that query will used the cached version stored
- in $ADODB_CACHE_DIR. To force a query to execute and flush the cache, call CacheExecute()
- with the first parameter set to zero. Alternatively, use the CacheFlush($sql)
- call. For the sake of security, we recommend you set register_globals=off
- in php.ini if you are using $ADODB_CACHE_DIR. In ADOdb 1.80 onwards, the secs2cache parameter is optional in CacheSelectLimit() and
-CacheExecute(). If you leave it out, it will use the $connection->cacheSecs parameter, which defaults
-to 60 minutes.
- Please note that magic_quotes_runtime should be turned off. More info.
-
- Since ADOdb 2.30, we support the generation of SQL to
- create pivot tables, also known as cross-tabulations. For further explanation
- read this DevShed Cross-Tabulation
- tutorial. We assume that your database supports the SQL case-when expression.
- In this example, we will use the Northwind database from Microsoft. In the
- database, we have a products table, and we want to analyze this table by suppliers
- versus product categories. We will place the suppliers on each row, and
- pivot on categories. So from the table on the left, we generate the pivot-table on the right: The following code will generate the SQL for a cross-tabulation:
- This will generate the following SQL: You can also pivot on numerical columns and generate totals
- by using ranges. This code was revised in ADODB 2.41
- and is not backward compatible. The second example shows this: Which generates: Function parameters with [ ] around them are optional. If the database driver API does not support counting the number of records
- returned in a SELECT statement, the function RecordCount() is emulated when
- the global variable $ADODB_COUNTRECS is set to true, which is the default.
- We emulate this by buffering the records, which can take up large amounts
- of memory for big recordsets. Set this variable to false for the best performance.
- This variable is checked every time a query is executed, so you can selectively
- choose which recordsets to count. If you are using recordset caching, this is the directory to save your recordsets
- in. Define this before you call any caching functions such as CacheExecute(
- ). We recommend setting register_globals=off in php.ini if you use this
- feature for security reasons. If you are using Unix and apache, you might need to set your cache directory
- permissions to something similar to the following: chown -R apache /path/to/adodb/cache This is a global variable that determines how arrays are retrieved by recordsets.
- The recordset saves this value on creation (eg. in Execute( ) or SelectLimit(
- )), and any subsequent changes to $ADODB_FETCH_MODE have no affect on existing
- recordsets, only on recordsets created in the future. The following constants are defined: define('ADODB_FETCH_DEFAULT',0); An example:
- As you can see in the above example, both recordsets store and use different
- fetch modes based on the $ADODB_FETCH_MODE setting when the recordset was
- created by Execute(). If no fetch mode is predefined, the fetch mode defaults to ADODB_FETCH_DEFAULT.
- The behaviour of this default mode varies from driver to driver, so do not
- rely on ADODB_FETCH_DEFAULT. For portability, we recommend sticking to ADODB_FETCH_NUM
- or ADODB_FETCH_ASSOC. Many drivers do not support ADODB_FETCH_BOTH. SetFetchMode Function Some programmers prefer to use a more object-oriented solution, where the fetch
- mode is set by a object function, SetFetchMode.
- Once this function is called for a connection object, that connection object
- will ignore the global variable $ADODB_FETCH_MODE and will use the internal
- fetchMode property exclusively. To retrieve the previous fetch mode, you can use check the $db->fetchMode
- property, or use the return value of SetFetchMode( ).
- You can control the associative fetch case for certain drivers which behave
- differently. For the sybase, oci8po, mssql, odbc and ibase drivers and all
- drivers derived from them, ADODB_ASSOC_CASE will by default generate recordsets
- where the field name keys are lower-cased. Use the constant ADODB_ASSOC_CASE
- to change the case of the keys. There are 3 possible values: 0 = assoc lowercase field names. $rs->fields['orderid'] To use it, declare it before you incldue adodb.inc.php. define('ADODB_ASSOC_CASE', 2); # use native-case for ADODB_FETCH_ASSOC Object that performs the connection to the database, executes SQL statements
- and has a set of utility functions for standardising the format of SQL statements
- for issues such as concatenation and date formats. databaseType: Name of the database system we are connecting to. Eg.
- odbc or mssql or mysql. dataProvider: The underlying mechanism used to connect to the database.
- Normally set to native, unless using odbc or ado. host: Name of server or data source name (DSN) to connect to. database: Name of the database or to connect to. If ado is used, it
- will hold the ado data provider. user: Login id to connect to database. Password is not saved for security
- reasons. raiseErrorFn: Allows you to define an error handling function. See adodb-errorhandler.inc.php
- for an example. debug: Set to true to make debug statements to appear. concat_operator: Set to '+' or '||' normally. The operator used to concatenate
- strings in SQL. Used by the Concat function. fmtDate: The format used by the DBDate
- function to send dates to the database. is '#Y-m-d#' for Microsoft Access,
- and ''Y-m-d'' for MySQL. fmtTimeStamp: The format used by the DBTimeStamp
- function to send timestamps to the database. true: The value used to represent true.Eg. '.T.'. for Foxpro, '1' for
- Microsoft SQL. false: The value used to represent false. Eg. '.F.'. for Foxpro, '0'
- for Microsoft SQL. replaceQuote: The string used to escape quotes. Eg. double single-quotes
- for Microsoft SQL, and backslash-quote for MySQL. Used by qstr. autoCommit: indicates whether automatic commit is enabled. Default is
- true. charSet: set the default charset to use. Currently only interbase supports
- this. dialect: set the default sql dialect to use. Currently only interbase
- supports this. metaTablesSQL: SQL statement to return a list of available tables. Eg.
- SHOW TABLES in MySQL. genID: The latest id generated by GenID() if supported by the database. cacheSecs: The number of seconds to cache recordsets if CacheExecute()
- or CacheSelectLimit() omit the $secs2cache parameter. Defaults to 60 minutes. sysDate: String that holds the name of the database function to call
- to get the current date. Useful for inserts and updates. sysTimeStamp: String that holds the name of the database function to
- call to get the current timestamp/datetime value. leftOuter: String that holds operator for left outer join, if known.
- Otherwise set to false. rightOuter: String that holds operator for left outer join, if known.
- Otherwise set to false. ansiOuter: Boolean that if true indicates that ANSI style outer joins
- are permitted. Eg. select * from table1 left join table2 on p1=p2. connectSID: Boolean that indicates whether to treat the $database parameter
- in connects as the SID for the oci8 driver. Defaults to false. Useful for
- Oracle 8.0.5 and earlier. autoRollback: Persistent connections are auto-rollbacked in PConnect(
- ) if this is set to true. Default is false. ADOConnection( ) Constructor function. Do not call this directly. Use ADONewConnection( ) instead. Connect($host,[$user],[$password],[$database]) Non-persistent connect to data source or server $host, using userid
- $user and password $password. If the server supports multiple
- databases, connect to database $database. Returns true/false depending on connection. ADO Note: If you are using a Microsoft ADO and not OLEDB, you can set the $database
- parameter to the OLEDB data provider you are using. PostgreSQL: An alternative way of connecting to the database is to pass the
- standard PostgreSQL connection string in the first parameter $host, and the
- other parameters will be ignored. For Oracle and Oci8, there are two ways to connect. First is to use the TNS
- name defined in your local tnsnames.ora (or ONAMES or HOSTNAMES). Place the
- name in the $database field, and set the $host field to false. Alternatively,
- set $host to the server, and $database to the database SID, this bypassed
- tnsnames.ora.
- Examples:
- There are many examples of connecting to a database at php.weblogs.com/ADOdb,
- and in the testdatabases.inc.php file included in the release. PConnect($host,[$user],[$password],[$database]) Persistent connect to data source or server $host, using userid $user
- and password $password. If the server supports multiple databases,
- connect to database $database. We now perform a rollback on persistent connection for selected databases since
- 2.21, as advised in the PHP manual. See change log or source code for which
- databases are affected.
- Returns true/false depending on connection. See Connect( ) above for more info. Since ADOdb 2.21, we also support autoRollback. If you set: Then when doing a persistent connection with PConnect( ), ADOdb will
- perform a rollback first. This is because it is documented that PHP is
- not guaranteed to rollback existing failed transactions when
- persistent connections are used. This is implemented in Oracle,
- MySQL, PgSQL, MSSQL, ODBC currently.
- Since ADOdb 3.11, you can force non-persistent
-connections even if PConnect is called by defining the constant
-ADODB_NEVER_PERSIST before you call PConnect.
- NConnect($host,[$user],[$password],[$database]) Always force new connection. In contrast, PHP sometimes reuses connections
- when you use Connect() or PConnect(). Currently works only on mysql (PHP 4.3.0
- or later) and oci8-derived drivers. For other drivers, NConnect() works like
- Connect().
-
-
- Execute SQL statement $sql and return derived class of ADORecordSet
- if successful. Note that a record set is always returned on success, even
- if we are executing an insert or update statement. Returns derived class of ADORecordSet. Eg. if connecting via mysql, then ADORecordSet_mysql
- would be returned. False is returned if there was an error in executing the
- sql. The $inputarr parameter can be used for binding variables to parameters. Below
- is an Oracle example: Another example, using ODBC,which uses the ? convention: Variable binding in the odbc and oci8po drivers.
- CacheExecute([$secs2cache,]$sql,$inputarr=false) Similar to Execute, except that the recordset is cached for $secs2cache seconds
- in the $ADODB_CACHE_DIR directory. If CacheExecute() is called again with
- the same parameters, same database, same userid, same password, and the cached
- recordset has not expired, the cached recordset is returned.
- Alternatively, since ADOdb 1.80, the $secs2cache parameter is optional: Performance note: I have done some benchmarks and found that they vary so greatly
- that it's better to talk about when caching is of benefit. When your database
- server is much slower than your Web server or the database is very
- overloaded then ADOdb's caching is good because it reduces the load on
- your database server. If your database server is lightly loaded or much faster
- than your Web server, then caching could actually reduce performance. ExecuteCursor($sql,$cursorName='rs',$parameters=false) Execute an Oracle stored procedure, and returns an Oracle REF cursor variable as
- a regular ADOdb recordset. Does not work with any other database except oci8.
- Thanks to Robert Tuttle for the design.
- ExecuteCursor() is a helper function that does the following internally:
- SelectLimit($sql,$numrows=-1,$offset=-1,$inputarr=false) Returns a recordset if successful. Returns false otherwise. Performs a select
- statement, simulating PostgreSQL's SELECT statement, LIMIT $numrows OFFSET
- $offset clause. In PostgreSQL, SELECT * FROM TABLE LIMIT 3 will return the first 3 records
- only. The equivalent is And SELECT * FROM TABLE LIMIT 3 OFFSET 2 will return records 3, 4 and 5 (eg.
- after record 2, return 3 rows). The equivalent in ADOdb is Note that this is the opposite of MySQL's LIMIT clause. You can also
- set The last parameter $inputarr is for databases that support variable binding
- such as Oracle oci8. This substantially reduces SQL compilation overhead.
- Below is an Oracle example: The oci8po driver (oracle portable driver) uses the more standard bind variable
- of ?:
-
- Ron Wilson reports that SelectLimit does not work with UNIONs.
- CacheSelectLimit([$secs2cache,] $sql, $numrows=-1,$offset=-1,$inputarr=false) Similar to SelectLimit, except that the recordset returned is cached for $secs2cache
- seconds in the $ADODB_CACHE_DIR directory. Since 1.80, $secs2cache has been optional, and you can define the caching time
- in $connection->cacheSecs. CacheFlush($sql=false,$inputarr=false) Flush (delete) any cached recordsets for the SQL statement $sql in $ADODB_CACHE_DIR.
- If no parameter is passed in, then all adodb_*.cache files are deleted.
- If you want to flush all cached recordsets manually, execute the following
- PHP code (works only under Unix): For general cleanup of all expired files, you should use crontab
- on Unix, or at.exe on Windows, and a shell script similar to the following: Returns a virtualized error number, based on PEAR DB's error number system. You might
-need to include adodb-error.inc.php before you call this function. The parameter $errno
-is the native error number you want to convert. If you do not pass any parameter, MetaError
-will call ErrorNo() for you and convert it. If the error number cannot be virtualized, MetaError
-will return -1 (DB_ERROR). Pass the error number returned by MetaError() for the equivalent textual error message. Returns the last status or error message. This can return a string even if
- no error occurs. In general you do not need to call this function unless an
- ADOdb function returns false on an error. Note: If debug is enabled, the SQL error message is always displayed
- when the Execute function is called. Returns the last error number. Note that old versions of PHP (pre 4.0.6) do
- not support error number for ODBC. In general you do not need to call this
- function unless an ADOdb function returns false on an error. Sets the current fetch mode for the connection and stores
- it in $db->fetchMode. Legal modes are ADODB_FETCH_ASSOC and ADODB_FETCH_NUM.
- For more info, see $ADODB_FETCH_MODE. Returns the previous fetch mode, which could be false
- if SetFetchMode( ) has not been called before. CreateSequence($seqName = 'adodbseq',$startID=1) Create a sequence. The next time GenID( ) is called, the value returned will
- be $startID. Added in 2.60.
- DropSequenceD($seqName = 'adodbseq') Delete a sequence. Added in 2.60.
- GenID($seqName = 'adodbseq',$startID=1) Generate a sequence number (an integer except for mssql). Works for interbase,
- mysql, postgresql, oci8, oci8po, mssql, ODBC based (access,vfp,db2,etc) drivers
- currently. Uses $seqName as the name of the sequence. GenID() will automatically
- create the sequence for you if it does not exist (provided the userid has
- permission to do so). Otherwise you will have to create the sequence yourself.
- If your database driver emulates sequences, the name of the table is the sequence
- name. The table has one column, "id" which should be of type integer, or if
- you need something larger - numeric(16).
- For ODBC and databases that do not support sequences natively (eg mssql, mysql),
- we create a table for each sequence. If the sequence has not been defined
- earlier, it is created with the starting value set in $startID. Note that the mssql driver's GenID() used to generate 16 byte GUID's. We now
- return integers since 1.90. UpdateBlob($table,$column,$val,$where) Usage:
-
- Returns true if succesful, false otherwise. Supported by MySQL, PostgreSQL,
- Oci8, Oci8po and Interbase drivers. Other drivers might work, depending on
- the state of development. Note that when an Interbase blob is retrieved using SELECT, it still needs
- to be decoded using $connection->DecodeBlob($blob); to derive the original
- value in versions of PHP before 4.1.0.
- For PostgreSQL, you can store your blob using blob oid's or as a bytea field.
- You can use bytea fields but not blob oid's currently with UpdateBlob( ).
- Conversely UpdateBlobFile( ) supports oid's, but not bytea data. UpdateClob($table,$column,$val,$where) Usage:
- UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') Similar to UpdateBlob, except that we pass in a file path to where the blob
- resides.
- For PostgreSQL, if you are using blob oid's, use this interface. This interface
- does not support bytea fields.
- Returns true if successful, false otherwise.
- Some databases require blob's to be encoded manually before upload. Note if
- you use UpdateBlob( ) or UpdateBlobFile( ) the conversion is done automatically
- for you and you do not have to call this function. For PostgreSQL, currently,
- BlobEncode() can only be used for bytea fields.
- Returns the encoded blob value.
- Note that there is a connection property called blobEncodeType which
- has 3 legal values:
- false - no need to perform encoding or decoding. This is purely for documentation purposes, so that programs that accept multiple
- database drivers know what is the right thing to do when processing blobs.
- Some databases require blob's to be decoded manually after doing a select statement.
- If the database does not require decoding, then this function will return
- the blob unchanged. Currently BlobDecode is only required for one database,
- PostgreSQL, and only if you are using blob oid's (if you are using bytea fields,
- we auto-decode for you). Replace($table, $arrFields, $keyCols,$autoQuote=false) Try to update a record, and if the record is not found, an insert statement
- is generated and executed. Returns 0 on failure, 1 if update statement worked,
- 2 if no record was found and the insert was executed successfully. This differs
- from MySQL's replace which deletes the record and inserts a new record. This
- also means you cannot update the primary key. The only exception to this is
- Interbase and its derivitives, which uses delete and insert because of some
- Interbase API limitations.
- The parameters are $table which is the table name, the $keyCols which is an
- associative array where the keys are the field names, and keyCols is the name
- of the primary key, or an array of field names if it is a compound key. If
- $autoQuote is set to true, then Replace() will quote all values that are non-numeric;
- auto-quoting will not quote nulls. Note that auto-quoting will not work if
- you use SQL functions or operators.
- Examples:
- GetUpdateSQL(&$rs, $arrFields, $forceUpdate=false,$magicq=false) Generate SQL to update a table given a recordset $rs, and the modified fields
- of the array $arrFields (which must be an associative array holding the column
- names and the new values) are compared with the current recordset. If $forceUpdate
- is true, then we also generate the SQL even if $arrFields is identical to
- $rs->fields. Requires the recordset to be associative. $magicq is used
- to indicate whether magic quotes are enabled (see qstr()). The field names in the array
- are case-insensitive. GetInsertSQL(&$rs, $arrFields,$magicq=false) Generate SQL to insert into a table given a recordset $rs. Requires the query
- to be associative. $magicq is used to indicate whether magic quotes are enabled
- (for qstr()). The field names in the array are case-insensitive. Used for pagination of recordset. $page is 1-based. See Example
- 8. CachePageExecute($secs2cache,
- $sql, $nrows, $page, $inputarr=false) Used for pagination of recordset. $page is 1-based. See
- Example 8. Caching version of PageExecute. Close the database connection. PHP4 proudly states that we no longer have to
- clean up at the end of the connection because the reference counting mechanism
- of PHP4 will automatically clean up for us. Start a monitored transaction. As SQL statements are executed, ADOdb will monitor
- for SQL errors, and if any are detected, when CompleteTrans() is called, we auto-rollback.
-
- To understand why StartTrans() is superior to BeginTrans(),
- let us examine a few ways of using BeginTrans().
- The following is the wrong way to use transactions:
- because you perform no error checking. It is possible to update table1 and
- for the update on table2 to fail. Here is a better way:
- Another way is (since ADOdb 2.0):
- Now it is a headache monitoring $ok all over the place. StartTrans() is an
-improvement because it monitors all SQL errors for you. This is particularly
-useful if you are calling black-box functions in which SQL queries might be executed.
- Also all BeginTrans, CommitTrans and RollbackTrans calls inside a StartTrans block
- will be disabled, so even if the black box function does a commit, it will be ignored.
- Note that a StartTrans blocks are nestable, the inner blocks are ignored.
- CompleteTrans($autoComplete=true) Complete a transaction called with StartTrans(). This function monitors
- for SQL errors, and will commit if no errors have occured, otherwise it will rollback.
- Returns true on commit, false on rollback. If the parameter $autoComplete is true
- monitor sql errors and commit and rollback as appropriate. Set $autoComplete to false
- to force rollback even if no SQL error detected.
- Begin a transaction. Turns off autoCommit. Returns true if successful. Some
- databases will always return false if transaction support is not available.
- Interbase, Oracle and MSSQL support transactions. Any open transactions will
- be rolled back when the connection is closed. Note that StartTrans() and CompleteTrans() is a superior method of
- handling transactions, available since ADOdb 3.40. For a explanation, see the StartTrans() documentation.
-
- You can also use the ADOdb error handler to die
- and rollback your transactions for you transparently. Some buggy database extensions
- are known to commit all outstanding tranasactions, so you might want to explicitly
- do a $DB->RollbackTrans() in your error handler for safety.
- Since ADOdb 2.50, you are able to detect when you are inside a transaction. Check
- that $connection->transCnt > 0. This variable is incremented whenever BeginTrans() is called,
- and decremented whenever RollbackTrans() or CommitTrans() is called.
- End a transaction successfully. Returns true if successful. If the database
- does not support transactions, will return true also as data is always committed.
- If you pass the parameter $ok=false, the data is rolled back. See example in
- BeginTrans(). End a transaction, rollback all changes. Returns true if successful. If the
- database does not support transactions, will return false as data is never rollbacked.
- Executes the SQL and returns the first field of the first row. The recordset
- and remaining rows are discarded for you automatically. If an error occur, false
- is returned. Executes the SQL and returns the first row as an array. The recordset and remaining
- rows are discarded for you automatically. If an error occurs, false is returned. Executes the SQL and returns the all the rows as a 2-dimensional
- array. The recordset is discarded for you automatically. If an error occurs,
- false is returned. GetCol($sql,$inputarr=false,$trim=false) Executes the SQL and returns all elements of the first column as a
-1-dimensional array. The recordset is discarded for you automatically. If an error occurs,
- false is returned. CacheGetOne([$secs2cache,]
- $sql,$inputarr=false), CacheGetRow([$secs2cache,] $sql,$inputarr=false), CacheGetAll([$secs2cache,]
- $sql,$inputarr=false), CacheGetCol([$secs2cache,]
- $sql,$inputarr=false,$trim=false) Similar to above Get* functions, except that the recordset is serialized and
- cached in the $ADODB_CACHE_DIR directory for $secs2cache seconds. Good for speeding
- up queries on rarely changing data. Note that the $secs2cache parameter is optional.
- If omitted, we use the value in $connection->cacheSecs (default is 3600 seconds,
- or 1 hour). Prepares an SQL query for repeated execution. Only supported
- internally by interbase, oci8 and selected ODBC-based drivers, otherwise it
- is emulated. There is no performance advantage to using Prepare() with emulation.
- Returns an array containing the original sql statement
- in the first array element; the remaining elements of the array are driver dependent.
- If there is an error, or we are emulating Prepare( ), we return the original
- $sql string. This is because all error-handling has been centralized in Execute(
- ). Example:
-Important: Due to limitations or bugs in PHP, if you are getting errors when you using prepared queries, try
-setting $ADODB_COUNTRECS = false before preparing. This behaviour has been observed with ODBC.
- In the mssql driver, preparing stored procedures requires a special function
- call, mssql_init( ), which is called by this function. PrepareSP( ) is available
- in all other drivers, and is emulated by calling Prepare( ). For examples of
- usage, see Parameter( ) below. Returns the same array or $sql string as Prepare( ) above. Parameter($stmt, $var, $name, $isOutput=false,
- $maxLen = 4000, $type = false ) Adds a bind parameter in a fashion that is compatible with Microsoft SQL Server
- and Oracle oci8. The parameters are: In mssql, $opt can hold the following elements: array('type' => integer,
- maxLen =>integer). Example: An oci8 example: Note that the only difference between the oci8 and mssql implementations is
- the syntax of $sql. Lastly, in oci8, bind parameters can be reused without calling PrepareSP( )
- or Parameters again. This is not possible with mssql. An oci8 example: Bind($stmt, $var, $size=4001, $type=false, $name=false) This is a low-level function supported only by the oci8
- driver. Avoid using unless you only want to support Oracle. The Parameter(
- ) function is the recommended way to go with bind variables. Bind( ) allows you to use bind variables in your sql
- statement. This binds a PHP variable to a name defined in an Oracle sql statement
- that was previously prepared using Prepare(). Oracle named variables begin with
- a colon, and ADOdb requires the named variables be called :0, :1, :2, :3, etc.
- The first invocation of Bind() will match :0, the second invocation will match
- :1, etc. Binding can provide 100% speedups for insert, select and update statements.
- The other variables, $size sets the buffer size for data storage, $type is the optional
-descriptor type OCI_B_FILE (Binary-File), OCI_B_CFILE (Character-File), OCI_B_CLOB (Character-LOB), OCI_B_BLOB (Binary-LOB) and OCI_B_ROWID (ROWID).
-Lastly, instead of using the default :0, :1, etc names, you can define your own bind-name using
-$name.
- The following example shows 3 bind variables being used:
- p1, p2 and p3. These variables are bound to :0, :1 and :2. You can also use named variables: fnExecute and fnCacheExecute properties These two properties allow you to define bottleneck functions for all sql statements
- processed by ADOdb. This allows you to perform statistical analysis and query-rewriting
- of your sql. For example, to count all cached queries and non-cached queries,
- you can do this: The fnExecute function is called before the sql is parsed and executed, so
- you can perform a query rewrite. If you are passing in a prepared statement,
- then $sql is an array (see Prepare). The fnCacheExecute
- function is only called if the recordset returned was cached.
- The function parameters match the Execute and CacheExecute functions respectively,
- except that $this (the connection object) is passed as the first parameter. No longer available - removed since 1.99. Generates the sql string used to concatenate $s1, $s2, etc together. Uses the
- string in the concat_operator field to generate the concatenation. Override
- this function if a concatenation operator is not used, eg. MySQL. Returns the concatenated string. Format the $date in the format the database accepts; this can be a Unix
- integer timestamp or an ISO format Y-m-d. Uses the fmtDate field, which holds
- the format to use. If null or false or '' is passed in, it will be converted
- to an SQL null. Returns the date as a quoted string. Format the timestamp $ts in the format the database accepts; this can
- be a Unix integer timestamp or an ISO format Y-m-d H:i:s. Uses the fmtTimeStamp
- field, which holds the format to use. If null or false or '' is passed in,
- it will be converted to an SQL null. Returns the timestamp as a quoted string. qstr($s,[$magic_quotes_enabled=false]) Quotes a string to be sent to the database. The $magic_quotes_enabled
- parameter may look funny, but the idea is if you are quoting a string extracted
- from a POST/GET variable, then pass get_magic_quotes_gpc() as the second parameter.
- This will ensure that the variable is not quoted twice, once by qstr
- and once by the magic_quotes_gpc. Eg. $s = $db->qstr(HTTP_GET_VARS['name'],get_magic_quotes_gpc()); Returns the quoted string. Quotes the string, automatically checking get_magic_quotes_gpc() first. If
- get_magic_quotes_gpc() is set, then we do not quote the string.
- Returns the number of rows affected by a update or delete statement. Returns
- false if function not supported. Not supported by interbase/firebird currently. Returns the last autonumbering ID inserted. Returns false if function not supported.
- Only supported by databases that support auto-increment or object id's, such
- as PostgreSQL, MySQL and MSSQL currently. PostgreSQL returns the OID, which
- can change on a database reload. Returns a list of databases available on the server as an array. You have to
- connect to the server first. Only available for ODBC, MySQL and ADO. Returns an array of tables and views for the current database as an array.
- The array should exclude system catalog tables if possible. Returns an array of ADOFieldObject's, one field object for every column of
- $table. Currently Sybase does not recognise date types, and ADO cannot identify
- the correct data type (so we default to varchar).. Returns an array of column names for $table.
- Returns an array containing column names that are the
- primary keys of $table. Only supported by mysql, postgres, oci8 currently.
-
- Returns an array of containing two elements 'description'
- and 'version'. The 'description' element contains the string description of
- the database. The 'version' naturally holds the version number (which is also
- a string).
- When an SQL statement successfully is executed by ADOConnection->Execute($sql),an
- ADORecordSet object is returned. This object contains a virtual cursor so
- we can move from row to row, functions to obtain information about the columns
- and column types, and helper functions to deal with formating the results
- to show to the user. fields: Array containing the current row. This is not associative, but
- is an indexed array from 0 to columns-1. See also the function Fields,
- which behaves like an associative array. dataProvider: The underlying mechanism used to connect to the database.
- Normally set to native, unless using odbc or ado. blobSize: Maximum size of a char, string or varchar object before it
- is treated as a Blob (Blob's should be shown with textarea's). See the MetaType
- function. sql: Holds the sql statement used to generate this record set. canSeek: Set to true if Move( ) function works. EOF: True if we have scrolled the cursor past the last record. ADORecordSet( ) Constructer. Normally you never call this function yourself. Generates an associative array from the recordset if the number of columns
- is greater than 2. The array is generated from the current cursor position
- till EOF. The first column of the recordset becomes the key to the rest of
- the array. If the columns is equal to two, then the key directly maps to the
- value unless $force_array is set to true, when an array is created for each
- key. Inspired by PEAR's getAssoc. Example: We have the following data in a recordset: row1: Apple, Fruit, Edible GetAssoc will generate the following associative array: Apple => [Fruit, Edible] Returns: The associative array, or false if an error occurs. Generate a 2-dimensional array of records from the current cursor position,
- indexed from 0 to $number_of_rows - 1. If $number_of_rows is undefined, till
- EOF. GetMenu($name, [$default_str=''], [$blank1stItem=true],
- [$multiple_select=false], [$size=0], [$moreAttr='']) Generate a HTML menu (<select><option><option></select>).
- The first column of the recordset (fields[0]) will hold the string to display
- in the option tags. If the recordset has more than 1 column, the second column
- (fields[1]) is the value to send back to the web server.. The menu will be
- given the name $name.
- If $default_str is defined, then if $default_str == fields[0],
- that field is selected. If $blank1stItem is true, the first option
- is empty. You can also set the first option strings by setting $blank1stItem
- = "$value:$text". $Default_str can be array for a multiple select listbox. To get a listbox, set the $size to a non-zero value (or pass $default_str
- as an array). If $multiple_select is true then a listbox will be generated
- with $size items (or if $size==0, then 5 items) visible, and we will
- return an array to a server. Lastly use $moreAttr to add additional
- attributes such as javascript or styles. Menu Example 1: Menu Example 2: For the same data, GetMenu2($name, [$default_str=''], [$blank1stItem=true],
- [$multiple_select=false], [$size=0], [$moreAttr='']) This is nearly identical to GetMenu, except that the $default_str is
- matched to fields[1] (the option values). Menu Example 3: Given the data in menu example 2, Converts the date string $str to another format.UserDate calls UnixDate
- to parse $str, and $fmt defaults to Y-m-d if not defined. Converts the timestamp string $str to another format. The timestamp
- format is Y-m-d H:i:s, as in '2002-02-28 23:00:12'. UserTimeStamp calls UnixTimeStamp
- to parse $str, and $fmt defaults to Y-m-d H:i:s if not defined.
- Parses the date string $str and returns it in unix mktime format (eg.
- a number indicating the seconds after January 1st, 1970). Expects the date
- to be in Y-m-d H:i:s format, except for Sybase and Microsoft SQL Server, where
- M d Y is also accepted (the 3 letter month strings are controlled by a global
- array, which might need localisation). This function is available in both ADORecordSet and ADOConnection since 1.91. Parses the timestamp string $str and returns it in unix mktime format
- (eg. a number indicating the seconds after January 1st, 1970). Expects the
- date to be in Y-m-d H:i:s format, except for Sybase and Microsoft SQL Server,
- where M d Y h:i:sA is also accepted (the 3 letter month strings are controlled
- by a global array, which might need localisation). This function is available in both ADORecordSet and ADOConnection
- since 1.91. OffsetDate($dayFraction,
- $basedate=false) Allows you to calculate future and past dates based on
- $basedate in a portable fashion. If $basedate is not defined, then the current
- date (at 12 midnight) is used. Returns the SQL string that performs the calculation
- when passed to Execute(). For example, in Oracle, to find the date and time that
- is 2.5 days from today, you can use: This function is available for mysql, mssql, oracle, oci8 and postgresql drivers
- since 2.13. It might work with other drivers provided
- they allow performing numeric day arithmetic on dates. SQLDate($dateFormat,
- $basedate=false) All other characters are treated as strings. You can also use \ to escape characters. Available
- on selected databases, including mysql, postgresql, mssql, oci8 and DB2.
- This is useful in writing portable sql statements that GROUP BY on dates. For example to display
- total cost of goods sold broken by quarter (dates are stored in a field called postdate):
- Move the internal cursor to the next row. The $this->fields array is automatically
- updated. Return false if unable to do so (normally because EOF has been reached), otherwise true.
- If EOF is reached, then the $this->fields array is set to false (this was only implemented consistently
- in ADOdb 3.30).
- Note that if false is returned, then the previous array in $this->fields is preserved. Example: Moves the internal cursor to a specific row $to. Rows are zero-based
- eg. 0 is the first row. The fields array is automatically updated. For
- databases that do not support scrolling internally, ADOdb will simulate forward
- scrolling. Some databases do not support backward scrolling. If the $to
- position is after the EOF, $to will move to the end of the RecordSet
- for most databases. Some obscure databases using odbc might not behave this
- way. Note: This function uses absolute positioning, unlike Microsoft's ADO. Returns true or false. If false, the internal cursor is not moved in most implementations,
- so AbsolutePosition( ) will return the last cursor position before the Move(
- ). Internally calls Move(0). Note that some databases do not support this function. Internally calls Move(RecordCount()-1). Note that some databases do not support
- this function. The above function is no longer the prefered way of getting associative arrays.
- Use the $ADODB_FETCH_MODE variable instead. Returns an associative array containing the current row. The keys to the array
- are the column names. The column names are upper-cased for easy access. To get
- the next row, you will still need to call MoveNext(). For example: Note: do not use GetRowAssoc() with $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC.
- Because they have the same functionality, they will interfere with each other. Returns the current page. Requires PageExecute()/CachePageExecute() to be called. See Example 8. AtFirstPage($status='') Returns true if at first page (1-based). Requires PageExecute()/CachePageExecute()
- to be called. See Example 8. AtLastPage($status='') Returns true if at last page (1-based). Requires PageExecute()/CachePageExecute()
- to be called. See Example 8. This function is deprecated. Use $ADODB_FETCH_MODE
- instead. Some database extensions (eg. MySQL) return arrays that are both associative
- and indexed if you use the native extensions. GetRowAssoc() does not return
- arrays that combine associative and indexed elements. Returns the value of the
- associated column $colname for the current row. The column name is case-insensitive. Returns array containing current row, or false if EOF.
- FetchRow( ) internally moves to the next record after returning the current
- row. Warning: Do not mix using FetchRow() with MoveNext(). Usage: Sets $array to the current row. Returns PEAR_Error object
- if EOF, 1 if ok (DB_OK constant). If PEAR is undefined, false is returned when
- EOF. FetchInto( ) internally moves to the next
- record after returning the current row. FetchRow() is easier to use. See above. Returns an object containing the name, type and max_length
- of the associated field. If the max_length cannot be determined reliably,
- it will be set to -1. The column numbers are zero-based. See example
- 2. Returns the number of fields (columns) in the record set. Returns the number of rows in the record set. If the number of records returned
- cannot be determined from the database driver API, we will buffer all rows
- and return a count of the rows after all the records have been retrieved.
- This buffering can be disabled (for performance reasons) by setting the global
- variable $ADODB_COUNTRECS = false. When disabled, RecordCount( ) will return
- -1 for certain databases. See the supported databases list above for more
- details. RowCount is a synonym for RecordCount. PO_RecordCount($table, $where) Returns the number of rows in the record set. If the database does not support
- this, it will perform a SELECT COUNT(*) on the table $table, with the given
- $where condition to return an estimate of the recordset size. $numrows = $rs->PO_RecordCount("articles_table", "group=$group"); For databases that allow multiple recordsets to be returned in one query, this
- function allows you to switch to the next recordset. Currently only supported
- by mssql driver. Returns the current row as an object. If you set $toupper to true, then the
- object fields are set to upper-case. Note: The newer FetchNextObject() is
- the recommended way of accessing rows as objects. See below. FetchNextObject($toupper=true) Gets the current row as an object and moves to the next row automatically.
- Returns false if at end-of-file. If you set $toupper to true, then the object
- fields are set to upper-case. There is some trade-off in speed in using FetchNextObject(). If performance
- is important, you should access rows with the Returns the current record as an object. Fields are not upper-cased, unlike
- FetchObject.
- Returns the current record as an object and moves to
- the next record. If EOF, false is returned. Fields are not upper-cased, unlike
- FetctNextObject. Returns the current row of the record set. 0 is the first row. Synonym for CurrentRow for compatibility with ADO. Returns the current
- row of the record set. 0 is the first row. MetaType($nativeDBType[,$field_max_length],[$fieldobj]) Determine what generic meta type a database field type is given its
- native type $nativeDBType as a string and the length of the field $field_max_length.
- Note that field_max_length can be -1 if it is not known. The field object
- returned by the database driver can be passed in $fieldobj. This is
- useful for databases such as mysql which has additional properties
- in the field object such as primary_key. Uses the field blobSize and compares it with $field_max_length
- to determine whether the character field is actually a blob. Returns: Since ADOdb 3.0, MetaType accepts $fieldobj as the first
- parameter, instead of $nativeDBType. Close the recordset. This is a standalone function (rs2html = recordset to html) that is similar
- to PHP's odbc_result_all function, it prints a ADORecordSet, $adorecordset
- as a HTML table. $tableheader_attributes allow you to control the table
- cellpadding, cellspacing and border attributes. Lastly
- you can replace the database column names with your own column titles with
- the array $col_titles. This is designed more as a quick debugging mechanism,
- not a production table recordset viewer. You will need to include the file tohtml.inc.php. This describes how to create a class to connect to a new database. To ensure
- there is no duplication of work, kindly email me at jlim#natsoft.com.my if
- you decide to create such a class. First decide on a name in lower case to call the database type. Let's say we
- call it xbase. Then we need to create two classes ADODB_xbase and ADORecordSet_xbase
- in the file adodb-xbase.inc.php. The simplest form of database driver is an adaptation of an existing ODBC driver.
- Then we just need to create the class ADODB_xbase extends ADODB_odbc
- to support the new date and timestamp formats, the concatenation
- operator used, true and false. For the ADORecordSet_xbase
- extends ADORecordSet_odbc we need to change the MetaType function.
- See adodb-vfp.inc.php as an example. More complicated is a totally new database driver that connects to a new PHP
- extension. Then you will need to implement several functions. Fortunately,
- you do not have to modify most of the complex code. You only need to override
- a few stub functions. See adodb-mysql.inc.php for example. The default date format of ADOdb internally is YYYY-MM-DD (Ansi-92). All dates
- should be converted to that format when passing to an ADOdb date function.
- See Oracle for an example how we use ALTER SESSION to change the default date
- format in _pconnect _connect. ADOConnection Functions to Override Defining a constructor for your ADOConnection derived function is optional.
- There is no need to call the base class constructor. _connect: Low level implementation of Connect. Returns true or false.
- Should set the _connectionID. _pconnect: Low level implemention of PConnect. Returns true or false.
- Should set the _connectionID. _query: Execute a query. Returns the queryID, or false. _close: Close the connection -- PHP should clean up all recordsets.
- ErrorMsg: Stores the error message in the private variable _errorMsg.
- ADOConnection Fields to Set _bindInputArray: Set to true if binding of parameters for SQL inserts
- and updates is allowed using ?, eg. as with ODBC. fmtDate fmtTimeStamp true false concat_operator replaceQuote hasLimit support SELECT * FROM TABLE LIMIT 10 of MySQL. hasTop support Microsoft style SELECT TOP 10 * FROM TABLE. ADORecordSet Functions to Override You will need to define a constructor for your ADORecordSet derived class that
- calls the parent class constructor. FetchField: as documented above in ADORecordSet _initrs: low level initialization of the recordset: setup the _numOfRows
- and _numOfFields fields -- called by the constructor. _seek: seek to a particular row. Do not load the data into the fields
- array. This is done by _fetch. Returns true or false. Note that some implementations
- such as Interbase do not support seek. Set canSeek to false. _fetch: fetch a row using the database extension function and then move
- to the next row. Sets the fields array. If the parameter $ignore_fields
- is true then there is no need to populate the fields array, just move
- to the next row. then Returns true or false. _close: close the recordset Fields: If the array row returned by the PHP extension is not an associative
- one, you will have to override this. See adodb-odbc.inc.php for an example.
- For databases such as MySQL and MSSQL where an associative array is returned,
- there is no need to override this function. ADOConnection Fields to Set canSeek: Set to true if the _seek function works. See the RoadMap article. Also see the ADOdb proxy article
- for bridging Windows and Unix databases using http remote procedure calls.
- For your education, visit palslib.com for
- database info, and read this article on Optimizing
- PHP. 3.40 ?? March 2003 Modified postgresql UpdateBlobFile() because it did not work in safe mode.
- Now connection object is passed to raiseErrorFn as last parameter. Needed by StartTrans().
- Added StartTrans() and CompleteTrans(). It is recommended that you do not modify transOff, but
-use the above functions.
- oci8po now obeys ADODB_ASSOC_CASE settings.
- Added virtualized error codes, using PEAR DB equivalents. Requires you to manually include
- adodb-error.inc.php yourself, with MetaError() and MetaErrorMsg($errno).
- GetRowAssoc for mysql and pgsql were flawed. Fix by Ross Smith.
- Added to datadict types I1, I2, I4 and I8. Changed datadict type 'T' to map to
-timestamp instead of datetime for postgresql.
- Error handling in ExecuteSQLArray(), adodb-datadict.inc.php did not work.
- We now auto-quote postgresql connection parameters when building connection string.
- Added session expiry notification.
- We now test with odbc mysql - made some changes to odbc recordset constructor.
- MetaColumns now special cases access and other databases for odbc.
- 3.31 17 March 2003 Added row checking for _fetch in postgres.
- Added Interval type to MetaType for postgres.
- Remapped postgres driver to call postgres7 driver internally.
- Adorecordset_array::getarray() did not return array when nRows >= 0.
- Postgresql: at times, no error message returned by pg_result_error()
- but error message returned in pg_last_error(). Recoded again.
- Interbase blob's now use chunking for updateblob.
- Move() did not set EOF correctly. Reported by Jorma T.
- We properly support mysql timestamp fields when we are creating mysql
- tables using the data-dict interface.
- Table regex includes backticks character now.
- 3.30 3 March 2003 Added $ADODB_EXTENSION and $ADODB_COMPAT_FETCH constant.
- Made blank1stItem configurable using syntax "value:text" in GetMenu/GetMenu2. Thx to Gabriel Birke.
- Previously ADOdb differed from the Microsoft standard because it did not define
- what to set $this->fields when EOF was reached. Now at EOF, ADOdb sets $this->fields
- to false for all databases, which is consist with Microsoft's implementation.
- Postgresql and mysql have always worked this way (in 3.11 and earlier). If
- you are experiencing compatibility problems (and you are not using postgresql
- nor mysql) on upgrading to 3.30, try setting the global variables $ADODB_COUNTRECS
- = true (which is the default) and $ADODB_FETCH_COMPAT = true (this is a new
- global variable).
- We now check both pg_result_error and pg_last_error as sometimes pg_result_error does not display anything.
- Iman Mayes
-
-We no longer check for magic quotes gpc in Quote().
-
-Misc fixes for table creation in adodb-datadict.inc.php. Thx to iamsure.
-
-Time calculations use adodb_time library for all negative timestamps
-due to problems in Red Hat 7.3 or later. Formerly, only did this for
-Windows.
-
-In mssqlpo, we now check if $sql in _query is a string before we change || to +. This is
-to support prepared stmts.
-
-Move() and MoveLast() internals changed to support to support EOF and $this->fields change.
-
-Added ADODB_FETCH_BOTH support to mssql. Thx to Angel Fradejas afradejas#mediafusion.es
-
-We now check if link resource exists before we run mysql_escape_string in qstr().
-
-Before we flock in csv code, we check that it is not a http url.
- 3.20 17 Feb 2003 Added new Data Dictionary classes for creating tables and indexes. Warning - this is very much alpha quality code.
-The API can still change. See adodb/tests/test-datadict.php for more info.
- We now ignore $ADODB_COUNTRECS for mysql, because PHP truncates incomplete recordsets
- when mysql_unbuffered_query() is called a second time.
- Now postgresql works correctly when $ADODB_COUNTRECS = false.
- Changed _adodb_getcount to properly support SELECT DISTINCT.
- Discovered that $ADODB_COUNTRECS=true has some problems with prepared queries - suspect
-PHP bug.
- Now GetOne and GetRow run in $ADODB_COUNTRECS=false mode for better performance.
- Added support for mysql_real_escape_string() and pg_escape_string() in qstr().
- Added an intermediate variable for mysql _fetch() and MoveNext() to store fields, to prevent
-overwriting field array with boolean when mysql_fetch_array() returns false.
- Made arrays for getinsertsql and getupdatesql case-insensitive. Suggested by Tim Uckun" tim#diligence.com
- 3.11 11 Feb 2003 Added check for ADODB_NEVER_PERSIST constant in PConnect().
-If defined, then PConnect() will actually call non-persistent Connect().
- Modified interbase to properly work with Prepare().
- Added $this->ibase_timefmt to allow you to change the date and time format.
- Added support for $input_array parameter in CacheFlush().
- Added experimental support for dbx, which was then removed when i found that
-it was slower than using native calls.
- Added MetaPrimaryKeys for mssql and ibase/firebird.
- Added new $trim parameter to GetCol and CacheGetCol
- Uses updated adodb-time.inc.php 0.06.
- 3.10 27 Jan 2003
- Added adodb_date(), adodb_getdate(), adodb_mktime() and adodb-time.inc.php.
- For interbase, added code to handle unlimited number of bind parameters.
-From Daniel Hasan daniel#hasan.cl.
- Added BlobDecode and UpdateBlob for informix. Thx to Fernando Ortiz.
- Added constant ADODB_WINDOWS. If defined, means that running on Windows.
- Added constant ADODB_PHPVER which stores php version as a hex num. Removed $ADODB_PHPVER variable.
- Felho Bacsi reported a minor white-space regular expression problem in GetInsertSQL.
- Modified ADO to use variant to store _affectedRows
- Changed ibase to use base class Replace(). Modified base class Replace() to support ibase.
- Changed odbc to auto-detect when 0 records returned is wrong due to bad odbc drivers.
- Changed mssql to use datetimeconvert ini setting only when 4.30 or later (does not work in 4.23).
- ExecuteCursor($stmt, $cursorname, $params) now accepts a new $params array of additional bind
-parameters -- William Lovaton walovaton#yahoo.com.mx.
- Added support for sybase_unbuffered_query if ADODB_COUNTRECS == false. Thx to chuck may.
- Fixed FetchNextObj() bug. Thx to Jorma Tuomainen.
- We now use SCOPE_IDENTITY() instead of @@IDENTITY for mssql - thx to marchesini#eside.it
- Changed postgresql movenext logic to prevent illegal row number from being passed to pg_fetch_array().
- Postgresql initrs bug found by "Bogdan RIPA" bripa#interakt.ro $f1 accidentally named $f
- 3.00 6 Jan 2003
- Fixed adodb-pear.inc.php syntax error.
- Improved _adodb_getcount() to use SELECT COUNT(*) FROM ($sql) for languages that
-accept it.
- Fixed _adodb_getcount() caching error.
- Added sql to retrive table and column info for odbc_mssql.
- 2.91 3 Jan 2003
- Revised PHP version checking to use $ADODB_PHPVER with legal values 0x4000, 0x4050, 0x4200, 0x4300.
- Added support for bytea fields and oid blobs in postgres by allowing BlobDecode()
- to detect and convert non-oid fields. Also added BlobEncode to postgres when
- you want to encode oid blobs.
- Added blobEncodeType property for connections to inform phpLens what encoding
-method to use for blobs.
- Added BlobDecode() and BlobEncode() to base ADOConnection class.
- Added umask() to _gencachename() when creating directories.
- Added charPage for ado drivers, so you can set the code page.
- Modified _seek in mysql to check for num rows=0.
- Added to metatypes new informix types for IDS 9.30. Thx Fernando Ortiz.
- _maxrecordcount returned in CachePageExecute $rsreturn
- Fixed sybase cacheselectlimit( ) problems
- MetaColumns() max_length should use precision for types X and C for ms access. Fixed.
- Speedup of odbc non-SELECT sql statements.
- Added support in MetaColumns for Wide Char types for ODBC. We halve max_length
- if unicode/wide char.
- Added 'B' to types handled by GetUpdateSQL/GetInsertSQL.
- Fixed warning message in oci8 driver with $persist variable when using PConnect.
- 2.90 11 Dec 2002
- Mssql and mssqlpo and oci8po now support ADODB_ASSOC_CASE.
- Now MetaType() can accept a field object as the first parameter.
- New $arr = $db->ServerInfo( ) function. Returns $arr['description'] which
- is the string description, and $arr['version'].
- PostgreSQL and MSSQL speedups for insert/updates.
- Implemented new SetFetchMode() that removes the need to use $ADODB_FETCH_MODE.
- Each connection has independant fetchMode.
- ADODB_ASSOC_CASE now defaults to 2, use native defaults. This is because we would
-break backward compat for too many applications otherwise.
- Patched encrypted sessions to use replace()
- The qstr function supports quoting of nulls when escape character is \
- Rewrote bits and pieces of session code to check for time synch and improve reliability.
- Added property ADOConnection::hasTransactions = true/false;
- Added CreateSequence and DropSequence functions
- Found misplaced MoveNext() in adodb-postgres.inc.php. Fixed.
- Sybase SelectLimit not reliable because 'set rowcount' not cached - fixed.
- Moved ADOConnection to adodb-connection.inc.php and ADORecordSet to adodb-recordset.inc.php.
-This allows us to use doxygen to generate documentation. Doxygen doesn't like the classes
-in the main adodb.inc.php file for some mysterious reason.
- 2.50, 14 Nov 2002
- Added transOff and transCnt properties for disabling (transOff = true)
-and tracking transaction status (transCnt>0).
- Added inputarray handling into _adodb_pageexecute_all_rows - "Ross Smith" RossSmith#bnw.com.
- Fixed postgresql inconsistencies in date handling.
- Added support for mssql_fetch_assoc.
- Fixed $ADODB_FETCH_MODE bug in odbc MetaTables() and MetaPrimaryKeys().
- Accidentally declared UnixDate() twice, making adodb incompatible with php 4.3.0. Fixed.
- Fixed pager problems with some databases that returned -1 for _currentRow on MoveLast() by
-switching to MoveNext() in adodb-lib.inc.php.
- Also fixed uninited $discard in adodb-lib.inc.php.
- 2.43, 25 Oct 2002 Added support for NConnect() for oracle OCINLogin.
- Fixed NumCols() bug.
- Changed session handler to use Replace() on write.
- Fixed oci8 SelectLimit aggregate function bug again.
- Rewrote pivoting code.
- 2.42, 4 Oct 2002 Fixed ibase_fetch() problem with nulls. Also interbase now does automatic blob decoding,
-and is backward compatible. Suggested by Heinz Hombergs heinz#hhombergs.de.
- Fixed postgresql MoveNext() problems when called repeatedly after EOF.
-Also suggested by Heinz Hombergs.
- PageExecute() does not rewrite queries if SELECT DISTINCT is used. Requested by hans#velum.net
- Added additional fixes to oci8 SelectLimit handling with aggregate functions - thx to Christian Bugge
-for reporting the problem.
- 2.41, 2 Oct 2002 Fixed ADODB_COUNTRECS bug in odbc. Thx to Joshua Zoshi jzoshi#hotmail.com.
- Increased buffers for adodb-csvlib.inc.php for extremely long sql from 8192 to 32000.
- Revised pivottable.inc.php code. Added better support for aggregate fields.
- Fixed mysql text/blob types problem in MetaTypes base class - thx to horacio degiorgi.
- Added SQLDate($fmt,$date) function, which allows an sql date format string to be generated -
-useful for group by's.
- Fixed bug in oci8 SelectLimit when offset>100.
- 2.40 4 Sept 2002 Added new NLS_DATE_FORMAT property to oci8. Suggested by Laurent NAVARRO ln#altidev.com
- Now use bind parameters in oci8 selectlimit for better performance.
- Fixed interbase replaceQuote for dialect != 1. Thx to
-"BEGUIN Pierre-Henri - INFOCOB" phb#infocob.com.
- Added white-space check to QA.
- Changed unixtimestamp to support fractional seconds (we always round down/floor the seconds).
- Thanks to beezly#beezly.org.uk.
- Now you can set the trigger_error type your own user-defined type in adodb-errorhandler.inc.php.
-Suggested by Claudio Bustos clbustos#entelchile.net.
- Added recordset filters with rsfilter.inc.php.
- $conn->_rs2rs does not create a new recordset when it detects it is of type array. Some
-trickery there as there seems to be a bug in Zend Engine
- Added render_pagelinks to adodb-pager.inc.php. Code by "Pablo Costa" pablo#cbsp.com.br.
- MetaType() speedup in adodb.inc.php by using hashing instead of switch. Best performance
-if constant arrays are supported, as they are in PHP5.
- adodb-session.php now updates only the expiry date if the crc32 check indicates
- that the data has not been modified. 0.10 Sept 9 2000 First release
-
\n version=$dbc->version");
- // @ added below for php 4.0.1 and earlier
- @$dbc->Open((string) $argHostname);
-
- $this->_connectionID = $dbc;
-
- $dbc->CursorLocation = $this->_cursor_location;
- return $dbc->State > 0;
- }
-
- // returns true or false
- function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL')
- {
- return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider);
- }
-
-/*
- adSchemaCatalogs = 1,
- adSchemaCharacterSets = 2,
- adSchemaCollations = 3,
- adSchemaColumns = 4,
- adSchemaCheckConstraints = 5,
- adSchemaConstraintColumnUsage = 6,
- adSchemaConstraintTableUsage = 7,
- adSchemaKeyColumnUsage = 8,
- adSchemaReferentialContraints = 9,
- adSchemaTableConstraints = 10,
- adSchemaColumnsDomainUsage = 11,
- adSchemaIndexes = 12,
- adSchemaColumnPrivileges = 13,
- adSchemaTablePrivileges = 14,
- adSchemaUsagePrivileges = 15,
- adSchemaProcedures = 16,
- adSchemaSchemata = 17,
- adSchemaSQLLanguages = 18,
- adSchemaStatistics = 19,
- adSchemaTables = 20,
- adSchemaTranslations = 21,
- adSchemaProviderTypes = 22,
- adSchemaViews = 23,
- adSchemaViewColumnUsage = 24,
- adSchemaViewTableUsage = 25,
- adSchemaProcedureParameters = 26,
- adSchemaForeignKeys = 27,
- adSchemaPrimaryKeys = 28,
- adSchemaProcedureColumns = 29,
- adSchemaDBInfoKeywords = 30,
- adSchemaDBInfoLiterals = 31,
- adSchemaCubes = 32,
- adSchemaDimensions = 33,
- adSchemaHierarchies = 34,
- adSchemaLevels = 35,
- adSchemaMeasures = 36,
- adSchemaProperties = 37,
- adSchemaMembers = 38
-
-*/
-
- function MetaTables()
- {
- $arr= array();
- $dbc = $this->_connectionID;
-
- $adors=@$dbc->OpenSchema(20);//tables
- if ($adors){
- $f = $adors->Fields(2);//table/view name
- $t = $adors->Fields(3);//table type
- while (!$adors->EOF){
- $tt=substr($t->value,0,6);
- if ($tt!='SYSTEM' && $tt !='ACCESS')
- $arr[]=$f->value;
- //print $f->value . ' ' . $t->value.'
';
- $adors->MoveNext();
- }
- $adors->Close();
- }
-
- return $arr;
- }
-
- function MetaColumns($table)
- {
- $table = strtoupper($table);
- $arr= array();
- $dbc = $this->_connectionID;
-
- $adors=@$dbc->OpenSchema(4);//tables
-
- if ($adors){
- $t = $adors->Fields(2);//table/view name
- while (!$adors->EOF){
-
-
- if (strtoupper($t->Value) == $table) {
-
- $fld = new ADOFieldObject();
- $c = $adors->Fields(3);
- $fld->name = $c->Value;
- $fld->type = 'CHAR'; // cannot discover type in ADO!
- $fld->max_length = -1;
- $arr[strtoupper($fld->name)]=$fld;
- }
-
- $adors->MoveNext();
- }
- $adors->Close();
- }
-
- return $arr;
- }
-
- /* returns queryID or false */
- function &_query($sql,$inputarr=false)
- {
-
- $dbc = $this->_connectionID;
-
- // return rs
- if ($inputarr) {
-
- if (!empty($this->charPage))
- $oCmd = new COM('ADODB.Command',null,$this->charPage);
- else
- $oCmd = new COM('ADODB.Command');
- $oCmd->ActiveConnection = $dbc;
- $oCmd->CommandText = $sql;
- $oCmd->CommandType = 1;
-
- foreach($inputarr as $val) {
- // name, type, direction 1 = input, len,
- $this->adoParameterType = 130;
- $p = $oCmd->CreateParameter('name',$this->adoParameterType,1,strlen($val),$val);
- //print $p->Type.' '.$p->value;
- $oCmd->Parameters->Append($p);
- }
- $p = false;
- $rs = $oCmd->Execute();
- $e = $dbc->Errors;
- if ($dbc->Errors->Count > 0) return false;
- return $rs;
- }
-
- $rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option);
- /*
- $rs = new COM('ADODB.Recordset');
- if ($rs) {
- $rs->Open ($sql, $dbc, $this->_cursor_type,$this->_lock_type, $this->_execute_option);
- }
- */
- if ($dbc->Errors->Count > 0) return false;
- if (! $rs) return false;
-
- if ($rs->State == 0) return true; // 0 = adStateClosed means no records returned
- return $rs;
- }
-
-
- function BeginTrans()
- {
- if ($this->transOff) return true;
-
- if (isset($this->_thisTransactions))
- if (!$this->_thisTransactions) return false;
- else {
- $o = $this->_connectionID->Properties("Transaction DDL");
- $this->_thisTransactions = $o ? true : false;
- if (!$o) return false;
- }
- @$this->_connectionID->BeginTrans();
- $this->transCnt += 1;
- return true;
- }
- function CommitTrans($ok=true)
- {
- if (!$ok) return $this->RollbackTrans();
- if ($this->transOff) return true;
-
- @$this->_connectionID->CommitTrans();
- if ($this->transCnt) @$this->transCnt -= 1;
- return true;
- }
- function RollbackTrans() {
- if ($this->transOff) return true;
- @$this->_connectionID->RollbackTrans();
- if ($this->transCnt) @$this->transCnt -= 1;
- return true;
- }
-
- /* Returns: the last error message from previous database operation */
-
- function ErrorMsg()
- {
- $errc = $this->_connectionID->Errors;
- if ($errc->Count == 0) return '';
- $err = $errc->Item($errc->Count-1);
- return $err->Description;
- }
-
- function ErrorNo()
- {
- $errc = $this->_connectionID->Errors;
- if ($errc->Count == 0) return 0;
- $err = $errc->Item($errc->Count-1);
- return $err->NativeError;
- }
-
- // returns true or false
- function _close()
- {
- if ($this->_connectionID) $this->_connectionID->Close();
- $this->_connectionID = false;
- return true;
- }
-
-
-}
-
-/*--------------------------------------------------------------------------------------
- Class Name: Recordset
---------------------------------------------------------------------------------------*/
-
-class ADORecordSet_ado extends ADORecordSet {
-
- var $bind = false;
- var $databaseType = "ado";
- var $dataProvider = "ado";
- var $_tarr = false; // caches the types
- var $_flds; // and field objects
- var $canSeek = true;
- var $hideErrors = true;
-
- function ADORecordSet_ado($id,$mode=false)
- {
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- $this->fetchMode = $mode;
- return $this->ADORecordSet($id,$mode);
- }
-
-
- // returns the field object
- function FetchField($fieldOffset = -1) {
- $off=$fieldOffset+1; // offsets begin at 1
-
- $o= new ADOFieldObject();
- $rs = $this->_queryID;
- $f = $rs->Fields($fieldOffset);
- $o->name = $f->Name;
- $t = $f->Type;
- $o->type = $this->MetaType($t);
- $o->max_length = $f->DefinedSize;
- $o->ado_type = $t;
-
-
- //print "off=$off name=$o->name type=$o->type len=$o->max_length
";
- return $o;
- }
-
- /* Use associative array to get fields array */
- function Fields($colname)
- {
- if ($this->fetchMode & ADODB_FETCH_ASSOC) 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 _initrs()
- {
- $rs = $this->_queryID;
- $this->_numOfRows = $rs->RecordCount;
-
- $f = $rs->Fields;
- $this->_numOfFields = $f->Count;
- }
-
-
- // should only be used to move forward as we normally use forward-only cursors
- function _seek($row)
- {
- $rs = $this->_queryID;
- // absoluteposition doesn't work -- my maths is wrong ?
- // $rs->AbsolutePosition->$row-2;
- // return true;
- if ($this->_currentRow > $row) return false;
- @$rs->Move((integer)$row - $this->_currentRow-1); //adBookmarkFirst
- return true;
- }
-
-/*
- OLEDB types
-
- enum DBTYPEENUM
- { DBTYPE_EMPTY = 0,
- DBTYPE_NULL = 1,
- DBTYPE_I2 = 2,
- DBTYPE_I4 = 3,
- DBTYPE_R4 = 4,
- DBTYPE_R8 = 5,
- DBTYPE_CY = 6,
- DBTYPE_DATE = 7,
- DBTYPE_BSTR = 8,
- DBTYPE_IDISPATCH = 9,
- DBTYPE_ERROR = 10,
- DBTYPE_BOOL = 11,
- DBTYPE_VARIANT = 12,
- DBTYPE_IUNKNOWN = 13,
- DBTYPE_DECIMAL = 14,
- DBTYPE_UI1 = 17,
- DBTYPE_ARRAY = 0x2000,
- DBTYPE_BYREF = 0x4000,
- DBTYPE_I1 = 16,
- DBTYPE_UI2 = 18,
- DBTYPE_UI4 = 19,
- DBTYPE_I8 = 20,
- DBTYPE_UI8 = 21,
- DBTYPE_GUID = 72,
- DBTYPE_VECTOR = 0x1000,
- DBTYPE_RESERVED = 0x8000,
- DBTYPE_BYTES = 128,
- DBTYPE_STR = 129,
- DBTYPE_WSTR = 130,
- DBTYPE_NUMERIC = 131,
- DBTYPE_UDT = 132,
- DBTYPE_DBDATE = 133,
- DBTYPE_DBTIME = 134,
- DBTYPE_DBTIMESTAMP = 135
-
- ADO Types
-
- adEmpty = 0,
- adTinyInt = 16,
- adSmallInt = 2,
- adInteger = 3,
- adBigInt = 20,
- adUnsignedTinyInt = 17,
- adUnsignedSmallInt = 18,
- adUnsignedInt = 19,
- adUnsignedBigInt = 21,
- adSingle = 4,
- adDouble = 5,
- adCurrency = 6,
- adDecimal = 14,
- adNumeric = 131,
- adBoolean = 11,
- adError = 10,
- adUserDefined = 132,
- adVariant = 12,
- adIDispatch = 9,
- adIUnknown = 13,
- adGUID = 72,
- adDate = 7,
- adDBDate = 133,
- adDBTime = 134,
- adDBTimeStamp = 135,
- adBSTR = 8,
- adChar = 129,
- adVarChar = 200,
- adLongVarChar = 201,
- adWChar = 130,
- adVarWChar = 202,
- adLongVarWChar = 203,
- adBinary = 128,
- adVarBinary = 204,
- adLongVarBinary = 205,
- adChapter = 136,
- adFileTime = 64,
- adDBFileTime = 137,
- adPropVariant = 138,
- adVarNumeric = 139
-*/
- function MetaType($t,$len=-1,$fieldobj=false)
- {
- if (is_object($t)) {
- $fieldobj = $t;
- $t = $fieldobj->type;
- $len = $fieldobj->max_length;
- }
-
- if (!is_numeric($t)) return $t;
-
- switch ($t) {
- case 0:
- case 12: // variant
- case 8: // bstr
- case 129: //char
- case 130: //wc
- case 200: // varc
- case 202:// varWC
- case 128: // bin
- case 204: // varBin
- case 72: // guid
- if ($len <= $this->blobSize) return 'C';
-
- case 201:
- case 203:
- return 'X';
- case 128:
- case 204:
- case 205:
- return 'B';
- case 7:
- case 133: return 'D';
-
- case 134:
- case 135: return 'T';
-
- case 11: return 'L';
-
- case 16:// adTinyInt = 16,
- case 2://adSmallInt = 2,
- case 3://adInteger = 3,
- case 4://adBigInt = 20,
- case 17://adUnsignedTinyInt = 17,
- case 18://adUnsignedSmallInt = 18,
- case 19://adUnsignedInt = 19,
- case 20://adUnsignedBigInt = 21,
- return 'I';
- default: return 'N';
- }
- }
-
- // time stamp not supported yet
- function _fetch()
- {
- $rs = $this->_queryID;
- if (!$rs or $rs->EOF) {
- $this->fields = false;
- return false;
- }
- $this->fields = array();
-
- if (!$this->_tarr) {
- $tarr = array();
- $flds = array();
- for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
- $f = $rs->Fields($i);
- $flds[] = $f;
- $tarr[] = $f->Type;
- }
- // bind types and flds only once
- $this->_tarr = $tarr;
- $this->_flds = $flds;
- }
- $t = reset($this->_tarr);
- $f = reset($this->_flds);
-
- if ($this->hideErrors) $olde = error_reporting(E_ERROR|E_CORE_ERROR);// sometimes $f->value be null
- for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
-
- switch($t) {
- case 135: // timestamp
- $this->fields[] = date('Y-m-d H:i:s',(integer)$f->value);
- break;
-
- case 133:// A date value (yyyymmdd)
- $val = $f->value;
- $this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2);
- break;
- case 7: // adDate
- $this->fields[] = date('Y-m-d',(integer)$f->value);
- break;
- case 1: // null
- $this->fields[] = false;
- break;
- case 6: // currency is not supported properly;
- ADOConnection::outp( ''.$f->Name.': currency type not supported by PHP');
- $this->fields[] = (float) $f->value;
- break;
- default:
- $this->fields[] = $f->value;
- break;
- }
- //print " $f->value $t, ";
- $f = next($this->_flds);
- $t = next($this->_tarr);
- } // for
- if ($this->hideErrors) error_reporting($olde);
- @$rs->MoveNext(); // @ needed for some versions of PHP!
-
- if ($this->fetchMode & ADODB_FETCH_ASSOC) {
- $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);
- }
- return true;
- }
-
-
- function _close() {
- $this->_flds = false;
- @$this->_queryID->Close();// by Pete Dishman (peterd@telephonetics.co.uk)
- $this->_queryID = false;
- }
-
-}
-
+_affectedRows = new VARIANT;
+ }
+
+ function ServerInfo()
+ {
+ if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider;
+ return array('description' => $desc, 'version' => '');
+ }
+
+ function _affectedrows()
+ {
+ return $this->_affectedRows->value;
+ }
+
+ /* you can also pass a connection string like this: */
+ /* */
+ /* $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB'); */
+ function _connect($argHostname, $argUsername, $argPassword, $argProvider= 'MSDASQL')
+ {
+ $u = 'UID';
+ $p = 'PWD';
+
+ if (!empty($this->charPage))
+ $dbc = new COM('ADODB.Connection',null,$this->charPage);
+ else
+ $dbc = new COM('ADODB.Connection');
+
+ if (! $dbc) return false;
+
+ /* special support if provider is mssql or access */
+ if ($argProvider=='mssql') {
+ $u = 'User Id'; /* User parameter name for OLEDB */
+ $p = 'Password';
+ $argProvider = "SQLOLEDB"; /* SQL Server Provider */
+
+ /* not yet */
+ /* if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename"; */
+
+ /* use trusted conection for SQL if username not specified */
+ if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes";
+ } else if ($argProvider=='access')
+ $argProvider = "Microsoft.Jet.OLEDB.4.0"; /* Microsoft Jet Provider */
+
+ if ($argProvider) $dbc->Provider = $argProvider;
+
+ if ($argUsername) $argHostname .= ";$u=$argUsername";
+ if ($argPassword)$argHostname .= ";$p=$argPassword";
+
+ if ($this->debug) ADOConnection::outp( "Host=".$argHostname."
\n version=$dbc->version");
+ /* @ added below for php 4.0.1 and earlier */
+ @$dbc->Open((string) $argHostname);
+
+ $this->_connectionID = $dbc;
+
+ $dbc->CursorLocation = $this->_cursor_location;
+ return $dbc->State > 0;
+ }
+
+ /* returns true or false */
+ function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL')
+ {
+ return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider);
+ }
+
+/*
+ adSchemaCatalogs = 1,
+ adSchemaCharacterSets = 2,
+ adSchemaCollations = 3,
+ adSchemaColumns = 4,
+ adSchemaCheckConstraints = 5,
+ adSchemaConstraintColumnUsage = 6,
+ adSchemaConstraintTableUsage = 7,
+ adSchemaKeyColumnUsage = 8,
+ adSchemaReferentialContraints = 9,
+ adSchemaTableConstraints = 10,
+ adSchemaColumnsDomainUsage = 11,
+ adSchemaIndexes = 12,
+ adSchemaColumnPrivileges = 13,
+ adSchemaTablePrivileges = 14,
+ adSchemaUsagePrivileges = 15,
+ adSchemaProcedures = 16,
+ adSchemaSchemata = 17,
+ adSchemaSQLLanguages = 18,
+ adSchemaStatistics = 19,
+ adSchemaTables = 20,
+ adSchemaTranslations = 21,
+ adSchemaProviderTypes = 22,
+ adSchemaViews = 23,
+ adSchemaViewColumnUsage = 24,
+ adSchemaViewTableUsage = 25,
+ adSchemaProcedureParameters = 26,
+ adSchemaForeignKeys = 27,
+ adSchemaPrimaryKeys = 28,
+ adSchemaProcedureColumns = 29,
+ adSchemaDBInfoKeywords = 30,
+ adSchemaDBInfoLiterals = 31,
+ adSchemaCubes = 32,
+ adSchemaDimensions = 33,
+ adSchemaHierarchies = 34,
+ adSchemaLevels = 35,
+ adSchemaMeasures = 36,
+ adSchemaProperties = 37,
+ adSchemaMembers = 38
+
+*/
+
+ function &MetaTables()
+ {
+ $arr= array();
+ $dbc = $this->_connectionID;
+
+ $adors=@$dbc->OpenSchema(20);/* tables */
+ if ($adors){
+ $f = $adors->Fields(2);/* table/view name */
+ $t = $adors->Fields(3);/* table type */
+ while (!$adors->EOF){
+ $tt=substr($t->value,0,6);
+ if ($tt!='SYSTEM' && $tt !='ACCESS')
+ $arr[]=$f->value;
+ /* print $f->value . ' ' . $t->value.'
'; */
+ $adors->MoveNext();
+ }
+ $adors->Close();
+ }
+
+ return $arr;
+ }
+
+ function &MetaColumns($table)
+ {
+ $table = strtoupper($table);
+ $arr= array();
+ $dbc = $this->_connectionID;
+
+ $adors=@$dbc->OpenSchema(4);/* tables */
+
+ if ($adors){
+ $t = $adors->Fields(2);/* table/view name */
+ while (!$adors->EOF){
+
+
+ if (strtoupper($t->Value) == $table) {
+
+ $fld = new ADOFieldObject();
+ $c = $adors->Fields(3);
+ $fld->name = $c->Value;
+ $fld->type = 'CHAR'; /* cannot discover type in ADO! */
+ $fld->max_length = -1;
+ $arr[strtoupper($fld->name)]=$fld;
+ }
+
+ $adors->MoveNext();
+ }
+ $adors->Close();
+ }
+
+ return $arr;
+ }
+
+ /* returns queryID or false */
+ function &_query($sql,$inputarr=false)
+ {
+
+ $dbc = $this->_connectionID;
+
+ /* return rs */
+ if ($inputarr) {
+
+ if (!empty($this->charPage))
+ $oCmd = new COM('ADODB.Command',null,$this->charPage);
+ else
+ $oCmd = new COM('ADODB.Command');
+ $oCmd->ActiveConnection = $dbc;
+ $oCmd->CommandText = $sql;
+ $oCmd->CommandType = 1;
+
+ foreach($inputarr as $val) {
+ /* name, type, direction 1 = input, len, */
+ $this->adoParameterType = 130;
+ $p = $oCmd->CreateParameter('name',$this->adoParameterType,1,strlen($val),$val);
+ /* print $p->Type.' '.$p->value; */
+ $oCmd->Parameters->Append($p);
+ }
+ $p = false;
+ $rs = $oCmd->Execute();
+ $e = $dbc->Errors;
+ if ($dbc->Errors->Count > 0) return false;
+ return $rs;
+ }
+
+ $rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option);
+ /*
+ $rs = new COM('ADODB.Recordset');
+ if ($rs) {
+ $rs->Open ($sql, $dbc, $this->_cursor_type,$this->_lock_type, $this->_execute_option);
+ }
+ */
+ if ($dbc->Errors->Count > 0) return false;
+ if (! $rs) return false;
+
+ if ($rs->State == 0) return true; /* 0 = adStateClosed means no records returned */
+ return $rs;
+ }
+
+
+ function BeginTrans()
+ {
+ if ($this->transOff) return true;
+
+ if (isset($this->_thisTransactions))
+ if (!$this->_thisTransactions) return false;
+ else {
+ $o = $this->_connectionID->Properties("Transaction DDL");
+ $this->_thisTransactions = $o ? true : false;
+ if (!$o) return false;
+ }
+ @$this->_connectionID->BeginTrans();
+ $this->transCnt += 1;
+ return true;
+ }
+ function CommitTrans($ok=true)
+ {
+ if (!$ok) return $this->RollbackTrans();
+ if ($this->transOff) return true;
+
+ @$this->_connectionID->CommitTrans();
+ if ($this->transCnt) @$this->transCnt -= 1;
+ return true;
+ }
+ function RollbackTrans() {
+ if ($this->transOff) return true;
+ @$this->_connectionID->RollbackTrans();
+ if ($this->transCnt) @$this->transCnt -= 1;
+ return true;
+ }
+
+ /* Returns: the last error message from previous database operation */
+
+ function ErrorMsg()
+ {
+ $errc = $this->_connectionID->Errors;
+ if ($errc->Count == 0) return '';
+ $err = $errc->Item($errc->Count-1);
+ return $err->Description;
+ }
+
+ function ErrorNo()
+ {
+ $errc = $this->_connectionID->Errors;
+ if ($errc->Count == 0) return 0;
+ $err = $errc->Item($errc->Count-1);
+ return $err->NativeError;
+ }
+
+ /* returns true or false */
+ function _close()
+ {
+ if ($this->_connectionID) $this->_connectionID->Close();
+ $this->_connectionID = false;
+ return true;
+ }
+
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_ado extends ADORecordSet {
+
+ var $bind = false;
+ var $databaseType = "ado";
+ var $dataProvider = "ado";
+ var $_tarr = false; /* caches the types */
+ var $_flds; /* and field objects */
+ var $canSeek = true;
+ var $hideErrors = true;
+
+ function ADORecordSet_ado($id,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ $this->fetchMode = $mode;
+ return $this->ADORecordSet($id,$mode);
+ }
+
+
+ /* returns the field object */
+ function FetchField($fieldOffset = -1) {
+ $off=$fieldOffset+1; /* offsets begin at 1 */
+
+ $o= new ADOFieldObject();
+ $rs = $this->_queryID;
+ $f = $rs->Fields($fieldOffset);
+ $o->name = $f->Name;
+ $t = $f->Type;
+ $o->type = $this->MetaType($t);
+ $o->max_length = $f->DefinedSize;
+ $o->ado_type = $t;
+
+
+ /* print "off=$off name=$o->name type=$o->type len=$o->max_length
"; */
+ return $o;
+ }
+
+ /* Use associative array to get fields array */
+ function Fields($colname)
+ {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) 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 _initrs()
+ {
+ $rs = $this->_queryID;
+ $this->_numOfRows = $rs->RecordCount;
+
+ $f = $rs->Fields;
+ $this->_numOfFields = $f->Count;
+ }
+
+
+ /* should only be used to move forward as we normally use forward-only cursors */
+ function _seek($row)
+ {
+ $rs = $this->_queryID;
+ /* absoluteposition doesn't work -- my maths is wrong ? */
+ /* $rs->AbsolutePosition->$row-2; */
+ /* return true; */
+ if ($this->_currentRow > $row) return false;
+ @$rs->Move((integer)$row - $this->_currentRow-1); /* adBookmarkFirst */
+ return true;
+ }
+
+/*
+ OLEDB types
+
+ enum DBTYPEENUM
+ { DBTYPE_EMPTY = 0,
+ DBTYPE_NULL = 1,
+ DBTYPE_I2 = 2,
+ DBTYPE_I4 = 3,
+ DBTYPE_R4 = 4,
+ DBTYPE_R8 = 5,
+ DBTYPE_CY = 6,
+ DBTYPE_DATE = 7,
+ DBTYPE_BSTR = 8,
+ DBTYPE_IDISPATCH = 9,
+ DBTYPE_ERROR = 10,
+ DBTYPE_BOOL = 11,
+ DBTYPE_VARIANT = 12,
+ DBTYPE_IUNKNOWN = 13,
+ DBTYPE_DECIMAL = 14,
+ DBTYPE_UI1 = 17,
+ DBTYPE_ARRAY = 0x2000,
+ DBTYPE_BYREF = 0x4000,
+ DBTYPE_I1 = 16,
+ DBTYPE_UI2 = 18,
+ DBTYPE_UI4 = 19,
+ DBTYPE_I8 = 20,
+ DBTYPE_UI8 = 21,
+ DBTYPE_GUID = 72,
+ DBTYPE_VECTOR = 0x1000,
+ DBTYPE_RESERVED = 0x8000,
+ DBTYPE_BYTES = 128,
+ DBTYPE_STR = 129,
+ DBTYPE_WSTR = 130,
+ DBTYPE_NUMERIC = 131,
+ DBTYPE_UDT = 132,
+ DBTYPE_DBDATE = 133,
+ DBTYPE_DBTIME = 134,
+ DBTYPE_DBTIMESTAMP = 135
+
+ ADO Types
+
+ adEmpty = 0,
+ adTinyInt = 16,
+ adSmallInt = 2,
+ adInteger = 3,
+ adBigInt = 20,
+ adUnsignedTinyInt = 17,
+ adUnsignedSmallInt = 18,
+ adUnsignedInt = 19,
+ adUnsignedBigInt = 21,
+ adSingle = 4,
+ adDouble = 5,
+ adCurrency = 6,
+ adDecimal = 14,
+ adNumeric = 131,
+ adBoolean = 11,
+ adError = 10,
+ adUserDefined = 132,
+ adVariant = 12,
+ adIDispatch = 9,
+ adIUnknown = 13,
+ adGUID = 72,
+ adDate = 7,
+ adDBDate = 133,
+ adDBTime = 134,
+ adDBTimeStamp = 135,
+ adBSTR = 8,
+ adChar = 129,
+ adVarChar = 200,
+ adLongVarChar = 201,
+ adWChar = 130,
+ adVarWChar = 202,
+ adLongVarWChar = 203,
+ adBinary = 128,
+ adVarBinary = 204,
+ adLongVarBinary = 205,
+ adChapter = 136,
+ adFileTime = 64,
+ adDBFileTime = 137,
+ adPropVariant = 138,
+ adVarNumeric = 139
+*/
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+
+ if (!is_numeric($t)) return $t;
+
+ switch ($t) {
+ case 0:
+ case 12: /* variant */
+ case 8: /* bstr */
+ case 129: /* char */
+ case 130: /* wc */
+ case 200: /* varc */
+ case 202:/* varWC */
+ case 128: /* bin */
+ case 204: /* varBin */
+ case 72: /* guid */
+ if ($len <= $this->blobSize) return 'C';
+
+ case 201:
+ case 203:
+ return 'X';
+ case 128:
+ case 204:
+ case 205:
+ return 'B';
+ case 7:
+ case 133: return 'D';
+
+ case 134:
+ case 135: return 'T';
+
+ case 11: return 'L';
+
+ case 16:/* adTinyInt = 16, */
+ case 2:/* adSmallInt = 2, */
+ case 3:/* adInteger = 3, */
+ case 4:/* adBigInt = 20, */
+ case 17:/* adUnsignedTinyInt = 17, */
+ case 18:/* adUnsignedSmallInt = 18, */
+ case 19:/* adUnsignedInt = 19, */
+ case 20:/* adUnsignedBigInt = 21, */
+ return 'I';
+ default: return 'N';
+ }
+ }
+
+ /* time stamp not supported yet */
+ function _fetch()
+ {
+ $rs = $this->_queryID;
+ if (!$rs or $rs->EOF) {
+ $this->fields = false;
+ return false;
+ }
+ $this->fields = array();
+
+ if (!$this->_tarr) {
+ $tarr = array();
+ $flds = array();
+ for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
+ $f = $rs->Fields($i);
+ $flds[] = $f;
+ $tarr[] = $f->Type;
+ }
+ /* bind types and flds only once */
+ $this->_tarr = $tarr;
+ $this->_flds = $flds;
+ }
+ $t = reset($this->_tarr);
+ $f = reset($this->_flds);
+
+ if ($this->hideErrors) $olde = error_reporting(E_ERROR|E_CORE_ERROR);/* sometimes $f->value be null */
+ for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
+
+ switch($t) {
+ case 135: /* timestamp */
+ $this->fields[] = date('Y-m-d H:i:s',(integer)$f->value);
+ break;
+
+ case 133:/* A date value (yyyymmdd) */
+ $val = $f->value;
+ $this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2);
+ break;
+ case 7: /* adDate */
+ $this->fields[] = date('Y-m-d',(integer)$f->value);
+ break;
+ case 1: /* null */
+ $this->fields[] = false;
+ break;
+ case 6: /* currency is not supported properly; */
+ ADOConnection::outp( ''.$f->Name.': currency type not supported by PHP');
+ $this->fields[] = (float) $f->value;
+ break;
+ default:
+ $this->fields[] = $f->value;
+ break;
+ }
+ /* print " $f->value $t, "; */
+ $f = next($this->_flds);
+ $t = next($this->_tarr);
+ } /* for */
+ if ($this->hideErrors) error_reporting($olde);
+ @$rs->MoveNext(); /* @ needed for some versions of PHP! */
+
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);
+ }
+ return true;
+ }
+
+
+ function _close() {
+ $this->_flds = false;
+ @$this->_queryID->Close();/* by Pete Dishman (peterd@telephonetics.co.uk) */
+ $this->_queryID = false;
+ }
+
+}
+
?>
\ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-ado_access.inc.php b/lib/adodb/drivers/adodb-ado_access.inc.php
index c3748e5e999..53bb5c295ae 100644
--- a/lib/adodb/drivers/adodb-ado_access.inc.php
+++ b/lib/adodb/drivers/adodb-ado_access.inc.php
@@ -1,46 +1,46 @@
-ADODB_ado();
- }
-
- function BeginTrans() { return false;}
-
-}
-
-
-class ADORecordSet_ado_access extends ADORecordSet_ado {
-
- var $databaseType = "ado_access";
-
- function ADORecordSet_ado_access($id,$mode=false)
- {
- return $this->ADORecordSet_ado($id,$mode);
- }
-}
+ADODB_ado();
+ }
+
+ function BeginTrans() { return false;}
+
+}
+
+
+class ADORecordSet_ado_access extends ADORecordSet_ado {
+
+ var $databaseType = "ado_access";
+
+ function ADORecordSet_ado_access($id,$mode=false)
+ {
+ return $this->ADORecordSet_ado($id,$mode);
+ }
+}
?>
\ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-ado_mssql.inc.php b/lib/adodb/drivers/adodb-ado_mssql.inc.php
index bf295892ee5..ae6fa20d3e7 100644
--- a/lib/adodb/drivers/adodb-ado_mssql.inc.php
+++ b/lib/adodb/drivers/adodb-ado_mssql.inc.php
@@ -1,59 +1,59 @@
-ADODB_ado();
- }
-
- function _insertid()
- {
- return $this->GetOne('select @@identity');
- }
-
- function _affectedrows()
- {
- return $this->GetOne('select @@rowcount');
- }
-
-}
-
-class ADORecordSet_ado_mssql extends ADORecordSet_ado {
-
- var $databaseType = 'ado_mssql';
-
- function ADORecordSet_ado_mssql($id,$mode=false)
- {
- return $this->ADORecordSet_ado($id,$mode);
- }
-}
+ADODB_ado();
+ }
+
+ function _insertid()
+ {
+ return $this->GetOne('select @@identity');
+ }
+
+ function _affectedrows()
+ {
+ return $this->GetOne('select @@rowcount');
+ }
+
+}
+
+class ADORecordSet_ado_mssql extends ADORecordSet_ado {
+
+ var $databaseType = 'ado_mssql';
+
+ function ADORecordSet_ado_mssql($id,$mode=false)
+ {
+ return $this->ADORecordSet_ado($id,$mode);
+ }
+}
?>
\ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-borland_ibase.inc.php b/lib/adodb/drivers/adodb-borland_ibase.inc.php
index 05a49158736..da95a55af65 100644
--- a/lib/adodb/drivers/adodb-borland_ibase.inc.php
+++ b/lib/adodb/drivers/adodb-borland_ibase.inc.php
@@ -1,79 +1,79 @@
-ADODB_ibase();
- }
-
- function ServerInfo()
- {
- $arr['dialect'] = $this->dialect;
- switch($arr['dialect']) {
- case '':
- case '1': $s = 'Interbase 6.5, Dialect 1'; break;
- case '2': $s = 'Interbase 6.5, Dialect 2'; break;
- default:
- case '3': $s = 'Interbase 6.5, Dialect 3'; break;
- }
- $arr['version'] = '6.5';
- $arr['description'] = $s;
- return $arr;
- }
-
- // Note that Interbase 6.5 uses ROWS instead - don't you love forking wars!
- // SELECT col1, col2 FROM table ROWS 5 -- get 5 rows
- // SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2
- // Firebird uses
- // SELECT FIRST 5 SKIP 2 col1, col2 FROM TABLE
- function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false,$secs2cache=0)
- {
- if ($nrows > 0) {
- if ($offset <= 0) $str = " ROWS $nrows ";
- else {
- $a = $offset+1;
- $b = $offset+$nrows;
- $str = " ROWS $a TO $b";
- }
- } else {
- // ok, skip
- $a = $offset + 1;
- $str = " ROWS $a TO 999999999"; // 999 million
- }
- $sql .= $str;
-
- return ($secs2cache) ?
- $this->CacheExecute($secs2cache,$sql,$inputarr,$arg3)
- :
- $this->Execute($sql,$inputarr,$arg3);
- }
-
-};
-
-
-class ADORecordSet_borland_ibase extends ADORecordSet_ibase {
-
- var $databaseType = "borland_ibase";
-
- function ADORecordSet_borland_ibase($id,$mode=false)
- {
- $this->ADORecordSet_ibase($id,$mode);
- }
-}
+ADODB_ibase();
+ }
+
+ function ServerInfo()
+ {
+ $arr['dialect'] = $this->dialect;
+ switch($arr['dialect']) {
+ case '':
+ case '1': $s = 'Interbase 6.5, Dialect 1'; break;
+ case '2': $s = 'Interbase 6.5, Dialect 2'; break;
+ default:
+ case '3': $s = 'Interbase 6.5, Dialect 3'; break;
+ }
+ $arr['version'] = '6.5';
+ $arr['description'] = $s;
+ return $arr;
+ }
+
+ /* Note that Interbase 6.5 uses ROWS instead - don't you love forking wars! */
+ /* SELECT col1, col2 FROM table ROWS 5 -- get 5 rows */
+ /* SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2 */
+ /* Firebird uses */
+ /* SELECT FIRST 5 SKIP 2 col1, col2 FROM TABLE */
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false,$secs2cache=0)
+ {
+ if ($nrows > 0) {
+ if ($offset <= 0) $str = " ROWS $nrows ";
+ else {
+ $a = $offset+1;
+ $b = $offset+$nrows;
+ $str = " ROWS $a TO $b";
+ }
+ } else {
+ /* ok, skip */
+ $a = $offset + 1;
+ $str = " ROWS $a TO 999999999"; /* 999 million */
+ }
+ $sql .= $str;
+
+ return ($secs2cache) ?
+ $this->CacheExecute($secs2cache,$sql,$inputarr,$arg3)
+ :
+ $this->Execute($sql,$inputarr,$arg3);
+ }
+
+};
+
+
+class ADORecordSet_borland_ibase extends ADORecordSet_ibase {
+
+ var $databaseType = "borland_ibase";
+
+ function ADORecordSet_borland_ibase($id,$mode=false)
+ {
+ $this->ADORecordSet_ibase($id,$mode);
+ }
+}
?>
\ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-csv.inc.php b/lib/adodb/drivers/adodb-csv.inc.php
index 79240845270..921be0db5c8 100644
--- a/lib/adodb/drivers/adodb-csv.inc.php
+++ b/lib/adodb/drivers/adodb-csv.inc.php
@@ -1,202 +1,202 @@
-_insertid;
- }
-
- function _affectedrows()
- {
- return $this->_affectedrows;
- }
-
- function &MetaDatabases()
- {
- return false;
- }
-
-
- // returns true or false
- function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
- {
- if (strtolower(substr($argHostname,0,7)) !== 'http://') return false;
- $this->_url = $argHostname;
- return true;
- }
-
- // returns true or false
- function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
- {
- if (strtolower(substr($argHostname,0,7)) !== 'http://') return false;
- $this->_url = $argHostname;
- return true;
- }
-
- function &MetaColumns($table)
- {
- return false;
- }
-
-
- // parameters use PostgreSQL convention, not MySQL
- function &SelectLimit($sql,$nrows=-1,$offset=-1,$arg3=false)
- {
- global $ADODB_FETCH_MODE;
-
- $url = $this->_url.'?sql='.urlencode($sql)."&nrows=$nrows&fetch=".
- (($this->fetchMode !== false)?$this->fetchMode : $ADODB_FETCH_MODE).
- "&offset=$offset&arg3=".urlencode($arg3);
- $err = false;
- $rs = csv2rs($url,$err,false);
-
- if ($this->debug) print "$url
$err
";
-
- $at = strpos($err,'::::');
- if ($at === false) {
- $this->_errorMsg = $err;
- $this->_errorNo = (integer)$err;
- } else {
- $this->_errorMsg = substr($err,$at+4,1024);
- $this->_errorNo = -9999;
- }
- if ($this->_errorNo)
- if ($fn = $this->raiseErrorFn) {
- $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,'');
- }
-
- if (is_object($rs)) {
-
- $rs->databaseType='csv';
- $rs->fetchMode = ($this->fetchMode !== false) ? $this->fetchMode : $ADODB_FETCH_MODE;
- $rs->connection = &$this;
- }
- return $rs;
- }
-
- // returns queryID or false
- function &Execute($sql,$inputarr=false,$arg3=false)
- {
- global $ADODB_FETCH_MODE;
-
- if (!$this->_bindInputArray && $inputarr) {
- $sqlarr = explode('?',$sql);
- $sql = '';
- $i = 0;
- foreach($inputarr as $v) {
-
- $sql .= $sqlarr[$i];
- // from Ron Baldwin
$err
";
- $at = strpos($err,'::::');
- if ($at === false) {
- $this->_errorMsg = $err;
- $this->_errorNo = (integer)$err;
- } else {
- $this->_errorMsg = substr($err,$at+4,1024);
- $this->_errorNo = -9999;
- }
-
- if ($this->_errorNo)
- if ($fn = $this->raiseErrorFn) {
- $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr);
- }
- if (is_object($rs)) {
- $rs->fetchMode = ($this->fetchMode !== false) ? $this->fetchMode : $ADODB_FETCH_MODE;
-
- $this->_affectedrows = $rs->affectedrows;
- $this->_insertid = $rs->insertid;
- $rs->databaseType='csv';
- $rs->connection = &$this;
- }
- return $rs;
- }
-
- /* Returns: the last error message from previous database operation */
- function ErrorMsg()
- {
- return $this->_errorMsg;
- }
-
- /* Returns: the last error number from previous database operation */
- function ErrorNo()
- {
- return $this->_errorNo;
- }
-
- // returns true or false
- function _close()
- {
- return true;
- }
-} // class
-
-class ADORecordset_csv extends ADORecordset {
- function ADORecordset_csv($id,$mode=false)
- {
- $this->ADORecordset($id,$mode);
- }
-
- function _close()
- {
- return true;
- }
-}
-
-} // define
-
+_insertid;
+ }
+
+ function _affectedrows()
+ {
+ return $this->_affectedrows;
+ }
+
+ function &MetaDatabases()
+ {
+ return false;
+ }
+
+
+ /* returns true or false */
+ function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (strtolower(substr($argHostname,0,7)) !== 'http:/* ') return false; */
+ $this->_url = $argHostname;
+ return true;
+ }
+
+ /* returns true or false */
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (strtolower(substr($argHostname,0,7)) !== 'http:/* ') return false; */
+ $this->_url = $argHostname;
+ return true;
+ }
+
+ function &MetaColumns($table)
+ {
+ return false;
+ }
+
+
+ /* parameters use PostgreSQL convention, not MySQL */
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$arg3=false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $url = $this->_url.'?sql='.urlencode($sql)."&nrows=$nrows&fetch=".
+ (($this->fetchMode !== false)?$this->fetchMode : $ADODB_FETCH_MODE).
+ "&offset=$offset&arg3=".urlencode($arg3);
+ $err = false;
+ $rs = csv2rs($url,$err,false);
+
+ if ($this->debug) print "$url
$err
";
+
+ $at = strpos($err,'::::');
+ if ($at === false) {
+ $this->_errorMsg = $err;
+ $this->_errorNo = (integer)$err;
+ } else {
+ $this->_errorMsg = substr($err,$at+4,1024);
+ $this->_errorNo = -9999;
+ }
+ if ($this->_errorNo)
+ if ($fn = $this->raiseErrorFn) {
+ $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,'');
+ }
+
+ if (is_object($rs)) {
+
+ $rs->databaseType='csv';
+ $rs->fetchMode = ($this->fetchMode !== false) ? $this->fetchMode : $ADODB_FETCH_MODE;
+ $rs->connection = &$this;
+ }
+ return $rs;
+ }
+
+ /* returns queryID or false */
+ function &Execute($sql,$inputarr=false,$arg3=false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ if (!$this->_bindInputArray && $inputarr) {
+ $sqlarr = explode('?',$sql);
+ $sql = '';
+ $i = 0;
+ foreach($inputarr as $v) {
+
+ $sql .= $sqlarr[$i];
+ /* from Ron Baldwin
$err
";
+ $at = strpos($err,'::::');
+ if ($at === false) {
+ $this->_errorMsg = $err;
+ $this->_errorNo = (integer)$err;
+ } else {
+ $this->_errorMsg = substr($err,$at+4,1024);
+ $this->_errorNo = -9999;
+ }
+
+ if ($this->_errorNo)
+ if ($fn = $this->raiseErrorFn) {
+ $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr);
+ }
+ if (is_object($rs)) {
+ $rs->fetchMode = ($this->fetchMode !== false) ? $this->fetchMode : $ADODB_FETCH_MODE;
+
+ $this->_affectedrows = $rs->affectedrows;
+ $this->_insertid = $rs->insertid;
+ $rs->databaseType='csv';
+ $rs->connection = &$this;
+ }
+ return $rs;
+ }
+
+ /* Returns: the last error message from previous database operation */
+ function ErrorMsg()
+ {
+ return $this->_errorMsg;
+ }
+
+ /* Returns: the last error number from previous database operation */
+ function ErrorNo()
+ {
+ return $this->_errorNo;
+ }
+
+ /* returns true or false */
+ function _close()
+ {
+ return true;
+ }
+} /* class */
+
+class ADORecordset_csv extends ADORecordset {
+ function ADORecordset_csv($id,$mode=false)
+ {
+ $this->ADORecordset($id,$mode);
+ }
+
+ function _close()
+ {
+ return true;
+ }
+}
+
+} /* define */
+
?>
\ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-db2.inc.php b/lib/adodb/drivers/adodb-db2.inc.php
index 2ba16955afa..4d000f2fe95 100644
--- a/lib/adodb/drivers/adodb-db2.inc.php
+++ b/lib/adodb/drivers/adodb-db2.inc.php
@@ -1,196 +1,265 @@
-curMode = SQL_CUR_USE_ODBC;
-$db->Connect($dsn, $userid, $pwd);
-
-*/
-
-if (!defined('_ADODB_ODBC_LAYER')) {
- include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
-}
-if (!defined('ADODB_DB2')){
-define('ADODB_DB2',1);
-
-class ADODB_DB2 extends ADODB_odbc {
- var $databaseType = "db2";
- var $concat_operator = 'CONCAT';
- var $sysDate = 'CURRENT DATE';
- var $sysTimeStamp = 'CURRENT TIMESTAMP';
- var $ansiOuter = true;
- //var $curmode = SQL_CUR_USE_ODBC;
-
- function ADODB_DB2()
- {
- $this->ADODB_odbc();
- }
-
- function RowLock($tables,$where)
- {
- if ($this->_autocommit) $this->BeginTrans();
- return $this->GetOne("select 1 as ignore from $tables where $where for update");
- }
-
- // Format date column in sql string given an input format that understands Y M D
- function SQLDate($fmt, $col=false)
- {
- // use right() and replace() ?
- if (!$col) $col = $this->sysDate;
- $s = '';
-
- $len = strlen($fmt);
- for ($i=0; $i < $len; $i++) {
- if ($s) $s .= '+';
- $ch = $fmt[$i];
- switch($ch) {
- case 'Y':
- case 'y':
- $s .= "char(year($col))";
- break;
- case 'M':
- case 'm':
- $s .= "right(digits(month($col)),2)";
- break;
- case 'D':
- case 'd':
- $s .= "right(digits(day($col)),2)";
- break;
- default:
- $s .= $this->qstr($ch);
- }
- }
- return $s;
- }
-
-
- function &SelectLimit($sql,$nrows=-1,$offset=-1,$arg3=false)
- {
- if ($offset <= 0) {
- // could also use " OPTIMIZE FOR $nrows ROWS "
- $sql .= " FETCH FIRST $nrows ROWS ONLY ";
- return $this->Execute($sql,false,$arg3);
- } else {
- $nrows += $offset;
- $sql .= " FETCH FIRST $nrows ROWS ONLY ";
- return ADOConnection::SelectLimit($sql,-1,$offset,$arg3);
- }
- }
-
-};
-
-
-class ADORecordSet_db2 extends ADORecordSet_odbc {
-
- var $databaseType = "db2";
-
- function ADORecordSet_db2($id,$mode=false)
- {
- $this->ADORecordSet_odbc($id,$mode);
- }
-
- function MetaType($t,$len=-1,$fieldobj=false)
- {
- switch (strtoupper($t)) {
- case 'VARCHAR':
- case 'CHAR':
- case 'CHARACTER':
- if ($len <= $this->blobSize) return 'C';
-
- case 'LONGCHAR':
- case 'TEXT':
- case 'CLOB':
- case 'DBCLOB': // double-byte
- return 'X';
-
- case 'BLOB':
- case 'GRAPHIC':
- case 'VARGRAPHIC':
- return 'B';
-
- case 'DATE':
- return 'D';
-
- case 'TIME':
- case 'TIMESTAMP':
- return 'T';
-
- //case 'BOOLEAN':
- //case 'BIT':
- // return 'L';
-
- //case 'COUNTER':
- // return 'R';
-
- case 'INT':
- case 'INTEGER':
- case 'BIGINT':
- case 'SMALLINT':
- return 'I';
-
- default: return 'N';
- }
- }
-}
-
-} //define
+curMode = SQL_CUR_USE_ODBC;
+$db->Connect($dsn, $userid, $pwd);
+
+*/
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+ include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+if (!defined('ADODB_DB2')){
+define('ADODB_DB2',1);
+
+class ADODB_DB2 extends ADODB_odbc {
+ var $databaseType = "db2";
+ var $concat_operator = '||';
+ var $sysDate = 'CURRENT_DATE';
+ var $sysTimeStamp = 'CURRENT TIMESTAMP';
+ var $ansiOuter = true;
+ var $identitySQL = 'values IDENTITY_VAL_LOCAL()';
+
+ function ADODB_DB2()
+ {
+ if (strpos(PHP_OS,'WIN') !== false) $this->curmode = SQL_CUR_USE_ODBC;
+ $this->ADODB_odbc();
+ }
+
+ function ServerInfo()
+ {
+ /* odbc_setoption($this->_connectionID,1,101 /*SQL_ATTR_ACCESS_MODE*/, 1 /*SQL_MODE_READ_ONLY*/); */
+ $vers = $this->GetOne('select versionnumber from sysibm.sysversions');
+ /* odbc_setoption($this->_connectionID,1,101, 0 /*SQL_MODE_READ_WRITE*/); */
+ return array('description'=>'DB2 ODBC driver', 'version'=>$vers);
+ }
+
+ function _insertid()
+ {
+ return $this->GetOne($this->identitySQL);
+ }
+
+ function RowLock($tables,$where)
+ {
+ if ($this->_autocommit) $this->BeginTrans();
+ return $this->GetOne("select 1 as ignore from $tables where $where for update");
+ }
+
+ function &MetaTables($showSchema=false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $qid = odbc_tables($this->_connectionID);
+
+ $rs = new ADORecordSet_odbc($qid);
+
+ $ADODB_FETCH_MODE = $savem;
+ if (!$rs) return false;
+
+ $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+
+ /* print_r($rs); */
+ $arr =& $rs->GetArray();
+ $rs->Close();
+ $arr2 = array();
+ /* print_r($arr); */
+ for ($i=0; $i < sizeof($arr); $i++) {
+ $row = $arr[$i];
+ if ($row[2] && strncmp($row[1],'SYS',3) != 0)
+ if ($showSchema) $arr2[] = $row[1].'.'.$row[2];
+ else $arr2[] = $row[2];
+ }
+ return $arr2;
+ }
+
+ /* Format date column in sql string given an input format that understands Y M D */
+ function SQLDate($fmt, $col=false)
+ {
+ /* use right() and replace() ? */
+ if (!$col) $col = $this->sysDate;
+ $s = '';
+
+ $len = strlen($fmt);
+ for ($i=0; $i < $len; $i++) {
+ if ($s) $s .= '||';
+ $ch = $fmt[$i];
+ switch($ch) {
+ case 'Y':
+ case 'y':
+ $s .= "char(year($col))";
+ break;
+ case 'M':
+ $s .= "substr(monthname($col),1,3)";
+ break;
+ case 'm':
+ $s .= "right(digits(month($col)),2)";
+ break;
+ case 'D':
+ case 'd':
+ $s .= "right(digits(day($col)),2)";
+ break;
+ case 'H':
+ case 'h':
+ if ($col != $this->sysDate) $s .= "right(digits(hour($col)),2)";
+ else $s .= "''";
+ break;
+ case 'i':
+ case 'I':
+ if ($col != $this->sysDate)
+ $s .= "right(digits(minute($col)),2)";
+ else $s .= "''";
+ break;
+ case 'S':
+ case 's':
+ if ($col != $this->sysDate)
+ $s .= "right(digits(second($col)),2)";
+ else $s .= "''";
+ break;
+ default:
+ if ($ch == '\\') {
+ $i++;
+ $ch = substr($fmt,$i,1);
+ }
+ $s .= $this->qstr($ch);
+ }
+ }
+ return $s;
+ }
+
+
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$arg3=false)
+ {
+ if ($offset <= 0) {
+ /* could also use " OPTIMIZE FOR $nrows ROWS " */
+ if ($nrows >= 0) $sql .= " FETCH FIRST $nrows ROWS ONLY ";
+ return $this->Execute($sql,false,$arg3);
+ } else {
+ if ($offset > 0 && $nrows < 0);
+ else {
+ $nrows += $offset;
+ $sql .= " FETCH FIRST $nrows ROWS ONLY ";
+ }
+ return ADOConnection::SelectLimit($sql,-1,$offset,$arg3);
+ }
+ }
+
+};
+
+
+class ADORecordSet_db2 extends ADORecordSet_odbc {
+
+ var $databaseType = "db2";
+
+ function ADORecordSet_db2($id,$mode=false)
+ {
+ $this->ADORecordSet_odbc($id,$mode);
+ }
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ switch (strtoupper($t)) {
+ case 'VARCHAR':
+ case 'CHAR':
+ case 'CHARACTER':
+ if ($len <= $this->blobSize) return 'C';
+
+ case 'LONGCHAR':
+ case 'TEXT':
+ case 'CLOB':
+ case 'DBCLOB': /* double-byte */
+ return 'X';
+
+ case 'BLOB':
+ case 'GRAPHIC':
+ case 'VARGRAPHIC':
+ return 'B';
+
+ case 'DATE':
+ return 'D';
+
+ case 'TIME':
+ case 'TIMESTAMP':
+ return 'T';
+
+ /* case 'BOOLEAN': */
+ /* case 'BIT': */
+ /* return 'L'; */
+
+ /* case 'COUNTER': */
+ /* return 'R'; */
+
+ case 'INT':
+ case 'INTEGER':
+ case 'BIGINT':
+ case 'SMALLINT':
+ return 'I';
+
+ default: return 'N';
+ }
+ }
+}
+
+} /* define */
?>
\ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-fbsql.inc.php b/lib/adodb/drivers/adodb-fbsql.inc.php
index 9affce5671c..b4a30b469ec 100644
--- a/lib/adodb/drivers/adodb-fbsql.inc.php
+++ b/lib/adodb/drivers/adodb-fbsql.inc.php
@@ -1,262 +1,262 @@
-.
- Set tabs to 8.
-*/
-
-if (! defined("_ADODB_FBSQL_LAYER")) {
- define("_ADODB_FBSQL_LAYER", 1 );
-
-class ADODB_fbsql extends ADOConnection {
- var $databaseType = 'fbsql';
- var $hasInsertID = true;
- var $hasAffectedRows = true;
- var $metaTablesSQL = "SHOW TABLES";
- var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
- var $fmtTimeStamp = "'Y-m-d H:i:s'";
- var $hasLimit = false;
-
- function ADODB_fbsql()
- {
- }
-
- function _insertid()
- {
- return fbsql_insert_id($this->_connectionID);
- }
-
- function _affectedrows()
- {
- return fbsql_affected_rows($this->_connectionID);
- }
-
- function &MetaDatabases()
- {
- $qid = fbsql_list_dbs($this->_connectionID);
- $arr = array();
- $i = 0;
- $max = fbsql_num_rows($qid);
- while ($i < $max) {
- $arr[] = fbsql_tablename($qid,$i);
- $i += 1;
- }
- return $arr;
- }
-
- // returns concatenated string
- function Concat()
- {
- $s = "";
- $arr = func_get_args();
- $first = true;
-
- $s = implode(',',$arr);
- if (sizeof($arr) > 0) return "CONCAT($s)";
- else return '';
- }
-
- // returns true or false
- function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
- {
- $this->_connectionID = fbsql_connect($argHostname,$argUsername,$argPassword);
- if ($this->_connectionID === false) return false;
- if ($argDatabasename) return $this->SelectDB($argDatabasename);
- return true;
- }
-
- // returns true or false
- function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
- {
- $this->_connectionID = fbsql_pconnect($argHostname,$argUsername,$argPassword);
- if ($this->_connectionID === false) return false;
- if ($argDatabasename) return $this->SelectDB($argDatabasename);
- return true;
- }
-
- function &MetaColumns($table)
- {
- if ($this->metaColumnsSQL) {
-
- $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
-
- if ($rs === false) return false;
-
- $retarr = array();
- while (!$rs->EOF){
- $fld = new ADOFieldObject();
- $fld->name = $rs->fields[0];
- $fld->type = $rs->fields[1];
-
- // split type into type(length):
- if (preg_match("/^(.+)\((\d+)\)$/", $fld->type, $query_array)) {
- $fld->type = $query_array[1];
- $fld->max_length = $query_array[2];
- } else {
- $fld->max_length = -1;
- }
- $fld->not_null = ($rs->fields[2] != 'YES');
- $fld->primary_key = ($rs->fields[3] == 'PRI');
- $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
- $fld->binary = (strpos($fld->type,'blob') !== false);
-
- $retarr[strtoupper($fld->name)] = $fld;
- $rs->MoveNext();
- }
- $rs->Close();
- return $retarr;
- }
- return false;
- }
-
- // returns true or false
- function SelectDB($dbName)
- {
- $this->databaseName = $dbName;
- if ($this->_connectionID) {
- return @fbsql_select_db($dbName,$this->_connectionID);
- }
- else return false;
- }
-
-
- // returns queryID or false
- function _query($sql,$inputarr)
- {
- return fbsql_query("$sql;",$this->_connectionID);
- }
-
- /* Returns: the last error message from previous database operation */
- function ErrorMsg()
- {
- $this->_errorMsg = @fbsql_error($this->_connectionID);
- return $this->_errorMsg;
- }
-
- /* Returns: the last error number from previous database operation */
- function ErrorNo()
- {
- return @fbsql_errno($this->_connectionID);
- }
-
- // returns true or false
- function _close()
- {
- return @fbsql_close($this->_connectionID);
- }
-
-}
-
-/*--------------------------------------------------------------------------------------
- Class Name: Recordset
---------------------------------------------------------------------------------------*/
-
-class ADORecordSet_fbsql extends ADORecordSet{
-
- var $databaseType = "fbsql";
- var $canSeek = true;
-
- function ADORecordSet_fbsql($queryID,$mode=false)
- {
- if (!$mode) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- switch ($mode) {
- case ADODB_FETCH_NUM: $this->fetchMode = FBSQL_NUM; break;
- default:
- case ADODB_FETCH_BOTH: $this->fetchMode = FBSQL_BOTH; break;
- case ADODB_FETCH_ASSOC: $this->fetchMode = FBSQL_ASSOC; break;
- }
- return $this->ADORecordSet($queryID);
- }
-
- function _initrs()
- {
- GLOBAL $ADODB_COUNTRECS;
- $this->_numOfRows = ($ADODB_COUNTRECS) ? @fbsql_num_rows($this->_queryID):-1;
- $this->_numOfFields = @fbsql_num_fields($this->_queryID);
- }
-
-
-
- function &FetchField($fieldOffset = -1) {
- if ($fieldOffset != -1) {
- $o = @fbsql_fetch_field($this->_queryID, $fieldOffset);
- //$o->max_length = -1; // fbsql returns the max length less spaces -- so it is unrealiable
- $f = @fbsql_field_flags($this->_queryID,$fieldOffset);
- $o->binary = (strpos($f,'binary')!== false);
- }
- else if ($fieldOffset == -1) { /* The $fieldOffset argument is not provided thus its -1 */
- $o = @fbsql_fetch_field($this->_queryID);// fbsql returns the max length less spaces -- so it is unrealiable
- //$o->max_length = -1;
- }
-
- return $o;
- }
-
- function _seek($row)
- {
- return @fbsql_data_seek($this->_queryID,$row);
- }
-
- function _fetch($ignore_fields=false)
- {
- $this->fields = @fbsql_fetch_array($this->_queryID,$this->fetchMode);
- return ($this->fields == true);
- }
-
- function _close() {
- return @fbsql_free_result($this->_queryID);
- }
-
- function MetaType($t,$len=-1,$fieldobj=false)
- {
- if (is_object($t)) {
- $fieldobj = $t;
- $t = $fieldobj->type;
- $len = $fieldobj->max_length;
- }
- $len = -1; // fbsql max_length is not accurate
- switch (strtoupper($t)) {
- case 'CHARACTER':
- case 'CHARACTER VARYING':
- case 'BLOB':
- case 'CLOB':
- case 'BIT':
- case 'BIT VARYING':
- if ($len <= $this->blobSize) return 'C';
-
- // so we have to check whether binary...
- case 'IMAGE':
- case 'LONGBLOB':
- case 'BLOB':
- case 'MEDIUMBLOB':
- return !empty($fieldobj->binary) ? 'B' : 'X';
-
- case 'DATE': return 'D';
-
- case 'TIME':
- case 'TIME WITH TIME ZONE':
- case 'TIMESTAMP':
- case 'TIMESTAMP WITH TIME ZONE': return 'T';
-
- case 'PRIMARY_KEY':
- return 'R';
- case 'INTEGER':
- case 'SMALLINT':
- case 'BOOLEAN':
-
- if (!empty($fieldobj->primary_key)) return 'R';
- else return 'I';
-
- default: return 'N';
- }
- }
-
-} //class
-} // defined
+.
+ Set tabs to 8.
+*/
+
+if (! defined("_ADODB_FBSQL_LAYER")) {
+ define("_ADODB_FBSQL_LAYER", 1 );
+
+class ADODB_fbsql extends ADOConnection {
+ var $databaseType = 'fbsql';
+ var $hasInsertID = true;
+ var $hasAffectedRows = true;
+ var $metaTablesSQL = "SHOW TABLES";
+ var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
+ var $hasLimit = false;
+
+ function ADODB_fbsql()
+ {
+ }
+
+ function _insertid()
+ {
+ return fbsql_insert_id($this->_connectionID);
+ }
+
+ function _affectedrows()
+ {
+ return fbsql_affected_rows($this->_connectionID);
+ }
+
+ function &MetaDatabases()
+ {
+ $qid = fbsql_list_dbs($this->_connectionID);
+ $arr = array();
+ $i = 0;
+ $max = fbsql_num_rows($qid);
+ while ($i < $max) {
+ $arr[] = fbsql_tablename($qid,$i);
+ $i += 1;
+ }
+ return $arr;
+ }
+
+ /* returns concatenated string */
+ function Concat()
+ {
+ $s = "";
+ $arr = func_get_args();
+ $first = true;
+
+ $s = implode(',',$arr);
+ if (sizeof($arr) > 0) return "CONCAT($s)";
+ else return '';
+ }
+
+ /* returns true or false */
+ function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ $this->_connectionID = fbsql_connect($argHostname,$argUsername,$argPassword);
+ if ($this->_connectionID === false) return false;
+ if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ }
+
+ /* returns true or false */
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ $this->_connectionID = fbsql_pconnect($argHostname,$argUsername,$argPassword);
+ if ($this->_connectionID === false) return false;
+ if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ }
+
+ function &MetaColumns($table)
+ {
+ if ($this->metaColumnsSQL) {
+
+ $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
+
+ if ($rs === false) return false;
+
+ $retarr = array();
+ while (!$rs->EOF){
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+ $fld->type = $rs->fields[1];
+
+ /* split type into type(length): */
+ if (preg_match("/^(.+)\((\d+)\)$/", $fld->type, $query_array)) {
+ $fld->type = $query_array[1];
+ $fld->max_length = $query_array[2];
+ } else {
+ $fld->max_length = -1;
+ }
+ $fld->not_null = ($rs->fields[2] != 'YES');
+ $fld->primary_key = ($rs->fields[3] == 'PRI');
+ $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
+ $fld->binary = (strpos($fld->type,'blob') !== false);
+
+ $retarr[strtoupper($fld->name)] = $fld;
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ return $retarr;
+ }
+ return false;
+ }
+
+ /* returns true or false */
+ function SelectDB($dbName)
+ {
+ $this->databaseName = $dbName;
+ if ($this->_connectionID) {
+ return @fbsql_select_db($dbName,$this->_connectionID);
+ }
+ else return false;
+ }
+
+
+ /* returns queryID or false */
+ function _query($sql,$inputarr)
+ {
+ return fbsql_query("$sql;",$this->_connectionID);
+ }
+
+ /* Returns: the last error message from previous database operation */
+ function ErrorMsg()
+ {
+ $this->_errorMsg = @fbsql_error($this->_connectionID);
+ return $this->_errorMsg;
+ }
+
+ /* Returns: the last error number from previous database operation */
+ function ErrorNo()
+ {
+ return @fbsql_errno($this->_connectionID);
+ }
+
+ /* returns true or false */
+ function _close()
+ {
+ return @fbsql_close($this->_connectionID);
+ }
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_fbsql extends ADORecordSet{
+
+ var $databaseType = "fbsql";
+ var $canSeek = true;
+
+ function ADORecordSet_fbsql($queryID,$mode=false)
+ {
+ if (!$mode) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ switch ($mode) {
+ case ADODB_FETCH_NUM: $this->fetchMode = FBSQL_NUM; break;
+ default:
+ case ADODB_FETCH_BOTH: $this->fetchMode = FBSQL_BOTH; break;
+ case ADODB_FETCH_ASSOC: $this->fetchMode = FBSQL_ASSOC; break;
+ }
+ return $this->ADORecordSet($queryID);
+ }
+
+ function _initrs()
+ {
+ GLOBAL $ADODB_COUNTRECS;
+ $this->_numOfRows = ($ADODB_COUNTRECS) ? @fbsql_num_rows($this->_queryID):-1;
+ $this->_numOfFields = @fbsql_num_fields($this->_queryID);
+ }
+
+
+
+ function &FetchField($fieldOffset = -1) {
+ if ($fieldOffset != -1) {
+ $o = @fbsql_fetch_field($this->_queryID, $fieldOffset);
+ /* $o->max_length = -1; // fbsql returns the max length less spaces -- so it is unrealiable */
+ $f = @fbsql_field_flags($this->_queryID,$fieldOffset);
+ $o->binary = (strpos($f,'binary')!== false);
+ }
+ else if ($fieldOffset == -1) { /* The $fieldOffset argument is not provided thus its -1 */
+ $o = @fbsql_fetch_field($this->_queryID);/* fbsql returns the max length less spaces -- so it is unrealiable */
+ /* $o->max_length = -1; */
+ }
+
+ return $o;
+ }
+
+ function _seek($row)
+ {
+ return @fbsql_data_seek($this->_queryID,$row);
+ }
+
+ function _fetch($ignore_fields=false)
+ {
+ $this->fields = @fbsql_fetch_array($this->_queryID,$this->fetchMode);
+ return ($this->fields == true);
+ }
+
+ function _close() {
+ return @fbsql_free_result($this->_queryID);
+ }
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+ $len = -1; /* fbsql max_length is not accurate */
+ switch (strtoupper($t)) {
+ case 'CHARACTER':
+ case 'CHARACTER VARYING':
+ case 'BLOB':
+ case 'CLOB':
+ case 'BIT':
+ case 'BIT VARYING':
+ if ($len <= $this->blobSize) return 'C';
+
+ /* so we have to check whether binary... */
+ case 'IMAGE':
+ case 'LONGBLOB':
+ case 'BLOB':
+ case 'MEDIUMBLOB':
+ return !empty($fieldobj->binary) ? 'B' : 'X';
+
+ case 'DATE': return 'D';
+
+ case 'TIME':
+ case 'TIME WITH TIME ZONE':
+ case 'TIMESTAMP':
+ case 'TIMESTAMP WITH TIME ZONE': return 'T';
+
+ case 'PRIMARY_KEY':
+ return 'R';
+ case 'INTEGER':
+ case 'SMALLINT':
+ case 'BOOLEAN':
+
+ if (!empty($fieldobj->primary_key)) return 'R';
+ else return 'I';
+
+ default: return 'N';
+ }
+ }
+
+} /* class */
+} /* defined */
?>
\ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-firebird.inc.php b/lib/adodb/drivers/adodb-firebird.inc.php
index 5789618601d..01a0924cefd 100644
--- a/lib/adodb/drivers/adodb-firebird.inc.php
+++ b/lib/adodb/drivers/adodb-firebird.inc.php
@@ -1,68 +1,67 @@
-ADODB_ibase();
- }
-
- function ServerInfo()
- {
- $arr['dialect'] = $this->dialect;
- switch($arr['dialect']) {
- case '':
- case '1': $s = 'Firebird Dialect 1'; break;
- case '2': $s = 'Firebird Dialect 2'; break;
- default:
- case '3': $s = 'Firebird Dialect 3'; break;
- }
- $arr['version'] = ADOConnection::_findvers($s);
- $arr['description'] = $s;
- return $arr;
- }
-
- // Note that Interbase 6.5 uses this ROWS instead - don't you love forking wars!
- // SELECT col1, col2 FROM table ROWS 5 -- get 5 rows
- // SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2
- function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false,$secs=0)
- {
- $str = 'SELECT ';
- if ($nrows >= 0) $str .= "FIRST $nrows ";
- $str .=($offset>=0) ? "SKIP $offset " : '';
-
- $sql = preg_replace('/^[ \t]*select/i',$str,$sql);
- return ($secs) ?
- $this->CacheExecute($secs,$sql,$inputarr,$arg3)
- :
- $this->Execute($sql,$inputarr,$arg3);
- }
-
-
-};
-
-
-class ADORecordSet_firebird extends ADORecordSet_ibase {
-
- var $databaseType = "firebird";
-
- function ADORecordSet_firebird($id,$mode=false)
- {
- $this->ADORecordSet_ibase($id,$mode);
- }
-}
+ADODB_ibase();
+ }
+
+ function ServerInfo()
+ {
+ $arr['dialect'] = $this->dialect;
+ switch($arr['dialect']) {
+ case '':
+ case '1': $s = 'Firebird Dialect 1'; break;
+ case '2': $s = 'Firebird Dialect 2'; break;
+ default:
+ case '3': $s = 'Firebird Dialect 3'; break;
+ }
+ $arr['version'] = ADOConnection::_findvers($s);
+ $arr['description'] = $s;
+ return $arr;
+ }
+
+ /* Note that Interbase 6.5 uses this ROWS instead - don't you love forking wars! */
+ /* SELECT col1, col2 FROM table ROWS 5 -- get 5 rows */
+ /* SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2 */
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false,$secs=0)
+ {
+ $str = 'SELECT ';
+ if ($nrows >= 0) $str .= "FIRST $nrows ";
+ $str .=($offset>=0) ? "SKIP $offset " : '';
+
+ $sql = preg_replace('/^[ \t]*select/i',$str,$sql);
+ return ($secs) ?
+ $this->CacheExecute($secs,$sql,$inputarr,$arg3)
+ :
+ $this->Execute($sql,$inputarr,$arg3);
+ }
+
+
+};
+
+
+class ADORecordSet_firebird extends ADORecordSet_ibase {
+
+ var $databaseType = "firebird";
+
+ function ADORecordSet_firebird($id,$mode=false)
+ {
+ $this->ADORecordSet_ibase($id,$mode);
+ }
+}
?>
\ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-ibase.inc.php b/lib/adodb/drivers/adodb-ibase.inc.php
index 5a1870c215c..b20cc5933fe 100644
--- a/lib/adodb/drivers/adodb-ibase.inc.php
+++ b/lib/adodb/drivers/adodb-ibase.inc.php
@@ -1,665 +1,665 @@
-
- changed transaction handling and added experimental blob stuff
-
- Docs to interbase at the website
- http://www.synectics.co.za/php3/tutorial/IB_PHP3_API.html
-
- To use gen_id(), see
- http://www.volny.cz/iprenosil/interbase/ip_ib_code.htm#_code_creategen
-
- $rs = $conn->Execute('select gen_id(adodb,1) from rdb$database');
- $id = $rs->fields[0];
- $conn->Execute("insert into table (id, col1,...) values ($id, $val1,...)");
-*/
-
-
-class ADODB_ibase extends ADOConnection {
- var $databaseType = "ibase";
- var $dataProvider = "ibase";
- var $replaceQuote = "''"; // string to use to replace quotes
- var $ibase_timefmt = '%Y-%m-%d';
- var $fmtDate = "'Y-m-d'";
- var $fmtTimeStamp = "'Y-m-d, H:i:s'";
- var $concat_operator='||';
- var $_transactionID;
- var $metaTablesSQL = "select rdb\$relation_name from rdb\$relations where rdb\$relation_name not like 'RDB\$%'";
- var $metaColumnsSQL = "select a.rdb\$field_name,b.rdb\$field_type,b.rdb\$field_length from rdb\$relation_fields a join rdb\$fields b on a.rdb\$field_source=b.rdb\$field_name where rdb\$relation_name ='%s'";
- var $ibasetrans = IBASE_DEFAULT;
- var $hasGenID = true;
- var $_bindInputArray = true;
- var $buffers = 0;
- var $dialect = 1;
- var $sysDate = "cast('TODAY' as date)";
- var $sysTimeStamp = "cast('NOW' as timestamp)";
- var $ansiOuter = true;
- var $hasAffectedRows = false;
- var $poorAffectedRows = true;
- var $blobEncodeType = 'C';
-
- function ADODB_ibase()
- {
- }
-
- function MetaPrimaryKeys($table,$owner_notused=false,$internalKey=false)
- {
- if ($internalKey) return array('RDB$DB_KEY');
-
- $table = strtoupper($table);
-
- $sql = 'SELECT S.RDB$FIELD_NAME AFIELDNAME
- FROM RDB$INDICES I JOIN RDB$INDEX_SEGMENTS S ON I.RDB$INDEX_NAME=S.RDB$INDEX_NAME
- WHERE I.RDB$RELATION_NAME=\''.$table.'\' and I.RDB$INDEX_NAME like \'RDB$PRIMARY%\'
- ORDER BY I.RDB$INDEX_NAME,S.RDB$FIELD_POSITION';
-
- $a = $this->GetCol($sql,false,true);
- if ($a && sizeof($a)>0) return $a;
- return false;
- }
-
- function ServerInfo()
- {
- $arr['dialect'] = $this->dialect;
- switch($arr['dialect']) {
- case '':
- case '1': $s = 'Interbase 5.5 or earlier'; break;
- case '2': $s = 'Interbase 5.6'; break;
- default:
- case '3': $s = 'Interbase 6.0'; break;
- }
- $arr['version'] = ADOConnection::_findvers($s);
- $arr['description'] = $s;
- return $arr;
- }
-
- function BeginTrans()
- {
- if ($this->transOff) return true;
- $this->transCnt += 1;
- $this->autoCommit = false;
- $this->_transactionID = $this->_connectionID;//ibase_trans($this->ibasetrans, $this->_connectionID);
- return $this->_transactionID;
- }
-
- function CommitTrans($ok=true)
- {
- if (!$ok) return $this->RollbackTrans();
- if ($this->transOff) return true;
- if ($this->transCnt) $this->transCnt -= 1;
- $ret = false;
- $this->autoCommit = true;
- if ($this->_transactionID) {
- //print ' commit ';
- $ret = ibase_commit($this->_transactionID);
- }
- $this->_transactionID = false;
- return $ret;
- }
-
- function RollbackTrans()
- {
- if ($this->transOff) return true;
- if ($this->transCnt) $this->transCnt -= 1;
- $ret = false;
- $this->autoCommit = true;
- if ($this->_transactionID)
- $ret = ibase_rollback($this->_transactionID);
- $this->_transactionID = false;
-
- return $ret;
- }
-
- // See http://community.borland.com/article/0,1410,25844,00.html
- function RowLock($tables,$where,$col)
- {
- if ($this->autoCommit) $this->BeginTrans();
- $this->Execute("UPDATE $table SET $col=$col WHERE $where "); // is this correct - jlim?
- return 1;
- }
-
- /*// use delete and insert instead
- function Replace($table, $fieldArray, $keyCol,$autoQuote=false)
- {
- if (count($fieldArray) == 0) return 0;
-
- if (!is_array($keyCol)) {
- $keyCol = array($keyCol);
- }
-
- if ($autoQuote)
- foreach($fieldArray as $k => $v) {
- if (!is_numeric($v) and $v[0] != "'" and strcasecmp($v,'null')!=0) {
- $v = $this->qstr($v);
- $fieldArray[$k] = $v;
- }
- }
-
- $first = true;
- foreach ($keyCol as $v) {
- if ($first) {
- $first = false;
- $where = "$v=$fieldArray[$v]";
- } else {
- $where .= " and $v=$fieldArray[$v]";
- }
- }
-
- $first = true;
- foreach($fieldArray as $k => $v) {
- if ($first) {
- $first = false;
- $iCols = "$k";
- $iVals = "$v";
- } else {
- $iCols .= ",$k";
- $iVals .= ",$v";
- }
- }
- $this->BeginTrans();
- $this->Execute("DELETE FROM $table WHERE $where");
- $ok = $this->Execute("INSERT INTO $table ($iCols) VALUES ($iVals)");
- $this->CommitTrans();
-
- return ($ok) ? 2 : 0;
- }
- */
- function CreateSequence($seqname,$startID=1)
- {
- $ok = $this->Execute(("INSERT INTO RDB\$GENERATORS (RDB\$GENERATOR_NAME) VALUES (UPPER('$seqname'))" ));
- if (!$ok) return false;
- return $this->Execute("SET GENERATOR $seqname TO ".($startID-1).';');
- }
-
- function DropSequence($seqname)
- {
- $seqname = strtoupper($seqname);
- $this->Execute("delete from RDB\$GENERATORS where RDB\$GENERATOR_NAME='$seqname'");
- }
-
- function GenID($seqname='adodbseq',$startID=1)
- {
- $getnext = ("SELECT Gen_ID($seqname,1) FROM RDB\$DATABASE");
- $rs = @$this->Execute($getnext);
- if (!$rs) {
- $this->Execute(("INSERT INTO RDB\$GENERATORS (RDB\$GENERATOR_NAME) VALUES (UPPER('$seqname'))" ));
- $this->Execute("SET GENERATOR $seqname TO ".($startID-1).';');
- $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;
- }
-
- function SelectDB($dbName)
- {
- return false;
- }
-
- function _handleerror()
- {
- $this->_errorMsg = ibase_errmsg();
- }
-
- function ErrorNo()
- {
- if (preg_match('/error code = ([\-0-9]*)/i', $this->_errorMsg,$arr)) return (integer) $arr[1];
- else return 0;
- }
-
- function ErrorMsg()
- {
- return $this->_errorMsg;
- }
-
- // returns true or false
- function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
- {
- if ($argDatabasename) $argHostname .= ':'.$argDatabasename;
- $this->_connectionID = ibase_connect($argHostname,$argUsername,$argPassword,$this->charSet,$this->buffers,$this->dialect);
- if ($this->dialect != 1) { // http://www.ibphoenix.com/ibp_60_del_id_ds.html
- $this->replaceQuote = "''";
- }
- if ($this->_connectionID === false) {
- $this->_handleerror();
- return false;
- }
-
- ibase_timefmt($this->ibase_timefmt);
- return true;
- }
- // returns true or false
- function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
- {
- if ($argDatabasename) $argHostname .= ':'.$argDatabasename;
- $this->_connectionID = ibase_pconnect($argHostname,$argUsername,$argPassword,$this->charSet,$this->buffers,$this->dialect);
- if ($this->dialect != 1) { // http://www.ibphoenix.com/ibp_60_del_id_ds.html
- $this->replaceQuote = "''";
- }
- if ($this->_connectionID === false) {
- $this->_handleerror();
- return false;
- }
-
- ibase_timefmt($this->ibase_timefmt);
- return true;
- }
-
- function Prepare($sql)
- {
- // return $sql;
- $stmt = ibase_prepare($sql);
- if (!$stmt) return false;
- return array($sql,$stmt);
- }
-
- // returns query ID if successful, otherwise false
- // there have been reports of problems with nested queries - the code is probably not re-entrant?
- function _query($sql,$iarr=false)
- {
-
- if (!$this->autoCommit && $this->_transactionID) {
- $conn = $this->_transactionID;
- $docommit = false;
- } else {
- $conn = $this->_connectionID;
- $docommit = true;
- }
- if (is_array($sql)) {
- $fn = 'ibase_execute';
- $sql = $sql[1];
-
- if (is_array($iarr)) {
- if (ADODB_PHPVER >= 0x4050) { // actually 4.0.4
- $fnarr = array_merge( array($sql) , $iarr);
- $ret = call_user_func_array($fn,$fnarr);
- } else {
- switch(sizeof($iarr)) {
- case 1: $ret = $fn($sql,$iarr[0]); break;
- case 2: $ret = $fn($sql,$iarr[0],$iarr[1]); break;
- case 3: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2]); break;
- case 4: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3]); break;
- case 5: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4]); break;
- case 6: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5]); break;
- case 7: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6]); break;
- default: ADOConnection::outp( "Too many parameters to ibase query $sql");
- case 8: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6],$iarr[7]); break;
- }
- }
- } else $ret = $fn($sql);
- } else {
- $fn = 'ibase_query';
-
- if (is_array($iarr)) {
- if (ADODB_PHPVER >= 0x4050) { // actually 4.0.4
- $fnarr = array_merge( array($conn,$sql) , $iarr);
- $ret = call_user_func_array($fn,$fnarr);
- } else {
- switch(sizeof($iarr)) {
- case 1: $ret = $fn($conn,$sql,$iarr[0]); break;
- case 2: $ret = $fn($conn,$sql,$iarr[0],$iarr[1]); break;
- case 3: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2]); break;
- case 4: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3]); break;
- case 5: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4]); break;
- case 6: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5]); break;
- case 7: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6]); break;
- default: ADOConnection::outp( "Too many parameters to ibase query $sql");
- case 8: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6],$iarr[7]); break;
- }
- }
- } else $ret = $fn($conn,$sql);
- }
- if ($docommit && $ret === true) ibase_commit($this->_connectionID);
-
- $this->_handleerror();
- return $ret;
- }
-
- // returns true or false
- function _close()
- {
- if (!$this->autoCommit) @ibase_rollback($this->_connectionID);
- return @ibase_close($this->_connectionID);
- }
-
- // returns array of ADOFieldObjects for current table
- function &MetaColumns($table)
- {
- global $ADODB_FETCH_MODE;
-
- if ($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 = trim($rs->fields[0]);
- $tt = $rs->fields[1];
- switch($tt)
- {
- case 7:
- case 8:
- case 9:$tt = 'INTEGER'; break;
- case 10:
- case 27:
- case 11:$tt = 'FLOAT'; break;
- default:
- case 40:
- case 14:$tt = 'CHAR'; break;
- case 35:$tt = 'DATE'; break;
- case 37:$tt = 'VARCHAR'; break;
- case 261:$tt = 'BLOB'; break;
- case 14: $tt = 'TEXT'; break;
- case 13:
- case 35:$tt = 'TIMESTAMP'; break;
- }
- $fld->type = $tt;
- $fld->max_length = $rs->fields[2];
- $retarr[strtoupper($fld->name)] = $fld;
-
- $rs->MoveNext();
- }
- $rs->Close();
- return $retarr;
- }
- return false;
- }
-
- function BlobEncode( $blob )
- {
- $blobid = ibase_blob_create( $this->_connectionID);
- ibase_blob_add( $blobid, $blob );
- return ibase_blob_close( $blobid );
- }
-
- // since we auto-decode all blob's since 2.42,
- // BlobDecode should not do any transforms
- function BlobDecode($blob)
- {
- return $blob;
- }
-
- // old blobdecode function
- // still used to auto-decode all blob's
- function _BlobDecode( $blob )
- {
- $blobid = ibase_blob_open( $blob );
- $realblob = ibase_blob_get( $blobid,$this->maxblobsize); // 2nd param is max size of blob -- Kevin Boillet
"; flush();
- if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword);
- else $this->_connectionID = odbc_pconnect($argDSN,$argUsername,$argPassword,$this->curmode);
-
- $this->_errorMsg = $php_errormsg;
- if ($this->_connectionID && $this->autoRollback) @odbc_rollback($this->_connectionID);
- return $this->_connectionID != false;
- }
-
- function BeginTrans()
- {
- if (!$this->hasTransactions) return false;
- if ($this->transOff) return true;
- $this->transCnt += 1;
- $this->_autocommit = false;
- return odbc_autocommit($this->_connectionID,false);
- }
-
- function CommitTrans($ok=true)
- {
- if ($this->transOff) return true;
- if (!$ok) return $this->RollbackTrans();
- if ($this->transCnt) $this->transCnt -= 1;
- $this->_autocommit = true;
- $ret = odbc_commit($this->_connectionID);
- odbc_autocommit($this->_connectionID,true);
- return $ret;
- }
-
- function RollbackTrans()
- {
- if ($this->transOff) return true;
- if ($this->transCnt) $this->transCnt -= 1;
- $this->_autocommit = true;
- $ret = odbc_rollback($this->_connectionID);
- odbc_autocommit($this->_connectionID,true);
- return $ret;
- }
-
- function MetaPrimaryKeys($table)
- {
- global $ADODB_FETCH_MODE;
-
- $savem = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
- $qid = @odbc_primarykeys($this->_connectionID,'','',$table);
-
- if (!$qid) {
- $ADODB_FETCH_MODE = $savem;
- return false;
- }
- $rs = new ADORecordSet_odbc($qid);
- $ADODB_FETCH_MODE = $savem;
-
- if (!$rs) return false;
- $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
-
- $arr = $rs->GetArray();
- $rs->Close();
- //print_r($arr);
- $arr2 = array();
- for ($i=0; $i < sizeof($arr); $i++) {
- if ($arr[$i][3]) $arr2[] = $arr[$i][3];
- }
- return $arr2;
- }
-
- function MetaTables()
- {
- global $ADODB_FETCH_MODE;
-
- $savem = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
- $qid = odbc_tables($this->_connectionID);
-
- $rs = new ADORecordSet_odbc($qid);
-
- $ADODB_FETCH_MODE = $savem;
- if (!$rs) return false;
-
- $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
-
- //print_r($rs);
- $arr = $rs->GetArray();
-
- $rs->Close();
- $arr2 = array();
- for ($i=0; $i < sizeof($arr); $i++) {
- if ($arr[$i][2]) $arr2[] = $arr[$i][2];
- }
- return $arr2;
- }
-
-/*
-/ SQL data type codes /
-#define SQL_UNKNOWN_TYPE 0
-#define SQL_CHAR 1
-#define SQL_NUMERIC 2
-#define SQL_DECIMAL 3
-#define SQL_INTEGER 4
-#define SQL_SMALLINT 5
-#define SQL_FLOAT 6
-#define SQL_REAL 7
-#define SQL_DOUBLE 8
-#if (ODBCVER >= 0x0300)
-#define SQL_DATETIME 9
-#endif
-#define SQL_VARCHAR 12
-
-/ One-parameter shortcuts for date/time data types /
-#if (ODBCVER >= 0x0300)
-#define SQL_TYPE_DATE 91
-#define SQL_TYPE_TIME 92
-#define SQL_TYPE_TIMESTAMP 93
-
-#define SQL_UNICODE (-95)
-#define SQL_UNICODE_VARCHAR (-96)
-#define SQL_UNICODE_LONGVARCHAR (-97)
-*/
- function ODBCTypes($t)
- {
- switch ((integer)$t) {
- case 1:
- case 12:
- case 0:
- case -95:
- case -96:
- return 'C';
- case -97:
- case -1: //text
- return 'X';
- case -4: //image
- return 'B';
-
- case 91:
- case 11:
- return 'D';
-
- case 92:
- case 93:
- case 9: return 'T';
- case 4:
- case 5:
- case -6:
- return 'I';
-
- case -11: // uniqidentifier
- return 'R';
- case -7: //bit
- return 'L';
-
- default:
- return 'N';
- }
- }
-
- function MetaColumns($table)
- {
- global $ADODB_FETCH_MODE;
-
- $table = strtoupper($table);
-
- $savem = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-
- if (false) { // after testing, confirmed that the following does not work becoz of a bug
- $qid2 = odbc_tables($this->_connectionID);
- $rs = new ADORecordSet_odbc($qid2);
- $ADODB_FETCH_MODE = $savem;
- if (!$rs) return false;
- $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
- $rs->_fetch();
-
- while (!$rs->EOF) {
- if ($table == strtoupper($rs->fields[2])) {
- $q = $rs->fields[0];
- $o = $rs->fields[1];
- break;
- }
- $rs->MoveNext();
- }
- $rs->Close();
-
- $qid = odbc_columns($this->_connectionID,$q,$o,strtoupper($table),'%');
- } else if ($this->databaseType == 'access') {
- $qid = odbc_columns($this->_connectionID);
- } else {
- $qid = odbc_columns($this->_connectionID,'%','%',strtoupper($table),'%');
- }
-
- $rs = new ADORecordSet_odbc($qid);
- $ADODB_FETCH_MODE = $savem;
-
- if (!$rs) return false;
-
- //print_r($rs);
- $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
- $rs->_fetch();
- $retarr = array();
-
- /*
- $rs->fields indices
- 0 TABLE_QUALIFIER
- 1 TABLE_SCHEM
- 2 TABLE_NAME
- 3 COLUMN_NAME
- 4 DATA_TYPE
- 5 TYPE_NAME
- 6 PRECISION
- 7 LENGTH
- 8 SCALE
- 9 RADIX
- 10 NULLABLE
- 11 REMARKS
- */
- while (!$rs->EOF) {
- //print_r($rs->fields);
- if (strtoupper($rs->fields[2]) == $table) {
- $fld = new ADOFieldObject();
- $fld->name = $rs->fields[3];
- $fld->type = $this->ODBCTypes($rs->fields[4]);
-
- // ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp
- // access uses precision to store length for char/varchar
- if ($fld->type == 'C' or $fld->type == 'X') {
- if ($this->databaseType == 'access')
- $fld->max_length = $rs->fields[6];
- else if ($rs->fields[4] <= -95) // UNICODE
- $fld->max_length = $rs->fields[7]/2;
- else
- $fld->max_length = $rs->fields[7];
- } else
- $fld->max_length = $rs->fields[7];
- $fld->not_null = !empty($rs->fields[10]);
- $retarr[strtoupper($fld->name)] = $fld;
- } else if (sizeof($retarr)>0)
- break;
- $rs->MoveNext();
- }
- $rs->Close(); //-- crashes 4.03pl1 -- why?
-
- return $retarr;
- }
-
- function Prepare($sql)
- {
- if (! $this->_bindInputArray) return $sql; // no binding
- $stmt = odbc_prepare($this->_connectionID,$sql);
- if (!$stmt) {
- // print "Prepare Error for ($sql) ".$this->ErrorMsg()."
";
- return $sql;
- }
- return array($sql,$stmt,false);
- }
-
- /* returns queryID or false */
- function _query($sql,$inputarr=false)
- {
- GLOBAL $php_errormsg;
- $php_errormsg = '';
- $this->_error = '';
-
- if ($inputarr) {
- if (is_array($sql)) {
- $stmtid = $sql[1];
- } else {
- $stmtid = odbc_prepare($this->_connectionID,$sql);
-
- if ($stmtid == false) {
- $this->_errorMsg = $php_errormsg;
- return false;
- }
- }
- if (! odbc_execute($stmtid,$inputarr)) {
- //@odbc_free_result($stmtid);
- return false;
- }
-
- } else if (is_array($sql)) {
- $stmtid = $sql[1];
- if (!odbc_execute($stmtid)) {
- //@odbc_free_result($stmtid);
- return false;
- }
- } else
- $stmtid = odbc_exec($this->_connectionID,$sql);
-
- if ($stmtid) {
- if (@odbc_num_fields($stmtid) == 0) {
- $this->_lastAffectedRows = odbc_num_rows($stmtid);
- $stmtid = true;
- } else {
- odbc_binmode($stmtid,$this->binmode);
- odbc_longreadlen($stmtid,$this->maxblobsize);
- }
- }
- $this->_errorMsg = $php_errormsg;
- return $stmtid;
- }
-
- /*
- Insert a null into the blob field of the table first.
- Then use UpdateBlob to store the blob.
-
- Usage:
-
- $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;
- }
-
- // returns true or false
- function _close()
- {
- $ret = @odbc_close($this->_connectionID);
- $this->_connectionID = false;
- return $ret;
- }
-
- function _affectedrows()
- {
- return $this->_lastAffectedRows;
- }
-
-}
-
-/*--------------------------------------------------------------------------------------
- Class Name: Recordset
---------------------------------------------------------------------------------------*/
-
-class ADORecordSet_odbc extends ADORecordSet {
-
- var $bind = false;
- var $databaseType = "odbc";
- var $dataProvider = "odbc";
- var $useFetchArray;
- var $_has_stupid_odbc_fetch_api_change;
-
- function ADORecordSet_odbc($id,$mode=false)
- {
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- $this->fetchMode = $mode;
-
- $this->_queryID = $id;
-
- // the following is required for mysql odbc driver in 4.3.1 -- why?
- $this->EOF = false;
- $this->_currentRow = -1;
- //$this->ADORecordSet($id);
- }
-
-
- // returns the field object
- function &FetchField($fieldOffset = -1)
- {
-
- $off=$fieldOffset+1; // offsets begin at 1
-
- $o= new ADOFieldObject();
- $o->name = @odbc_field_name($this->_queryID,$off);
- $o->type = @odbc_field_type($this->_queryID,$off);
- $o->max_length = @odbc_field_len($this->_queryID,$off);
-
- return $o;
- }
-
- /* Use associative array to get fields array */
- function Fields($colname)
- {
- if ($this->fetchMode & ADODB_FETCH_ASSOC) 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 _initrs()
- {
- global $ADODB_COUNTRECS;
- $this->_numOfRows = ($ADODB_COUNTRECS) ? @odbc_num_rows($this->_queryID) : -1;
- $this->_numOfFields = @odbc_num_fields($this->_queryID);
- // some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0
- if ($this->_numOfRows == 0) $this->_numOfRows = -1;
- //$this->useFetchArray = $this->connection->useFetchArray;
- $this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200;
- }
-
- function _seek($row)
- {
- return false;
- }
-
- // speed up SelectLimit() by switching to ADODB_FETCH_NUM as ADODB_FETCH_ASSOC is emulated
- function GetArrayLimit($nrows,$offset=-1)
- {
- if ($offset <= 0) return $this->GetArray($nrows);
- $savem = $this->fetchMode;
- $this->fetchMode = ADODB_FETCH_NUM;
- $this->Move($offset);
- $this->fetchMode = $savem;
-
- if ($this->fetchMode & ADODB_FETCH_ASSOC) {
- $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);
- }
-
- $results = array();
- $cnt = 0;
- while (!$this->EOF && $nrows != $cnt) {
- $results[$cnt++] = $this->fields;
- $this->MoveNext();
- }
-
- return $results;
- }
-
-
- function MoveNext()
- {
- if ($this->_numOfRows != 0 && !$this->EOF) {
- $this->_currentRow++;
- $row = 0;
- if ($this->_has_stupid_odbc_fetch_api_change)
- $rez = @odbc_fetch_into($this->_queryID,$this->fields);
- else
- $rez = @odbc_fetch_into($this->_queryID,$row,$this->fields);
- if ($rez) {
- if ($this->fetchMode & ADODB_FETCH_ASSOC) {
- $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);
- }
- return true;
- }
- }
- $this->fields = false;
- $this->EOF = true;
- return false;
- }
-
- function _fetch()
- {
- $row = 0;
- if ($this->_has_stupid_odbc_fetch_api_change)
- $rez = @odbc_fetch_into($this->_queryID,$this->fields,$row);
- else
- $rez = @odbc_fetch_into($this->_queryID,$row,$this->fields);
-
- if ($rez) {
- if ($this->fetchMode & ADODB_FETCH_ASSOC) {
- $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);
- }
- return true;
- }
- $this->fields = false;
- return false;
- }
-
- function _close()
- {
- return @odbc_free_result($this->_queryID);
- }
-
-}
-
-?>
+_haserrorfunctions = ADODB_PHPVER >= 0x4050;
+ $this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200;
+ }
+
+ function ServerInfo()
+ {
+
+ if (!empty($this->host) && ADODB_PHPVER >= 0x4300) {
+ $dsn = strtoupper($this->host);
+ $first = true;
+ $found = false;
+
+ if (!function_exists('odbc_data_source')) return false;
+
+ while(true) {
+
+ $rez = odbc_data_source($this->_connectionID,
+ $first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT);
+ $first = false;
+ if (!is_array($rez)) break;
+ if (strtoupper($rez['server']) == $dsn) {
+ $found = true;
+ break;
+ }
+ }
+ if (!$found) return ADOConnection::ServerInfo();
+ if (!isset($rez['version'])) $rez['version'] = '';
+ return $rez;
+ } else {
+ return ADOConnection::ServerInfo();
+ }
+ }
+
+ function ErrorMsg()
+ {
+ if ($this->_haserrorfunctions) {
+ if (empty($this->_connectionID)) return @odbc_errormsg();
+ return @odbc_errormsg($this->_connectionID);
+ } else return ADOConnection::ErrorMsg();
+ }
+
+ function CreateSequence($seqname='adodbseq',$start=1)
+ {
+ if (empty($this->_genSeqSQL)) return false;
+ $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
+ if (!$ok) return false;
+ $start -= 1;
+ return $this->Execute("insert into $seqname values($start)");
+ }
+
+ var $_dropSeqSQL = 'drop table %s';
+ function DropSequence($seqname)
+ {
+ if (empty($this->_dropSeqSQL)) return false;
+ return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
+ }
+
+ /*
+ This algorithm is not very efficient, but works even if table locking
+ is not available.
+
+ Will return false if unable to generate an ID after $MAXLOOPS attempts.
+ */
+ function GenID($seq='adodbseq',$start=1)
+ {
+ /* if you have to modify the parameter below, your database is overloaded, */
+ /* or you need to implement generation of id's yourself! */
+ $MAXLOOPS = 100;
+ /* $this->debug=1; */
+ while (--$MAXLOOPS>=0) {
+ $num = $this->GetOne("select id from $seq");
+ if ($num === false) {
+ $this->Execute(sprintf($this->_genSeqSQL ,$seq));
+ $start -= 1;
+ $num = '0';
+ $ok = $this->Execute("insert into $seq values($start)");
+ if (!$ok) return false;
+ }
+ $this->Execute("update $seq set id=id+1 where id=$num");
+
+ if ($this->affected_rows() > 0) {
+ $num += 1;
+ $this->genID = $num;
+ return $num;
+ }
+ }
+ if ($fn = $this->raiseErrorFn) {
+ $fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num);
+ }
+ return false;
+ }
+
+ function ErrorNo()
+ {
+ if ($this->_haserrorfunctions) {
+ if (empty($this->_connectionID)) $e = @odbc_error();
+ else $e = @odbc_error($this->_connectionID);
+
+ /* bug in 4.0.6, error number can be corrupted string (should be 6 digits) */
+ /* so we check and patch */
+ if (strlen($e)<=2) return 0;
+ return $e;
+ } else return ADOConnection::ErrorNo();
+ }
+
+
+ /* returns true or false */
+ function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
+ {
+ global $php_errormsg;
+ if ($this->debug && $argDatabasename) {
+ ADOConnection::outp("For odbc Connect(), $argDatabasename is not used. Place dsn in 1st parameter.");
+ }
+ $php_errormsg = '';
+ if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword);
+ else $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword,$this->curmode);
+ $this->_errorMsg = $php_errormsg;
+ if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
+
+ /* if ($this->_connectionID) odbc_autocommit($this->_connectionID,true); */
+ return $this->_connectionID != false;
+ }
+
+ /* returns true or false */
+ function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
+ {
+ global $php_errormsg;
+ $php_errormsg = '';
+ if ($this->debug && $argDatabasename) {
+ ADOConnection::outp("For odbc PConnect(), $argDatabasename is not used. Place dsn in 1st parameter.");
+ }
+ /* print "dsn=$argDSN u=$argUsername p=$argPassword
"; flush(); */
+ if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword);
+ else $this->_connectionID = odbc_pconnect($argDSN,$argUsername,$argPassword,$this->curmode);
+
+ $this->_errorMsg = $php_errormsg;
+ if ($this->_connectionID && $this->autoRollback) @odbc_rollback($this->_connectionID);
+ if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
+
+ return $this->_connectionID != false;
+ }
+
+ function BeginTrans()
+ {
+ if (!$this->hasTransactions) return false;
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+ $this->_autocommit = false;
+ return odbc_autocommit($this->_connectionID,false);
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if ($this->transOff) return true;
+ if (!$ok) return $this->RollbackTrans();
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->_autocommit = true;
+ $ret = odbc_commit($this->_connectionID);
+ odbc_autocommit($this->_connectionID,true);
+ return $ret;
+ }
+
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->_autocommit = true;
+ $ret = odbc_rollback($this->_connectionID);
+ odbc_autocommit($this->_connectionID,true);
+ return $ret;
+ }
+
+ function MetaPrimaryKeys($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $qid = @odbc_primarykeys($this->_connectionID,'','',$table);
+
+ if (!$qid) {
+ $ADODB_FETCH_MODE = $savem;
+ return false;
+ }
+ $rs = new ADORecordSet_odbc($qid);
+ $ADODB_FETCH_MODE = $savem;
+
+ if (!$rs) return false;
+ $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+
+ $arr =& $rs->GetArray();
+ $rs->Close();
+ /* print_r($arr); */
+ $arr2 = array();
+ for ($i=0; $i < sizeof($arr); $i++) {
+ if ($arr[$i][3]) $arr2[] = $arr[$i][3];
+ }
+ return $arr2;
+ }
+
+ function &MetaTables()
+ {
+ global $ADODB_FETCH_MODE;
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $qid = odbc_tables($this->_connectionID);
+
+ $rs = new ADORecordSet_odbc($qid);
+
+ $ADODB_FETCH_MODE = $savem;
+ if (!$rs) return false;
+
+ $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+
+ /* print_r($rs); */
+ $arr =& $rs->GetArray();
+
+ $rs->Close();
+ $arr2 = array();
+ for ($i=0; $i < sizeof($arr); $i++) {
+ if ($arr[$i][2]) $arr2[] = $arr[$i][2];
+ }
+ return $arr2;
+ }
+
+/*
+/ SQL data type codes /
+#define SQL_UNKNOWN_TYPE 0
+#define SQL_CHAR 1
+#define SQL_NUMERIC 2
+#define SQL_DECIMAL 3
+#define SQL_INTEGER 4
+#define SQL_SMALLINT 5
+#define SQL_FLOAT 6
+#define SQL_REAL 7
+#define SQL_DOUBLE 8
+#if (ODBCVER >= 0x0300)
+#define SQL_DATETIME 9
+#endif
+#define SQL_VARCHAR 12
+
+/ One-parameter shortcuts for date/time data types /
+#if (ODBCVER >= 0x0300)
+#define SQL_TYPE_DATE 91
+#define SQL_TYPE_TIME 92
+#define SQL_TYPE_TIMESTAMP 93
+
+#define SQL_UNICODE (-95)
+#define SQL_UNICODE_VARCHAR (-96)
+#define SQL_UNICODE_LONGVARCHAR (-97)
+*/
+ function ODBCTypes($t)
+ {
+ switch ((integer)$t) {
+ case 1:
+ case 12:
+ case 0:
+ case -95:
+ case -96:
+ return 'C';
+ case -97:
+ case -1: /* text */
+ return 'X';
+ case -4: /* image */
+ return 'B';
+
+ case 91:
+ case 11:
+ return 'D';
+
+ case 92:
+ case 93:
+ case 9: return 'T';
+ case 4:
+ case 5:
+ case -6:
+ return 'I';
+
+ case -11: /* uniqidentifier */
+ return 'R';
+ case -7: /* bit */
+ return 'L';
+
+ default:
+ return 'N';
+ }
+ }
+
+ function &MetaColumns($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $table = strtoupper($table);
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+
+ if (false) { /* after testing, confirmed that the following does not work becoz of a bug */
+ $qid2 = odbc_tables($this->_connectionID);
+ $rs = new ADORecordSet_odbc($qid2);
+ $ADODB_FETCH_MODE = $savem;
+ if (!$rs) return false;
+ $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+ $rs->_fetch();
+
+ while (!$rs->EOF) {
+ if ($table == strtoupper($rs->fields[2])) {
+ $q = $rs->fields[0];
+ $o = $rs->fields[1];
+ break;
+ }
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ $qid = odbc_columns($this->_connectionID,$q,$o,strtoupper($table),'%');
+ } else switch ($this->databaseType) {
+ case 'access':
+ case 'vfp':
+ case 'db2':
+ $qid = odbc_columns($this->_connectionID);
+ break;
+
+ default:
+ $qid = @odbc_columns($this->_connectionID,'%','%',strtoupper($table),'%');
+ if (empty($qid)) $qid = odbc_columns($this->_connectionID);
+ break;
+ }
+ if (empty($qid)) return false;
+
+ $rs = new ADORecordSet_odbc($qid);
+ $ADODB_FETCH_MODE = $savem;
+
+ if (!$rs) return false;
+
+ /* print_r($rs); */
+ $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+ $rs->_fetch();
+ $retarr = array();
+
+ /*
+ $rs->fields indices
+ 0 TABLE_QUALIFIER
+ 1 TABLE_SCHEM
+ 2 TABLE_NAME
+ 3 COLUMN_NAME
+ 4 DATA_TYPE
+ 5 TYPE_NAME
+ 6 PRECISION
+ 7 LENGTH
+ 8 SCALE
+ 9 RADIX
+ 10 NULLABLE
+ 11 REMARKS
+ */
+ while (!$rs->EOF) {
+ /* print_r($rs->fields); */
+ if (strtoupper($rs->fields[2]) == $table) {
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[3];
+ $fld->type = $this->ODBCTypes($rs->fields[4]);
+
+ /* ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp */
+ /* access uses precision to store length for char/varchar */
+ if ($fld->type == 'C' or $fld->type == 'X') {
+ if ($this->databaseType == 'access')
+ $fld->max_length = $rs->fields[6];
+ else if ($rs->fields[4] <= -95) /* UNICODE */
+ $fld->max_length = $rs->fields[7]/2;
+ else
+ $fld->max_length = $rs->fields[7];
+ } else
+ $fld->max_length = $rs->fields[7];
+ $fld->not_null = !empty($rs->fields[10]);
+ $fld->scale = $rs->fields[8];
+ $retarr[strtoupper($fld->name)] = $fld;
+ } else if (sizeof($retarr)>0)
+ break;
+ $rs->MoveNext();
+ }
+ $rs->Close(); /* -- crashes 4.03pl1 -- why? */
+
+ return $retarr;
+ }
+
+ function Prepare($sql)
+ {
+ if (! $this->_bindInputArray) return $sql; /* no binding */
+ $stmt = odbc_prepare($this->_connectionID,$sql);
+ if (!$stmt) {
+ /* print "Prepare Error for ($sql) ".$this->ErrorMsg()."
"; */
+ return $sql;
+ }
+ return array($sql,$stmt,false);
+ }
+
+ /* returns queryID or false */
+ function _query($sql,$inputarr=false)
+ {
+ GLOBAL $php_errormsg;
+ $php_errormsg = '';
+ $this->_error = '';
+
+ if ($inputarr) {
+ if (is_array($sql)) {
+ $stmtid = $sql[1];
+ } else {
+ $stmtid = odbc_prepare($this->_connectionID,$sql);
+
+ if ($stmtid == false) {
+ $this->_errorMsg = $php_errormsg;
+ return false;
+ }
+ }
+ if (! odbc_execute($stmtid,$inputarr)) {
+ /* @odbc_free_result($stmtid); */
+ return false;
+ }
+
+ } else if (is_array($sql)) {
+ $stmtid = $sql[1];
+ if (!odbc_execute($stmtid)) {
+ /* @odbc_free_result($stmtid); */
+ return false;
+ }
+ } else
+ $stmtid = odbc_exec($this->_connectionID,$sql);
+
+ $this->_lastAffectedRows = 0;
+ if ($stmtid) {
+ if (@odbc_num_fields($stmtid) == 0) {
+ $this->_lastAffectedRows = odbc_num_rows($stmtid);
+ $stmtid = true;
+ } else {
+ $this->_lastAffectedRows = 0;
+ odbc_binmode($stmtid,$this->binmode);
+ odbc_longreadlen($stmtid,$this->maxblobsize);
+ }
+ }
+
+ $this->_errorMsg = $php_errormsg;
+ return $stmtid;
+ }
+
+ /*
+ Insert a null into the blob field of the table first.
+ Then use UpdateBlob to store the blob.
+
+ Usage:
+
+ $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;
+ }
+
+ /* returns true or false */
+ function _close()
+ {
+ $ret = @odbc_close($this->_connectionID);
+ $this->_connectionID = false;
+ return $ret;
+ }
+
+ function _affectedrows()
+ {
+ return $this->_lastAffectedRows;
+ }
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_odbc extends ADORecordSet {
+
+ var $bind = false;
+ var $databaseType = "odbc";
+ var $dataProvider = "odbc";
+ var $useFetchArray;
+ var $_has_stupid_odbc_fetch_api_change;
+
+ function ADORecordSet_odbc($id,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ $this->fetchMode = $mode;
+
+ $this->_queryID = $id;
+
+ /* the following is required for mysql odbc driver in 4.3.1 -- why? */
+ $this->EOF = false;
+ $this->_currentRow = -1;
+ /* $this->ADORecordSet($id); */
+ }
+
+
+ /* returns the field object */
+ function &FetchField($fieldOffset = -1)
+ {
+
+ $off=$fieldOffset+1; /* offsets begin at 1 */
+
+ $o= new ADOFieldObject();
+ $o->name = @odbc_field_name($this->_queryID,$off);
+ $o->type = @odbc_field_type($this->_queryID,$off);
+ $o->max_length = @odbc_field_len($this->_queryID,$off);
+ if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name);
+ else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name);
+ return $o;
+ }
+
+ /* Use associative array to get fields array */
+ function Fields($colname)
+ {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) 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 _initrs()
+ {
+ global $ADODB_COUNTRECS;
+ $this->_numOfRows = ($ADODB_COUNTRECS) ? @odbc_num_rows($this->_queryID) : -1;
+ $this->_numOfFields = @odbc_num_fields($this->_queryID);
+ /* some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0 */
+ if ($this->_numOfRows == 0) $this->_numOfRows = -1;
+ /* $this->useFetchArray = $this->connection->useFetchArray; */
+ $this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200;
+ }
+
+ function _seek($row)
+ {
+ return false;
+ }
+
+ /* speed up SelectLimit() by switching to ADODB_FETCH_NUM as ADODB_FETCH_ASSOC is emulated */
+ function &GetArrayLimit($nrows,$offset=-1)
+ {
+ if ($offset <= 0) return $this->GetArray($nrows);
+ $savem = $this->fetchMode;
+ $this->fetchMode = ADODB_FETCH_NUM;
+ $this->Move($offset);
+ $this->fetchMode = $savem;
+
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);
+ }
+
+ $results = array();
+ $cnt = 0;
+ while (!$this->EOF && $nrows != $cnt) {
+ $results[$cnt++] = $this->fields;
+ $this->MoveNext();
+ }
+
+ return $results;
+ }
+
+
+ function MoveNext()
+ {
+ if ($this->_numOfRows != 0 && !$this->EOF) {
+ $this->_currentRow++;
+ $row = 0;
+ if ($this->_has_stupid_odbc_fetch_api_change)
+ $rez = @odbc_fetch_into($this->_queryID,$this->fields);
+ else
+ $rez = @odbc_fetch_into($this->_queryID,$row,$this->fields);
+ if ($rez) {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);
+ }
+ return true;
+ }
+ }
+ $this->fields = false;
+ $this->EOF = true;
+ return false;
+ }
+
+ function _fetch()
+ {
+ $row = 0;
+ if ($this->_has_stupid_odbc_fetch_api_change)
+ $rez = @odbc_fetch_into($this->_queryID,$this->fields,$row);
+ else
+ $rez = @odbc_fetch_into($this->_queryID,$row,$this->fields);
+
+ if ($rez) {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);
+ }
+ return true;
+ }
+ $this->fields = false;
+ return false;
+ }
+
+ function _close()
+ {
+ return @odbc_free_result($this->_queryID);
+ }
+
+}
+
+?>
diff --git a/lib/adodb/drivers/adodb-odbc_mssql.inc.php b/lib/adodb/drivers/adodb-odbc_mssql.inc.php
index 1f2bbf0570f..74923bd553a 100644
--- a/lib/adodb/drivers/adodb-odbc_mssql.inc.php
+++ b/lib/adodb/drivers/adodb-odbc_mssql.inc.php
@@ -1,135 +1,164 @@
-ADODB_odbc();
- }
-
- function xServerInfo()
- {
- $row = $this->GetRow("execute sp_server_info 2");
- $arr['description'] = $row[2];
- $arr['version'] = ADOConnection::_findvers($arr['description']);
- return $arr;
- }
-
-
- function _insertid()
- {
- // SCOPE_IDENTITY()
- // Returns the last IDENTITY value inserted into an IDENTITY column in
- // the same scope. A scope is a module -- a stored procedure, trigger,
- // function, or batch. Thus, two statements are in the same scope if
- // they are in the same stored procedure, function, or batch.
- return $this->GetOne($this->identitySQL);
- }
-
- function MetaTables()
- {
- return ADOConnection::MetaTables();
- }
-
- function MetaColumns($table)
- {
- return ADOConnection::MetaColumns($table);
- }
-
- // "Stein-Aksel Basma"
";
- return $o;
- }
-
- function _seek($row)
- {
- return @pg_fetch_row($this->_queryID,$row);
- }
-
- function _decode($blob)
- {
-
- eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";');
- return $realblob;
-
- }
- function _fixblobs()
- {
- if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) {
- foreach($this->_blobArr as $k => $v) {
- $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]);
- }
- }
- if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) {
- foreach($this->_blobArr as $k => $v) {
- $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]);
- }
- }
- }
-
- // 10% speedup to move MoveNext to child class
- function MoveNext()
- {
- if (!$this->EOF) {
- $this->_currentRow++;
- if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
- $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
-
- if (is_array($this->fields)) {
- if (isset($this->_blobArr)) $this->_fixblobs();
- return true;
- }
- }
- $this->fields = false;
- $this->EOF = true;
- }
- return false;
- }
-
- function _fetch()
- {
- if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)
- return false;
-
- $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
- if (isset($this->_blobArr)) $this->_fixblobs();
-
- return (is_array($this->fields));
- }
-
- function _close()
- {
- return @pg_freeresult($this->_queryID);
- }
-
- function MetaType($t,$len=-1,$fieldobj=false)
- {
- if (is_object($t)) {
- $fieldobj = $t;
- $t = $fieldobj->type;
- $len = $fieldobj->max_length;
- }
- switch (strtoupper($t)) {
- case 'INTERVAL':
- case 'CHAR':
- case 'CHARACTER':
- case 'VARCHAR':
- case 'NAME':
- case 'BPCHAR':
- if ($len <= $this->blobSize) return 'C';
-
- case 'TEXT':
- return 'X';
-
- case 'IMAGE': // user defined type
- case 'BLOB': // user defined type
- case 'BIT': // This is a bit string, not a single bit, so don't return 'L'
- case 'VARBIT':
- case 'BYTEA':
- return 'B';
-
- case 'BOOL':
- case 'BOOLEAN':
- return 'L';
-
- case 'DATE':
- return 'D';
-
- case 'TIME':
- case 'DATETIME':
- case 'TIMESTAMP':
- case 'TIMESTAMPTZ':
- return 'T';
-
- case 'SMALLINT':
- case 'BIGINT':
- case 'INTEGER':
- case 'INT8':
- case 'INT4':
- case 'INT2':
- if (isset($fieldobj) &&
- empty($fieldobj->primary_key) && empty($fieldobj->unique)) return 'I';
-
- case 'OID':
- case 'SERIAL':
- return 'R';
-
- default:
- return 'N';
- }
- }
-
-}
-?>
+
+ jlim - changed concat operator to || and data types to MetaType to match documented pgsql types
+ see http://www.postgresql.org/devel-corner/docs/postgres/datatype.htm
+ 22 Nov 2000 jlim - added changes to FetchField() and MetaTables() contributed by "raser"
"; */
+ return $o;
+ }
+
+ function _seek($row)
+ {
+ return @pg_fetch_row($this->_queryID,$row);
+ }
+
+ function _decode($blob)
+ {
+ eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";');
+ return $realblob;
+ }
+
+ function _fixblobs()
+ {
+ if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) {
+ foreach($this->_blobArr as $k => $v) {
+ $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]);
+ }
+ }
+ if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) {
+ foreach($this->_blobArr as $k => $v) {
+ $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]);
+ }
+ }
+ }
+
+ /* 10% speedup to move MoveNext to child class */
+ function MoveNext()
+ {
+ if (!$this->EOF) {
+ $this->_currentRow++;
+ if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
+ $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+
+ if (is_array($this->fields)) {
+ if (isset($this->_blobArr)) $this->_fixblobs();
+ return true;
+ }
+ }
+ $this->fields = false;
+ $this->EOF = true;
+ }
+ return false;
+ }
+
+ function _fetch()
+ {
+ if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)
+ return false;
+
+ $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+ if (isset($this->_blobArr)) $this->_fixblobs();
+
+ return (is_array($this->fields));
+ }
+
+ function _close()
+ {
+ return @pg_freeresult($this->_queryID);
+ }
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+ switch (strtoupper($t)) {
+ case 'INTERVAL':
+ case 'CHAR':
+ case 'CHARACTER':
+ case 'VARCHAR':
+ case 'NAME':
+ case 'BPCHAR':
+ if ($len <= $this->blobSize) return 'C';
+
+ case 'TEXT':
+ return 'X';
+
+ case 'IMAGE': /* user defined type */
+ case 'BLOB': /* user defined type */
+ case 'BIT': /* This is a bit string, not a single bit, so don't return 'L' */
+ case 'VARBIT':
+ case 'BYTEA':
+ return 'B';
+
+ case 'BOOL':
+ case 'BOOLEAN':
+ return 'L';
+
+ case 'DATE':
+ return 'D';
+
+ case 'TIME':
+ case 'DATETIME':
+ case 'TIMESTAMP':
+ case 'TIMESTAMPTZ':
+ return 'T';
+
+ case 'SMALLINT':
+ case 'BIGINT':
+ case 'INTEGER':
+ case 'INT8':
+ case 'INT4':
+ case 'INT2':
+ if (isset($fieldobj) &&
+ empty($fieldobj->primary_key) && empty($fieldobj->unique)) return 'I';
+
+ case 'OID':
+ case 'SERIAL':
+ return 'R';
+
+ default:
+ return 'N';
+ }
+ }
+
+}
+?>
diff --git a/lib/adodb/drivers/adodb-postgres7.inc.php b/lib/adodb/drivers/adodb-postgres7.inc.php
index 28e083597af..c79d76062be 100644
--- a/lib/adodb/drivers/adodb-postgres7.inc.php
+++ b/lib/adodb/drivers/adodb-postgres7.inc.php
@@ -1,74 +1,74 @@
-ADODB_postgres64();
- }
-
- // the following should be compat with postgresql 7.2,
- // which makes obsolete the LIMIT limit,offset syntax
- function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$arg3=false,$secs2cache=0)
- {
- $offsetStr = ($offset >= 0) ? " OFFSET $offset" : '';
- $limitStr = ($nrows >= 0) ? " LIMIT $nrows" : '';
- return $secs2cache ?
- $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr,$arg3)
- :
- $this->Execute($sql."$limitStr$offsetStr",$inputarr,$arg3);
- }
-
-
-}
-
-/*--------------------------------------------------------------------------------------
- Class Name: Recordset
---------------------------------------------------------------------------------------*/
-
-class ADORecordSet_postgres7 extends ADORecordSet_postgres64{
-
- var $databaseType = "postgres7";
-
- function ADORecordSet_postgres7($queryID,$mode=false)
- {
- $this->ADORecordSet_postgres64($queryID,$mode);
- }
-
- // 10% speedup to move MoveNext to child class
- function MoveNext()
- {
- if (!$this->EOF) {
- $this->_currentRow++;
- if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
- $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
-
- if (is_array($this->fields)) {
- if (isset($this->_blobArr)) $this->_fixblobs();
- return true;
- }
- }
- $this->fields = false;
- $this->EOF = true;
- }
- return false;
- }
-
-}
+ADODB_postgres64();
+ }
+
+ /* the following should be compat with postgresql 7.2, */
+ /* which makes obsolete the LIMIT limit,offset syntax */
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$arg3=false,$secs2cache=0)
+ {
+ $offsetStr = ($offset >= 0) ? " OFFSET $offset" : '';
+ $limitStr = ($nrows >= 0) ? " LIMIT $nrows" : '';
+ return $secs2cache ?
+ $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr,$arg3)
+ :
+ $this->Execute($sql."$limitStr$offsetStr",$inputarr,$arg3);
+ }
+
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_postgres7 extends ADORecordSet_postgres64{
+
+ var $databaseType = "postgres7";
+
+ function ADORecordSet_postgres7($queryID,$mode=false)
+ {
+ $this->ADORecordSet_postgres64($queryID,$mode);
+ }
+
+ /* 10% speedup to move MoveNext to child class */
+ function MoveNext()
+ {
+ if (!$this->EOF) {
+ $this->_currentRow++;
+ if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
+ $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+
+ if (is_array($this->fields)) {
+ if (isset($this->_blobArr)) $this->_fixblobs();
+ return true;
+ }
+ }
+ $this->fields = false;
+ $this->EOF = true;
+ }
+ return false;
+ }
+
+}
?>
\ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-proxy.inc.php b/lib/adodb/drivers/adodb-proxy.inc.php
index 9b69ef338bd..8237fdb5dd4 100644
--- a/lib/adodb/drivers/adodb-proxy.inc.php
+++ b/lib/adodb/drivers/adodb-proxy.inc.php
@@ -1,30 +1,30 @@
-ADORecordset($id,$mode);
- }
- };
-} // define
-
+ADORecordset($id,$mode);
+ }
+ };
+} /* define */
+
?>
\ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-sqlanywhere.inc.php b/lib/adodb/drivers/adodb-sqlanywhere.inc.php
index af44f5f3301..85f14e2e177 100644
--- a/lib/adodb/drivers/adodb-sqlanywhere.inc.php
+++ b/lib/adodb/drivers/adodb-sqlanywhere.inc.php
@@ -1,166 +1,166 @@
-create_blobvar($blobVarName);
-
- b) load blob var from file. $filename must be complete path
-
- $dbcon->load_blobvar_from_file($blobVarName, $filename);
-
- c) Use the $blobVarName in SQL insert or update statement in the values
- clause:
-
- $recordSet = $dbconn->Execute('INSERT INTO tabname (idcol, blobcol) '
- .
- 'VALUES (\'test\', ' . $blobVarName . ')');
-
- instead of loading blob from a file, you can also load from
- an unformatted (raw) blob variable:
- $dbcon->load_blobvar_from_var($blobVarName, $varName);
-
- d) drop blob variable on db server to free up resources:
- $dbconn->drop_blobvar($blobVarName);
-
- Sybase_SQLAnywhere data driver. Requires ODBC.
-
-*/
-
-if (!defined('_ADODB_ODBC_LAYER')) {
- include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
-}
-
-if (!defined('ADODB_SYBASE_SQLANYWHERE')){
-
- define('ADODB_SYBASE_SQLANYWHERE',1);
-
- class ADODB_sqlanywhere extends ADODB_odbc {
- var $databaseType = "sqlanywhere";
- var $hasInsertID = true;
-
- function ADODB_sqlanywhere()
- {
- $this->ADODB_odbc();
- }
-
- function _insertid() {
- return $this->GetOne('select @@identity');
- }
-
- function create_blobvar($blobVarName) {
- $this->Execute("create variable $blobVarName long binary");
- return;
- }
-
- function drop_blobvar($blobVarName) {
- $this->Execute("drop variable $blobVarName");
- return;
- }
-
- function load_blobvar_from_file($blobVarName, $filename) {
- $chunk_size = 1000;
-
- $fd = fopen ($filename, "rb");
-
- $integer_chunks = (integer)filesize($filename) / $chunk_size;
- $modulus = filesize($filename) % $chunk_size;
- if ($modulus != 0){
- $integer_chunks += 1;
- }
-
- for($loop=1;$loop<=$integer_chunks;$loop++){
- $contents = fread ($fd, $chunk_size);
- $contents = bin2hex($contents);
-
- $hexstring = '';
-
- for($loop2=0;$loop2$sql";
- $rs = $gDB->Execute($sql);
- rs2html($rs);
-
-/*
-Generated SQL:
-
-SELECT CompanyName,QuantityPerUnit,
- SUM(CASE WHEN CategoryName='Beverages' THEN 1 ELSE 0 END) AS "Beverages",
- SUM(CASE WHEN CategoryName='Condiments' THEN 1 ELSE 0 END) AS "Condiments",
- SUM(CASE WHEN CategoryName='Confections' THEN 1 ELSE 0 END) AS "Confections",
- SUM(CASE WHEN CategoryName='Dairy Products' THEN 1 ELSE 0 END) AS "Dairy Products",
- SUM(CASE WHEN CategoryName='Grains/Cereals' THEN 1 ELSE 0 END) AS "Grains/Cereals",
- SUM(CASE WHEN CategoryName='Meat/Poultry' THEN 1 ELSE 0 END) AS "Meat/Poultry",
- SUM(CASE WHEN CategoryName='Produce' THEN 1 ELSE 0 END) AS "Produce",
- SUM(CASE WHEN CategoryName='Seafood' THEN 1 ELSE 0 END) AS "Seafood",
- SUM(1) as Total
-FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID
-GROUP BY CompanyName,QuantityPerUnit
-*/
-//=====================================================================
-
-# example2
-#
-# Query the main "product" table
-# Set the rows to CompanyName and QuantityPerUnit
-# and the columns to the UnitsInStock for different ranges
-# and define the joins to link to lookup tables
-# "categories" and "suppliers"
-#
- $sql = PivotTableSQL(
- $gDB, # adodb connection
- 'products p ,categories c ,suppliers s', # tables
- 'CompanyName,QuantityPerUnit', # row fields
- # column ranges
-array(
-' 0 ' => 'UnitsInStock <= 0',
-"1 to 5" => '0 < UnitsInStock and UnitsInStock <= 5',
-"6 to 10" => '5 < UnitsInStock and UnitsInStock <= 10',
-"11 to 15" => '10 < UnitsInStock and UnitsInStock <= 15',
-"16+" =>'15 < UnitsInStock'
-),
- ' p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID', # joins/where
- 'UnitsInStock', # sum this field
- 'Sum' # sum label prefix
-);
- print "
$sql";
- $rs = $gDB->Execute($sql);
- rs2html($rs);
- /*
- Generated SQL:
-
-SELECT CompanyName,QuantityPerUnit,
- SUM(CASE WHEN UnitsInStock <= 0 THEN UnitsInStock ELSE 0 END) AS "Sum 0 ",
- SUM(CASE WHEN 0 < UnitsInStock and UnitsInStock <= 5 THEN UnitsInStock ELSE 0 END) AS "Sum 1 to 5",
- SUM(CASE WHEN 5 < UnitsInStock and UnitsInStock <= 10 THEN UnitsInStock ELSE 0 END) AS "Sum 6 to 10",
- SUM(CASE WHEN 10 < UnitsInStock and UnitsInStock <= 15 THEN UnitsInStock ELSE 0 END) AS "Sum 11 to 15",
- SUM(CASE WHEN 15 < UnitsInStock THEN UnitsInStock ELSE 0 END) AS "Sum 16+",
- SUM(UnitsInStock) AS "Sum UnitsInStock",
- SUM(1) as Total
-FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID
-GROUP BY CompanyName,QuantityPerUnit
- */
-}
+GetCol("select distinct $colfield from $tables $where order by 1");
+ if (!$aggfield) $hidecnt = false;
+
+ $sel = "$rowfields, ";
+ if (is_array($colfield)) {
+ foreach ($colfield as $k => $v) {
+ if (!$hidecnt) $sel .= "\n\t$aggfn(CASE WHEN $v THEN 1 ELSE 0 END) AS \"$k\", ";
+ if ($aggfield)
+ $sel .= "\n\t$aggfn(CASE WHEN $v THEN $aggfield ELSE 0 END) AS \"$sumlabel$k\", ";
+ }
+ } else {
+ foreach ($colarr as $v) {
+ if (!is_numeric($v)) $vq = $db->qstr($v);
+ else $vq = $v;
+ if (strlen($v) == 0 ) $v = 'null';
+ if (!$hidecnt) $sel .= "\n\t$aggfn(CASE WHEN $colfield=$vq THEN 1 ELSE 0 END) AS \"$v\", ";
+ if ($aggfield) {
+ if ($hidecnt) $label = $v;
+ else $label = "{$v}_$aggfield";
+ $sel .= "\n\t$aggfn(CASE WHEN $colfield=$vq THEN $aggfield ELSE 0 END) AS \"$label\", ";
+ }
+ }
+ }
+ if ($aggfield && $aggfield != '1'){
+ $agg = "$aggfn($aggfield)";
+ $sel .= "\n\t$agg as \"$sumlabel$aggfield\", ";
+ }
+
+ if ($showcount)
+ $sel .= "\n\tSUM(1) as Total";
+
+
+ $sql = "SELECT $sel \nFROM $tables $where \nGROUP BY $rowfields";
+ return $sql;
+ }
+
+/* EXAMPLES USING MS NORTHWIND DATABASE */
+if (0) {
+
+# example1
+#
+# Query the main "product" table
+# Set the rows to CompanyName and QuantityPerUnit
+# and the columns to the Categories
+# and define the joins to link to lookup tables
+# "categories" and "suppliers"
+#
+
+ $sql = PivotTableSQL(
+ $gDB, # adodb connection
+ 'products p ,categories c ,suppliers s', # tables
+ 'CompanyName,QuantityPerUnit', # row fields
+ 'CategoryName', # column fields
+ 'p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID' # joins/where
+);
+ print "$sql";
+ $rs = $gDB->Execute($sql);
+ rs2html($rs);
+
+/*
+Generated SQL:
+
+SELECT CompanyName,QuantityPerUnit,
+ SUM(CASE WHEN CategoryName='Beverages' THEN 1 ELSE 0 END) AS "Beverages",
+ SUM(CASE WHEN CategoryName='Condiments' THEN 1 ELSE 0 END) AS "Condiments",
+ SUM(CASE WHEN CategoryName='Confections' THEN 1 ELSE 0 END) AS "Confections",
+ SUM(CASE WHEN CategoryName='Dairy Products' THEN 1 ELSE 0 END) AS "Dairy Products",
+ SUM(CASE WHEN CategoryName='Grains/Cereals' THEN 1 ELSE 0 END) AS "Grains/Cereals",
+ SUM(CASE WHEN CategoryName='Meat/Poultry' THEN 1 ELSE 0 END) AS "Meat/Poultry",
+ SUM(CASE WHEN CategoryName='Produce' THEN 1 ELSE 0 END) AS "Produce",
+ SUM(CASE WHEN CategoryName='Seafood' THEN 1 ELSE 0 END) AS "Seafood",
+ SUM(1) as Total
+FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID
+GROUP BY CompanyName,QuantityPerUnit
+*/
+/* ===================================================================== */
+
+# example2
+#
+# Query the main "product" table
+# Set the rows to CompanyName and QuantityPerUnit
+# and the columns to the UnitsInStock for different ranges
+# and define the joins to link to lookup tables
+# "categories" and "suppliers"
+#
+ $sql = PivotTableSQL(
+ $gDB, # adodb connection
+ 'products p ,categories c ,suppliers s', # tables
+ 'CompanyName,QuantityPerUnit', # row fields
+ # column ranges
+array(
+' 0 ' => 'UnitsInStock <= 0',
+"1 to 5" => '0 < UnitsInStock and UnitsInStock <= 5',
+"6 to 10" => '5 < UnitsInStock and UnitsInStock <= 10',
+"11 to 15" => '10 < UnitsInStock and UnitsInStock <= 15',
+"16+" =>'15 < UnitsInStock'
+),
+ ' p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID', # joins/where
+ 'UnitsInStock', # sum this field
+ 'Sum' # sum label prefix
+);
+ print "
$sql";
+ $rs = $gDB->Execute($sql);
+ rs2html($rs);
+ /*
+ Generated SQL:
+
+SELECT CompanyName,QuantityPerUnit,
+ SUM(CASE WHEN UnitsInStock <= 0 THEN UnitsInStock ELSE 0 END) AS "Sum 0 ",
+ SUM(CASE WHEN 0 < UnitsInStock and UnitsInStock <= 5 THEN UnitsInStock ELSE 0 END) AS "Sum 1 to 5",
+ SUM(CASE WHEN 5 < UnitsInStock and UnitsInStock <= 10 THEN UnitsInStock ELSE 0 END) AS "Sum 6 to 10",
+ SUM(CASE WHEN 10 < UnitsInStock and UnitsInStock <= 15 THEN UnitsInStock ELSE 0 END) AS "Sum 11 to 15",
+ SUM(CASE WHEN 15 < UnitsInStock THEN UnitsInStock ELSE 0 END) AS "Sum 16+",
+ SUM(UnitsInStock) AS "Sum UnitsInStock",
+ SUM(1) as Total
+FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID
+GROUP BY CompanyName,QuantityPerUnit
+ */
+}
?>
\ No newline at end of file
diff --git a/lib/adodb/readme.htm b/lib/adodb/readme.htm
index 6e8ad23e177..599d1977031 100644
--- a/lib/adodb/readme.htm
+++ b/lib/adodb/readme.htm
@@ -10,2608 +10,57 @@
-
ADOdb Library for PHP
-
- Unique Features
- How People are using ADOdb
- Feature Requests and Bug Reports
- Installation
- Initializing Code ADONewConnection
- NewADOConnection
- Supported Databases
- Tutorial
- Example 1: Select
- Example 2: Advanced Select
- Example 3: Insert
- Example 4: Debugging rs2html example
- Example 5: MySQL and Menus
- Example 6: Connecting to Multiple Databases at once
- Example 7: Generating Update and Insert SQL
- Example 8: Implementing Scrolling with Next and Previous
- Example 9: Exporting in CSV or Tab-Delimited Format
- Example 10: Custom filters
- Using Custom Error Handlers and PEAR_Error
- Data Source Names
- Caching
- Pivot Tables
-
- Constants: ADODB_ASSOC_CASE
-
- ADOConnection
- Connections: Connect PConnect
- NConnect
- Executing SQL: Execute CacheExecute
- SelectLimit CacheSelectLimit
- Prepare PrepareSP Parameter
-
- GetOne CacheGetOne
- GetRow CacheGetRow
- GetAll CacheGetAll
- GetCol CacheGetCol
- Replace
- ExecuteCursor
- (oci8 only)
- Generates SQL: GetUpdateSQL GetInsertSQL
- Blobs: UpdateBlob UpdateClob
- UpdateBlobFile BlobEncode
- BlobDecode
- Paging/Scrolling: PageExecute CachePageExecute
- Cleanup: CacheFlush Close
- Transactions: BeginTrans CommitTrans
- RollbackTrans StartTrans CompleteTrans
- Fetching Data: SetFetchMode
- Strings: concat qstr quote
- Dates: DBDate DBTimeStamp
- UnixDate UnixTimeStamp
- OffsetDate SQLDate
- Rows Management: Affected_Rows Insert_ID
- GenID CreateSequence DropSequence
-
- Error Handling: ErrorMsg ErrorNo
- MetaError MetaErrorMsg
- Data Dictionary (metadata): MetaDatabases MetaTables
- MetaColumns MetaColumnNames
- MetaPrimaryKeys ServerInfo
-
- Statistics and Query-Rewriting: fnExecute and fnCacheExecute
- Deprecated: Bind BlankRecordSet
-
- ADORecordSet
- Returns one row:FetchRow FetchInto
- FetchObject FetchNextObject
- FetchObj FetchNextObj
- Returns all rows:GetArray GetRows
- GetAssoc
- Scrolling:Move MoveNext MoveFirst
- MoveLast AbsolutePosition CurrentRow
- AtFirstPage AtLastPage
- AbsolutePage
- Menu generation:GetMenu GetMenu2
- Dates:UserDate UserTimeStamp
- UnixDate UnixTimeStamp
- Recordset Info:RecordCount PO_RecordSet
- NextRecordSet
- Field Info:FieldCount FetchField
- MetaType
- Cleanup: Close
- Deprecated: GetRowAssoc Fields
-
- Differences between ADOdb and ADO
- Database Driver Guide
- Change Log
-Introduction
-Unique Features of ADOdb
-
-
-How People are using ADOdb
+ADOdb Library for PHP
+Installation
+Make sure you are running PHP4.0.4 or later. Unpack all the files into a directory accessible by your webserver.
+
+<?php
+include('adodb/adodb.inc.php');
+
+$db = ADONewConnection($driver); # eg. 'mysql' or 'oci8'
+$db->debug = true;
+$db->Connect($server, $user, $password, $database);
+$rs = $db->Execute('select * from some_small_table');
+print "<pre>";
+print_r($rs->GetRows());
+print "</pre>";
+?>
+
+How are people using ADOdb
Here are some examples of how people are using ADOdb (for a much longer list,
visit http://php.weblogs.com/adodb-cool-applications):
-
Feature Requests and Bug Reports
-Installation Guide
-<?php
- include('adodb/adodb.inc.php');
- $db = ADONewConnection($database);
- $db->debug = true;
- $db->Connect($server, $user, $password, $database);
- $rs = $db->Execute('select * from some_small_table');
- print "<pre>";
- print_r($rs->GetRows());
- print "</pre>";
-?>
-Code Initialization
-
-include('/path/to/set/here/adodb.inc.php');
-$conn = &ADONewConnection('mysql');
-
-$conn->Connect() or
-$conn->PConnect() to perform the actual connection.Databases Supported
-
-
-
-
-
- Name
- Tested
- Database
- RecordCount() usable
- Prerequisites
- Operating Systems
-
-
- access
- B
- Microsoft Access/Jet. You need to create an ODBC DSN.
- Y/N
- ODBC
- Windows only
-
-
- ado
- B
-
- ? depends on database
- ADO or OLEDB provider
- Windows only
-
-
- ado_access
- B
- Microsoft Access/Jet using ADO. Allows DSN-less connections.
- For best performance, use an OLEDB provider.
- Y/N
- ADO or OLEDB provider
- Windows only
-
-
- ado_mssql
- B
- Microsoft SQL Server using ADO. Allows DSN-less connections.
- For best performance, use an OLEDB provider.
- Y/N
- ADO or OLEDB provider
- Windows only
-
-
- db2
- C
- DB2. Should work reliably as based on ODBC
- driver.
- Y/N
- DB2 CLI/ODBC interface
-
-
-
-
- vfp
- A
- Microsoft Visual FoxPro. You need to create an ODBC DSN.
- Y/N
- ODBC
- Windows only
-
-
- fbsql
- C
- FrontBase.
- Y
- ?
-
-
-
-
- ibase
- B
- Interbase 6 or earlier. Some users report you might need
- to use this
-
- $db->PConnect('localhost:c:/ibase/employee.gdb', "sysdba", "masterkey")
- to connect. Lacks Affected_Rows currently.
-
- You can set $db->dialect, $db->buffers and $db->charSet before
- connecting.Y/N
- Interbase client
- Unix and Windows
-
-
- firebird
- C
- Firebird version of interbase.
- Y/N
- Interbase client
- Unix and Windows
-
-
- borland_ibase
- C
- Borland version of Interbase 6.5 or later. Very sad that
- the forks differ.
- Y/N
- Interbase client
- Unix and Windows
-
-
- informix72
- C
- Informix databases before Informix 7.3 that do no support
- SELECT FIRST.
- Y/N
- Informix client
- Unix and Windows
-
-
- informix
- C
- Generic informix driver.
- Y/N
- Informix client
- Unix and Windows
-
-
- mssql
- A
-
-
- Y/N
- Mssql client
-
-
-
- Unix install howto and
- another one.
-
-
- mssqlpo
- A
-
-
- Y/N
- Mssql client
-
-
-
- Unix install howto.
-
- mysql
- A
- MySQL without transaction support. You can also set
- $db->clientFlags before connecting.
- Y/N
- MySQL client
- Unix and Windows
-
-
- mysqlt or maxsql
- A
-
-
-
- mysqld --ansi or mysqld --sql-mode=PIPES_AS_CONCATY/N
- MySQL client
- Unix and Windows
-
-
- oci8
- A
- Oracle 8/9. Has more functionality than oracle driver
- (eg. Affected_Rows). You might have to putenv('ORACLE_HOME=...') before
- Connect/PConnect.
-
-
- PConnect('serverip:1521','scott','tiger','service')
- or using an entry in TNSNAMES.ORA or ONAMES or HOSTNAMES:
- PConnect(false, 'scott', 'tiger', $oraname).
- Y/N
- Oracle client
- Unix and Windows
-
-
- oci805
- C
- Supports reduced Oracle functionality for Oracle 8.0.5.
- SelectLimit is not as efficient as in the oci8 or oci8po drivers.
- Y/N
- Oracle client
- Unix and Windows
-
-
- oci8po
- A
- Oracle 8/9 portable driver. This is nearly identical with
- the oci8 driver except (a) bind variables in Prepare() use the ? convention,
- instead of :bindvar, (b) field names use the more common PHP convention
- of lowercase names.
-
- Y/N
- Oracle client
- Unix and Windows
-
-
- odbc
- A
- Generic ODBC, not tuned for specific databases. To connect,
- use
-
- PConnect('DSN','user','pwd'). This is the base class for all odbc
- derived drivers.? depends on database
- ODBC
- Unix and Windows. Unix
- hints.
-
-
- odbc_mssql
- C
- Uses ODBC to connect to MSSQL
- Y/N
- ODBC
- Unix and Windows.
-
-
- odbc_oracle
- C
- Uses ODBC to connect to Oracle
- Y/N
- ODBC
- Unix and Windows.
-
-
- oracle
- C
- Implements old Oracle 7 client API. Use oci8
- driver if possible for better performance.
- Y/N
- Oracle client
- Unix and Windows
-
-
- postgres
- A
- Generic PostgreSQL driver. Currently identical to postgres7
- driver.
- Y
- PostgreSQL client
- Unix and Windows.
-
-
- postgres64
- A
- For PostgreSQL 6.4 and earlier which does not support LIMIT
- internally.
- Y
- PostgreSQL client
- Unix and Windows.
-
-
- postgres7
- A
- PostgreSQL which supports LIMIT and other version 7 functionality.
- Y
- PostgreSQL client
- Unix and Windows.
-
-
- sqlanywhere
- C
- Sybase SQL Anywhere. Should work reliably as based on ODBC
- driver.
- Y/N
- SQL Anywhere ODBC client
-
-
-
-
- sybase
- C
- Sybase.
- Y/N
- Sybase client
-
-
-
- A = well tested and used by many people
- B = tested and usable, but some features might not be implemented
- C = user contributed or experimental driver. Might not fully support all of
- the latest features of ADOdb.
-Tutorial
-Example 1: Select Statement
-
-<?
-include('adodb.inc.php'); # load code common to ADOdb
-$conn = &ADONewConnection('access'); # create a connection
-$conn->PConnect('northwind'); # connect to MS-Access, northwind DSN
-$recordSet = &$conn->Execute('select * from products');
-if (!$recordSet)
- print $conn->ErrorMsg();
-else
-while (!$recordSet->EOF) {
- print $recordSet->fields[0].' '.$recordSet->fields[1].'<BR>';
- $recordSet->MoveNext();
-}
-
-$recordSet->Close(); # optional
-$conn->Close(); # optional
-
-?>
-
-$recordSet->fields[] array is generated by the PHP database
- extension. Some database extensions only index by number and do not index
- the array by field name. To force indexing by name - that is associative arrays
- - use the SetFetchMode function. Each recordset saves and uses whatever fetch
- mode was set when the recordset was created in Execute() or SelectLimit().
-
- $db->SetFetchMode(ADODB_FETCH_NUM);
- $rs1 = $db->Execute('select * from table');
- $db->SetFetchMode(ADODB_FETCH_ASSOC);
- $rs2 = $db->Execute('select * from table');
- print_r($rs1->fields); # shows array([0]=>'v0',[1] =>'v1')
- print_r($rs2->fields); # shows array(['col1']=>'v0',['col2'] =>'v1')
-
-Example 2: Advanced Select with Field Objects
-
-<?
-include('adodb.inc.php'); # load code common to ADOdb
-$conn = &ADONewConnection('access'); # create a connection
-$conn->PConnect('northwind'); # connect to MS-Access, northwind dsn
-$recordSet = &$conn->Execute('select CustomerID,OrderDate from Orders');
-if (!$recordSet)
- print $conn->ErrorMsg();
-else
-while (!$recordSet->EOF) {
- $fld = $recordSet->FetchField(1);
- $type = $recordSet->MetaType($fld->type);
-
- if ( $type == 'D' || $type == 'T')
- print $recordSet->fields[0].' '.
- $recordSet->UserDate($recordSet->fields[1],'m/d/Y').'<BR>';
- else
- print $recordSet->fields[0].' '.$recordSet->fields[1].'<BR>';
-
- $recordSet->MoveNext();
-}
-$recordSet->Close(); # optional
-$conn->Close(); # optional
-
-?>
-
-
-
-
-
-Example 3: Inserting
-
-<?
-include('adodb.inc.php'); # load code common to ADOdb
-$conn = &ADONewConnection('access'); # create a connection
-
-$conn->PConnect('northwind'); # connect to MS-Access, northwind dsn
-$shipto = $conn->qstr("John's Old Shoppe");
-
-$sql = "insert into orders (customerID,EmployeeID,OrderDate,ShipName) ";
-$sql .= "values ('ANATR',2,".$conn->DBDate(time()).",$shipto)";
-
-if ($conn->Execute($sql) === false) {
- print 'error inserting: '.$conn->ErrorMsg().'<BR>';
-}
-?>
-
- Example 4: Debugging
-<?
-include('adodb.inc.php'); # load code common to ADOdb
-$conn = &ADONewConnection('access'); # create a connection
-$conn->PConnect('northwind'); # connect to MS-Access, northwind dsn
-$shipto = $conn->qstr("John's Old Shoppe");
-$sql = "insert into orders (customerID,EmployeeID,OrderDate,ShipName) ";
-$sql .= "values ('ANATR',2,".$conn->FormatDate(time()).",$shipto)";
-$conn->debug = true;
-if ($conn->Execute($sql) === false) print 'error inserting';
-?>
-
-Example 5: MySQL and Menus
-<?
-include('adodb.inc.php'); # load code common to ADOdb
-$conn = &ADONewConnection('mysql'); # create a connection
-$conn->PConnect('localhost','userid','','agora');# connect to MySQL, agora db
-$sql = 'select CustomerName, CustomerID from customers';
-$rs = $conn->Execute($sql);
-print $rs->GetMenu('GetCust','Mary Rosli');
-?>
-Example 6: Connecting to 2 Databases At Once
-<?
-include('adodb.inc.php'); # load code common to ADOdb
-$conn1 = &ADONewConnection('mysql'); # create a mysql connection
-$conn2 = &ADONewConnection('oracle'); # create a oracle connection
-
-$conn1->PConnect($server, $userid, $password, $database);
-$conn2->PConnect(false, $ora_userid, $ora_pwd, $oraname);
-
-$conn1->Execute('insert ...');
-$conn2->Execute('update ...');
-?>
-Example 7: Generating Update and Insert SQL
-ADOdb 1.31 and later supports two new recordset functions: GetUpdateSQL( ) and
-GetInsertSQL( ). This allow you to perform a "SELECT * FROM table query WHERE...",
-make a copy of the $rs->fields, modify the fields, and then generate the SQL to
-update or insert into the table automatically.
-<?
-#==============================================
-# SAMPLE GetUpdateSQL() and GetInsertSQL() code
-#==============================================
-include('adodb.inc.php');
-include('tohtml.inc.php');
-
-#==========================
-# This code tests an insert
-
-$sql = "SELECT * FROM ADOXYZ WHERE id = -1";
-# Select an empty record from the database
-
-$conn = &ADONewConnection("mysql"); # create a connection
-$conn->debug=1;
-$conn->PConnect("localhost", "admin", "", "test"); # connect to MySQL, testdb
-$rs = $conn->Execute($sql); # Execute the query and get the empty recordset
-
-$record = array(); # Initialize an array to hold the record data to insert
-
-# Set the values for the fields in the record
-# Note that field names are case-insensitive
-$record["firstname"] = "Bob";
-$record["lastNamE"] = "Smith";
-$record["creaTed"] = time();
-
-# Pass the empty recordset and the array containing the data to insert
-# into the GetInsertSQL function. The function will process the data and return
-# a fully formatted insert sql statement.
-$insertSQL = $conn->GetInsertSQL($rs, $record);
-
-$conn->Execute($insertSQL); # Insert the record into the database
-
-#==========================
-# This code tests an update
-
-$sql = "SELECT * FROM ADOXYZ WHERE id = 1";
-# Select a record to update
-
-$rs = $conn->Execute($sql); # Execute the query and get the existing record to update
-
-$record = array(); # Initialize an array to hold the record data to update
-
-# Set the values for the fields in the record
-# Note that field names are case-insensitive
-$record["firstname"] = "Caroline";
-$record["LasTnAme"] = "Smith"; # Update Caroline's lastname from Miranda to Smith
-
-# Pass the single record recordset and the array containing the data to update
-# into the GetUpdateSQL function. The function will process the data and return
-# a fully formatted update sql statement with the correct WHERE clause.
-# If the data has not changed, no recordset is returned
-$updateSQL = $conn->GetUpdateSQL($rs, $record);
-
-$conn->Execute($updateSQL); # Update the record in the database
-$conn->Close();
-?>
-
-Example 8: Implementing Scrolling with Next and Previous
-
-include_once('../adodb.inc.php');
-include_once('../adodb-pager.inc.php');
-session_start();
-
-$db = NewADOConnection('mysql');
-
-$db->Connect('localhost','root','','xphplens');
-
-$sql = "select * from adoxyz ";
-
-$pager = new ADODB_Pager($db,$sql);
-$pager->Render($rows_per_page=5);
-
-
-
- |< <<
- >> >|
-
-
-
-
-ID First Name Last Name Date Created
-
-
-
-
-36
- Alan
- Turing
- Sat 06, Oct 2001
-
-
-
-37
- Serena
- Williams
- Sat 06, Oct 2001
-
-
-
-38
- Yat Sun
- Sun
- Sat 06, Oct 2001
-
-
-
-39
- Wai Hun
- See
- Sat 06, Oct 2001
-
-
-
-40
- Steven
- Oey
- Sat 06, Oct 2001
-Page 8/10 $sql = 'select id as "ID", firstname as "First Name",
- lastname as "Last Name", created as "Date Created"
-
from adoxyz';Example 9: Exporting in CSV or Tab-Delimited Format
-include_once('/path/to/adodb/toexport.inc.php');
-
include_once('/path/to/adodb/adodb.inc.php');
-$db = &NewADOConnection('mysql');
$db->Connect($server, $userid, $password, $database);
$rs = $db->Execute('select fname as "First Name", surname as "Surname" from table');
-
-print "<pre>";
print rs2csv($rs); # return a string, CSV format
$rs->MoveFirst(); # note, some databases do not support MoveFirst
print rs2tab($rs,false); # return a string, tab-delimited
- # false == suppress field names in first line
$rs->MoveFirst();
rs2tabout($rs); # send to stdout directly (there is also an rs2csvout function)
-print "</pre>";
-
-$rs->MoveFirst();
$fp = fopen($path, "w");
-if ($fp) {
rs2csvfile($rs, $fp); # write to file (there is also an rs2tabfile function)
- fclose($fp);
}
-
-Example 10: Recordset Filters
-
-include_once('adodb/rsfilter.inc.php');
-include_once('adodb/adodb.inc.php');
-
-// ucwords() every element in the recordset
-function do_ucwords(&$arr,$rs)
-{
- foreach($arr as $k => $v) {
- $arr[$k] = ucwords($v);
- }
-}
-
-$db = NewADOConnection('mysql');
-$db->PConnect('server','user','pwd','db');
-
-$rs = $db->Execute('select ... from table');
-$rs = RSFilter($rs,'do_ucwords');
-
-Using Custom Error Handlers and PEAR_Error
-Apart from the old $con->debug = true; way of debugging, ADOdb 1.50 onwards provides
-another way of handling errors using ADOdb's custom error handlers.
-
-(a) Connect() or PConnect() fails, or
-(b) a function that executes SQL statements such as Execute() or SelectLimit() has an error.
-(c) GenID() appears to go into an infinite loop.
-
-<?php
-error_reporting(E_ALL); # show any error messages triggered
-include('adodb-errorhandler.inc.php');
-include('adodb.inc.php');
-include('tohtml.inc.php');
-$c = NewADOConnection('mysql');
-$c->PConnect('localhost','root','','northwind');
-$rs=$c->Execute('select * from productsz'); #invalid table productsz');
-if ($rs) $rs2html($rs);
-?>
-
-
-<?php
-error_reporting(0); # do not echo any errors
-define('ADODB_ERROR_LOG_TYPE',3);
-define('ADODB_ERROR_LOG_DEST','C:/errors.log');
-include('adodb-errorhandler.inc.php');
-include('adodb.inc.php');
-include('tohtml.inc.php');
-
-$c = NewADOConnection('mysql');
-$c->PConnect('localhost','root','','northwind');
-$rs=$c->Execute('select * from productsz'); ## invalid table productsz
-if ($rs) $rs2html($rs);
-?>
-
-The following message will be logged in the error.log file:
-
-(2001-10-28 14:20:38) mysql error: [1146: Table 'northwind.productsz' doesn't exist] in
- EXECUTE("select * from productsz")
-
-The second error handler is adodb-errorpear.inc.php. This will create a
-PEAR_Error derived object whenever an error occurs. The last PEAR_Error object
-created can be retrieved using ADODB_Pear_Error().
-
-<?php
-include('adodb-errorpear.inc.php');
-include('adodb.inc.php');
-include('tohtml.inc.php');
-$c = NewADOConnection('mysql');
-$c->PConnect('localhost','root','','northwind');
-$rs=$c->Execute('select * from productsz'); #invalid table productsz');
-if ($rs) $rs2html($rs);
-else {
- $e = ADODB_Pear_Error();
- echo '<p>',$e->message,'</p>';
-}
-?>
-
-
-include('PEAR.php');
-PEAR::setErrorHandling('PEAR_ERROR_DIE');
-
-Error Messages
- Data Source Names
- include_once('../adodb/adodb-pear.inc.php');
- $username = 'root';
- $password = '';
- $hostname = 'localhost';
- $databasename = 'xphplens';
- $driver = 'mysql';
- $dsn = "$driver://$username:$password@$hostname/$databasename";
- $db = DB::Connect($dsn);
-
$rs = $db->Execute('select firstname,lastname from adoxyz');
- $cnt = 0;
- while ($arr = $rs->FetchRow()) {
- print_r($arr); print "<br>";
- }Caching of Recordsets
-
-include('adodb.inc.php'); # load code common to ADOdb
-$ADODB_CACHE_DIR = '/usr/ADODB_cache';
-$conn = &ADONewConnection('mysql'); # create a connection
-$conn->PConnect('localhost','userid','','agora');# connect to MySQL, agora db
-$sql = 'select CustomerName, CustomerID from customers';
-$rs = $conn->CacheExecute(15,$sql);
-
- $conn->Connect(...);
- $conn->cacheSecs = 3600*24; # cache 24 hours
- $rs = $conn->CacheExecute('select * from table');
-
-Pivot Tables
-
-
-
-
-
-
-
-
-
-
-
-
- Supplier
- Category
-
-
- supplier1
- category1
-
-
- supplier2
- category1
-
-
- supplier2
- category2
- -->
-
-
-
-
-
-
-
- category1
- category2
- total
-
-
- supplier1
- 1
- 0
- 1
-
-
- supplier2
- 1
- 1
- 2
-
-# Query the main "product" table
-# Set the rows to CompanyName
-# and the columns to the values of Categories
-# and define the joins to link to lookup tables
-# "categories" and "suppliers"
-#
- include "adodb/pivottable.php";
- $sql = PivotTableSQL(
- $gDB, # adodb connection
- 'products p ,categories c ,suppliers s', # tables
- 'CompanyName', # rows (multiple fields allowed)
- 'CategoryName', # column to pivot on
- 'p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID' # joins/where
-);
-
-
-SELECT CompanyName,
- SUM(CASE WHEN CategoryName='Beverages' THEN 1 ELSE 0 END) AS "Beverages",
-
- SUM(CASE WHEN CategoryName='Condiments' THEN 1 ELSE 0 END) AS "Condiments",
-
- SUM(CASE WHEN CategoryName='Confections' THEN 1 ELSE 0 END) AS "Confections",
-
- SUM(CASE WHEN CategoryName='Dairy Products' THEN 1 ELSE 0 END) AS "Dairy
- Products",
- SUM(CASE WHEN CategoryName='Grains/Cereals' THEN 1 ELSE 0 END) AS "Grains/Cereals",
-
- SUM(CASE WHEN CategoryName='Meat/Poultry' THEN 1 ELSE 0 END) AS "Meat/Poultry",
-
- SUM(CASE WHEN CategoryName='Produce' THEN 1 ELSE 0 END) AS "Produce",
-
- SUM(CASE WHEN CategoryName='Seafood' THEN 1 ELSE 0 END) AS "Seafood",
-
- SUM(1) as Total
- FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID
- and s.SupplierID= p.SupplierID
- GROUP BY CompanyName
- $sql = PivotTableSQL(
- $gDB, # adodb connection
- 'products p ,categories c ,suppliers s', # tables
- 'CompanyName', # rows (multiple fields allowed)
- array( # column ranges
- ' 0 ' => 'UnitsInStock <= 0',
- "1 to 5" => '0 < UnitsInStock and UnitsInStock <= 5',
- "6 to 10" => '5 < UnitsInStock and UnitsInStock <= 10',
- "11 to 15" => '10 < UnitsInStock and UnitsInStock <= 15',
- "16+" => '15 < UnitsInStock'
- ),
- ' p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID', # joins/where
- 'UnitsInStock', # sum this field
- 'Sum ' # sum label prefix
-);
-
- SELECT CompanyName,
- SUM(CASE WHEN UnitsInStock <= 0 THEN UnitsInStock ELSE 0 END) AS "Sum
- 0 ",
- SUM(CASE WHEN 0 < UnitsInStock and UnitsInStock <= 5 THEN UnitsInStock
- ELSE 0 END) AS "Sum 1 to 5",
- SUM(CASE WHEN 5 < UnitsInStock and UnitsInStock <= 10 THEN UnitsInStock
- ELSE 0 END) AS "Sum 6 to 10",
- SUM(CASE WHEN 10 < UnitsInStock and UnitsInStock <= 15 THEN UnitsInStock
- ELSE 0 END) AS "Sum 11 to 15",
- SUM(CASE WHEN 15 < UnitsInStock THEN UnitsInStock ELSE 0 END) AS "Sum
- 16+",
- SUM(UnitsInStock) AS "Sum UnitsInStock",
- SUM(1) as Total,
- FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID
- and s.SupplierID= p.SupplierID
- GROUP BY CompanyName
-
-Class Reference
-Global Variables
-$ADODB_COUNTRECS
-$ADODB_CACHE_DIR
-
-
- chgrp -R apache /path/to/adodb/cache $ADODB_FETCH_MODE
-
- define('ADODB_FETCH_NUM',1);
- define('ADODB_FETCH_ASSOC',2);
- define('ADODB_FETCH_BOTH',3);
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
- $rs1 = $db->Execute('select * from table');
- $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
- $rs2 = $db->Execute('select * from table');
- print_r($rs1->fields); # shows array([0]=>'v0',[1] =>'v1')
- print_r($rs2->fields); # shows array(['col1']=>'v0',['col2'] =>'v1')
-
-
- $db->SetFetchMode(ADODB_FETCH_NUM);
- $rs1 = $db->Execute('select * from table');
- $db->SetFetchMode(ADODB_FETCH_ASSOC);
- $rs2 = $db->Execute('select * from table');
- print_r($rs1->fields); # shows array([0]=>'v0',[1] =>'v1')
- print_r($rs2->fields); # shows array(['col1']=>'v0',['col2'] =>'v1')
-
- 1 = assoc uppercase field names. $rs->fields['ORDERID']
- 2 = use native-case field names. $rs->fields['OrderID'] -- this is the
- default since ADOdb 2.90
- include('adodb.inc.php');
-ADOConnection
-ADOConnection Fields
-
-ADOConnection Main Functions
- # $oraname in tnsnames.ora/ONAMES/HOSTNAMES
- $conn->Connect(false, 'scott', 'tiger', $oraname);
- $conn->Connect('server:1521', 'scott', 'tiger', 'ServiceName'); # bypass tnsnames.ora
- $conn = &NewADOConnection('mysql');
- $conn->autoRollback = true; # default is false
- $conn->PConnect(...); # rollback here
-
- $conn->Execute("SELECT * FROM TABLE WHERE COND=:val", array('val'=> $val));
-
-
- $conn->Execute("SELECT * FROM TABLE WHERE COND=?", array($val));
-
-Binding variables
-Variable binding speeds the compilation and caching of SQL statements, leading
-to higher performance. Currently Oracle and ODBC support variable binding. ODBC
-style ? binding is emulated in databases that do not support binding.
-
-$rs = $db->Execute('select * from table where val=?', array('10'));
-
-Variable binding in the oci8 driver.
-
-$rs = $db->Execute('select name from table where val=:key',
- array('key' => 10));
-
-
- include('adodb.inc.php');
- include('tohtml.inc.php');
- $ADODB_CACHE_DIR = '/usr/local/ADOdbcache';
- $conn = &ADONewConnection('mysql');
- $conn->PConnect('localhost','userid','password','database');
- $rs = $conn->CacheExecute(15, 'select * from table'); # cache 15 secs
- rs2html($rs); /* recordset to html table */
-
-
- $conn->Connect(...);
- $conn->cacheSecs = 3600*24; // cache 24 hours
- $rs = $conn->CacheExecute('select * from table');
-
-Note that the $secs2cache parameter is optional. If omitted, we use the value
-in $connection->cacheSecs (default is 3600 seconds, or 1 hour). Use CacheExecute()
-only with SELECT statements.
-
- $db = ADONewConnection("oci8");
- $db->Connect("foo.com:1521", "uid", "pwd", "FOO");
- $rs = $db->ExecuteCursor("begin :cursorvar := getdata(:param1); end;",
- 'cursorvar',
- array('param1'=>10));
- # $rs is now just like any other ADOdb recordset object
-
rs2html($rs);
- $stmt = $db->Prepare("BEGIN :RS := SP_FOO(); END;");
- $db->Parameter($stmt, $cur, 'RS', false, -1, OCI_B_CURSOR);
- $rs = $db->Execute($stmt);
-$connection->SelectLimit('SELECT * FROM TABLE',3).
- This functionality is simulated for databases that do not possess this feature.$connection->SelectLimit('SELECT
- * FROM TABLE',3,2).$connection->SelectLimit('SELECT * FROM TABLE',-1,10) to
- get rows 11 to the last row.
- $conn->SelectLimit("SELECT * FROM TABLE WHERE COND=:val", 100,-1,array('val'=> $val));
-
-
- $conn->SelectLimit("SELECT * FROM TABLE WHERE COND=?", 100,-1,array('val'=> $val));
-
- $conn->Connect(...);
- $conn->cacheSecs = 3600*24; // cache 24 hours
- $rs = $conn->CacheSelectLimit('select * from table',10);
-
-
- system("rm -f `find ".$ADODB_CACHE_DIR." -name
- adodb_*.cache`");
- #------------------------------------------------------
- # This particular example deletes files in the TMPPATH
- # directory with the string ".cache" in their name that
- # are more than 7 days old.
- #------------------------------------------------------
- AGED=7
- find ${TMPPATH} -mtime +$AGED | grep "\.cache" | xargs rm -f
-
- # for oracle
- $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, empty_blob())');
- $conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1');
-
- # non oracle databases
- $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
- $conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1');
-
-
-
- If you do not pass in an oid, then UpdateBlob() assumes that you are storing
- in bytea fields.
-
- # for oracle
- $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, empty_clob())');
- $conn->UpdateBlob('clobtable','clobcol',$clobvalue,'id=1');
-
- # non oracle databases
- $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
- $conn->UpdateBlob('clobtable','clobcol',$clobvalue,'id=1');
-
-
- 'I' - blob encoding required, and returned encoded blob is a numeric value
- (no need to quote).
- 'C' - blob encoding required, and returned encoded blob is a character value
- (requires quoting).
-$rs = $db->Execute("select bloboid from postgres_table where id=$key");
-$blob = $db->BlobDecode( reset($rs->fields) );
-
-# single field primary key
-$ret = $db->Replace('atable',
- array('id'=>1000,'firstname'=>'Harun','lastname'=>'Al-Rashid'),
- 'id',
- 'firstname',$autoquote = true);
-# generates UPDATE atable SET firstname='Harun',lastname='Al-Rashid' WHERE id=1000
-# or INSERT INTO atable (id,firstname,lastname) VALUES (1000,'Harun','Al-Rashid')
-
-# compound key
-$ret = $db->Replace('atable2',
- array('firstname'=>'Harun','lastname'=>'Al-Rashid', 'age' => 33, 'birthday' => 'null'),
- array('lastname','firstname'),
- 'firstname',$autoquote = true);
-
-# no auto-quoting
-$ret = $db->Replace('atable2',
- array('firstname'=>"'Harun'",'lastname'=>"'Al-Rashid'", 'age' => 'null'),
- array('lastname','firstname'),
- 'firstname');
-
-
-
-$DB->BeginTrans();
-$DB->Execute("update table1 set val=$val1 where id=$id");
-$DB->Execute("update table2 set val=$val2 where id=$id");
-$DB->CommitTrans();
-
-
-$DB->BeginTrans();
-$ok = $DB->Execute("update table1 set val=$val1 where id=$id");
-if ($ok) $ok = $DB->Execute("update table2 set val=$val2 where id=$id");
-if ($ok) $DB->CommitTrans();
-else $DB->RollbackTrans();
-
-
-$DB->BeginTrans();
-$ok = $DB->Execute("update table1 set val=$val1 where id=$id");
-if ($ok) $ok = $DB->Execute("update table2 set val=$val2 where id=$id");
-$DB->CommitTrans($ok);
-
-
-$DB->StartTrans();
-CallBlackBox();
-$DB->Execute("update table1 set val=$val1 where id=$id");
-$DB->Execute("update table2 set val=$val2 where id=$id");
-$DB->CompleteTrans($ok);
-
-Detecting Transactions
- $stmt = $DB->Prepare('insert into table (col1,col2) values (?,?)');
-for ($i=0; $i < $max; $i++)
-
$DB->Execute($stmt,array((string) rand(), $i));
-
-
- $stmt Statement returned by Prepare() or PrepareSP().
- $var PHP variable to bind to. Make sure you pre-initialize it!
- $name Name of stored procedure variable name to bind to.
- [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT
- 2= IN/OUT. This is ignored in oci8 as this driver auto-detects the direction.
- [$maxLen] Maximum length of the parameter variable.
- [$type] Consult mssql_bind and ocibindbyname
- docs at php.net for more info on legal values for type.# @RETVAL = SP_RUNSOMETHING @myid,@group
-
$stmt = $db->PrepareSP('SP_RUNSOMETHING');
# note that the parameter name does not have @ in front!
$db->Parameter($stmt,$id,'myid');
$db->Parameter($stmt,$group,'group',false,64);
# return value in mssql - RETVAL is hard-coded name
$db->Parameter($stmt,$ret,'RETVAL',true);
$db->Execute($stmt); # For oracle, Prepare and PrepareSP are identical
-$stmt = $db->PrepareSP(
- "declare RETVAL integer;
-
begin
:RETVAL := SP_RUNSOMETHING(:myid,:group);
end;");
$db->Parameter($stmt,$id,'myid');
$db->Parameter($stmt,$group,'group',false,64);
-$db->Parameter($stmt,$ret,'RETVAL',true);
$db->Execute($stmt);
-$id = 0; $i = 0;
-$stmt = $db->PrepareSP( "update table set val=:i where id=:id");
-$db->Parameter($stmt,$id,'id');
-$db->Parameter($stmt,$i, 'i');
-for ($cnt=0; $cnt < 1000; $cnt++) {
- $id = $cnt;
-
$i = $cnt * $cnt; # works with oci8!
- $db->Execute($stmt);
}$stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)");
-$DB->Bind($stmt, $p1);
-$DB->Bind($stmt, $p2);
-$DB->Bind($stmt, $p3);
-for ($i = 0; $i < $max; $i++) {
- $p1 = ?; $p2 = ?; $p3 = ?;
- $DB->Execute($stmt);
-}
-
-$stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:name0, :name1, :name2)");
-$DB->Bind($stmt, $p1, "name0");
-$DB->Bind($stmt, $p2, "name1");
-$DB->Bind($stmt, $p3, "name2");
-for ($i = 0; $i < $max; $i++) {
- $p1 = ?; $p2 = ?; $p3 = ?;
- $DB->Execute($stmt);
-}
-
-# $db is the connection object
-function CountExecs($db, $sql, $inputarray)
-{
-
global $EXECS; $EXECS++;
-}
-
-# $db is the connection object
-function CountCachedExecs($db, $secs2cache, $sql, $inputarray)
-{
global $CACHED; $CACHED++;
-}
-
$db = NewADOConnection('mysql');
-$db->Connect(...);
-$db->fnExecute = 'CountExecs';
-$db->fnCacheExecute = 'CountCachedExecs';
- :
- :
# After many sql statements:`
-printf("<p>Total queries=%d; total cached=%d</p>",$EXECS+$CACHED, $CACHED);
-ADOConnection Utility Functions
-
-
-ADORecordSet
-ADORecordSet Fields
-ADORecordSet Functions
-
- row2: Cactus, Plant, Inedible
- row3: Rose, Flower, Edible
- Cactus => [Plant, Inedible]
- Rose => [Flower,Edible]GetMenu('menu1','A',true) will generate a menu:
-
- for the data (A,1), (B,2), (C,3). Also see example 5.GetMenu('menu1',array('A','B'),false)
- will generate a menu with both A and B selected:
-
-GetMenu2('menu1',array('1','2'),false)
- will generate a menu with both A and B selected in menu example 2, but this
- time the selection is based on the 2nd column, which holds the values to return
- to the Web server.
-# get date one week from now
-$fld = $conn->OffsetDate(7); // returns "(trunc(sysdate)+7")
-# get date and time that is 60 hours from current date and time
-$fld = $conn->OffsetDate(2.5, $conn->sysTimeStamp); // returns "(sysdate+2.5)"
-
-$conn->Execute("UPDATE TABLE SET dodate=$fld WHERE ID=$id");
-
- Y: 4-digit Year
- Q: Quarter (1-4)
- M: Month (01-12)
- D: Day (01-31)
-
- $sqlfn = $db->SQLDate('Y-\QQ','postdate'); # get sql that formats postdate to output 2002-Q1
- $sql = "SELECT $sqlfn,SUM(cogs) FROM table GROUP BY $sqlfn ORDER BY 1 desc";
-
-
-$rs = $db->Execute($sql);
-if ($rs)
- while (!$rs->EOF) {
- ProcessArray($rs->fields);
- $rs->MoveNext();
- }
-
-
- Array ( [ID] => 1 [FIRSTNAME] => Caroline [LASTNAME] => Miranda [CREATED] =>
- 2001-07-05 ) $rs = $db->Execute($sql);
-if ($rs)
- while ($arr = $rs->FetchRow()) {
- # process $arr
- }
-
-
-$rs = $db->Execute('execute return_multiple_rs');
-$arr1 = $rs->GetArray();
-$rs->NextRecordSet();
-$arr2 = $rs->GetArray();
-
-
-$rs = $db->Execute('select firstname,lastname from table');
-if ($rs) {
- while ($o = $rs->FetchNextObject()) {
- print "$o->FIRSTNAME, $o->LASTNAME<BR>";
- }
-}
-
-fields[] array.
-FetchObj()
-
-
-
-
-function rs2html($adorecordset,[$tableheader_attributes],
- [$col_titles])
-<?
-include('tohtml.inc.php'); # load code common to ADOdb
-include('adodb.inc.php'); # load code common to ADOdb
-$conn = &ADONewConnection('mysql'); # create a connection
-$conn->PConnect('localhost','userid','','agora');# connect to MySQL, agora db
-$sql = 'select CustomerName, CustomerID from customers';
-$rs = $conn->Execute($sql);
-rs2html($rs,'border=2 cellpadding=3',array('Customer Name','Customer ID'));
-?>
-
-Differences between this ADOdb library and Microsoft ADO
-
-
-
-Database Driver Guide
-ToDo:
-Change Log
-
-$conn->charPage = CP_UTF8;
-$conn->Connect($dsn);
-
-
-Old changelog history moved to old-changelog.htm.
-