";
+}
+*/
+?>
diff --git a/lib/adodb/adodb-csvlib.inc.php b/lib/adodb/adodb-csvlib.inc.php
new file mode 100644
index 0000000000..4b93f22741
--- /dev/null
+++ b/lib/adodb/adodb-csvlib.inc.php
@@ -0,0 +1,272 @@
+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, 8192, ",")) {
+ // 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 = fgetcsv($fp, 8192, ",");
+ 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";
+ //print "$url ";print_r($meta);
+ //die();
+ return false;
+ }
+
+ // slurp in the data
+ $MAXSIZE = 128000;
+ $text = fread($fp,$MAXSIZE);
+ if (strlen($text) == $MAXSIZE) {
+ $text .= fread($fp,filesize($url)-$MAXSIZE);
+ }
+
+ fclose($fp);
+ //$text = substr($text,0,44);
+ $arr = @unserialize($text);
+
+ //var_dump($arr);
+ if (!is_array($arr)) {
+ $err = "Recordset had unexpected EOF 3";
+ return false;
+ }
+ $rs = new ADORecordSet_array();
+ $rs->timeCreated = $ttl;
+ $rs->InitArrayFields($arr,$flds);
+ return $rs;
+ }
+
+ /*
+ # The following code was an alternative method of saving
+ # recordsets and is experimental and was never used.
+ # It is faster, but provides very little error checking.
+
+ //High speed rs2csv 10% faster
+ function & xrs2csv(&$rs)
+ {
+ return time()."\n".serialize($rs);
+ }
+ function & xcsv2rs($url,&$err,$timeout)
+ {
+ $t = filemtime($url);// this is cached - should we clearstatcache() ?
+ if ($t === false) {
+ $err = 'File not found 1';
+ return false;
+ }
+
+ if (time() > $t + $timeout){
+ $err = " Timeout 1";
+ return false;
+ }
+
+ $fp = @fopen($url,'r');
+ if (!$fp) {
+ $err = ' file not found ';
+ return false;
+ }
+
+ flock($fp,LOCK_SH);
+ $t = fgets($fp,100);
+ if ($t === false){
+ fclose($fp);
+ $err = " EOF 1 ";
+ return false;
+ }
+ /*
+ if (time() > ((integer)$t) + $timeout){
+ fclose($fp);
+ $err = " Timeout 2";
+ return false;
+ }* /
+
+ $txt = &fread($fp,1999999); // Increase if EOF 2 error returned
+ fclose($fp);
+ $o = @unserialize($txt);
+ if (!is_object($o)) {
+ $err = " EOF 2";
+ return false;
+ }
+ $o->timeCreated = $t;
+ return $o;
+ }
+ */
+?>
\ No newline at end of file
diff --git a/lib/adodb/adodb-errorhandler.inc.php b/lib/adodb/adodb-errorhandler.inc.php
new file mode 100644
index 0000000000..9bf1c3632c
--- /dev/null
+++ b/lib/adodb/adodb-errorhandler.inc.php
@@ -0,0 +1,73 @@
+$s
";
+ trigger_error($s,E_USER_ERROR);
+}
+?>
diff --git a/lib/adodb/adodb-errorpear.inc.php b/lib/adodb/adodb-errorpear.inc.php
new file mode 100644
index 0000000000..0ca4aa5b9b
--- /dev/null
+++ b/lib/adodb/adodb-errorpear.inc.php
@@ -0,0 +1,86 @@
+!$s";
+}
+
+/**
+* Returns last PEAR_Error object. This error might be for an error that
+* occured several sql statements ago.
+*/
+function &ADODB_PEAR_Error()
+{
+global $ADODB_Last_PEAR_Error;
+
+ return $ADODB_Last_PEAR_Error;
+}
+
+?>
\ No newline at end of file
diff --git a/lib/adodb/adodb-lib.inc.php b/lib/adodb/adodb-lib.inc.php
new file mode 100644
index 0000000000..e20d81c6c5
--- /dev/null
+++ b/lib/adodb/adodb-lib.inc.php
@@ -0,0 +1,276 @@
+rowsPerPage) {
+ $rows = ($rs->RecordCount()+$rs->rowsPerPage-1) / $rs->rowsPerPage;
+ if ($rows < 0) return -1;
+ else return $rows;
+ } else return -1;
+}
+
+// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM
+function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
+ $size=0, $selectAttr='',$compareFields0=true)
+{
+ $hasvalue = false;
+
+ if ($multiple or is_array($defstr)) {
+ if ($size==0) $size=5;
+ $attr = " multiple size=$size";
+ if (!strpos($name,'[]')) $name .= '[]';
+ } else if ($size) $attr = " size=$size";
+ else $attr ='';
+
+
+ $s = "\n";
+}
+
+function &_adodb_pageexecute(&$zthis, $sql, $nrows, $page, $inputarr=false, $arg3=false, $secs2cache=0)
+{
+
+ $atfirstpage = false;
+ $atlastpage = false;
+
+ if (!isset($page) || $page <= 1) { // If page number <= 1, then we are at the first page
+ $page = 1;
+ $atfirstpage = true;
+ }
+ if ($nrows <= 0) $nrows = 10; // If an invalid nrows is supplied, we assume a default value of 10 rows per page
+
+ // ***** Here we check whether $page is the last page or whether we are trying to retrieve a page number greater than
+ // the last page number.
+ $pagecounter = $page + 1;
+ $pagecounteroffset = ($pagecounter * $nrows) - $nrows;
+ if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr, $arg3);
+ else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $arg3, $secs2cache);
+ if ($rstest) {
+ while ($rstest && $rstest->EOF && $pagecounter>0) {
+ $atlastpage = true;
+ $pagecounter--;
+ $pagecounteroffset = $nrows * ($pagecounter - 1);
+ $rstest->Close();
+ if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr, $arg3);
+ else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $arg3, $secs2cache);
+ }
+ if ($rstest) $rstest->Close();
+ }
+ if ($atlastpage) { // If we are at the last page or beyond it, we are going to retrieve it
+ $page = $pagecounter;
+ if ($page == 1) $atfirstpage = true; // We have to do this again in case the last page is the same as the first
+ //... page, that is, the recordset has only 1 page.
+ }
+
+ // We get the data we want
+ $offset = $nrows * ($page-1);
+ if ($secs2cache > 0) $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr, $arg3);
+ else $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $arg3, $secs2cache);
+
+ // Before returning the RecordSet, we set the pagination properties we need
+ if ($rsreturn) {
+ $rsreturn->rowsPerPage = $nrows;
+ $rsreturn->AbsolutePage($page);
+ $rsreturn->AtFirstPage($atfirstpage);
+ $rsreturn->AtLastPage($atlastpage);
+ }
+ return $rsreturn;
+}
+
+function _adodb_getupdatesql(&$zthis,&$rs, $arrFields,$forceUpdate=false,$magicq=false)
+{
+ if (!$rs) {
+ printf(ADODB_BAD_RS,'GetUpdateSQL');
+ return false;
+ }
+
+ $fieldUpdatedCount = 0;
+
+ // Get the table name from the existing query.
+ preg_match("/FROM\s".ADODB_TABLE_REGEX."/i", $rs->sql, $tableName);
+
+ // Get the full where clause excluding the word "WHERE" from
+ // the existing query.
+ preg_match("/WHERE\s(.*)/i", $rs->sql, $whereClause);
+
+ // updateSQL will contain the full update query when all
+ // processing has completed.
+ $updateSQL = "UPDATE " . $tableName[1] . " SET ";
+
+ // Loop through all of the fields in the recordset
+ for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
+
+ // Get the field from the recordset
+ $field = $rs->FetchField($i);
+
+ // If the recordset field is one
+ // of the fields passed in then process.
+ if (isset($arrFields[$field->name])) {
+
+ // If the existing field value in the recordset
+ // is different from the value passed in then
+ // go ahead and append the field name and new value to
+ // the update query.
+
+ if ($forceUpdate || strcmp($rs->fields[$i], $arrFields[$field->name])) {
+ // Set the counter for the number of fields that will be updated.
+ $fieldUpdatedCount++;
+
+ // Based on the datatype of the field
+ // Format the value properly for the database
+ $mt = $rs->MetaType($field->type);
+
+ // "mike" patch and "Ryan Bailey"
+ //PostgreSQL uses a 't' or 'f' and therefore needs to be processed as a string ('C') type field.
+ if ((substr($zthis->databaseType,0,8) == "postgres") && ($mt == "L")) $mt = "C";
+
+ switch($mt) {
+ case "C":
+ case "X":
+ $updateSQL .= $field->name . " = " . $zthis->qstr($arrFields[$field->name],$magicq) . ", ";
+ break;
+ case "D":
+ $updateSQL .= $field->name . " = " . $zthis->DBDate($arrFields[$field->name]) . ", ";
+ break;
+ case "T":
+ $updateSQL .= $field->name . " = " . $zthis->DBTimeStamp($arrFields[$field->name]) . ", ";
+ break;
+ default:
+ $updateSQL .= $field->name . " = " . (float) $arrFields[$field->name] . ", ";
+ break;
+ };
+ };
+ };
+ };
+
+ // If there were any modified fields then build the rest of the update query.
+ if ($fieldUpdatedCount > 0 || $forceUpdate) {
+ // Strip off the comma and space on the end of the update query.
+ $updateSQL = substr($updateSQL, 0, -2);
+
+ // If the recordset has a where clause then use that same where clause
+ // for the update.
+ if ($whereClause[1]) $updateSQL .= " WHERE " . $whereClause[1];
+
+ return $updateSQL;
+ } else {
+ return false;
+ };
+}
+
+function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false)
+{
+ $values = '';
+ $fields = '';
+
+ if (!$rs) {
+ printf(ADODB_BAD_RS,'GetInsertSQL');
+ return false;
+ }
+
+ $fieldInsertedCount = 0;
+
+ // Get the table name from the existing query.
+ preg_match("/FROM\s".ADODB_TABLE_REGEX."/i", $rs->sql, $tableName);
+
+ // Loop through all of the fields in the recordset
+ for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
+
+ // Get the field from the recordset
+ $field = $rs->FetchField($i);
+ // If the recordset field is one
+ // of the fields passed in then process.
+ if (isset($arrFields[$field->name])) {
+
+ // Set the counter for the number of fields that will be inserted.
+ $fieldInsertedCount++;
+
+ // Get the name of the fields to insert
+ $fields .= $field->name . ", ";
+
+ $mt = $rs->MetaType($field->type);
+
+ // "mike" patch and "Ryan Bailey"
+ //PostgreSQL uses a 't' or 'f' and therefore needs to be processed as a string ('C') type field.
+ if ((substr($zthis->databaseType,0,8) == "postgres") && ($mt == "L")) $mt = "C";
+
+ // Based on the datatype of the field
+ // Format the value properly for the database
+ switch($mt) {
+ case "C":
+ case "X":
+ $values .= $zthis->qstr($arrFields[$field->name],$magicq) . ", ";
+ break;
+ case "D":
+ $values .= $zthis->DBDate($arrFields[$field->name]) . ", ";
+ break;
+ case "T":
+ $values .= $zthis->DBTimeStamp($arrFields[$field->name]) . ", ";
+ break;
+ default:
+ $values .= (float) $arrFields[$field->name] . ", ";
+ break;
+ };
+ };
+ };
+
+ // If there were any inserted fields then build the rest of the insert query.
+ if ($fieldInsertedCount > 0) {
+
+ // Strip off the comma and space on the end of both the fields
+ // and their values.
+ $fields = substr($fields, 0, -2);
+ $values = substr($values, 0, -2);
+
+ // Append the fields and their values to the insert query.
+ $insertSQL = "INSERT INTO " . $tableName[1] . " ( $fields ) VALUES ( $values )";
+
+ return $insertSQL;
+
+ } else {
+ return false;
+ };
+}
+?>
\ No newline at end of file
diff --git a/lib/adodb/adodb-pear.inc.php b/lib/adodb/adodb-pear.inc.php
new file mode 100644
index 0000000000..474c30124d
--- /dev/null
+++ b/lib/adodb/adodb-pear.inc.php
@@ -0,0 +1,342 @@
+ |
+ * and Tomas V.V.Cox
+ */
+
+ /*
+ We support:
+
+ DB_Common
+ ---------
+ query - returns PEAR_Error on error
+ limitQuery - return PEAR_Error on error
+ prepare - does not return PEAR_Error on error
+ execute - does not return PEAR_Error on error
+ setFetchMode - supports ASSOC and ORDERED
+ errorNative
+ quote
+ nextID
+ disconnect
+
+ DB_Result
+ ---------
+ numRows - returns -1 if not supported
+ numCols
+ fetchInto - does not support passing of fetchmode
+ fetchRows - does not support passing of fetchmode
+ free
+ */
+
+define('ADODB_PEAR',dirname(__FILE__));
+require_once "PEAR.php";
+require_once ADODB_PEAR."/adodb-errorpear.inc.php";
+require_once ADODB_PEAR."/adodb.inc.php";
+
+if (!defined('DB_OK')) {
+define("DB_OK", 1);
+define("DB_ERROR",-1);
+/**
+ * This is a special constant that tells DB the user hasn't specified
+ * any particular get mode, so the default should be used.
+ */
+
+define('DB_FETCHMODE_DEFAULT', 0);
+
+/**
+ * Column data indexed by numbers, ordered from 0 and up
+ */
+
+define('DB_FETCHMODE_ORDERED', 1);
+
+/**
+ * Column data indexed by column names
+ */
+
+define('DB_FETCHMODE_ASSOC', 2);
+
+/* for compatibility */
+
+define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED);
+define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC);
+
+/**
+ * these are constants for the tableInfo-function
+ * they are bitwised or'ed. so if there are more constants to be defined
+ * in the future, adjust DB_TABLEINFO_FULL accordingly
+ */
+
+define('DB_TABLEINFO_ORDER', 1);
+define('DB_TABLEINFO_ORDERTABLE', 2);
+define('DB_TABLEINFO_FULL', 3);
+}
+
+/**
+ * The main "DB" class is simply a container class with some static
+ * methods for creating DB objects as well as some utility functions
+ * common to all parts of DB.
+ *
+ */
+
+class DB
+{
+ /**
+ * Create a new DB object for the specified database type
+ *
+ * @param $type string database type, for example "mysql"
+ *
+ * @return object a newly created DB object, or a DB error code on
+ * error
+ */
+
+ function &factory($type)
+ {
+ include_once(ADODB_DIR."/drivers/adodb-$type.inc.php");
+ $obj = &NewADOConnection($type);
+ if (!is_object($obj)) return new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
+ return $obj;
+}
+
+ /**
+ * Create a new DB object and connect to the specified database
+ *
+ * @param $dsn mixed "data source name", see the DB::parseDSN
+ * method for a description of the dsn format. Can also be
+ * specified as an array of the format returned by DB::parseDSN.
+ *
+ * @param $options mixed if boolean (or scalar), tells whether
+ * this connection should be persistent (for backends that support
+ * this). This parameter can also be an array of options, see
+ * DB_common::setOption for more information on connection
+ * options.
+ *
+ * @return object a newly created DB connection object, or a DB
+ * error object on error
+ *
+ * @see DB::parseDSN
+ * @see DB::isError
+ */
+ function &connect($dsn, $options = false)
+ {
+ if (is_array($dsn)) {
+ $dsninfo = $dsn;
+ } else {
+ $dsninfo = DB::parseDSN($dsn);
+ }
+ switch ($dsninfo["phptype"]) {
+ case 'pgsql': $type = 'postgres7'; break;
+ case 'ifx': $type = 'informix9'; break;
+ default: $type = $dsninfo["phptype"]; break;
+ }
+
+ if (is_array($options) && isset($options["debug"]) &&
+ $options["debug"] >= 2) {
+ // expose php errors with sufficient debug level
+ @include_once("adodb-$type.inc.php");
+ } else {
+ @include_once("adodb-$type.inc.php");
+ }
+
+ @$obj =&NewADOConnection($type);
+ if (!is_object($obj)) return new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
+
+ if (is_array($options)) {
+ $persist = !empty($options['persistent']);
+ } else {
+ $persist = true;
+ }
+
+ if($persist) $ok = $obj->PConnect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
+ else $ok = $obj->Connect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
+
+ if (!$ok) return ADODB_PEAR_Error();
+ return $obj;
+ }
+
+ /**
+ * Return the DB API version
+ *
+ * @return int the DB API version number
+ */
+ function apiVersion()
+ {
+ return 2;
+ }
+
+ /**
+ * Tell whether a result code from a DB method is an error
+ *
+ * @param $value int result code
+ *
+ * @return bool whether $value is an error
+ */
+ function isError($value)
+ {
+ return (is_object($value) &&
+ (get_class($value) == 'db_error' ||
+ is_subclass_of($value, 'db_error')));
+ }
+
+
+ /**
+ * Tell whether a result code from a DB method is a warning.
+ * Warnings differ from errors in that they are generated by DB,
+ * and are not fatal.
+ *
+ * @param $value mixed result value
+ *
+ * @return bool whether $value is a warning
+ */
+ function isWarning($value)
+ {
+ return is_object($value) &&
+ (get_class( $value ) == "db_warning" ||
+ is_subclass_of($value, "db_warning"));
+ }
+
+ /**
+ * Parse a data source name
+ *
+ * @param $dsn string Data Source Name to be parsed
+ *
+ * @return array an associative array with the following keys:
+ *
+ * phptype: Database backend used in PHP (mysql, odbc etc.)
+ * dbsyntax: Database used with regards to SQL syntax etc.
+ * protocol: Communication protocol to use (tcp, unix etc.)
+ * hostspec: Host specification (hostname[:port])
+ * database: Database to use on the DBMS server
+ * username: User name for login
+ * password: Password for login
+ *
+ * The format of the supplied DSN is in its fullest form:
+ *
+ * phptype(dbsyntax)://username:password@protocol+hostspec/database
+ *
+ * Most variations are allowed:
+ *
+ * phptype://username:password@protocol+hostspec:110//usr/db_file.db
+ * phptype://username:password@hostspec/database_name
+ * phptype://username:password@hostspec
+ * phptype://username@hostspec
+ * phptype://hostspec/database
+ * phptype://hostspec
+ * phptype(dbsyntax)
+ * phptype
+ *
+ * @author Tomas V.V.Cox
+ */
+ function parseDSN($dsn)
+ {
+ if (is_array($dsn)) {
+ return $dsn;
+ }
+
+ $parsed = array(
+ 'phptype' => false,
+ 'dbsyntax' => false,
+ 'protocol' => false,
+ 'hostspec' => false,
+ 'database' => false,
+ 'username' => false,
+ 'password' => false
+ );
+
+ // Find phptype and dbsyntax
+ if (($pos = strpos($dsn, '://')) !== false) {
+ $str = substr($dsn, 0, $pos);
+ $dsn = substr($dsn, $pos + 3);
+ } else {
+ $str = $dsn;
+ $dsn = NULL;
+ }
+
+ // Get phptype and dbsyntax
+ // $str => phptype(dbsyntax)
+ if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
+ $parsed['phptype'] = $arr[1];
+ $parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : $arr[2];
+ } else {
+ $parsed['phptype'] = $str;
+ $parsed['dbsyntax'] = $str;
+ }
+
+ if (empty($dsn)) {
+ return $parsed;
+ }
+
+ // Get (if found): username and password
+ // $dsn => username:password@protocol+hostspec/database
+ if (($at = strpos($dsn,'@')) !== false) {
+ $str = substr($dsn, 0, $at);
+ $dsn = substr($dsn, $at + 1);
+ if (($pos = strpos($str, ':')) !== false) {
+ $parsed['username'] = urldecode(substr($str, 0, $pos));
+ $parsed['password'] = urldecode(substr($str, $pos + 1));
+ } else {
+ $parsed['username'] = urldecode($str);
+ }
+ }
+
+ // Find protocol and hostspec
+ // $dsn => protocol+hostspec/database
+ if (($pos=strpos($dsn, '/')) !== false) {
+ $str = substr($dsn, 0, $pos);
+ $dsn = substr($dsn, $pos + 1);
+ } else {
+ $str = $dsn;
+ $dsn = NULL;
+ }
+
+ // Get protocol + hostspec
+ // $str => protocol+hostspec
+ if (($pos=strpos($str, '+')) !== false) {
+ $parsed['protocol'] = substr($str, 0, $pos);
+ $parsed['hostspec'] = urldecode(substr($str, $pos + 1));
+ } else {
+ $parsed['hostspec'] = urldecode($str);
+ }
+
+ // Get dabase if any
+ // $dsn => database
+ if (!empty($dsn)) {
+ $parsed['database'] = $dsn;
+ }
+
+ return $parsed;
+ }
+
+ /**
+ * Load a PHP database extension if it is not loaded already.
+ *
+ * @access public
+ *
+ * @param $name the base name of the extension (without the .so or
+ * .dll suffix)
+ *
+ * @return bool true if the extension was already or successfully
+ * loaded, false if it could not be loaded
+ */
+ function assertExtension($name)
+ {
+ if (!extension_loaded($name)) {
+ $dlext = (substr(PHP_OS, 0, 3) == 'WIN') ? '.dll' : '.so';
+ @dl($name . $dlext);
+ }
+ if (!extension_loaded($name)) {
+ return false;
+ }
+ return true;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/lib/adodb/adodb-session.php b/lib/adodb/adodb-session.php
new file mode 100644
index 0000000000..0306f6ee7e
--- /dev/null
+++ b/lib/adodb/adodb-session.php
@@ -0,0 +1,229 @@
+\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}";
+
+
+ Installation
+ ============
+ 1. Create a new database in MySQL or Access "sessions" like
+so:
+
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY int(11) unsigned not null,
+ 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.2 or later. There are documented
+session bugs in
+ earlier versions of PHP.
+
+*/
+
+if (!defined('_ADODB_LAYER')) {
+ include ('adodb.inc.php');
+}
+
+
+
+if (!defined('ADODB_SESSION')) {
+
+ define('ADODB_SESSION',1);
+
+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_SESS_INSERT;
+
+ //$ADODB_SESS_DEBUG = true;
+
+ /* SET THE FOLLOWING PARAMETERS */
+if (empty($ADODB_SESSION_DRIVER)) {
+ $ADODB_SESSION_DRIVER='mysql';
+ $ADODB_SESSION_CONNECT='localhost';
+ $ADODB_SESSION_USER ='root';
+ $ADODB_SESSION_PWD ='';
+ $ADODB_SESSION_DB ='xphplens_2';
+}
+if (empty($ADODB_SESSION_TBL)){
+ $ADODB_SESSION_TBL = 'sessions';
+}
+
+$ADODB_SESS_LIFE = get_cfg_var('session.gc_maxlifetime');
+if ($ADODB_SESS_LIFE <= 1) {
+ // bug in PHP 4.0.3 pl 1 -- how about other versions?
+ //print "
";
+}
+
+?>
diff --git a/lib/adodb/adodb.inc.php b/lib/adodb/adodb.inc.php
new file mode 100644
index 0000000000..a33969a5fc
--- /dev/null
+++ b/lib/adodb/adodb.inc.php
@@ -0,0 +1,2369 @@
+Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;');
+
+ define('ADODB_FETCH_DEFAULT',0);
+ define('ADODB_FETCH_NUM',1);
+ define('ADODB_FETCH_ASSOC',2);
+ define('ADODB_FETCH_BOTH',3);
+
+ // allow [ ] @ and . in table names
+ define('ADODB_TABLE_REGEX','([]0-9a-z_\.\@\[-]*)');
+ if (!defined('MAX_BLOB_SIZE')) define('MAX_BLOB_SIZE',999999); // 900K
+
+ if (!defined('ADODB_PREFETCH_ROWS')) define('ADODB_PREFETCH_ROWS',10);
+
+ /**
+ * Set ADODB_DIR to the directory where this file resides...
+ * This constant was formerly called $ADODB_RootPath
+ */
+ if (!defined('ADODB_DIR')) define('ADODB_DIR',dirname(__FILE__));
+
+ //==============================================================================================
+ // GLOBAL VARIABLES
+ //==============================================================================================
+
+ GLOBAL
+ $ADODB_vers, // database version
+ $ADODB_Database, // last database driver used
+ $ADODB_COUNTRECS, // count number of records returned - slows down query
+ $ADODB_CACHE_DIR, // directory to cache recordsets
+ $ADODB_FETCH_MODE; // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...
+
+ //==============================================================================================
+ // GLOBAL SETUP
+ //==============================================================================================
+
+ $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
+
+ if (!isset($ADODB_CACHE_DIR)) {
+ $ADODB_CACHE_DIR = '/tmp';
+ } else {
+ // do not accept url based paths, eg. http:/ or ftp:/
+ if (strpos($ADODB_CACHE_DIR,'://') !== false)
+ die("Illegal path http:// or ftp://");
+ }
+
+ //==============================================================================================
+ // CHANGE NOTHING BELOW UNLESS YOU ARE CODING
+ //==============================================================================================
+
+
+ // Initialize random number generator for randomizing cache flushes
+ srand(((double)microtime())*1000000);
+
+ /**
+ * Name of last database driver loaded into memory. Set by ADOLoadCode().
+ */
+ $ADODB_Database = '';
+
+ /**
+ * ADODB version as a string.
+ */
+ $ADODB_vers = 'V2.00 13 May 2002 (c) 2000-2002 John Lim (jlim@natsoft.com.my). All rights reserved. Released BSD & LGPL.';
+
+ /**
+ * Determines whether recordset->RecordCount() is used.
+ * Set to false for highest performance -- RecordCount() will always return -1 then
+ * for databases that provide "virtual" recordcounts...
+ */
+ $ADODB_COUNTRECS = true;
+
+ //==============================================================================================
+ // CLASS ADOFieldObject
+ //==============================================================================================
+
+ /**
+ * Helper class for FetchFields -- holds info on a column
+ */
+ class ADOFieldObject {
+ var $name = '';
+ var $max_length=0;
+ var $type="";
+
+ // additional fields by dannym... (danny_milo@yahoo.com)
+ var $not_null = false;
+ // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^
+ // so we can as well make not_null standard (leaving it at "false" does not harm anyways)
+
+ var $has_default = false; // this one I have done only in mysql and postgres for now ...
+ // others to come (dannym)
+ var $default_value; // default, if any, and supported. Check has_default first.
+ }
+
+
+ //==============================================================================================
+ // CLASS ADOConnection
+ //==============================================================================================
+
+ /**
+ * Connection object. For connecting to databases, and executing queries.
+ */
+ class ADOConnection {
+ /*
+ * PUBLIC VARS
+ */
+ var $dataProvider = 'native';
+ var $databaseType = ''; // RDBMS currently in use, eg. odbc, mysql, mssql
+ var $database = ''; // Name of database to be used.
+ var $host = ''; // The hostname of the database server
+ var $user = ''; // The username which is used to connect to the database server.
+ var $password = ''; // Password for the username
+ var $debug = false; // if set to true will output sql statements
+ var $maxblobsize = 8000; // maximum size of blobs or large text fields -- some databases die otherwise like foxpro
+ var $concat_operator = '+'; // default concat operator -- change to || for Oracle/Interbase
+ var $fmtDate = "'Y-m-d'"; // used by DBDate() as the default date format used by the database
+ var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; // used by DBTimeStamp as the default timestamp fmt.
+ var $true = '1'; // string that represents TRUE for a database
+ var $false = '0'; // string that represents FALSE for a database
+ var $replaceQuote = "\\'"; // string to use to replace quotes
+ var $hasInsertID = false; // supports autoincrement ID?
+ var $hasAffectedRows = false; // supports affected rows for update/delete?
+ var $charSet=false; // character set to use - only for interbase
+ var $metaTablesSQL = '';
+ var $hasTop = false; // support mssql/access SELECT TOP 10 * FROM TABLE
+ var $hasLimit = false; // support pgsql/mysql SELECT * FROM TABLE LIMIT 10
+ var $readOnly = false; // this is a readonly database - used by phpLens
+ var $hasMoveFirst = false; // has ability to run MoveFirst(), scrolling backwards
+ var $hasGenID = false; // can generate sequences using GenID();
+ var $genID = 0; // sequence id used by GenID();
+ var $raiseErrorFn = false; // error function to call
+ var $upperCase = false; // uppercase function to call for searching/where
+ var $isoDates = false; // accepts dates in ISO format
+ 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';
+ // oracle specific stuff
+ var $noNullStrings = false;
+
+ /*
+ * PRIVATE VARS
+ */
+ var $_connectionID = false; // The returned link identifier whenever a successful database connection is made. */
+
+ var $_errorMsg = ''; // A variable which was used to keep the returned last error message. The value will
+ //then returned by the errorMsg() function
+
+ var $_queryID = false; // This variable keeps the last created result link identifier. */
+
+ var $_isPersistentConnection = false; // A boolean variable to state whether its a persistent connection or normal connection. */
+
+ var $_bindInputArray = false; // set to true if ADOConnection.Execute() permits binding of array parameters.
+
+ var $autoCommit = true; // do not modify this yourself - actually private
+
+ /**
+ * Constructor
+ */
+ function ADOConnection()
+ {
+ die('Virtual Class -- cannot instantiate');
+ }
+
+
+ /**
+ * Connect to database
+ *
+ * @param [argHostname] Host to connect to
+ * @param [argUsername] Userid to login
+ * @param [argPassword] Associated password
+ * @param [argDatabaseName] database
+ *
+ * @return true or false
+ */
+ function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
+ {
+ if ($argHostname != "") $this->host = $argHostname;
+ if ($argUsername != "") $this->user = $argUsername;
+ if ($argPassword != "") $this->password = $argPassword; // not stored for security reasons
+ if ($argDatabaseName != "") $this->database = $argDatabaseName;
+
+ $this->_isPersistentConnection = false;
+ if ($fn = $this->raiseErrorFn) {
+ if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
+ $err = $this->ErrorMsg();
+ if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
+ $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database);
+ } else
+ if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
+
+ if ($this->debug) print $this->host.': '.$this->ErrorMsg()." \n";
+
+ return false;
+ }
+
+
+ /**
+ * Establish persistent connect to database
+ *
+ * @param [argHostname] Host to connect to
+ * @param [argUsername] Userid to login
+ * @param [argPassword] Associated password
+ * @param [argDatabaseName] database
+ *
+ * @return return true or false
+ */
+ function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
+ {
+ if ($argHostname != "") $this->host = $argHostname;
+ if ($argUsername != "") $this->user = $argUsername;
+ if ($argPassword != "") $this->password = $argPassword;
+ if ($argDatabaseName != "") $this->database = $argDatabaseName;
+
+ $this->_isPersistentConnection = true;
+
+ if ($fn = $this->raiseErrorFn) {
+ if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
+ $err = $this->ErrorMsg();
+ if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
+ $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database);
+ } else
+ if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
+
+ if ($this->debug) print $this->host.': '.$this->ErrorMsg()." \n";
+
+ return false;
+ }
+
+ function UnixDate($d)
+ {
+ return ADORecordSet::UnixDate($d);
+ }
+
+ /**
+ * 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 - do not use internally.
+ */
+ function Quote($s)
+ {
+ return $this->qstr($s);
+ }
+
+
+ /**
+ * PEAR DB Compat - do not use internally.
+ */
+ function ErrorNative()
+ {
+ return $this->ErrorNo();
+ }
+
+
+ /**
+ * PEAR DB Compat - do not use internally.
+ */
+ function nextId($seq_name)
+ {
+ return $this->GenID($seq_name);
+ }
+
+ /**
+ * 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 :-)
+ */
+ function SetFetchMode($mode)
+ {
+ global $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = $mode;
+ }
+
+
+ /**
+ * PEAR DB Compat - do not use internally.
+ */
+ function &Query($sql, $inputarr=false)
+ {
+ $rs = &$this->Execute($sql, $inputarr);
+ if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+ return $rs;
+ }
+
+
+ /**
+ * PEAR DB Compat - do not use internally
+ */
+ function &LimitQuery($sql, $offset, $count)
+ {
+ $rs = &$this->SelectLimit($sql, $count, $offset); // swap
+ if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+ return $rs;
+ }
+
+
+ /**
+ * PEAR DB Compat - do not use internally
+ */
+ function Disconnect()
+ {
+ return $this->Close();
+ }
+
+ /*
+ 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;
+ }
+
+ /**
+ * 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->_bindInputArray && $inputarr) {
+ $sqlarr = explode('?',$sql);
+ $sql = '';
+ $i = 0;
+ foreach($inputarr as $v) {
+
+ $sql .= $sqlarr[$i];
+ // from Ron Baldwin
+ // Only quote string types
+ if (gettype($v) == 'string')
+ $sql .= $this->qstr($v);
+ else if ($v === null)
+ $sql .= 'NULL';
+ else
+ $sql .= $v;
+ $i += 1;
+
+ }
+ $sql .= $sqlarr[$i];
+ if ($i+1 != sizeof($sqlarr))
+ print "Input Array does not match ?: ".htmlspecialchars($sql);
+ $inputarr = false;
+ }
+
+ // debug version of query
+ if ($this->debug) {
+ global $HTTP_SERVER_VARS;
+
+ $ss = '';
+ if ($inputarr) {
+ foreach ($inputarr as $kk => $vv) {
+ if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
+ $ss .= "($kk=>'$vv') ";
+ }
+ $ss = "[ $ss ]";
+ }
+ if (is_array($sql)) $sqlTxt = $sql[0];
+ else $sqlTxt = $sql;
+
+ // check if running from browser or command-line
+ $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
+
+ if ($inBrowser)
+ print "\n($this->databaseType): ".htmlspecialchars($sqlTxt)." $ss\n\n";
+ else
+ print "=----\n($this->databaseType): ".($sqlTxt)." \n-----\n";
+ flush();
+
+ $this->_queryID = $this->_query($sql,$inputarr,$arg3);
+
+ if ($this->databaseType == 'mssql') {
+ // ErrorNo is a slow function call in mssql, and not reliable
+ // in PHP 4.0.6
+ if($this->ErrorMsg()) {
+ $err = $this->ErrorNo();
+ if ($err) {
+ print $err.': '.$this->ErrorMsg().(($inBrowser) ? " \n" : "\n");
+ flush();
+ }
+ }
+ } else
+ if (!$this->_queryID) {
+ print $this->ErrorNo().': '.$this->ErrorMsg().(($inBrowser) ? " \n" : "\n");
+ flush();
+ }
+ } else
+ // non-debug version of query
+ $this->_queryID =@$this->_query($sql,$inputarr,$arg3);
+
+ // error handling if query fails
+ if ($this->_queryID === false) {
+ if ($fn = $this->raiseErrorFn) {
+ $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr);
+ }
+ return false;
+ } else if ($this->_queryID === true){
+ // 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); // &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;
+
+ global $ADODB_COUNTRECS;
+ if ($rs->_numOfRows <= 0 && !$rs->EOF && $ADODB_COUNTRECS) {
+ $rs = &$this->_rs2rs($rs);
+ $rs->_queryID = $this->_queryID;
+ }
+ return $rs;
+ }
+
+
+ /**
+ * Generates a sequence id and stores it in $this->genID;
+ * GenID is only available if $this->hasGenID = true;
+ *
+ * @seqname name of sequence to use
+ * @startID if sequence does not exist, start at this ID
+ * @return 0 if not supported, otherwise a sequence id
+ */
+
+ function GenID($seqname='adodbseq',$startID=1)
+ {
+ if (!$this->hasGenID) {
+ return 0; // formerly returns false pre 1.60
+ }
+
+ $getnext = sprintf($this->_genIDSQL,$seqname);
+ $rs = @$this->Execute($getnext);
+ if (!$rs) {
+ $u = strtoupper($seqname);
+ $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
+ $rs = $this->Execute($getnext);
+ }
+ if ($rs && !$rs->EOF) $this->genID = (integer) reset($rs->fields);
+ else $this->genID = 0; // false
+
+ if ($rs) $rs->Close();
+
+ return $this->genID;
+ }
+
+ /**
+ * @return the last inserted ID. Not all databases support this.
+ */
+ function Insert_ID()
+ {
+ if ($this->hasInsertID) return $this->_insertid();
+ if ($this->debug) print '
Insert_ID error
';
+ return false;
+ }
+
+
+ /**
+ * Portable Insert ID. Pablo Roca
+ *
+ * @return the last inserted ID. All databases support this. But aware possible
+ * problems in multiuser environments. Heavy test this before deploying.
+ */
+ function PO_Insert_ID($table="", $id="")
+ {
+ if ($this->hasInsertID){
+ return $this->Insert_ID();
+ } else {
+ return $this->GetOne("SELECT MAX($id) FROM $table");
+ }
+ }
+
+
+ /**
+ * @return # rows affected by UPDATE/DELETE
+ */
+ function Affected_Rows()
+ {
+ if ($this->hasAffectedRows) {
+ $val = $this->_affectedrows();
+ return ($val < 0) ? false : $val;
+ }
+
+ if ($this->debug) print '
Affected_Rows error
';
+ return false;
+ }
+
+
+ /**
+ * @return the last error message
+ */
+ function ErrorMsg()
+ {
+ return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
+ }
+
+
+ /**
+ * @return the last error number. Normally 0 means no error.
+ */
+ function ErrorNo()
+ {
+ return ($this->_errorMsg) ? -1 : 0;
+ }
+
+
+ /**
+ * @returns an array with the primary key columns in it.
+ */
+ function MetaPrimaryKeys($table)
+ {
+ return false;
+ }
+
+
+ /**
+ * Choose a database to connect to. Many databases do not support this.
+ *
+ * @param dbName is the name of the database to select
+ * @return true or false
+ */
+ function SelectDB($dbName)
+ {return false;}
+
+
+ /**
+ * Will select, getting rows from $offset (1-based), for $nrows.
+ * This simulates the MySQL "select * from table limit $offset,$nrows" , and
+ * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
+ * MySQL and PostgreSQL parameter ordering is the opposite of the other.
+ * eg.
+ * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
+ * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
+ *
+ * Uses SELECT TOP for Microsoft databases (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 [rows] is the number of rows to get
+ * @param [inputarr] array of bind variables
+ * @param [arg3] is a private parameter only used by jlim
+ * @param [secs2cache] is a private parameter only used by jlim
+ * @return the recordset ($rs->databaseType == 'array')
+ */
+ function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$arg3=false,$secs2cache=0)
+ {
+ if ($this->hasTop && $nrows > 0) {
+ // suggested by Reinhard Balling. Access requires top after distinct
+
+ if ($offset <= 0) {
+ $sql = preg_replace(
+ '/(^[\\t\\n ]*select[\\t\\n ]*(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 {
+ $nrows += $offset;
+ $sql = preg_replace(
+ '/(^[\\t\\n ]*select[\\t\\n ]*(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
+ $nrows = -1;
+ }
+
+ }
+
+ // 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 recordset to an array recordset
+ * input recordset's cursor should be at beginning, and
+ * old $rs will be closed.
+ *
+ * @param rs the recordset to copy
+ * @param [nrows] number of rows to retrieve (optional)
+ * @param [offset] offset by number of rows (optional)
+ * @return the new recordset
+ */
+ function &_rs2rs(&$rs,$nrows=-1,$offset=-1)
+ {
+ $arr = &$rs->GetArrayLimit($nrows,$offset);
+ $flds = array();
+ for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++)
+ $flds[] = &$rs->FetchField($i);
+ $rs->Close();
+
+ $arrayClass = $this->arrayClass;
+
+ $rs2 = new $arrayClass();
+ $rs2->connection = &$this;
+ $rs2->sql = $rs->sql;
+ $rs2->InitArrayFields($arr,$flds);
+ return $rs2;
+ }
+
+
+ /**
+ * Return first element of first row of sql statement. Recordset is disposed
+ * for you.
+ *
+ * @param sql SQL statement
+ * @param [inputarr] input bind array
+ */
+ function GetOne($sql,$inputarr=false)
+ {
+ $ret = false;
+ $rs = &$this->Execute($sql,$inputarr);
+ if ($rs) {
+ if (!$rs->EOF) $ret = reset($rs->fields);
+ $rs->Close();
+ }
+
+ return $ret;
+ }
+
+
+ /**
+ * Return all rows. Compat with PEAR DB
+ *
+ * @param sql SQL statement
+ * @param [inputarr] input bind array
+ */
+ function &GetAll($sql,$inputarr=false)
+ {
+ $rs = $this->Execute($sql,$inputarr);
+ if (!$rs)
+ if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+ else return false;
+ return $rs->GetArray();
+ }
+
+
+ /**
+ * Return one row of sql statement. Recordset is disposed for you.
+ *
+ * @param sql SQL statement
+ * @param [inputarr] input bind array
+ */
+ function GetRow($sql,$inputarr=false)
+ {
+ $rs = $this->Execute($sql,$inputarr);
+ if ($rs) {
+ $arr = false;
+ if (!$rs->EOF) $arr = $rs->fields;
+ $rs->Close();
+ return $arr;
+ }
+ return false;
+ }
+
+
+
+ /**
+ * Will select, getting rows from $offset (1-based), for $nrows.
+ * This simulates the MySQL "select * from table limit $offset,$nrows" , and
+ * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
+ * MySQL and PostgreSQL parameter ordering is the opposite of the other.
+ * eg.
+ * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
+ * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
+ *
+ * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
+ *
+ * @param [secs2cache] seconds to cache data, set to 0 to force query. 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);
+ }
+ if ($sql === false) echo "Warning: \$sql missing from CacheSelectLimit() \n";
+ return $this->SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
+ }
+
+
+ function CacheFlush($sql)
+ {
+ $f = $this->_gencachename($sql,false);
+ adodb_write_file($f,''); // is adodb_write_file needed?
+ @unlink($f);
+ }
+
+
+ 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)
+ if(!file_exists($dir) && !mkdir($dir,0771))
+ if ($this->debug) print "Unable to mkdir $dir for $sql \n";
+ 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');
+ // cannot cache if $inputarr set
+ if ($inputarr) return $this->Execute($sql, $inputarr, $arg3);
+
+ $md5file = $this->_gencachename($sql,true);
+ $err = '';
+
+ if ($secs2cache > 0)$rs = &csv2rs($md5file,$err,$secs2cache);
+ else {
+ $err='Timeout 1';
+ $rs = false;
+ }
+
+ if (!$rs) {
+ // no cached rs found
+ if ($this->debug) print " $md5file cache failure: $err \n";
+ $rs = &$this->Execute($sql,$inputarr,$arg3);
+ if ($rs) {
+ $eof = $rs->EOF;
+ $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately
+ $txt = &rs2csv($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);
+ }
+ if ($this->debug) print " Cache write error \n";
+ }
+ if ($rs->EOF && !$eof) {
+ $rs = &csv2rs($md5file,$err);
+ $rs->connection = &$this; // Pablo suggestion
+ }
+
+ } else
+ @unlink($md5file);
+ } else {
+ // ok, set cached object found
+ $rs->connection = &$this; // Pablo suggestion
+ if ($this->debug){
+ $ttl = $rs->timeCreated + $secs2cache - time();
+ print " $md5file reloaded, ttl=$ttl \n";
+ }
+ }
+ 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"
+ */
+ function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false)
+ {
+ include_once(ADODB_DIR.'/adodb-lib.inc.php');
+ return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq);
+ }
+
+
+ /**
+ * Generates an Insert Query based on an existing recordset.
+ * $arrFields is an associative array of fields with the value
+ * that should be assigned.
+ *
+ * Note: This function should only be used on a recordset
+ * that is run against a single table.
+ */
+ function GetInsertSQL(&$rs, $arrFields,$magicq=false)
+ {
+ include_once(ADODB_DIR.'/adodb-lib.inc.php');
+ return _adodb_getinsertsql($this,$rs,$arrFields,$magicq);
+ }
+
+
+ /**
+ * Usage:
+ * UpdateBlob('TABLE', 'COLUMN', $var, 'ID=1', 'BLOB');
+ *
+ * $blobtype supports 'BLOB' and 'CLOB'
+ *
+ * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+ * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
+ */
+
+ function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+ {
+ return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
+ }
+
+ /**
+ * Usage:
+ * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1', 'BLOB');
+ *
+ * $blobtype supports 'BLOB' and 'CLOB'
+ *
+ * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+ * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
+ */
+ function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
+ {
+ $fd = fopen($path,'rb');
+ if ($fd === false) return false;
+ $val = fread($fd,filesize($path));
+ fclose($fd);
+ return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
+ }
+
+ /**
+ * Usage:
+ * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
+ *
+ * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
+ * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
+ */
+ function UpdateClob($table,$column,$val,$where)
+ {
+ return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
+ }
+
+
+ /**
+ * @meta contains the desired type, which could be...
+ * C for character. You will have to define the precision yourself.
+ * X for teXt. For unlimited character lengths.
+ * B for Binary
+ * F for floating point, with no need to define scale and precision
+ * N for decimal numbers, you will have to define the (scale, precision) yourself
+ * D for date
+ * T for timestamp
+ * L for logical/Boolean
+ * I for integer
+ * R for autoincrement counter/integer
+ * and if you want to use double-byte, add a 2 to the end, like C2 or X2.
+ *
+ *
+ * @return the actual type of the data or false if no such type available
+ */
+ function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C':
+ case 'X':
+ return 'VARCHAR';
+ case 'B':
+
+ case 'D':
+ case 'T':
+ case 'L':
+
+ case 'R':
+
+ case 'I':
+ case 'N':
+ return false;
+ }
+ }
+
+
+ /*
+ * Maximum size of C field
+ */
+ function CharMax()
+ {
+ return 255; // make it conservative if not defined
+ }
+
+
+ /*
+ * Maximum size of X field
+ */
+ function TextMax()
+ {
+ return 4000; // make it conservative if not defined
+ }
+
+
+ /**
+ * Close Connection
+ */
+ function Close()
+ {
+ return $this->_close();
+
+ // "Simon Lee" reports that persistent connections need
+ // to be closed too!
+ //if ($this->_isPersistentConnection != true) return $this->_close();
+ //else return true;
+ }
+
+
+ /**
+ * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
+ *
+ * @return true if succeeded or false if database does not support transactions
+ */
+ function BeginTrans() {return false;}
+
+
+ /**
+ * If database does not support transactions, always return true as data always commited
+ *
+ * @param $ok set to false to rollback transaction, true to commit
+ *
+ * @return true/false.
+ */
+ function CommitTrans($ok=true)
+ { return true;}
+
+
+ /**
+ * If database does not support transactions, rollbacks always fail, so return false
+ *
+ * @return true/false.
+ */
+ function RollbackTrans()
+ { return false;}
+
+
+ /**
+ * return the databases that the driver can connect to.
+ * Some databases will return an empty array.
+ *
+ * @return an array of database names.
+ */
+ function MetaDatabases()
+ {return false;}
+
+ /**
+ * @return array of tables for current database.
+ */
+ function MetaTables()
+ {
+ global $ADODB_FETCH_MODE;
+
+ if ($this->metaTablesSQL) {
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $rs = $this->Execute($this->metaTablesSQL);
+ $ADODB_FETCH_MODE = $save;
+
+ if ($rs === false) return false;
+ $arr = $rs->GetArray();
+ $arr2 = array();
+ for ($i=0; $i < sizeof($arr); $i++) {
+ $arr2[] = $arr[$i][0];
+ }
+ $rs->Close();
+ return $arr2;
+ }
+ return false;
+ }
+
+
+ /**
+ * List columns in a database as an array of ADOFieldObjects.
+ * See top of file for definition of object.
+ *
+ * @params table table name to query
+ * @params upper uppercase table name (required by some databases)
+ *
+ * @return array of ADOFieldObjects for current table.
+ */
+ function MetaColumns($table,$upper=true)
+ {
+ global $ADODB_FETCH_MODE;
+
+ if (!empty($this->metaColumnsSQL)) {
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $rs = $this->Execute(sprintf($this->metaColumnsSQL,($upper)?strtoupper($table):$table));
+ $ADODB_FETCH_MODE = $save;
+ if ($rs === false) return false;
+
+ $retarr = array();
+ while (!$rs->EOF) { //print_r($rs->fields);
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+ $fld->type = $rs->fields[1];
+ $fld->max_length = $rs->fields[2];
+ $retarr[strtoupper($fld->name)] = $fld;
+
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ return $retarr;
+ }
+ return false;
+ }
+
+ /**
+ * List columns names in a table as an array.
+ * @params table table name to query
+ *
+ * @return array of column names for current table.
+ */
+ function MetaColumnNames($table)
+ {
+ $objarr = $this->MetaColumns($table);
+ if (!is_array($objarr)) return false;
+
+ $arr = array();
+ foreach($objarr as $v) {
+ $arr[] = $v->name;
+ }
+ return $arr;
+ }
+
+ /**
+ * Different SQL databases used different methods to combine strings together.
+ * This function provides a wrapper.
+ *
+ * @param s variable number of string parameters
+ *
+ * Usage: $db->Concat($str1,$str2);
+ *
+ * @return concatenated string
+ */
+ function Concat()
+ {
+ $arr = func_get_args();
+ return implode($this->concat_operator, $arr);
+ }
+
+
+ /**
+ * Converts a date "d" to a string that the database can understand.
+ *
+ * @param d a date in Unix date time format.
+ *
+ * @return date string in database date format
+ */
+ function DBDate($d)
+ {
+
+ // note that we are limited to 1970 to 2038
+ if (empty($d) && $d !== 0) return 'null';
+
+ if (is_string($d) && !is_numeric($d))
+ if ($this->isoDates) return "'$d'";
+ else $d = ADOConnection::UnixDate($d);
+
+ return date($this->fmtDate,$d);
+ }
+
+
+ /**
+ * Converts a timestamp "ts" to a string that the database can understand.
+ *
+ * @param ts a timestamp in Unix date time format.
+ *
+ * @return timestamp string in database timestamp format
+ */
+ function DBTimeStamp($ts)
+ {
+ if (empty($ts) && $ts !== 0) return 'null';
+
+ if (is_string($ts) && !is_numeric($ts))
+ if ($this->isoDates) return "'$ts'";
+ else $ts = ADOConnection::UnixTimeStamp($ts);
+ return date($this->fmtTimeStamp,$ts);
+ }
+
+ /**
+ * Also in ADORecordSet.
+ * @param $v is a date string in YYYY-MM-DD format
+ *
+ * @return date in unix timestamp format, or 0 if before 1970, or false if invalid date format
+ */
+ function UnixDate($v)
+ {
+ if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})$|",
+ ($v), $rr)) return false;
+
+ if ($rr[1] <= 1970) return 0;
+ // h-m-s-MM-DD-YY
+ return mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
+ }
+
+
+ /**
+ * Also in ADORecordSet.
+ * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
+ *
+ * @return date in unix timestamp format, or 0 if before 1970, or false if invalid date format
+ */
+ function UnixTimeStamp($v)
+ {
+ if (!preg_match(
+ "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9]{1,2}))?$|",
+ ($v), $rr)) return false;
+ if ($rr[1] <= 1970 && $rr[2]<= 1) return 0;
+
+ // h-m-s-MM-DD-YY
+ return @mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
+ }
+
+ /**
+ * Converts a timestamp "ts" to a string that the database can understand.
+ * An example is $db->qstr("Don't bother",magic_quotes_runtime());
+ *
+ * @param s the string to quote
+ * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
+ * This undoes the stupidity of magic quotes for GPC.
+ *
+ * @return quoted string to be sent back to database
+ */
+ function qstr($s,$magic_quotes=false)
+ {
+ $nofixquotes=false;
+ if (!$magic_quotes) {
+
+ if ($this->replaceQuote[0] == '\\'){
+ $s = str_replace('\\','\\\\',$s);
+ }
+ return "'".str_replace("'",$this->replaceQuote,$s)."'";
+ }
+
+ // undo magic quotes for "
+ $s = str_replace('\\"','"',$s);
+
+ if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything
+ return "'$s'";
+ else {// change \' to '' for sybase/mssql
+ $s = str_replace('\\\\','\\',$s);
+ return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
+ }
+ }
+
+
+ /**
+ * Will select the supplied $page number from a recordset, given that it is paginated in pages of
+ * $nrows rows per page. It also saves two boolean values saying if the given page is the first
+ * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
+ *
+ * See readme.htm#ex8 for an example of usage.
+ *
+ * @param sql
+ * @param nrows is the number of rows per page to get
+ * @param page is the page number to get (1-based)
+ * @param [inputarr] array of bind variables
+ * @param [arg3] is a private parameter only used by jlim
+ * @param [secs2cache] is a private parameter only used by jlim
+ * @return the recordset ($rs->databaseType == 'array')
+ *
+ * NOTE: phpLens uses a different algorithm and does not use PageExecute().
+ *
+ */
+ function &PageExecute($sql, $nrows, $page, $inputarr=false, $arg3=false, $secs2cache=0)
+ {
+ include_once(ADODB_DIR.'/adodb-lib.inc.php');
+ return _adodb_pageexecute($this, $sql, $nrows, $page, $inputarr, $arg3, $secs2cache);
+
+ }
+
+
+ /**
+ * Will select the supplied $page number from a recordset, given that it is paginated in pages of
+ * $nrows rows per page. It also saves two boolean values saying if the given page is the first
+ * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
+ *
+ * @param secs2cache seconds to cache data, set to 0 to force query
+ * @param sql
+ * @param nrows is the number of rows per page to get
+ * @param page is the page number to get (1-based)
+ * @param [inputarr] array of bind variables
+ * @param [arg3] is a private parameter only used by jlim
+ * @return the recordset ($rs->databaseType == 'array')
+ */
+ function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false, $arg3=false) {
+ include_once(ADODB_DIR.'/adodb-lib.inc.php');
+ return _adodb_pageexecute($this, $sql, $nrows, $page, $inputarr, $arg3,$secs2cache);
+ }
+
+} // end class ADOConnection
+
+
+
+ //==============================================================================================
+ // CLASS ADOFetchObj
+ //==============================================================================================
+
+ /**
+ * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
+ */
+ class ADOFetchObj {
+ };
+
+ //==============================================================================================
+ // CLASS ADORecordSet_empty
+ //==============================================================================================
+
+ /**
+ * Lightweight recordset when there are no records to be returned
+ */
+ class ADORecordSet_empty
+ {
+ var $dataProvider = 'empty';
+ var $EOF = true;
+ var $_numOfRows = 0;
+ var $fields = false;
+ var $connection = false;
+ function RowCount() {return 0;}
+ function RecordCount() {return 0;}
+ function PO_RecordCount(){return 0;}
+ function Close(){return true;}
+ function FetchRow() {return false;}
+ function FieldCount(){ return 0;}
+ }
+
+ //==============================================================================================
+ // CLASS ADORecordSet
+ //==============================================================================================
+
+ /**
+ * RecordSet class that represents the dataset returned by the database.
+ * To keep memory overhead low, this class holds only the current row in memory.
+ * No prefetching of data is done, so the RecordCount() can return -1 ( which
+ * means recordcount not known).
+ */
+ class ADORecordSet {
+ /*
+ * public variables
+ */
+ var $dataProvider = "native";
+ var $fields = false; // holds the current row data
+ var $blobSize = 64; // any varchar/char field this size or greater is treated as a blob
+ // in other words, we use a text area for editting.
+ var $canSeek = false; // indicates that seek is supported
+ var $sql; // sql text
+ var $EOF = false; /* Indicates that the current record position is after the last record in a Recordset object. */
+
+ var $emptyTimeStamp = ' '; // what to display when $time==0
+ var $emptyDate = ' '; // what to display when $time==0
+ var $debug = false;
+ var $timeCreated=0; // datetime in Unix format rs created -- for cached recordsets
+
+ var $bind = false; // used by Fields() to hold array - should be private?
+ var $fetchMode; // default fetch mode
+ var $connection = false; // the parent connection
+ /*
+ * private variables
+ */
+ var $_numOfRows = -1; /* number of rows, or -1 */
+ var $_numOfFields = -1; /* number of fields in recordset */
+ var $_queryID = -1; /* This variable keeps the result link identifier. */
+ var $_currentRow = -1; /* This variable keeps the current row in the Recordset. */
+ var $_closed = false; /* has recordset been closed */
+ var $_inited = false; /* Init() should only be called once */
+ var $_obj; /* Used by FetchObj */
+ var $_names; /* Used by FetchObj */
+
+ var $_currentPage = -1; /* Added by Iván Oliva to implement recordset pagination */
+ var $_atFirstPage = false; /* Added by Iván Oliva to implement recordset pagination */
+ var $_atLastPage = false; /* Added by Iván Oliva to implement recordset pagination */
+
+
+ /**
+ * Constructor
+ *
+ * @param queryID this is the queryID returned by ADOConnection->_query()
+ *
+ */
+ function ADORecordSet($queryID)
+ {
+ $this->_queryID = $queryID;
+ }
+
+
+ function Init()
+ {
+ if ($this->_inited) return;
+ $this->_inited = true;
+
+ if ($this->_queryID) @$this->_initrs();
+ else {
+ $this->_numOfRows = 0;
+ $this->_numOfFields = 0;
+ }
+ if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
+ $this->_currentRow = 0;
+ $this->EOF = ($this->_fetch() === false);
+ } else
+ $this->EOF = true;
+ }
+
+
+ /**
+ * Generate a