From: moodler Date: Fri, 30 Jan 2004 03:11:47 +0000 (+0000) Subject: Upgrading ADOdb to 4.11 ... there were lots of little bug fixes X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=25be6cfff383bc97883500e875572741641fcea4;p=moodle.git Upgrading ADOdb to 4.11 ... there were lots of little bug fixes --- diff --git a/lib/adodb/adodb-csvlib.inc.php b/lib/adodb/adodb-csvlib.inc.php index ba59b6bcaa..37c46794ce 100644 --- a/lib/adodb/adodb-csvlib.inc.php +++ b/lib/adodb/adodb-csvlib.inc.php @@ -3,7 +3,7 @@ global $ADODB_INCLUDED_CSV; $ADODB_INCLUDED_CSV = 1; /* - V4.01 23 Oct 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved. + V4.11 27 Jan 2004 (c) 2000-2004 John Lim (jlim@natsoft.com.my). All rights reserved. Released under both BSD license and Lesser GPL library license. Whenever there is any discrepancy between the two licenses, the BSD license will take precedence. See License.txt. @@ -83,8 +83,8 @@ $ADODB_INCLUDED_CSV = 1; */ function &csv2rs($url,&$err,$timeout=0) { - $fp = @fopen($url,'r'); $err = false; + $fp = @fopen($url,'r'); if (!$fp) { $err = $url.' file/URL not found'; return false; diff --git a/lib/adodb/adodb-datadict.inc.php b/lib/adodb/adodb-datadict.inc.php index 0c73094f24..db9c2016df 100644 --- a/lib/adodb/adodb-datadict.inc.php +++ b/lib/adodb/adodb-datadict.inc.php @@ -1,7 +1,7 @@ $str

"; $a= Lens_ParseArgs($str); print "
";
 print_r($a);
 print "
"; } + +if (!function_exists('ctype_alnum')) { + function ctype_alnum($text) { + return preg_match('/^[a-z0-9]*$/i', $text); + } +} + //Lens_ParseTest(); /** Parse arguments, treat "text" (text) and 'text' as quotation marks. To escape, use "" or '' or )) + Will read in "abc def" sans quotes, as: abc def + Same with 'abc def'. + However if `abc def`, then will read in as `abc def` + @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. @@ -63,7 +74,9 @@ function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-') $tokarr[] = $ch; break; - + + case '`': + if ($intoken) $tokarr[] = $ch; case '(': case ')': case '"': @@ -98,6 +111,7 @@ function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-') $quoted = true; $intoken = true; $tokarr = array(); + if ($ch == '`') $tokarr[] = '`'; } break; @@ -143,14 +157,14 @@ function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-') class ADODB_DataDict { var $connection; var $debug = false; - var $dropTable = "DROP TABLE %s"; + var $dropTable = 'DROP TABLE %s'; + var $dropIndex = 'DROP INDEX %s'; var $addCol = ' ADD'; var $alterCol = ' ALTER COLUMN'; var $dropCol = ' DROP COLUMN'; var $schema = false; var $serverInfo = array(); var $autoIncrement = false; - var $quote = ''; 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. @@ -170,9 +184,9 @@ class ADODB_DataDict { return $this->connection->MetaTables(); } - function &MetaColumns($tab) + function &MetaColumns($tab,$schema=false,$upper=true) { - return $this->connection->MetaColumns($tab); + return $this->connection->MetaColumns($tab,$schema,$upper); } function &MetaPrimaryKeys($tab,$owner=false,$intkey=false) @@ -180,11 +194,34 @@ class ADODB_DataDict { return $this->connection->MetaPrimaryKeys($tab.$owner,$intkey); } + function &MetaIndexes($table, $primary = false, $owner = false) + { + return $this->connection->MetaIndexes($table, $primary, $owner); + } + function MetaType($t,$len=-1,$fieldobj=false) { return ADORecordSet::MetaType($t,$len,$fieldobj); } + function NameQuote($name) + { + if ( !is_object($this->connection) ) { + return $name; + } + + $replace = $this->connection->nameQuote .'$1'. $this->connection->nameQuote; + return preg_replace('/^`([^`]+)`$/', $replace, $name); + } + + function TableName($name) + { + if ( $this->schema ) { + return $this->NameQuote($this->schema) .'.'. $this->NameQuote($name); + } + return $this->NameQuote($name); + } + // Executes the sql array returned by GetTableSQL and GetIndexSQL function ExecuteSQLArray($sql, $continueOnError = true) { @@ -231,9 +268,12 @@ class ADODB_DataDict { function CreateDatabase($dbname,$options=false) { $options = $this->_Options($options); - if (!preg_match('/^[a-z0-9A-Z_]*$/',$dbname)) $dbname = $this->quote.$dbname.$this->quote; - $s = 'CREATE DATABASE '.$dbname; - if (isset($options[$this->upperName])) $s .= ' '.$options[$this->upperName]; + $sql = array(); + + $s = 'CREATE DATABASE ' . $this->NameQuote($dbname); + if (isset($options[$this->upperName])) + $s .= ' '.$options[$this->upperName]; + $sql[] = $s; return $sql; } @@ -243,8 +283,12 @@ class ADODB_DataDict { */ function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false) { - if ($this->schema) $tabname = $this->schema.'.'.$tabname; - return $this->_IndexSQL($idxname, $tabname, $flds, $this->_Options($idxoptions)); + return $this->_IndexSQL($this->NameQuote($idxname), $this->TableName($tabname), $flds, $this->_Options($idxoptions)); + } + + function DropIndexSQL ($idxname, $tabname = NULL) + { + return array(sprintf($this->dropIndex, $this->NameQuote($idxname))); } function SetSchema($schema) @@ -253,44 +297,44 @@ class ADODB_DataDict { } function AddColumnSQL($tabname, $flds) - { - if ($this->schema) $tabname = $this->schema.'.'.$tabname; + { + $tabname = $this->TableName ($tabname); $sql = array(); list($lines,$pkey) = $this->_GenFields($flds); + $alter = 'ALTER TABLE ' . $tabname . ' ' . $this->addCol . ' '; foreach($lines as $v) { - $sql[] = "ALTER TABLE $tabname $this->addCol $v"; + $sql[] = $alter . $v; } return $sql; } function AlterColumnSQL($tabname, $flds) { - if ($this->schema) $tabname = $this->schema.'.'.$tabname; + $tabname = $this->TableName ($tabname); $sql = array(); list($lines,$pkey) = $this->_GenFields($flds); - + $alter = 'ALTER TABLE ' . $tabname . ' ' . $this->alterCol . ' '; foreach($lines as $v) { - $sql[] = "ALTER TABLE $tabname $this->alterCol $v"; + $sql[] = $alter . $v; } return $sql; } function DropColumnSQL($tabname, $flds) { - if ($this->schema) $tabname = $this->schema.'.'.$tabname; + $tabname = $this->TableName ($tabname); if (!is_array($flds)) $flds = explode(',',$flds); $sql = array(); + $alter = 'ALTER TABLE ' . $tabname . ' ' . $this->dropCol . ' '; foreach($flds as $v) { - $sql[] = "ALTER TABLE $tabname $this->dropCol $v"; + $sql[] = $alter . $v; } return $sql; } function DropTableSQL($tabname) { - if ($this->schema) $tabname = $this->schema.'.'.$tabname; - $sql[] = sprintf($this->dropTable,$tabname); - return $sql; + return array (sprintf($this->dropTable, $this->TableName($tabname))); } /* @@ -299,11 +343,11 @@ class ADODB_DataDict { 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; + $tabname = $this->TableName ($tabname); $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions); $tsql = $this->_Triggers($tabname,$taboptions); @@ -370,7 +414,9 @@ class ADODB_DataDict { case 'NAME': $fname = $v; break; case '1': case 'TYPE': $ty = $v; $ftype = $this->ActualType(strtoupper($v)); break; - case 'SIZE': $dotat = strpos($v,'.'); + + case 'SIZE': + $dotat = strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,','); if ($dotat === false) $fsize = $v; else { $fsize = substr($v,0,$dotat); @@ -399,6 +445,8 @@ class ADODB_DataDict { return false; } + $fname = $this->NameQuote($fname); + if (!strlen($ftype)) { if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'"); return false; @@ -456,7 +504,7 @@ class ADODB_DataDict { { if (strlen($fsize) && $ty != 'X' && $ty != 'B' && strpos($ftype,'(') === false) { $ftype .= "(".$fsize; - if ($fprec) $ftype .= ",".$fprec; + if (strlen($fprec)) $ftype .= ",".$fprec; $ftype .= ')'; } return $ftype; @@ -475,14 +523,28 @@ class ADODB_DataDict { function _IndexSQL($idxname, $tabname, $flds, $idxoptions) { - if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX $idxname"; - if (isset($idxoptions['UNIQUE'])) $unique = ' UNIQUE'; - else $unique = ''; + $sql = array(); - 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)"; + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $idxname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + + $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : ''; + + $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' '; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s .= '(' . $flds . ')'; $sql[] = $s; return $sql; @@ -497,12 +559,15 @@ class ADODB_DataDict { { $sql = array(); - if (isset($tableoptions['REPLACE'])) { + if (isset($tableoptions['REPLACE']) || isset ($tableoptions['DROP'])) { $sql[] = sprintf($this->dropTable,$tabname); if ($this->autoIncrement) { - $sInc = $this->_DropAutoIncrement($tabname); + $sInc = $this->_DropAutoIncrement($tabname); if ($sInc) $sql[] = $sInc; } + if ( isset ($tableoptions['DROP']) ) { + return $sql; + } } $s = "CREATE TABLE $tabname (\n"; $s .= implode(",\n", $lines); @@ -557,15 +622,21 @@ own. */ function ChangeTableSQL($tablename, $flds,$tableoptions=false) { - if ($this->schema) $tabname = $this->schema.'.'.$tablename; - else $tabname = $tablename; + $tabname = $this->TableName ($tablename); $conn = &$this->connection; - if (!$conn) return false; + if (!is_object ($conn)) { + return false; + } $colarr = &$conn->MetaColumns($tabname); - if (!$colarr) return $this->CreateTableSQL($tablename,$flds,$tableoptions); - foreach($colarr as $col) $cols[strtoupper($col->name)] = " ALTER "; + if (!$colarr) { + return $this->CreateTableSQL($tablename,$flds,$tableoptions); + } + + foreach($colarr as $col) { + $cols[strtoupper($col->name)] = " ALTER "; + } $sql = array(); list($lines,$pkey) = $this->_GenFields($flds); diff --git a/lib/adodb/adodb-error.inc.php b/lib/adodb/adodb-error.inc.php index 7ecd7bba75..f874caf922 100644 --- a/lib/adodb/adodb-error.inc.php +++ b/lib/adodb/adodb-error.inc.php @@ -1,6 +1,6 @@ DB_ERROR_ALREADY_EXISTS, '/divide by zero$/' => DB_ERROR_DIVZERO, '/pg_atoi: error in .*: can\'t parse /' => DB_ERROR_INVALID_NUMBER, - '/ttribute [\"\'].*[\"\'] not found$|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => DB_ERROR_NOSUCHFIELD, + '/ttribute [\"\'].*[\"\'] not found|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => DB_ERROR_NOSUCHFIELD, '/parser: parse error at or near \"/' => DB_ERROR_SYNTAX, '/referential integrity violation/' => DB_ERROR_CONSTRAINT ); - - foreach ($error_regexps as $regexp => $code) { + reset($error_regexps); + while (list($regexp,$code) = each($error_regexps)) { if (preg_match($regexp, $errormsg)) { return $code; } @@ -190,6 +190,7 @@ static $MAP = array( function adodb_error_oci8() { static $MAP = array( + 1 => DB_ERROR_ALREADY_EXISTS, 900 => DB_ERROR_SYNTAX, 904 => DB_ERROR_NOSUCHFIELD, 923 => DB_ERROR_SYNTAX, @@ -199,7 +200,7 @@ static $MAP = array( 1722 => DB_ERROR_INVALID_NUMBER, 2289 => DB_ERROR_NOSUCHTABLE, 2291 => DB_ERROR_CONSTRAINT, - 2449 => DB_ERROR_CONSTRAINT, + 2449 => DB_ERROR_CONSTRAINT ); return $MAP; diff --git a/lib/adodb/adodb-errorhandler.inc.php b/lib/adodb/adodb-errorhandler.inc.php index c0489c9ae2..f57263f0c1 100644 --- a/lib/adodb/adodb-errorhandler.inc.php +++ b/lib/adodb/adodb-errorhandler.inc.php @@ -1,9 +1,9 @@ sql = $p1; + $this->params = $p2; + $s = "$dbms error: [$errno: $errmsg] in $fn(\"$p1\")\n"; + break; + + case 'PCONNECT': + case 'CONNECT': + $user = $thisConnection->user; + $s = "$dbms error: [$errno: $errmsg] in $fn($p1, '$user', '****', $p2)\n"; + break; + default: + $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n"; + break; + } + + $this->dbms = $dbms; + $this->host = $thisConnection->host; + $this->database = $thisConnection->database; + $this->fn = $fn; + $this->msg = $errmsg; + + parent::__construct($s,$errno); + } +} + +/** +* Default Error Handler. This will be called with the following params +* +* @param $dbms the RDBMS you are connecting to +* @param $fn the name of the calling function (in uppercase) +* @param $errno the native error number from the database +* @param $errmsg the native error msg from the database +* @param $p1 $fn specific parameter - see below +* @param $P2 $fn specific parameter - see below +*/ + +function adodb_throw($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection) +{ +global $ADODB_EXCEPTION; + + if (is_string($ADODB_EXCEPTION)) $errfn = $ADODB_EXCEPTION; + else $errfn = 'ADODB_EXCEPTION'; + throw new $errfn($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection); +} + + +?> \ No newline at end of file diff --git a/lib/adodb/adodb-iterator.inc.php b/lib/adodb/adodb-iterator.inc.php new file mode 100644 index 0000000000..1817fade30 --- /dev/null +++ b/lib/adodb/adodb-iterator.inc.php @@ -0,0 +1,56 @@ +Execute("select * from adoxyz"); + foreach($rs as $k => $v) { + echo $k; print_r($v); echo "
"; + } + */ + +class ADODB_Iterator implements Iterator { + + private $rs; + + function __construct($rs) + { + $this->rs = $rs; + } + function rewind() + { + $this->rs->MoveFirst(); + } + function hasMore() + { + return !$this->rs->EOF; + } + function key() + { + return $this->rs->_currentRow; + } + function current() + { + return $this->rs->fields; + } + function next() + { + $this->rs->MoveNext(); + } +} + + +class ADODB_BASE_RS implements IteratorAggregate { + function getIterator() { + return new ADODB_Iterator($this); + } +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodb-lib.inc.php b/lib/adodb/adodb-lib.inc.php index 7720ee1265..1c8d360d51 100644 --- a/lib/adodb/adodb-lib.inc.php +++ b/lib/adodb/adodb-lib.inc.php @@ -4,7 +4,7 @@ global $ADODB_INCLUDED_LIB; $ADODB_INCLUDED_LIB = 1; /* -V4.01 23 Oct 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved. +V4.11 27 Jan 2004 (c) 2000-2004 John Lim (jlim@natsoft.com.my). All rights reserved. Released under both BSD license and Lesser GPL library license. Whenever there is any discrepancy between the two licenses, the BSD license will take precedence. See License.txt. @@ -19,7 +19,7 @@ V4.01 23 Oct 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights rese function _array_change_key_case($an_array) { if (is_array($an_array)) { - foreach($an_array as $key => $value) + foreach($an_array as $key=>$value) $new_array[strtoupper($key)] = $value; return $new_array; @@ -28,6 +28,75 @@ function _array_change_key_case($an_array) return $an_array; } +function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc) +{ + 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 strncmp($v,"'",1) !== 0 and strcasecmp($v,'null')!=0) { + $v = $zthis->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"; + } + + $where = false; + foreach ($keyCol as $v) { + if ($where) $where .= " and $v=$fieldArray[$v]"; + else $where = "$v=$fieldArray[$v]"; + } + + if ($uSet && $where) { + $update = "UPDATE $table SET $uSet WHERE $where"; + + $rs = $zthis->Execute($update); + if ($rs) { + if ($zthis->poorAffectedRows) { + /* + The Select count(*) wipes out any errors that the update would have returned. + http://phplens.com/lens/lensforum/msgs.php?id=5696 + */ + if ($zthis->ErrorNo()<>0) return 0; + + # affected_rows == 0 if update field values identical to old values + # for mysql - which is silly. + + $cnt = $zthis->GetOne("select count(*) from $table where $where"); + if ($cnt > 0) return 1; // record already exists + } else + if (($zthis->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 = $zthis->Execute($insert); + return ($rs) ? 2 : 0; +} + // Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false, $size=0, $selectAttr='',$compareFields0=true) @@ -138,9 +207,12 @@ function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0) if ($qryRecs !== false) return $qryRecs; } + //-------------------------------------------- // query rewrite failed - so try slower way... + + // strip off unneeded ORDER BY $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql); - $rstest = &$zthis->Execute($rewritesql); + $rstest = &$zthis->Execute($rewritesql,$inputarr); if ($rstest) { $qryRecs = $rstest->RecordCount(); if ($qryRecs == -1) { @@ -400,79 +472,78 @@ function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false) $values = ''; $fields = ''; $arrFields = _array_change_key_case($arrFields); + if (!$rs) { - printf(ADODB_BAD_RS,'GetInsertSQL'); - return false; - } + printf(ADODB_BAD_RS,'GetInsertSQL'); + return false; + } - $fieldInsertedCount = 0; - - - // Loop through all of the fields in the recordset - for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) { + $fieldInsertedCount = 0; - // Get the field from the recordset - $field = $rs->FetchField($i); - // If the recordset field is one - // of the fields passed in then process. - $upperfname = strtoupper($field->name); - if (adodb_key_exists($upperfname,$arrFields)) { - - // Set the counter for the number of fields that will be inserted. - $fieldInsertedCount++; + // Loop through all of the fields in the recordset + for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) { - // 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 ((strncmp($zthis->databaseType,"postgres",8) === 0) && ($mt == "L")) $mt = "C"; - - // Based on the datatype of the field - // Format the value properly for the database - if ((defined('ADODB_FORCE_NULLS') && is_null($arrFields[$upperfname])) || $arrFields[$upperfname] === 'null') - $values .= "null, "; - else - switch($mt) { - case "C": - case "X": - case 'B': - $values .= $zthis->qstr($arrFields[$upperfname],$magicq) . ", "; - break; - case "D": - $values .= $zthis->DBDate($arrFields[$upperfname]) . ", "; - break; - case "T": - $values .= $zthis->DBTimeStamp($arrFields[$upperfname]) . ", "; - break; - default: - $val = $arrFields[$upperfname]; - if (!is_numeric($val)) $val = (float) $val; - $values .= $val . ", "; - break; - }; - }; - }; + // Get the field from the recordset + $field = $rs->FetchField($i); + // If the recordset field is one + // of the fields passed in then process. + $upperfname = strtoupper($field->name); + if (adodb_key_exists($upperfname,$arrFields)) { - // If there were any inserted fields then build the rest of the insert query. - if ($fieldInsertedCount > 0) { - // Get the table name from the existing query. - preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName); + // 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 ((strncmp($zthis->databaseType,"postgres",8) === 0) && ($mt == "L")) $mt = "C"; + + // Based on the datatype of the field + // Format the value properly for the database + if ((defined('ADODB_FORCE_NULLS') && is_null($arrFields[$upperfname])) || $arrFields[$upperfname] === 'null') + $values .= "null, "; + else + switch($mt) { + case "C": + case "X": + case 'B': + $values .= $zthis->qstr($arrFields[$upperfname],$magicq) . ", "; + break; + case "D": + $values .= $zthis->DBDate($arrFields[$upperfname]) . ", "; + break; + case "T": + $values .= $zthis->DBTimeStamp($arrFields[$upperfname]) . ", "; + break; + default: + $val = $arrFields[$upperfname]; + if (!is_numeric($val)) $val = (float) $val; + $values .= $val . ", "; + break; + }; + }; + }; - // 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); + // If there were any inserted fields then build the rest of the insert query. + if ($fieldInsertedCount <= 0) return false; + + // Get the table name from the existing query. + preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName); - // Append the fields and their values to the insert query. - $insertSQL = "INSERT INTO " . $tableName[1] . " ( $fields ) VALUES ( $values )"; + // 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); - return $insertSQL; + // Append the fields and their values to the insert query. + $insertSQL = "INSERT INTO " . $tableName[1] . " ( $fields ) VALUES ( $values )"; - } else { - return false; - }; + return $insertSQL; } + + ?> \ No newline at end of file diff --git a/lib/adodb/adodb-pager.inc.php b/lib/adodb/adodb-pager.inc.php index e96c5497d1..ebff53faf1 100644 --- a/lib/adodb/adodb-pager.inc.php +++ b/lib/adodb/adodb-pager.inc.php @@ -1,6 +1,6 @@ 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(); + if (!$ok) $obj = ADODB_PEAR_Error(); return $obj; } diff --git a/lib/adodb/adodb-perf.inc.php b/lib/adodb/adodb-perf.inc.php index bedd98f812..9c0efd24d7 100644 --- a/lib/adodb/adodb-perf.inc.php +++ b/lib/adodb/adodb-perf.inc.php @@ -1,6 +1,6 @@ fnExecute = false; $t0 = microtime(); $rs =& $conn->Execute($sql,$inputarr); @@ -58,8 +60,12 @@ global $HTTP_SERVER_VARS; $tracer = ''; $errM = ''; $errN = 0; - $conn->lastInsID = $conn->Insert_ID(); - + $dbg = $conn->debug; + $conn->debug = false; + if (!is_object($rs) || $rs->dataProvider == 'empty') + $conn->_affected = $conn->affected_rows(true); + $conn->lastInsID = @$conn->Insert_ID(); + $conn->debug = $dbg; } if (isset($HTTP_SERVER_VARS['HTTP_HOST'])) { $tracer .= '
'.$HTTP_SERVER_VARS['HTTP_HOST']; @@ -89,7 +95,7 @@ global $HTTP_SERVER_VARS; $conn->debug = 0; if ($conn->dataProvider == 'oci8' && $dbT != 'oci8po') { - $isql = "insert into adodb_logsql values($conn->sysTimeStamp,:b,:c,:d,:e,:f)"; + $isql = "insert into $perf_table values($conn->sysTimeStamp,:b,:c,:d,:e,:f)"; } else if ($dbT == 'odbc_mssql' || $dbT == 'informix') { $timer = $arr['f']; if ($dbT == 'informix') $sql2 = substr($sql2,0,230); @@ -99,13 +105,12 @@ global $HTTP_SERVER_VARS; $params = $conn->qstr($arr['d']); $tracer = $conn->qstr($arr['e']); - $isql = "insert into adodb_logsql (created,sql0,sql1,params,tracer,timer) values($conn->sysTimeStamp,$sql1,$sql2,$params,$tracer,$timer)"; + $isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values($conn->sysTimeStamp,$sql1,$sql2,$params,$tracer,$timer)"; if ($dbT == 'informix') $isql = str_replace(chr(10),' ',$isql); $arr = false; } else { - $isql = "insert into adodb_logsql (created,sql0,sql1,params,tracer,timer) values( $conn->sysTimeStamp,?,?,?,?,?)"; + $isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values( $conn->sysTimeStamp,?,?,?,?,?)"; } - $conn->_affected = $conn->affected_rows(true); $ok = $conn->Execute($isql,$arr); $conn->debug = $saved; @@ -118,7 +123,7 @@ global $HTTP_SERVER_VARS; if ($perf) { if ($perf->CreateLogTable()) $ok = $conn->Execute($isql,$arr); } else { - $ok = $conn->Execute("create table adodb_logsql ( + $ok = $conn->Execute("create table $perf_table ( created varchar(50), sql0 varchar(250), sql1 varchar(4000), @@ -165,7 +170,18 @@ class adodb_perf { var $explain = true; var $helpurl = "LogSQL help"; var $createTableSQL = false; + var $maxLength = 2000; + // Sets the tablename to be used + function table($newtable = false) + { + static $_table; + + if (!empty($newtable)) $_table = $newtable; + if (empty($_table)) $_table = 'adodb_logsql'; + return $_table; + } + // returns array with info to calculate CPU Load function _CPULoad() { @@ -285,10 +301,14 @@ Committed_AS: 348732 kB function Tracer($sql) { + $perf_table = adodb_perf::table(); + $saveE = $this->conn->fnExecute; + $this->conn->fnExecute = false; + $sqlq = $this->conn->qstr($sql); $arr = $this->conn->GetArray( "select count(*),tracer - from adodb_logsql where sql1=$sqlq + from $perf_table where sql1=$sqlq group by tracer order by 1 desc"); $s = ''; @@ -298,11 +318,17 @@ Committed_AS: 348732 kB $s .= sprintf("%4d",$k[0]).'   '.strip_tags($k[1]).'
'; } } + $this->conn->fnExecute = $saveE; return $s; } - function Explain($sql) - { + /* + Explain Plan for $sql. + If only a snippet of the $sql is passed in, then $partial will hold the crc32 of the + actual sql. + */ + function Explain($sql,$partial=false) + { return false; } @@ -314,7 +340,8 @@ Committed_AS: 348732 kB $s = '

Invalid SQL

'; $saveE = $this->conn->fnExecute; $this->conn->fnExecute = false; - $rs =& $this->conn->SelectLimit("select distinct count(*),sql1,tracer as error_msg from adodb_logsql where tracer like 'ERROR:%' group by sql1,tracer order by 1 desc",$numsql);//,$numsql); + $perf_table = adodb_perf::table(); + $rs =& $this->conn->SelectLimit("select distinct count(*),sql1,tracer as error_msg from $perf_table where tracer like 'ERROR:%' group by sql1,tracer order by 1 desc",$numsql);//,$numsql); $this->conn->fnExecute = $saveE; if ($rs) { $s .= rs2html($rs,false,false,false,false); @@ -323,6 +350,7 @@ Committed_AS: 348732 kB return $s; } + /* This script identifies the longest running SQL @@ -331,11 +359,13 @@ Committed_AS: 348732 kB { global $ADODB_FETCH_MODE,$HTTP_GET_VARS; + $perf_table = adodb_perf::table(); $saveE = $this->conn->fnExecute; $this->conn->fnExecute = false; if (isset($HTTP_GET_VARS['exps']) && isset($HTTP_GET_VARS['sql'])) { - echo "".$this->Explain($HTTP_GET_VARS['sql'])."\n"; + $partial = !empty($HTTP_GET_VARS['part']); + echo "".$this->Explain($HTTP_GET_VARS['sql'],$partial)."\n"; } if (isset($HTTP_GET_VARS['sql'])) return; @@ -346,7 +376,7 @@ Committed_AS: 348732 kB //$this->conn->debug=1; $rs =& $this->conn->SelectLimit( "select avg(timer) as avg_timer,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer - from adodb_logsql + from $perf_table where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT') and (tracer is null or tracer not like 'ERROR:%') group by sql1 @@ -358,14 +388,19 @@ Committed_AS: 348732 kB $s = "

Suspicious SQL

The following SQL have high average execution times
\n"; + $max = $this->maxLength; while (!$rs->EOF) { - $sql = trim($rs->fields[1]); - - $prefix = ""; + $sql = $rs->fields[1]; + $raw = urlencode($sql); + if (strlen($raw)>$max-100) { + $sql2 = substr($sql,0,$max-500); + $raw = urlencode($sql2).'&part='.crc32($sql); + } + $prefix = ""; $suffix = ""; - if ($this->explain == false || strlen($prefix)>2000) { + if ($this->explain == false || strlen($prefix)>$max) { + $suffix = ' ... String too long for GET parameter: '.strlen($prefix).''; $prefix = ''; - $suffix = ''; } $s .= ""; @@ -401,11 +436,13 @@ Committed_AS: 348732 kB { global $HTTP_GET_VARS,$ADODB_FETCH_MODE; + $perf_table = adodb_perf::table(); $saveE = $this->conn->fnExecute; $this->conn->fnExecute = false; if (isset($HTTP_GET_VARS['expe']) && isset($HTTP_GET_VARS['sql'])) { - echo "".$this->Explain($HTTP_GET_VARS['sql'])."\n"; + $partial = !empty($HTTP_GET_VARS['part']); + echo "".$this->Explain($HTTP_GET_VARS['sql'],$partial)."\n"; } if (isset($HTTP_GET_VARS['sql'])) return; @@ -415,7 +452,7 @@ Committed_AS: 348732 kB $ADODB_FETCH_MODE = ADODB_FETCH_NUM; $rs =& $this->conn->SelectLimit( "select sum(timer) as total,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer - from adodb_logsql + from $perf_table where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT') and (tracer is null or tracer not like 'ERROR:%') group by sql1 @@ -427,12 +464,17 @@ Committed_AS: 348732 kB $s = "

Expensive SQL

Tuning the following SQL will reduce the server load substantially
Avg TimeCountSQLMaxMin
".round($rs->fields[0],6)."".$rs->fields[2]."".$prefix.htmlspecialchars($sql).$suffix."". "".$rs->fields[3]."".$rs->fields[4]."
\n"; + $max = $this->maxLength; while (!$rs->EOF) { $sql = $rs->fields[1]; - - $prefix = ""; + $raw = urlencode($sql); + if (strlen($raw)>$max-100) { + $sql2 = substr($sql,0,$max-500); + $raw = urlencode($sql2).'&part='.crc32($sql); + } + $prefix = ""; $suffix = ""; - if($this->explain == false || strlen($prefix>2000)) { + if($this->explain == false || strlen($prefix>$max)) { $prefix = ''; $suffix = ''; } @@ -529,8 +571,9 @@ Committed_AS: 348732 kB function UI($pollsecs=5) { - global $HTTP_GET_VARS,$HTTP_SERVER_VARS; + global $HTTP_GET_VARS,$HTTP_SERVER_VARS,$HTTP_POST_VARS; + $perf_table = adodb_perf::table(); $conn = $this->conn; $app = $conn->host; @@ -541,7 +584,7 @@ Committed_AS: 348732 kB $savelog = $this->conn->LogSQL(false); $info = $conn->ServerInfo(); if (isset($HTTP_GET_VARS['clearsql'])) { - $this->conn->Execute('delete from adodb_logsql'); + $this->conn->Execute('delete from $perf_table'); } $this->conn->LogSQL($savelog); @@ -558,6 +601,7 @@ Committed_AS: 348732 kB if (isset($HTTP_GET_VARS['do'])) $do = $HTTP_GET_VARS['do']; + else if (isset($HTTP_POST_VARS['do'])) $do = $HTTP_POST_VARS['do']; else if (isset($HTTP_GET_VARS['sql'])) $do = 'viewsql'; else $do = 'stats'; @@ -568,11 +612,14 @@ Committed_AS: 348732 kB if ($do == 'viewsql') $form = ""; else $form = ""; + $allowsql = !defined('ADODB_PERF_NO_RUN_SQL'); + if (empty($HTTP_GET_VARS['hidem'])) echo "
LoadCountSQLMaxMin
# SQL:
 
ADOdb Performance Monitor for $app
Performance Stats   View SQL   View Tables   Poll Stats", + $allowsql ? '   Run SQL' : '', "$form", "
"; @@ -581,7 +628,7 @@ Committed_AS: 348732 kB default: case 'stats': echo $this->HealthCheck(); - + $this->conn->debug=1; echo $this->CheckMemory(); break; case 'poll': @@ -592,6 +639,12 @@ Committed_AS: 348732 kB echo "
";
 			$this->Poll($pollsecs);
 			break;
+		
+		case 'dosql':
+			if (!$allowsql) break;
+			
+			$this->DoSQLForm();
+			break;
 		case 'viewsql':
 			if (empty($HTTP_GET_VARS['hidem']))
 				echo "  Clear SQL Log
"; @@ -747,8 +800,103 @@ Committed_AS: 348732 kB $this->conn->LogSQL($savelog); return ($ok) ? true : false; } -} + + function DoSQLForm() + { + global $HTTP_SERVER_VARS,$HTTP_GET_VARS,$HTTP_POST_VARS,$HTTP_SESSION_VARS; + + $HTTP_VARS = array_merge($HTTP_GET_VARS,$HTTP_POST_VARS); + + $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; + $sql = isset($HTTP_VARS['sql']) ? $HTTP_VARS['sql'] : ''; + if (isset($HTTP_SESSION_VARS['phplens_sqlrows'])) $rows = $HTTP_SESSION_VARS['phplens_sqlrows']; + else $rows = 3; + + if (isset($HTTP_VARS['SMALLER'])) { + $rows /= 2; + if ($rows < 3) $rows = 3; + $HTTP_SESSION_VARS['phplens_sqlrows'] = $rows; + } + if (isset($HTTP_VARS['BIGGER'])) { + $rows *= 2; + $HTTP_SESSION_VARS['phplens_sqlrows'] = $rows; + } + +?> + +
+ + + + + + +
Form size: + + +
+
+
+ +undomq(trim($sql)); + if (substr($sql,strlen($sql)-1) === ';') { + $print = true; + $sqla = $this->SplitSQL($sql); + } else { + $print = false; + $sqla = array($sql); + } + foreach($sqla as $sqls) { + + if (!$sqls) continue; + + if ($print) { + print "

".htmlspecialchars($sqls)."

"; + flush(); + } + $savelog = $this->conn->LogSQL(false); + $rs = $this->conn->Execute($sqls); + $this->conn->LogSQL($savelog); + if ($rs && is_object($rs) && !$rs->EOF) { + rs2html($rs); + while ($rs->NextRecordSet()) { + print "
 
"; + rs2html($rs); + } + } else { + $e1 = (integer) $this->conn->ErrorNo(); + $e2 = $this->conn->ErrorMsg(); + if (($e1) || ($e2)) { + if (empty($e1)) $e1 = '-1'; // postgresql fix + print '   '.$e1.': '.$e2; + } else { + print "

No Recordset returned

"; + } + } + } // foreach + } + + function SplitSQL($sql) + { + $arr = explode(';',$sql); + return $arr; + } + + function undomq(&$m) + { + if (get_magic_quotes_gpc()) { + // undo the damage + $m = str_replace('\\\\','\\',$m); + $m = str_replace('\"','"',$m); + $m = str_replace('\\\'','\'',$m); + } + return $m; +} +} diff --git a/lib/adodb/adodb-php4.inc.php b/lib/adodb/adodb-php4.inc.php new file mode 100644 index 0000000000..ef2f55e393 --- /dev/null +++ b/lib/adodb/adodb-php4.inc.php @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/lib/adodb/adodb-time.inc.php b/lib/adodb/adodb-time.inc.php index 5ea9c9eef9..15545f12fe 100644 --- a/lib/adodb/adodb-time.inc.php +++ b/lib/adodb/adodb-time.inc.php @@ -23,7 +23,7 @@ This library replaces native functions as follows: date() with adodb_date() gmdate() with adodb_gmdate() mktime() with adodb_mktime() - gmmktime() with adodb_gmmktime()45 + gmmktime() with adodb_gmmktime()
The parameters are identical, except that adodb_date() accepts a subset @@ -56,7 +56,7 @@ adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582) COPYRIGHT (c) 2003 John Lim and released under BSD-style license except for code by jackbbs, -which includes adodb_mktime, adodb_get_gmt_different, adodb_is_leap_year +which includes adodb_mktime, adodb_get_gmt_diff, adodb_is_leap_year and originally found at http://www.php.net/manual/en/function.mktime.php ============================================================================= @@ -174,6 +174,9 @@ c. Implement daylight savings, which looks awfully complicated, see CHANGELOG +- 26 Oct 2003 0.11 +Because of daylight savings problems (some systems apply daylight savings to +January!!!), changed adodb_get_gmt_diff() to ignore daylight savings. - 9 Aug 2003 0.10 Fixed bug with dates after 2038. @@ -231,7 +234,7 @@ First implementation. /* Version Number */ -define('ADODB_DATE_VERSION',0.10); +define('ADODB_DATE_VERSION',0.11); /* We check for Windows as only +ve ints are accepted as dates on Windows. @@ -496,13 +499,13 @@ function adodb_year_digit_check($y) /** get local time zone offset from GMT */ -function adodb_get_gmt_different() +function adodb_get_gmt_diff() { -static $DIFF; - if (isset($DIFF)) return $DIFF; +static $TZ; + if (isset($TZ)) return $TZ; - $DIFF = mktime(0,0,0,1,2,1970) - gmmktime(0,0,0,1,2,1970); - return $DIFF; + $TZ = mktime(0,0,0,1,2,1970,0) - gmmktime(0,0,0,1,2,1970,0); + return $TZ; } /** @@ -527,7 +530,7 @@ function adodb_getdate($d=false,$fast=false) */ function _adodb_getdate($origd=false,$fast=false,$is_gmt=false) { - $d = $origd - ($is_gmt ? 0 : adodb_get_gmt_different()); + $d = $origd - ($is_gmt ? 0 : adodb_get_gmt_diff()); $_day_power = 86400; $_hour_power = 3600; @@ -709,7 +712,7 @@ function adodb_date($fmt,$d=false,$is_gmt=false) if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs; - $gmt = adodb_get_gmt_different(); + $gmt = adodb_get_gmt_diff(); $dates .= sprintf(' %s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break; case 'Y': $dates .= $year; break; @@ -738,9 +741,9 @@ function adodb_date($fmt,$d=false,$is_gmt=false) // HOUR case 'Z': - $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_different(); break; + $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff(); break; case 'O': - $gmt = ($is_gmt) ? 0 : adodb_get_gmt_different(); + $gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff(); $dates .= sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break; case 'H': @@ -820,7 +823,7 @@ function adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst=false,$is_gmt=false) return @mktime($hr,$min,$sec,$mon,$day,$year); } - $gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_different(); + $gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_diff(); $hr = intval($hr); $min = intval($min); diff --git a/lib/adodb/adodb.inc.php b/lib/adodb/adodb.inc.php index 4f40b6a2af..46a72684e5 100644 --- a/lib/adodb/adodb.inc.php +++ b/lib/adodb/adodb.inc.php @@ -2,7 +2,7 @@ /* * Set tabs to 4 for best viewing. * - * Latest version is available at http://php.weblogs.com + * Latest version is available at http://php.weblogs.com/adodb * * This is the main include file for ADOdb. * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php @@ -14,7 +14,7 @@ /** \mainpage - @version V4.01 23 Oct 2003 (c) 2000-2003 John Lim (jlim\@natsoft.com.my). All rights reserved. + @version V4.11 27 Jan 2004 (c) 2000-2004 John Lim (jlim\@natsoft.com.my). All rights reserved. Released under both BSD license and Lesser GPL library license. You can choose which license you prefer. @@ -40,28 +40,6 @@ // 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... @@ -69,15 +47,12 @@ */ 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 @@ -88,17 +63,47 @@ // 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); + if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) { + + define('ADODB_BAD_RS','

Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;

'); + + // allow [ ] @ ` and . in table names + define('ADODB_TABLE_REGEX','([]0-9a-z_\`\.\@\[-]*)'); + + // prefetching used by oracle + if (!defined('ADODB_PREFETCH_ROWS')) define('ADODB_PREFETCH_ROWS',10); + + + /* + Controls ADODB_FETCH_ASSOC field-name case. Default is 2, use native case-names. + This currently works only with mssql, odbc, oci8po and ibase derived drivers. + + 0 = assoc lowercase field names. $rs->fields['orderid'] + 1 = assoc uppercase field names. $rs->fields['ORDERID'] + 2 = use native-case field names. $rs->fields['OrderID'] + */ + + define('ADODB_FETCH_DEFAULT',0); + define('ADODB_FETCH_NUM',1); + define('ADODB_FETCH_ASSOC',2); + define('ADODB_FETCH_BOTH',3); + + if (!defined('TIMESTAMP_FIRST_YEAR')) define('TIMESTAMP_FIRST_YEAR',100); + + 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); + } + } + + //if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2); + /** Accepts $src and $dest arrays, replacing string $data @@ -121,7 +126,6 @@ { 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; @@ -140,22 +144,17 @@ // 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 = 'V4.01 23 Oct 2003 (c) 2000-2003 John Lim (jlim#natsoft.com.my). All rights reserved. Released BSD & LGPL.'; + $ADODB_vers = 'V4.11 27 Jan 2004 (c) 2000-2004 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; + if (!isset($ADODB_COUNTRECS)) $ADODB_COUNTRECS = true; } @@ -218,11 +217,16 @@ 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 $substr = 'substr'; /// substring operator + var $length = 'length'; /// string length operator + var $random = 'rand()'; /// random function + var $upperCase = false; /// uppercase function var $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the database var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt. var $true = '1'; /// string that represents TRUE for a database var $false = '0'; /// string that represents FALSE for a database var $replaceQuote = "\\'"; /// string to use to replace quotes + var $nameQuote = '"'; /// string to use to quote identifiers and names var $charSet=false; /// character set to use - only for interbase var $metaDatabasesSQL = ''; var $metaTablesSQL = ''; @@ -242,7 +246,6 @@ //-- 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 @@ -320,7 +323,7 @@ */ function outp($msg,$newline=true) { - global $HTTP_SERVER_VARS; + global $HTTP_SERVER_VARS,$ADODB_FLUSH; if (defined('ADODB_OUTP')) { $fn = ADODB_OUTP; @@ -332,7 +335,8 @@ if (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT'])) echo $msg; else echo strip_tags($msg); - flush(); + if (!empty($ADODB_FLUSH) && ob_get_length() !== false) flush(); // dp not flush if output buffering enabled - useless - thx to Jesse Mullan + } /** @@ -470,9 +474,9 @@ * if the database does not support prepare. * */ - function PrepareSP($sql) + function PrepareSP($sql,$param=false) { - return $this->Prepare($sql); + return $this->Prepare($sql,$param); } /** @@ -597,6 +601,23 @@ { return '?'; } + + /* + InParameter and OutParameter are self-documenting versions of Parameter(). + */ + function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) + { + return $this->Parameter($stmt,$var,$name,false,$maxLen,$type); + } + + /* + */ + function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) + { + return $this->Parameter($stmt,$var,$name,true,$maxLen,$type); + + } + /* Usage in oracle $stmt = $db->Prepare('select * from table where id =:myid and group=:group'); @@ -629,7 +650,6 @@ */ function StartTrans($errfn = 'ADODB_TransMonitor') { - if ($this->transOff > 0) { $this->transOff += 1; return; @@ -662,8 +682,11 @@ $this->transOff = 0; if ($this->_transOK && $autoComplete) { - $this->CommitTrans(); - if ($this->debug) ADOConnection::outp("Smart Commit occurred"); + if (!$this->CommitTrans()) { + $this->_transOK = false; + if ($this->debug) ADOConnection::outp("Smart Commit failed"); + } else + if ($this->debug) ADOConnection::outp("Smart Commit occurred"); } else { $this->RollbackTrans(); if ($this->debug) ADOCOnnection::outp("Smart Rollback occurred"); @@ -717,12 +740,11 @@ if (!is_array($sql) && !$this->_bindInputArray) { $sqlarr = explode('?',$sql); - + if (!$array_2d) $inputarr = array($inputarr); - while(list(,$arr) = each($inputarr)) { + foreach($inputarr as $arr) { $sql = ''; $i = 0; - reset($arr); - while(list(,$v) = each($arr)) { + foreach($arr as $v) { $sql .= $sqlarr[$i]; // from Ron Baldwin // Only quote string types @@ -735,18 +757,17 @@ $i += 1; } $sql .= $sqlarr[$i]; + if ($i+1 != sizeof($sqlarr)) ADOConnection::outp( "Input Array does not match ?: ".htmlspecialchars($sql)); - + $ret =& $this->_Execute($sql,false); if (!$ret) return $ret; - } - + } } else { - if ($array_2d) { $stmt = $this->Prepare($sql); - while(list(,$arr) = each($inputarr)) { + foreach($inputarr as $arr) { $ret =& $this->_Execute($stmt,$arr); if (!$ret) return $ret; } @@ -756,7 +777,7 @@ } else { $ret =& $this->_Execute($sql,false); } - + return $ret; } @@ -765,10 +786,9 @@ // debug version of query if ($this->debug) { global $HTTP_SERVER_VARS; - $ss = ''; if ($inputarr) { - foreach ($inputarr as $kk => $vv) { + foreach($inputarr as $kk=>$vv) { if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...'; $ss .= "($kk=>'$vv') "; } @@ -785,7 +805,6 @@ else ADOConnection::outp( "
\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); /* @@ -799,7 +818,6 @@ $err = $this->ErrorNo(); if ($err) { ADOConnection::outp($err.': '.$emsg); - flush(); } } } else @@ -807,7 +825,6 @@ $e = $this->ErrorNo(); $m = $this->ErrorMsg(); ADOConnection::outp($e .': '. $m ); - flush(); } } else { // non-debug version of query @@ -859,7 +876,7 @@ if (empty($this->_genSeqSQL)) return false; return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID)); } - + function DropSequence($seqname) { if (empty($this->_dropSeqSQL)) return false; @@ -874,7 +891,6 @@ * @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) { @@ -882,8 +898,11 @@ } $getnext = sprintf($this->_genIDSQL,$seqname); + + $holdtransOK = $this->_transOK; $rs = @$this->Execute($getnext); if (!$rs) { + $this->_transOK = $holdtransOK; //if the status was ok before reset $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID)); $rs = $this->Execute($getnext); } @@ -898,48 +917,49 @@ /** * @return the last inserted ID. Not all databases support this. */ - function Insert_ID() - { - if ($this->_logsql && $this->lastInsID) return $this->lastInsID; - if ($this->hasInsertID) return $this->_insertid(); - if ($this->debug) ADOConnection::outp( '

Insert_ID error

'); - return false; + function Insert_ID() + { + if ($this->_logsql && $this->lastInsID) return $this->lastInsID; + if ($this->hasInsertID) return $this->_insertid(); + if ($this->debug) { + ADOConnection::outp( '

Insert_ID error

'); + adodb_backtrace(); } - - + 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) { - if ($this->fnExecute === 'adodb_log_sql') { - - if ($this->_logsql && $this->_affected !== false) return $this->_affected; - } - $val = $this->_affectedrows(); - return ($val < 0) ? false : $val; - } + 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) { + if ($this->fnExecute === 'adodb_log_sql') { + if ($this->_logsql && $this->_affected !== false) return $this->_affected; + } + $val = $this->_affectedrows(); + return ($val < 0) ? false : $val; + } - if ($this->debug) ADOConnection::outp( '

Affected_Rows error

',false); - return false; - } + if ($this->debug) ADOConnection::outp( '

Affected_Rows error

',false); + return false; + } /** @@ -987,6 +1007,8 @@ } } if (sizeof($p)) return $p; + if (function_exists('ADODB_VIEW_PRIMARYKEYS')) + return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner); return false; } @@ -1089,6 +1111,19 @@ return $rs; } + /** + * Create serializable recordset. Breaks rs link to connection. + * + * @param rs the recordset to serialize + */ + function &SerializableRS(&$rs) + { + $rs2 =& $this->_rs2rs($rs); + $ignore = false; + $rs2->connection =& $ignore; + + return $rs2; + } /** * Convert database recordset to an array recordset @@ -1203,6 +1238,7 @@ $rv = false; $rs = &$this->Execute($sql, $inputarr); if ($rs) { + $rv = array(); if ($trim) { while (!$rs->EOF) { $rv[] = trim(reset($rs->fields)); @@ -1311,8 +1347,8 @@ $ADODB_COUNTRECS = $crecs; if ($rs) { - $arr = array(); if (!$rs->EOF) $arr = $rs->fields; + else $arr = array(); $rs->Close(); return $arr; } @@ -1354,76 +1390,10 @@ 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 strncmp($v,"'",1) !== 0 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"; + global $ADODB_INCLUDED_LIB; + if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php'); - $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; + return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc); } @@ -1451,7 +1421,7 @@ if ($sql === false) $sql = -1; if ($offset == -1) $offset = false; // sql, nrows, offset,inputarr - $rs =& $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$inputarr,$this->cacheSecs); + $rs =& $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs); } else { if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()"); $rs =& $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); @@ -1797,23 +1767,6 @@ } } - /* - * 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 @@ -1934,20 +1887,33 @@ } + function _findschema(&$table,&$schema) + { + if (!$schema && ($at = strpos($table,'.')) !== false) { + $schema = substr($table,0,$at); + $table = substr($table,$at+1); + } + } + /** * List columns in a database as an array of ADOFieldObjects. * See top of file for definition of object. * * @param table table name to query * @param upper uppercase table name (required by some databases) + * @schema is optional database schema to use - not supported by all databases. * * @return array of ADOFieldObjects for current table. - */ + */ function &MetaColumns($table,$upper=true) { global $ADODB_FETCH_MODE; - + if (!empty($this->metaColumnsSQL)) { + + $schema = false; + $this->_findschema($table,$schema); + $save = $ADODB_FETCH_MODE; $ADODB_FETCH_MODE = ADODB_FETCH_NUM; if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); @@ -1978,6 +1944,18 @@ return false; } + /** + * List indexes on a table as an array. + * @param table table name to query + * @param primary include primary keys. + * + * @return array of indexes on current table. + */ + function &MetaIndexes($table, $primary = false, $owner = false) + { + return FALSE; + } + /** * List columns names in a table as an array. * @param table table name to query @@ -2025,7 +2003,7 @@ if (empty($d) && $d !== 0) return 'null'; if (is_string($d) && !is_numeric($d)) { - if ($d === 'null') return $d; + if ($d === 'null' || strncmp($d,"'",1) === 0) return $d; if ($this->isoDates) return "'$d'"; $d = ADOConnection::UnixDate($d); } @@ -2045,12 +2023,14 @@ { if (empty($ts) && $ts !== 0) return 'null'; - if (is_string($ts) && !is_numeric($ts)) { - if ($ts === 'null') return $ts; - if ($this->isoDates) return "'$ts'"; - else $ts = ADOConnection::UnixTimeStamp($ts); - } - + # strlen(14) allows YYYYMMDDHHMMSS format + if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) + return adodb_date($this->fmtTimeStamp,$ts); + + if ($ts === 'null') return $ts; + if ($this->isoDates && strlen($ts) !== 14) return "'$ts'"; + + $ts = ADOConnection::UnixTimeStamp($ts); return adodb_date($this->fmtTimeStamp,$ts); } @@ -2123,7 +2103,8 @@ */ function UserTimeStamp($v,$fmt='Y-m-d H:i:s') { - if (is_numeric($v)) return adodb_date($fmt,$v); + # strlen(14) allows YYYYMMDDHHMMSS format + if (is_numeric($v) && strlen($v)<14) return adodb_date($fmt,$v); $tt = $this->UnixTimeStamp($v); // $tt == -1 if pre TIMESTAMP_FIRST_YEAR if (($tt === false || $tt == -1) && $v != false) return $v; @@ -2263,22 +2244,23 @@ //============================================================================================== // CLASS ADORecordSet //============================================================================================== - + if (PHP_VERSION < 5) include_once(ADODB_DIR.'/adodb-php4.inc.php'); + else include_once(ADODB_DIR.'/adodb-iterator.inc.php'); /** * RecordSet class that represents the dataset returned by the database. * To keep memory overhead low, this class holds only the current row in memory. * No prefetching of data is done, so the RecordCount() can return -1 ( which * means recordcount not known). */ - class ADORecordSet { + class ADORecordSet extends ADODB_BASE_RS { /* * public variables */ var $dataProvider = "native"; var $fields = false; /// holds the current row data var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob - /// in other words, we use a text area for editting. + /// in other words, we use a text area for editing. var $canSeek = false; /// indicates that seek is supported var $sql; /// sql text var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object. @@ -2534,7 +2516,7 @@ */ function UserTimeStamp($v,$fmt='Y-m-d H:i:s') { - if (is_numeric($v)) return adodb_date($fmt,$v); + if (is_numeric($v) && strlen($v)<14) return adodb_date($fmt,$v); $tt = $this->UnixTimeStamp($v); // $tt == -1 if pre TIMESTAMP_FIRST_YEAR if (($tt === false || $tt == -1) && $v != false) return $v; @@ -2792,16 +2774,14 @@ */ function &GetRowAssoc($upper=1) { - + $record = array(); + // if (!$this->fields) return $record; + if (!$this->bind) { $this->GetAssocKeys($upper); } - $record = array(); - reset($this->bind); - while(list($k,$v) = each($this->bind)) { - //echo " $k $v, "; - //foreach($this->bind as $k => $v) { + foreach($this->bind as $k => $v) { $record[$k] = $this->fields[$v]; } @@ -3067,6 +3047,7 @@ 'TIMESTAMPTZ' => 'T', 'T' => 'T', ## + 'BOOL' => 'L', 'BOOLEAN' => 'L', 'BIT' => 'L', 'L' => 'L', @@ -3122,7 +3103,7 @@ case 'C': // is the char field is too long, return as text field... - if (!empty($this->blobSize)) { + if ($this->blobSize >= 0) { if ($len > $this->blobSize) return 'X'; } else if ($len > 250) { return 'X'; @@ -3185,6 +3166,7 @@ if ($status != false) $this->_atLastPage = $status; return $this->_atLastPage; } + } // end class ADORecordSet //============================================================================================== @@ -3228,7 +3210,7 @@ /** - * Setup the Array. Later we will have XML-Data and CSV handlers + * Setup the array. * * @param array is a 2-dimensional array holding the data. * The first row should hold the column names @@ -3245,8 +3227,10 @@ if ($colnames) { $this->_skiprow1 = false; $this->_colnames = $colnames; - } else $this->_colnames = $array[0]; - + } else { + $this->_skiprow1 = true; + $this->_colnames = $array[0]; + } $this->Init(); } /** @@ -3316,7 +3300,9 @@ function _seek($row) { - if (sizeof($this->_array) && $row < $this->_numOfRows) { + if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) { + $this->_currentRow = $row; + if ($this->_skiprow1) $row += 1; $this->fields = $this->_array[$row]; return true; } @@ -3329,11 +3315,11 @@ $this->_currentRow++; $pos = $this->_currentRow; - if ($this->_skiprow1) $pos += 1; if ($this->_numOfRows <= $pos) { if (!$this->compat) $this->fields = false; } else { + if ($this->_skiprow1) $pos += 1; $this->fields = $this->_array[$pos]; return true; } @@ -3346,13 +3332,12 @@ function _fetch() { $pos = $this->_currentRow; - if ($this->_skiprow1) $pos += 1; if ($this->_numOfRows <= $pos) { if (!$this->compat) $this->fields = false; return false; } - + if ($this->_skiprow1) $pos += 1; $this->fields = $this->_array[$pos]; return true; } @@ -3369,7 +3354,7 @@ //============================================================================================== /** - * Synonym for ADOLoadCode. + * Synonym for ADOLoadCode. Private function. Do not use. * * @deprecated */ @@ -3379,21 +3364,28 @@ } /** - * Load the code for a specific database driver + * Load the code for a specific database driver. Private function. Do not use. */ function ADOLoadCode($dbType) { - GLOBAL $ADODB_Database; + global $ADODB_LASTDB; if (!$dbType) return false; - $ADODB_Database = strtolower($dbType); - switch ($ADODB_Database) { - case 'maxsql': $ADODB_Database = 'mysqlt'; break; + $db = strtolower($dbType); + switch ($db) { + case 'maxsql': $db = 'mysqlt'; break; case 'postgres': - case 'pgsql': $ADODB_Database = 'postgres7'; break; + case 'pgsql': $db = 'postgres7'; break; } - // Karsten Kraus - return @include_once(ADODB_DIR."/drivers/adodb-".$ADODB_Database.".inc.php"); + $ok = @include_once(ADODB_DIR."/drivers/adodb-".$db.".inc.php"); + $ADODB_LASTDB = $db; + + if ($ok) return $db; + + $file = ADODB_DIR."/drivers/adodb-".$db.".inc.php"; + if (file_exists($file)) ADOConnection::outp("Missing file: $file"); + else ADOConnection::outp("Syntax error in file: $file"); + return false; } /** @@ -3415,7 +3407,7 @@ */ function &ADONewConnection($db='') { - GLOBAL $ADODB_Database,$ADODB_NEWCONNECTION; + GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB; if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2); $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false; @@ -3428,30 +3420,30 @@ } } - $rez = true; - if ($db) { - if ($ADODB_Database != $db) ADOLoadCode($db); - } else { - if (!empty($ADODB_Database)) { - ADOLoadCode($ADODB_Database); - } else { - $rez = false; - } - } + if (!isset($ADODB_LASTDB)) $ADODB_LASTDB = ''; + if (empty($db)) $db = $ADODB_LASTDB; + + if ($db != $ADODB_LASTDB) $db = ADOLoadCode($db); - if (!$rez) { + if (!$db) { if ($errorfn) { // raise an error + $ignore = false; $errorfn('ADONewConnection', 'ADONewConnection', -998, "could not load the database driver for '$db", - $dbtype); + $db,false,$ignore); } else ADOConnection::outp( "

ADONewConnection: Unable to load database driver '$db'

",false); return false; } - $cls = 'ADODB_'.$ADODB_Database; + $cls = 'ADODB_'.$db; + if (!class_exists($cls)) { + adodb_backtrace(); + return false; + } + $obj =& new $cls(); if ($errorfn) $obj->raiseErrorFn = $errorfn; @@ -3515,6 +3507,7 @@ $dict->dataProvider = $conn->dataProvider; $dict->connection = &$conn; $dict->upperName = strtoupper($drivername); + $dict->quote = $conn->nameQuote; if (is_resource($conn->_connectionID)) $dict->serverInfo = $conn->ServerInfo(); @@ -3541,8 +3534,6 @@ if (strncmp(PHP_OS,'WIN',3) === 0) { // 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; @@ -3550,6 +3541,8 @@ if (!fwrite($fd,$contents)) $ok = false; fclose($fd); chmod($tmpname,0644); + // the tricky moment + @unlink($filename); if (!@rename($tmpname,$filename)) { unlink($tmpname); $ok = false; @@ -3573,57 +3566,74 @@ return $ok; } - + /* + Perform a print_r, with pre tags for better formatting. + */ function adodb_pr($var) { - echo "
\n";print_r($var);echo "
\n"; + if (isset($_SERVER['HTTP_USER_AGENT'])) { + echo "
\n";print_r($var);echo "
\n"; + } else + print_r($var); } - function adodb_backtrace($print=true,$levels=9999) + /* + Perform a stack-crawl and pretty print it. + + @param printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then). + @param levels Number of levels to display + */ + function adodb_backtrace($printOrArr=true,$levels=9999) { $s = ''; - if (PHPVERSION() >= 4.3) { + if (PHPVERSION() < 4.3) return; + + $html = (isset($_SERVER['HTTP_USER_AGENT'])); + $fmt = ($html) ? " %% line %4d, file: %s" : "%% line %4d, file: %s"; + + $MAXSTRLEN = 64; + + $s = ($html) ? '
' : '';
 		
-			$MAXSTRLEN = 64;
+		if (is_array($printOrArr)) $traceArr = $printOrArr;
+		else $traceArr = debug_backtrace();
+		array_shift($traceArr);
+		$tabs = sizeof($traceArr)-1;
 		
-			$s = '
';
-			$traceArr = debug_backtrace();
-			array_shift($traceArr);
-			$tabs = sizeof($traceArr)-1;
+		foreach ($traceArr as $arr) {
+			$levels -= 1;
+			if ($levels < 0) break;
 			
-			foreach ($traceArr as $arr) {
-				$levels -= 1;
-				if ($levels < 0) break;
-				
-				$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;
-					}
+			$args = array();
+			for ($i=0; $i < $tabs; $i++) $s .=  ($html) ? '   ' : "\t";
+			$tabs -= 1;
+			if ($html) $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; - } + } + $s .= $arr['function'].'('.implode(', ',$args).')'; + + + $s .= @sprintf($fmt, $arr['line'],$arr['file'],basename($arr['file'])); + + $s .= "\n"; + } + if ($html) $s .= '
'; + if ($printOrArr) print $s; + return $s; } - } // defined ?> \ No newline at end of file diff --git a/lib/adodb/datadict/datadict-access.inc.php b/lib/adodb/datadict/datadict-access.inc.php index 39ba17da1e..f1760c941b 100644 --- a/lib/adodb/datadict/datadict-access.inc.php +++ b/lib/adodb/datadict/datadict-access.inc.php @@ -1,7 +1,7 @@ schema) $tabname = $this->schema.'.'.$tabname; + { + $tabname = $this->TableName ($tabname); $f = array(); list($lines,$pkey) = $this->_GenFields($flds); $s = "ALTER TABLE $tabname $this->addCol"; @@ -82,9 +81,10 @@ class ADODB2_mssql extends ADODB_DataDict { return $sql; } + /* function AlterColumnSQL($tabname, $flds) { - if ($this->schema) $tabname = $this->schema.'.'.$tabname; + $tabname = $this->TableName ($tabname); $sql = array(); list($lines,$pkey) = $this->_GenFields($flds); foreach($lines as $v) { @@ -93,13 +93,15 @@ class ADODB2_mssql extends ADODB_DataDict { return $sql; } + */ function DropColumnSQL($tabname, $flds) { - if ($this->schema) $tabname = $this->schema.'.'.$tabname; - if (!is_array($flds)) $flds = explode(',',$flds); + $tabname = $this->TableName ($tabname); + if (!is_array($flds)) + $flds = explode(',',$flds); $f = array(); - $s = "ALTER TABLE $tabname"; + $s = 'ALTER TABLE ' . $tabname; foreach($flds as $v) { $f[] = "\n$this->dropCol $v"; } @@ -194,15 +196,29 @@ CREATE TABLE */ function _IndexSQL($idxname, $tabname, $flds, $idxoptions) { - if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX $tabname.$idxname"; - if (isset($idxoptions['UNIQUE'])) $unique = ' UNIQUE'; - else $unique = ''; - if (is_array($flds)) $flds = implode(', ',$flds); - if (isset($idxoptions['CLUSTERED'])) $clustered = ' CLUSTERED'; - else $clustered = ''; + $sql = array(); + + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $tabname . '.' . $idxname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + + $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : ''; + $clustered = isset($idxoptions['CLUSTERED']) ? ' CLUSTERED' : ''; - $s = "CREATE$unique$clustered INDEX $idxname ON $tabname ($flds)"; - if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName]; + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s = 'CREATE' . $unique . $clustered . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')'; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + $sql[] = $s; return $sql; diff --git a/lib/adodb/datadict/datadict-mysql.inc.php b/lib/adodb/datadict/datadict-mysql.inc.php index 068821a5c7..2eed142e66 100644 --- a/lib/adodb/datadict/datadict-mysql.inc.php +++ b/lib/adodb/datadict/datadict-mysql.inc.php @@ -1,7 +1,7 @@ dropIndex, $this->NameQuote($idxname), $this->TableName($tabname))); + } + function _IndexSQL($idxname, $tabname, $flds, $idxoptions) { - //if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX IF EXISTS $idxname"; - if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX $idxname ON $tabname"; - if (isset($idxoptions['FULLTEXT'])) $unique = ' FULLTEXT'; - else if (isset($idxoptions['UNIQUE'])) $unique = ' UNIQUE'; - else $unique = ''; + $sql = array(); + + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $idxname, $tabname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + + if (isset($idxoptions['FULLTEXT'])) { + $unique = ' FULLTEXT'; + } elseif (isset($idxoptions['UNIQUE'])) { + $unique = ' UNIQUE'; + } else { + $unique = ''; + } + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')'; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; - if (is_array($flds)) $flds = implode(', ',$flds); - $s = "CREATE$unique INDEX $idxname ON $tabname ($flds)"; - if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName]; $sql[] = $s; return $sql; diff --git a/lib/adodb/datadict/datadict-oci8.inc.php b/lib/adodb/datadict/datadict-oci8.inc.php index 17d71e12ec..e3afdd8067 100644 --- a/lib/adodb/datadict/datadict-oci8.inc.php +++ b/lib/adodb/datadict/datadict-oci8.inc.php @@ -1,7 +1,7 @@ dropIndex, $idxname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + if (isset($idxoptions['BITMAP'])) { $unique = ' BITMAP'; - } else if (isset($idxoptions['UNIQUE'])) + } elseif (isset($idxoptions['UNIQUE'])) { $unique = ' UNIQUE'; - else + } else { $unique = ''; + } + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')'; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; - if (is_array($flds)) $flds = implode(', ',$flds); - $s = "CREATE$unique INDEX $idxname ON $tabname ($flds)"; - if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName]; - if (isset($idxoptions['oci8'])) $s .= $idxoptions['oci8']; + if (isset($idxoptions['oci8'])) + $s .= $idxoptions['oci8']; + + $sql[] = $s; return $sql; diff --git a/lib/adodb/datadict/datadict-postgres.inc.php b/lib/adodb/datadict/datadict-postgres.inc.php index 89914501a8..6279227fe0 100644 --- a/lib/adodb/datadict/datadict-postgres.inc.php +++ b/lib/adodb/datadict/datadict-postgres.inc.php @@ -1,7 +1,7 @@ upperName])) $s .= $idxoptions[$this->upperName]; - $s .= "($flds)"; + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $idxname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + + $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : ''; + + $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' '; + + if (isset($idxoptions['HASH'])) + $s .= 'USING HASH '; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s .= '(' . $flds . ')'; $sql[] = $s; return $sql; diff --git a/lib/adodb/datadict/datadict-sybase.inc.php b/lib/adodb/datadict/datadict-sybase.inc.php index 0535812162..37d1874b90 100644 --- a/lib/adodb/datadict/datadict-sybase.inc.php +++ b/lib/adodb/datadict/datadict-sybase.inc.php @@ -1,7 +1,7 @@ schema) $tabname = $this->schema.'.'.$tabname; + { + $tabname = $this->TableName ($tabname); $f = array(); list($lines,$pkey) = $this->_GenFields($flds); $s = "ALTER TABLE $tabname $this->addCol"; @@ -84,7 +84,7 @@ class ADODB2_sybase extends ADODB_DataDict { function AlterColumnSQL($tabname, $flds) { - if ($this->schema) $tabname = $this->schema.'.'.$tabname; + $tabname = $this->TableName ($tabname); $sql = array(); list($lines,$pkey) = $this->_GenFields($flds); foreach($lines as $v) { @@ -96,7 +96,7 @@ class ADODB2_sybase extends ADODB_DataDict { function DropColumnSQL($tabname, $flds) { - if ($this->schema) $tabname = $this->schema.'.'.$tabname; + $tabname = $this->TableName ($tabname); if (!is_array($flds)) $flds = explode(',',$flds); $f = array(); $s = "ALTER TABLE $tabname"; @@ -194,15 +194,28 @@ CREATE TABLE */ function _IndexSQL($idxname, $tabname, $flds, $idxoptions) { - if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX $tabname.$idxname"; - if (isset($idxoptions['UNIQUE'])) $unique = ' UNIQUE'; - else $unique = ''; - if (is_array($flds)) $flds = implode(', ',$flds); - if (isset($idxoptions['CLUSTERED'])) $clustered = ' CLUSTERED'; - else $clustered = ''; + $sql = array(); + + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $tabname . '.' . $idxname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } - $s = "CREATE$unique$clustered INDEX $idxname ON $tabname ($flds)"; - if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName]; + if ( empty ($flds) ) { + return $sql; + } + + $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : ''; + $clustered = isset($idxoptions['CLUSTERED']) ? ' CLUSTERED' : ''; + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s = 'CREATE' . $unique . $clustered . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')'; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + $sql[] = $s; return $sql; diff --git a/lib/adodb/docs-adodb.htm b/lib/adodb/docs-adodb.htm index ed41f28f89..65b808eb25 100644 --- a/lib/adodb/docs-adodb.htm +++ b/lib/adodb/docs-adodb.htm @@ -11,7 +11,7 @@

ADOdb Library for PHP

-

V4.01 23 Oct 2003 (c) 2000-2003 John Lim (jlim#natsoft.com)

+

V4.11 27 Jan 2004 (c) 2000-2004 John Lim (jlim#natsoft.com)

This software is dual licensed using BSD-Style and LGPL. This means you can use it in compiled proprietary and commercial products.

Useful ADOdb links: Download   Other Docs @@ -21,12 +21,16 @@ How People are using ADOdb
Feature Requests and Bug Reports
Installation
- Initializing Code and Connection Examples

- Hacking ADOdb Safely
- ADONewConnection + Minimum Install
+ Initializing Code and Connection Examples
+ ADONewConnection NewADOConnection
+ High Speed ADOdb - tuning tips
+ Hacking and Modifying ADOdb Safely
+ PHP5 Features

+ foreach iterators exceptions
Supported Databases
- Tutorial
+ Tutorials
Example 1: Select
Example 2: Advanced Select
Example 3: Insert
@@ -45,7 +49,7 @@ Caching
Pivot Tables

REFERENCE -

Variables: $ADODB_COUNTRECS +

Variables: $ADODB_COUNTRECS $ADODB_ANSI_PADDING_OFF $ADODB_CACHE_DIR $ADODB_FETCH_MODE $ADODB_LANG
Constants:
ADODB_ASSOC_CASE @@ -56,7 +60,8 @@ Executing SQL: Execute CacheExecute SelectLimit CacheSelectLimit Param Prepare PrepareSP - Parameter
+ InParameter OutParameter +
              GetOne CacheGetOne GetRow CacheGetRow GetAll CacheGetAll GetCol @@ -65,9 +70,11 @@                ExecuteCursor (oci8 only)
Generates SQL strings: GetUpdateSQL GetInsertSQL - Concat IfNull substr Param + Concat IfNull length random substr + qstr Param OffsetDate SQLDate - DBDate DBTimeStamp
+ DBDate DBTimeStamp +
Blobs: UpdateBlob UpdateClob UpdateBlobFile BlobEncode BlobDecode
@@ -78,11 +85,11 @@ BeginTrans CommitTrans RollbackTrans
Fetching Data:
SetFetchMode
- Strings: concat qstr quote substr
+ Strings: concat length qstr quote substr
Dates: DBDate DBTimeStamp UnixDate UnixTimeStamp OffsetDate SQLDate
- Row Management: Affected_Rows Insert_ID + Row Management: Affected_Rows Insert_ID RowLock GenID CreateSequence DropSequence
Error Handling: ErrorMsg ErrorNo @@ -93,7 +100,8 @@ ServerInfo
Statistics and Query-Rewriting: LogSQL fnExecute and fnCacheExecute
-
Deprecated: Bind BlankRecordSet
+
Deprecated: Bind BlankRecordSet + Parameter
ADORecordSet

@@ -176,7 +184,7 @@ visit http://php.weblog

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:

+ the connection settings correctly. You can debug using $db->debug = true as shown below:

<?php
 	include('adodb/adodb.inc.php');
 	$db = ADONewConnection($dbdriver); # eg 'mysql' or 'postgres'
@@ -187,18 +195,32 @@ visit http://php.weblog
 	print_r($rs->GetRows());
 	print "</pre>";
 ?>
-

Code Initialization

+ +

Minimum Install

+

For developers who want to release a minimal install of ADOdb, you will need: +

    +
  • adodb.inc.php +
  • adodb-lib.inc.php +
  • adodb-time.inc.php +
  • adodb-csvlib.inc.php (if you use cached recordsets - CacheExecute(), etc) +
  • adodb-error.inc.php and lang/adodb-$lang.inc.php (if you use MetaError()) +
  • drivers/adodb-$database.inc.php +
  • license.txt (for legal reasons) +
+ +

Code Initialization Examples

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.

+ 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 first need to decide whether to use persistent or non-persistent connections. The advantage of persistent @@ -215,6 +237,7 @@ the creation of a new connection. PHP will share the same connection. This can cause problems if the connections are meant to different databases. The solution is to always use different userid's for different databases, or use NConnect(). +

Examples of Connecting to Databases

MySQL and Most Other Database Drivers

MySQL connections are very straightforward, and the parameters are identical @@ -240,19 +263,24 @@ You define the database in the $host parameter: $conn = &ADONewConnection('ibase'); $conn->PConnect('localhost:c:\ibase\employee.gdb','sysdba','masterkey'); - +

SQLite

+Sqlite will create database if it does not exist. +
+	$conn = &ADONewConnection('sqlite'); 
+	$conn->PConnect('c:\path\to\sqlite.db'); # sqlite will create if does not exist
+

Oracle

With Oracle, you can connect in multiple ways.

a. PHP and Oracle reside on the same machine, use default SID.

	$conn->Connect(false, 'scott', 'tiger');
-

b. TNS Name defined, eg. 'TNSDB'

-
	$conn->PConnect(false, 'scott', 'tiger', TNSDB');
+

b. TNS Name defined, eg. 'myTNS'

+
	$conn->PConnect(false, 'scott', 'tiger', 'myTNS');
 

or

-
 	$conn->PConnect('TNSDB', 'scott', 'tiger');
-

c. Host address and SID

+
 	$conn->PConnect('myTNS', 'scott', 'tiger');
+

c. Host Address and SID

	$conn->Connect('192.168.0.1', 'scott', 'tiger', 'SID');
-

d. Host address and Service Name

+

d. Host Address and Service Name

	$conn->Connect('192.168.0.1', 'scott', 'tiger', 'servicename');

DSN-less ODBC (access and mssql examples)

@@ -262,7 +290,7 @@ You define the database in the $host parameter:

For Microsoft Access:

 	$db =& ADONewConnection('access');
-	$dsn = "Driver={Microsoft Access Driver (*.mdb)};Dbq=d:\northwind.mdb;Uid=Admin;Pwd=;";
+	$dsn = "Driver={Microsoft Access Driver (*.mdb)};Dbq=d:\\northwind.mdb;Uid=Admin;Pwd=;";
 	$db->Connect($dsn);
 
For Microsoft SQL Server: @@ -278,7 +306,6 @@ using the ADOdb library and Microsoft's ADO:
 <?php
 	include('adodb.inc.php'); 
-	ADOLoadCode("ado_mssql");
 	$db = &ADONewConnection("ado_mssql");
 	print "<h1>Connecting DSN-less $db->databaseType...</h1>";
 		
@@ -290,10 +317,36 @@ using the ADOdb library and Microsoft's ADO:
 	$arr = $rs->GetArray();
 	print_r($arr);
 ?>
-
- -

-

Hacking ADOdb Safely

+
+

High Speed ADOdb - tuning tips

+

ADOdb is a big class library, yet it consistently beats all other PHP class + libraries in performance. This is because it is designed in a layered fashion, + like an onion, with the fastest functions in the innermost layer. Stick to the + following functions for best performance:

+ + + + + + + +
Innermost Layer

Connect, PConnect, NConnect
+ Execute, CacheExecute
+ SelectLimit, SelectLimit
+ MoveNext, Close
+ qstr, Affected_Rows, Insert_ID

+

The fastest way to access the fields is by accessing the array $recordset->fields + directly. Also set the global variables $ADODB_FETCH_MODE + = ADODB_FETCH_NUM, and (for oci8, ibase/firebird and odbc) $ADODB_COUNTRECS = false + before you connect to your database. At the time of writing (Dec 2003).

+

Consider using bind parameters if your database supports it, as it improves + query plan reuse. Use ADOdb's performance tuning system to identify bottlenecks + quickly. At the time of writing (Dec 2003), this means oci8 and odbc drivers.

+

Lastly make sure you have a PHP accelerator cache installed such as APC, Turck + MMCache, Zend Accelerator or ionCube.

+

Informix tips: Disable scrollable cursors with $db->cursorType = 0. +

+

Hacking ADOdb Safely

You might want to modify ADOdb for your own purposes. Luckily you can still maintain backward compatibility by sub-classing ADOdb and using the $ADODB_NEWCONNECTION variable. $ADODB_NEWCONNECTION allows you to override the behaviour of ADONewConnection(). @@ -339,6 +392,35 @@ include_once('adodb.inc.php');

Don't forget to call the constructor of the parent class. + +

PHP5 Features

+ ADOdb 4.02 or later will transparently determine which version of PHP you are using. +If PHP5 is detected, the following features become available: +

Databases Supported

@@ -641,7 +723,7 @@ include_once('adodb.inc.php');

-

+

The "Tested" column indicates how extensively the code has been tested and used.
A = well tested and used by many people
@@ -659,7 +741,7 @@ include_once('adodb.inc.php'); is executed, so you can selectively choose which recordsets to count.


-

Tutorial

+

Tutorials

Example 1: Select Statement

Task: Connect to the Access Northwind DSN, display the first 2 columns of each row.

@@ -1124,7 +1206,7 @@ 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 ($rs) rs2html($rs); ?>

If you want to log the error message, you can do so by defining the following @@ -1145,7 +1227,7 @@ 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 ($rs) rs2html($rs); ?> The following message will be logged in the error.log file: @@ -1164,7 +1246,7 @@ 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 ($rs) rs2html($rs); else { $e = ADODB_Pear_Error(); echo '<p>',$e->message,'</p>'; @@ -1237,7 +1319,7 @@ $rs = $conn->CacheExec

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.

+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 @@ -1396,6 +1478,10 @@ tutorial. We assume that your database supports the SQL case-when expression

chown -R apache /path/to/adodb/cache
chgrp -R apache /path/to/adodb/cache

+

$ADODB_ANSI_PADDING_OFF

+

Determines whether to right trim CHAR fields (and also VARCHAR for ibase/firebird). +Set to true to trim. Default is false. Currently works for oci8po, ibase and firebird +drivers. Added in ADOdb 4.01.

$ADODB_LANG

Determines the language used in MetaErrorMsg(). The default is 'en', for English. To find out what languages are supported, see the files @@ -1562,7 +1648,7 @@ 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 + or later), postgresql and oci8-derived drivers. For other drivers, NConnect() works like Connect().

Execute($sql,$inputarr=false)

@@ -1587,6 +1673,7 @@ ADODB_NEVER_PERSIST before you call PConnect. Variable binding speeds the compilation and caching of SQL statements, leading to higher performance. Currently Oracle, Interbase and ODBC supports variable binding. Interbase/ODBC style ? binding is emulated in databases that do not support binding. +Note that you do not have to quote strings if you use binding.

Variable binding in the odbc, interbase and oci8po drivers.

 $rs = $db->Execute('select * from table where val=?', array('10'));
@@ -1654,7 +1741,7 @@ only with SELECT statements.
     # $rs is now just like any other ADOdb recordset object
rs2html($rs);

ExecuteCursor() is a helper function that does the following internally:

-	$stmt = $db->Prepare("BEGIN :RS := SP_FOO(); END;");
+	$stmt = $db->Prepare("BEGIN :RS := SP_FOO(); END;", true); 
 	$db->Parameter($stmt, $cur, 'RS', false, -1, OCI_B_CURSOR);
 	$rs = $db->Execute($stmt);

SelectLimit($sql,$numrows=-1,$offset=-1,$inputarr=false)

@@ -2048,7 +2135,7 @@ convention. for ($i=0; $i < $max; $i++)
$DB->Execute($stmt,array((string) rand(), $i)); -

Also see PrepareSP() and Parameter() below. Only supported internally by interbase, +

Also see InParameter(), OutParameter() and PrepareSP() below. 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.

Important: Due to limitations or bugs in PHP, if you are getting errors when @@ -2059,6 +2146,19 @@ for ($i=0; $i < $max; $i++)
$DB->Execute( the function that checks whether a $field is null for the given database, and if null, change the value returned to $nullReplacementValue. Eg.

$sql = 'SELECT '.$db->IfNull('name', "'- unknown -'"). ' FROM table';
+ +

length

+

This is not a function, but a property. Some databases have "length" and others "len" +as the function to measure the length of a string. To use this property: +

+  $sql = "SELECT ".$db->length."(field) from table";
+  $rs = $db->Execute($sql);
+
+ +

random

+

This is not a function, but a property. This is a string that holds the sql to +generate a random number between 0.0 and 1.0 inclusive. +

substr

This is not a function, but a property. Some databases have "substr" and others "substring" as the function to retrieve a sub-string. To use this property: @@ -2068,6 +2168,8 @@ as the function to retrieve a sub-string. To use this property:

For all databases, the 1st parameter of substr is the field, the 2nd is the offset (1-based) to the beginning of the sub-string, and the 3rd is the length of the sub-string. + +

Param($name )

Generates a bind placeholder portably. For most databases, the bind placeholder is "?". However some databases use named bind parameters such as Oracle, eg @@ -2086,12 +2188,72 @@ $stmt = $DB->Execute($stmt,array('one','two')); PrepareSP() allows you to do so.

Returns the same array or $sql string as Prepare( ) above. If you do not need to bind to return values, you should use Prepare( ) instead.

-

For examples of usage of PrepareSP( ), see Parameter( ) below. +

For examples of usage of PrepareSP( ), see InParameter( ) below.

Note: 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( ).

+

InParameter($stmt, $var, $name, + $maxLen = 4000, $type = false )

+Binds a PHP variable as input to a stored procedure variable. The parameter $stmt + is the value returned by PrepareSP(), $var is the PHP variable you want to bind, $name + is the name of the stored procedure variable. Optional is $maxLen, the maximum length of the + data to bind, and $type which is database dependant. + Consult mssql_bind and ocibindbyname docs + at php.net for more info on legal values for $type. +

+InParameter() is a wrapper function that calls Parameter() with $isOutput=false. +The advantage of this function is that it is self-documenting, because +the $isOutput parameter is no longer needed. Only for mssql + and oci8 currently. +

Here is an example using oci8: +

# For oracle, Prepare and PrepareSP are identical
+$stmt = $db->PrepareSP(
+	"declare RETVAL integer; 
+	begin
+	:RETVAL := SP_RUNSOMETHING(:myid,:group);
+	end;");
+$db->InParameter($stmt,$id,'myid');
+$db->InParameter($stmt,$group,'group',64);
+$db->OutParameter($stmt,$ret,'RETVAL');
$db->Execute($stmt); +
+

The same example using mssql:

+
+
# @RETVAL = SP_RUNSOMETHING @myid,@group
+$stmt = $db->PrepareSP('SP_RUNSOMETHING'); 
# note that the parameter name does not have @ in front! +$db->InParameter($stmt,$id,'myid'); +$db->InParameter($stmt,$group,'group',64); +# return value in mssql - RETVAL is hard-coded name +$db->OutParameter($stmt,$ret,'RETVAL'); +$db->Execute($stmt);
+ +

Note that the only difference between the oci8 and mssql implementations is $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'). +

OutParameter($stmt, $var, $name, + $maxLen = 4000, $type = false )

+ Binds a PHP variable as output from a stored procedure variable. The parameter $stmt + is the value returned by PrepareSP(), $var is the PHP variable you want to bind, $name + is the name of the stored procedure variable. Optional is $maxLen, the maximum length of the + data to bind, and $type which is database dependant. +

+ OutParameter() is a wrapper function that calls Parameter() with $isOutput=true. + The advantage of this function is that it is self-documenting, because +the $isOutput parameter is no longer needed. Only for mssql + and oci8 currently. +

+For an example, see InParameter. +

Parameter($stmt, $var, $name, $isOutput=false, $maxLen = 4000, $type = false )

+

Note: This function is deprecated, because of the new InParameter() and OutParameter() functions. +These are superior because they are self-documenting, unlike Parameter().

Adds a bind parameter suitable for return values or special data handling (eg. LOBs) after a statement has been prepared using PrepareSP(). Only for mssql and oci8 currently. The parameters are:
@@ -2105,25 +2267,6 @@ $stmt = $DB->Execute($stmt,array('one','two')); [$type] Consult mssql_bind and ocibindbyname docs at php.net for more info on legal values for type.

-

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;
@@ -2231,7 +2374,17 @@ Usage:
 	echo $perf->SuspiciousSQL();
 	echo $perf->ExpensiveSQL();
 
-

Also see Performance Monitor. +

One limitation of logging is that rollback also prevents SQL from being logged. +

+If you prefer to use another name for the table used to store the SQL, you can override it by calling +adodb_perf::table($tablename), where $tablename is the new table name (you will still need to manually +create the table yourself). An example: +

+	include('adodb.inc.php');
+	include('adodb-perf.inc.php');
+	adodb_perf::table('my_logsql_table');
+
+Also see Performance Monitor.

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 @@ -2318,8 +2471,18 @@ printf("<p>Total queries=%d; total cached=%d</p>",$EXECS+$

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 + as PostgreSQL, MySQL and MS SQL Server currently. PostgreSQL returns the OID, which can change on a database reload.

+

RowLock($table,$where)

+

Lock a table row for the duration of a transaction. For example to lock record $id in table1: +

+	$DB->StartTrans();
+	$DB->RowLock("table1","rowid=$id");
+	$DB->Execute($sql1);
+	$DB->Execute($sql2);
+	$DB->CompleteTrans();
+
+

Supported in db2, interbase, informix, mssql, oci8, postgres, sybase.

MetaDatabases()

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.

@@ -2333,10 +2496,15 @@ printf("<p>Total queries=%d; total cached=%d</p>",$EXECS+$

You can define a mask for matching. For example, setting $mask = 'TMP%' will match all tables that begin with 'TMP'. Currently only mssql, oci8, odbc_mssql and postgres* support $mask. -

MetaColumns($table)

+

MetaColumns($table,$toupper=true)

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)..

+ $table. A field object is a class instance with (name, type, max_length) defined. + Currently Sybase does not recognise date types, and ADO cannot identify + the correct data type (so we default to varchar). +

The $toupper parameter determines whether we uppercase the table name + (required for some databases). +

For schema support, pass in the $table parameter, "$schema.$tablename". This is only + supported for selected databases.

MetaColumnNames($table)

Returns an array of column names for $table.

MetaPrimaryKeys($table, @@ -2344,6 +2512,24 @@ printf("<p>Total queries=%d; total cached=%d</p>",$EXECS+$

Returns an array containing column names that are the primary keys of $table. Supported by mysql, odbc (including db2, odbc_mssql, etc), mssql, postgres, interbase/firebird, oci8 currently. +

Views (and some tables) have primary keys, but sometimes this information is not available from the +database. You can define a function ADODB_View_PrimaryKeys($databaseType, $database, $view, $owner) that +should return an array containing the fields that make up the primary key. If that function exists, +it will be called when MetaPrimaryKeys() cannot find a primary key for a table or view. +

+// In this example: dbtype = 'oci8', $db = 'mydb', $view = 'dataView', $owner = false 
+function ADODB_View_PrimaryKeys($dbtype,$db,$view,$owner)
+{
+	switch(strtoupper($view)) {
+	case 'DATAVIEW': return array('DATAID');
+	default: return false;
+	}
+}
+
+$db = NewADOConnection('oci8');
+$db->Connect('localhost','root','','mydb'); 
+$db->MetaPrimaryKeys('dataView');
+

ServerInfo($table)

Returns an array of containing two elements 'description' and 'version'. The 'description' element contains the string description of @@ -2437,12 +2623,12 @@ for GetArray() for compatibility with Microsoft ADO. time the selection is based on the 2nd column, which holds the values to return to the Web server.

UserDate($str, [$fmt])

-

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 date string $str to another format. The date format is Y-m-d, +or Unix timestamp format. The default $fmt is Y-m-d.

UserTimeStamp($str, [$fmt])

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. + format is Y-m-d H:i:s, as in '2002-02-28 23:00:12', or Unix timestamp format. + UserTimeStamp calls UnixTimeStamp to parse $str, and $fmt defaults to Y-m-d H:i:s if not defined.

UnixDate($str)

Parses the date string $str and returns it in unix mktime format (eg. @@ -2454,8 +2640,8 @@ for GetArray() for compatibility with Microsoft ADO.

UnixTimeStamp($str)

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 + to be in "Y-m-d, H:i:s" (1970-12-24, 00:00:00) or "Y-m-d H:i:s" (1970-12-24 00:00:00) or "YmdHis" (19701225000000) format, except for Sybase and Microsoft SQL Server, where + "M d Y h:i:sA" (Dec 25 1970 00:00:00AM) 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 @@ -2669,7 +2855,12 @@ For example, $db->MetaType('char') will return 'C'. parameter, instead of $nativeDBType.

Close( )

-

Close the recordset.

+

Closes the recordset, cleaning all memory and resources associated with the recordset. +

+If memory management is not an issue, you do not need to call this function as recordsets +are closed for you by PHP at the end of the script. +SQL statements such as INSERT/UPDATE/DELETE do not really return a recordset, so you do not have to call Close() +for such SQL statements.


function rs2html($adorecordset,[$tableheader_attributes], [$col_titles])

@@ -2778,17 +2969,93 @@ $rs = $conn->Execute

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, + your education, visit palslib.com for database info, and read this article on Optimizing PHP.

-
-

Change Log

+
+

Change Log

+

4.11 27 Jan 2004 +

Table misspelt in perf-oci8.inc.php. Changed v$conn_cache_advice to v$db_cache_advice. Reported by Steve W. +

UserTimeStamp and DBTimeStamp did not handle YYYYMMDDHHMMSS format properly. Reported by Mike Muir. Fixed. +

Changed oci8 Prepare(). Does not auto-allocate OCINewCursor automatically, unless 2nd param is set to true. +This will break backward compat, if Prepare/Execute is used instead of ExecuteCursor. Reported by Chris Jones. +

Added InParameter() and OutParameter(). Wrapper functions to Parameter(), but nicer because they +are self-documenting. +

Added 'R' handling in ActualType() to datadict-mysql.inc.php +

Added ADOConnection::SerializableRS($rs). Returns a recordset that can be serialized in a session. +

Added "Run SQL" to performance UI(). +

Misc spelling corrections in adodb-mysqli.inc.php, adodb-oci8.inc.php and datadict-oci8.inc.php, from Heinz Hombergs. +

MetaIndexes() for ibase contributed by Heinz Hombergs. +

4.10 12 Jan 2004 +

Dan Cech contributed extensive changes to data dictionary to support name quoting (with `), and drop table/index. +

Informix added cursorType property. Default remains IFX_SCROLL, but you can change to 0 (non-scrollable cursor) for performance. +

Added ADODB_View_PrimaryKeys() for returning view primary keys to MetaPrimaryKeys(). +

Simplified chinese file, adodb-cn.inc.php from cysoft. +

Added check for ctype_alnum in adodb-datadict.inc.php. Thx to Jason Judge. +

Added connection parameter to ibase Prepare(). Fix by Daniel Hassan. +

Added nameQuote for quoting identifiers and names to connection obj. Requested by Jason Judge. Also the +data dictionary parser now detects `field name` and generates column names with spaces correctly. +

BOOL type not recognised correctly as L. Fixed. +

Fixed paths in ADODB_DIR for session files, and back-ported it to 4.05 (15 Dec 2003) +

Added Schema to postgresql MetaTables. Thx to col#gear.hu +

Empty postgresql recordsets that had blob fields did not set EOF properly. Fixed. +

CacheSelectLimit internal parameters to SelectLimit were wrong. Thx to Nio. +

Modified adodb_pr() and adodb_backtrace() to support command-line usage (eg. no html). +

Fixed some fr and it lang errors. Thx to Gaetano G. +

Added contrib directory, with adodb rs to xmlrpc convertor by Gaetano G. +

Fixed array recordset bugs when _skiprow1 is true. Thx to Gaetano G. +

Fixed pivot table code when count is false. +

+ +

4.05 13 Dec 2003 +

Added MetaIndexes - thx to Dan Cech. +

Rewritten session code by Ross Smith. Moved code to adodb/session directory. +

Added function exists check on connecting to most drivers, so we don't crash with the unknown function error. +

Smart Transactions failed with GenID() when it no seq table has been created because the sql + statement fails. Fix by Mark Newnham. +

Added $db->length, which holds name of function that returns strlen. +

Fixed error handling for bad driver in ADONewConnection - passed too few params to error-handler. +

Datadict did not handle types like 16.0 properly in _GetSize. Fixed. +

Oci8 driver SelectLimit() bug &= instead of =& used. Thx to Swen Thümmler. +

Jesse Mullan suggested not flushing outp when output buffering enabled. Due to Apache 2.0 bug. Added. +

MetaTables/MetaColumns return ref bug with PHP5 fixed in adodb-datadict.inc.php. +

New mysqli driver contributed by Arjen de Rijke. Based on adodb 3.40 driver. +Then jlim added BeginTrans, CommitTrans, RollbackTrans, IfNull, SQLDate. Also fixed return ref bug. +

$ADODB_FLUSH added, if true then force flush in debugging outp. Default is false. In earlier +versions, outp defaulted to flush, which is not compat with apache 2.0. +

Mysql driver's GenID() function did not work when when sql logging is on. Fixed. +

$ADODB_SESSION_TBL not declared as global var. Not available if adodb-session.inc.php included in function. Fixed. +

The input array not passed to Execute() in _adodb_getcount(). Fixed. +

4.04 13 Nov 2003 +

Switched back to foreach - faster than list-each. +

Fixed bug in ado driver - wiping out $this->fields with date fields. +

Performance Monitor, View SQL, Explain Plan did not work if strlen($SQL)>max($_GET length). Fixed. +

Performance monitor, oci8 driver added memory sort ratio. +

Added random property, returns SQL to generate a floating point number between 0 and 1; +

4.03 6 Nov 2003 +

The path to adodb-php4.inc.php and adodb-iterators.inc.php was not setup properly. +

Patched SQLDate in interbase to support hours/mins/secs. Thx to ari kuorikoski. +

Force autorollback for pgsql persistent connections - +apparently pgsql did not autorollback properly before 4.3.4. See http://bugs.php.net/bug.php?id=25404 +

4.02 5 Nov 2003 +

Some errors in adodb_error_pg() fixed. Thx to Styve. +

Spurious Insert_ID() error was generated by LogSQL(). Fixed. +

Insert_ID was interfering with Affected_Rows() and Replace() when LogSQL() enabled. Fixed. +

More foreach loops optimized with list/each. +

Null dates not handled properly in ADO driver (it becomes 31 Dec 1969!). +

Heinz Hombergs contributed patches for mysql MetaColumns - adding scale, made +interbase MetaColumns work with firebird/interbase, and added lang/adodb-de.inc.php. +

Added INFORMIXSERVER environment variable. +

Added $ADODB_ANSI_PADDING_OFF for interbase/firebird. +

PHP 5 beta 2 compat check. Foreach (Iterator) support. Exceptions support.

4.01 23 Oct 2003 -

Informix ErrorNo() fixed. +

Fixed bug in rs2html(), tohtml.inc.php, that generated blank table cells. +

Fixed insert_id() incorrectly generated when logsql() enabled.

Modified PostgreSQL _fixblobs to use list/each instead of foreach. +

Informix ErrorNo() implemented correctly.

Modified several places to use list/each, including GetRowAssoc(). -

Fixed insert_id() incorrectly generated when logsql() enabled.

Added UserTimeStamp() to connection class. +

Added $ADODB_ANSI_PADDING_OFF for oci8po.

4.00 20 Oct 2003

Upgraded adodb-xmlschema to 1 Oct 2003 snapshot.

Fix to rs2html warning message. Thx to Filo. diff --git a/lib/adodb/docs-datadict.htm b/lib/adodb/docs-datadict.htm index 6840245a36..a5192d48ab 100644 --- a/lib/adodb/docs-datadict.htm +++ b/lib/adodb/docs-datadict.htm @@ -11,7 +11,7 @@

ADOdb Data Dictionary Library for PHP

-

V4.01 23 Oct 2003 (c) 2000-2003 John Lim (jlim#natsoft.com.my)

+

V4.11 27 Jan 2004 (c) 2000-2004 John Lim (jlim#natsoft.com.my)

This software is dual licensed using BSD-Style and LGPL. This means you can use it in compiled proprietary and commercial products.

Useful ADOdb links: Download   Other Docs @@ -65,9 +65,10 @@ $dict->ExecuteSQLArray($sqlarray);

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. -

+ +

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
@@ -97,40 +98,41 @@ N:  Numeric or decimal number
 

The $otheroptions include the following keywords (case-insensitive):

-AUTO			For autoincrement number. Emulated with triggers if not available.
+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.
+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.
+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', 
+	array('COLNAME',   'DECIMAL', '8.4', 'DEFAULT' => 0, 'NotNull'),
+	array('id',        'I'      , 'AUTO'),
+	array('`MY DATE`', '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, 
+ id I AUTO,
+ `MY DATE` D DEFDATE, 
  NAME C(32) CONSTRAINTS 'FOREIGN KEY REFERENCES reftable' 
 "; 
 

- The $taboptarray is the 3rd parameter of the CreateTableSQL function. + Note that if you have special characters in the field name (e.g. My Date), you should enclose it in back-quotes. Normally field names are not case-sensitive, but if you enclose it in back-quotes, some databases treat the names as case-sensitive, and some don't. So be careful. +

The $taboptarray is the 3rd parameter of the CreateTableSQL function. This contains table specific settings. Legal keywords include:

    @@ -138,6 +140,9 @@ Or the simpler declarative format: Indicates that the previous table definition should be removed (dropped)together with ALL data. See first example below.
    +
  • DROP
    + Drop table. Useful for removing unused tables.
    +
  • CONSTRAINTS
    Define this as the key, with the constraint as the value. See the postgresql example below. Additional constraints defined for the whole table. You @@ -177,6 +182,7 @@ Or the simpler declarative format: UNIQUE Make unique index FULLTEXT Make fulltext index (only mysql) HASH Create hash index (only postgres) + DROP Drop legacy index

function AddColumnSQL($tabname, $flds)

Add one or more columns. Not guaranteed to work under all situations. diff --git a/lib/adodb/docs-perf.htm b/lib/adodb/docs-perf.htm index 05c909cf9a..bfcaa77433 100644 --- a/lib/adodb/docs-perf.htm +++ b/lib/adodb/docs-perf.htm @@ -7,7 +7,7 @@

The ADOdb Performance Monitoring Library

-

V4.01 23 Oct 2003 (c) 2000-2003 John Lim (jlim#natsoft.com.my)

+

V4.11 27 Jan 2004 (c) 2000-2004 John Lim (jlim#natsoft.com.my)

This software is dual licensed using BSD-Style and LGPL. This means you can use it in compiled proprietary and commercial products.

Useful ADOdb links: Download   Other Docs diff --git a/lib/adodb/docs-session.htm b/lib/adodb/docs-session.htm index 16ca8cdc5f..04204789a6 100644 --- a/lib/adodb/docs-session.htm +++ b/lib/adodb/docs-session.htm @@ -3,22 +3,23 @@ ADODB Session Management Manual - + body,td {font-family:Arial,Helvetica,sans-serif;font-size:11pt} + pre {font-size:9pt} + .toplink {font-size:8pt} + /> +

ADODB Session Management Manual

-V4.01 23 Oct 2003 (c) 2000-2003 John Lim (jlim#natsoft.com.my) +V4.11 27 Jan 2004 (c) 2000-2004 John Lim (jlim#natsoft.com.my)

This software is dual licensed using BSD-Style and LGPL. This means you can use it in compiled proprietary and commercial products.

Useful ADOdb links: Download   Other Docs

Introduction

-

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. +

+We store state information specific to a user or web client in session variables. These session variables + persist throughout a session, as the user moves from page to page.

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 @@ -35,13 +36,15 @@ the session handler will keep track of the session by using a cookie. You can sa

Then 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 across multiple servers. +

Important Upgrade Notice: Since ADOdb 4.05, the session files have been moved to its own folder, adodb/session. This is a rewrite +of the session code by Ross Smith. The old session code is in adodb/session/old.

ADOdb Session Handler Features

  • Ability to define a notification function that is called when a session expires. Typically used to detect session logout and release global resources.
  • Optimization of database writes. We crc32 the session data and only perform an update to the session data if there is a data change. -
  • Support for large amounts of session data with CLOBs (see adodb-session-clob.inc.php). Useful +
  • Support for large amounts of session data with CLOBs (see adodb-session-clob.php). Useful for Oracle.
  • Support for encrypted session data, see adodb-cryptsession.inc.php. Enabling encryption is simply a matter of including adodb-cryptsession.inc.php instead of adodb-session.inc.php. @@ -49,110 +52,161 @@ is simply a matter of including adodb-cryptsession.inc.php instead of adodb-sess

    Setup

    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
    +adodb-session.php        : The default
    +adodb-session-clob.php   : Use this if you are storing DATA in clobs
    +adodb-cryptsession.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']}

    "; - + + include('adodb/adodb.inc.php'); + + $ADODB_SESSION_DRIVER='mysql'; + $ADODB_SESSION_CONNECT='localhost'; + $ADODB_SESSION_USER ='scott'; + $ADODB_SESSION_PWD ='tiger'; + $ADODB_SESSION_DB ='sessiondb'; + + include('adodb/session/adodb-session.php'); + session_start(); + + # + # Test session vars, the following should increment on refresh + # + $_SESSION['AVAR'] += 1; + print "<p>\$_SESSION['AVAR']={$_SESSION['AVAR']}</p>"; + 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']}

    "; - + + include('adodb/adodb.inc.php'); + + $ADODB_SESSION_DRIVER='mysql'; + $ADODB_SESSION_CONNECT='localhost'; + $ADODB_SESSION_USER ='scott'; + $ADODB_SESSION_PWD ='tiger'; + $ADODB_SESSION_DB ='sessiondb'; + + include('adodb/session/adodb-session.php'); + adodb_sess_open(false,false,false); + session_start(); + 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(); - + + include('adodb/adodb.inc.php'); + + $ADODB_SESSION_DRIVER='mysql'; + $ADODB_SESSION_CONNECT='localhost'; + $ADODB_SESSION_USER ='scott'; + $ADODB_SESSION_PWD ='tiger'; + $ADODB_SESSION_DB ='sessiondb'; + + include('adodb/session/adodb-cryptsession.php'); + session_start(); + +And the same technique for adodb-session-clob.php: + + include('adodb/adodb.inc.php'); + + $ADODB_SESSION_DRIVER='mysql'; + $ADODB_SESSION_CONNECT='localhost'; + $ADODB_SESSION_USER ='scott'; + $ADODB_SESSION_PWD ='tiger'; + $ADODB_SESSION_DB ='sessiondb'; + + include('adodb/session/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) - ); + 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) - ); + For the adodb-session-clob.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. You can either modify this file, or define them before this file is included: - - $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. - -

    Notifications

    - If you want to receive notifications when a session expires, then - you can tag a session with an EXPIREREF tag (see the definition of - the sessions table above), and before the session record is deleted, - we can call a function that will pass the contents of the EXPIREREF - field as the first parameter, and the session key as the 2nd parameter. - - To do this, define a notification function, say NotifyFn: + + $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'; # setting this is optional + + When the session is created, $ADODB_SESS_CONN holds the connection object. - function NotifyFn($expireref, $sesskey) - { - } - - Then you need to define a global variable $ADODB_SESSION_EXPIRE_NOTIFY. - This is an array with 2 elements, the first being the name of the variable + 3. Recommended is PHP 4.0.6 or later. There are documented session bugs + in earlier versions of PHP. +
    + +

    Notifications

    +

    If you want to receive notification when a session expires, then + tag the session record with a EXPIREREF tag (see the + definition of the sessions table above). Before any session record is deleted, + ADOdb will call a notification function, passing in the EXPIREREF. +

    +When a session is first created, we check a global variable $ADODB_SESSION_EXPIRE_NOTIFY. + This is an array with 2 elements, the first being the name of the session variable you would like to store in the EXPIREREF field, and the 2nd is the notification function's name. - - In this example, we want to be notified when a user's session - has expired, so we store the user id in the global variable $USERID, - store this value in the EXPIREREF field: - - $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn'); - - Then when the NotifyFn is called, we are passed the $USERID as the first - parameter, eg. NotifyFn($userid, $sesskey). - - NOTE: When you want to change the EXPIREREF, you will need to modify a session - variable to force a database record update because we checksum the session - variables, and only perform the update when the checksum changes. +

    + Suppose we want to be notified when a user's session + has expired, based on the userid. The user id in the global session variable $USERID. + The function name is 'NotifyFn'. So we define: +

     
    +        $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');
    +    
    + And when the NotifyFn is called (when the session expires), we pass the $USERID + as the first parameter, eg. NotifyFn($userid, $sesskey). The session key (which is + the primary key of the record in the sessions table) is the 2nd parameter. +

    + Here is an example of a Notification function that deletes some records in the database + and temporary files: +

    
    +        function NotifyFn($expireref, $sesskey)
    +        {
    +        global $ADODB_SESS_CONN; # the session connection object
    +
    +          $user = $ADODB_SESS_CONN->qstr($expireref);
    +          $ADODB_SESS_CONN->Execute("delete from shopping_cart where user=$user");
    +          system("rm /work/tmpfiles/$expireref/*");
    +        }
    +    
    +

    + +

    + NOTE: If you want to change the EXPIREREF after the session record has been + created, you will need to modify any session variable to force a database + record update. +

    Compression/Encryption Schemes

    +Since ADOdb 4.05, thanks to Ross Smith, multiple encryption and compression schemes are supported. + Currently, supported: +
    +  MD5Crypt (crypt.inc.php)
    +  MCrypt
    +  Secure (Horde's emulation of MCrypt, if MCrypt module is not available.)
    +  GZip
    +  BZip2
    +
    +These are stackable. E.g. +
    +ADODB_Session::filter(new ADODB_Compress_Bzip2());
    +ADODB_Session::filter(new ADODB_Encrypt_MD5());
     
    +will compress and then encrypt the record in the database.

    Also see the core ADOdb documentation. diff --git a/lib/adodb/drivers/adodb-access.inc.php b/lib/adodb/drivers/adodb-access.inc.php index e1078ee5d9..fca5a83285 100644 --- a/lib/adodb/drivers/adodb-access.inc.php +++ b/lib/adodb/drivers/adodb-access.inc.php @@ -1,6 +1,6 @@ fields[] = date('Y-m-d H:i:s',(integer)$f->value); - break; - + if (!strlen((string)$f->value)) $this->fields[] = false; + else $this->fields[] = adodb_date('Y-m-d H:i:s',(float)$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); + if ($val = $f->value) { + $this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2); + } else + $this->fields[] = false; break; case 7: // adDate - $this->fields[] = date('Y-m-d',(integer)$f->value); + if (!strlen((string)$f->value)) $this->fields[] = false; + else $this->fields[] = adodb_date('Y-m-d',(float)$f->value); break; case 1: // null $this->fields[] = false; @@ -577,7 +583,25 @@ class ADORecordSet_ado extends ADORecordSet { return true; } - + function NextRecordSet() + { + $rs = $this->_queryID; + $this->_queryID = $rs->NextRecordSet(); + //$this->_queryID = $this->_QueryId->NextRecordSet(); + if ($this->_queryID == null) return false; + + $this->_currentRow = -1; + $this->_currentPage = -1; + $this->bind = false; + $this->fields = false; + $this->_flds = false; + $this->_tarr = false; + + $this->_inited = false; + $this->Init(); + return true; + } + function _close() { $this->_flds = false; @$this->_queryID->Close();// by Pete Dishman (peterd@telephonetics.co.uk) diff --git a/lib/adodb/drivers/adodb-ado_access.inc.php b/lib/adodb/drivers/adodb-ado_access.inc.php index 4cb590e79f..946714defa 100644 --- a/lib/adodb/drivers/adodb-ado_access.inc.php +++ b/lib/adodb/drivers/adodb-ado_access.inc.php @@ -1,6 +1,6 @@ - // Only quote string types if (gettype($v) == 'string') $sql .= $this->qstr($v); else if ($v === null) diff --git a/lib/adodb/drivers/adodb-db2.inc.php b/lib/adodb/drivers/adodb-db2.inc.php index be68a98f75..24f6702033 100644 --- a/lib/adodb/drivers/adodb-db2.inc.php +++ b/lib/adodb/drivers/adodb-db2.inc.php @@ -1,6 +1,6 @@ = 0) $sql .= " FETCH FIRST $nrows ROWS ONLY "; - return $this->Execute($sql,false); + $rs =& $this->Execute($sql,false); } else { if ($offset > 0 && $nrows < 0); else { $nrows += $offset; $sql .= " FETCH FIRST $nrows ROWS ONLY "; } - return ADOConnection::SelectLimit($sql,-1,$offset); + $rs =& ADOConnection::SelectLimit($sql,-1,$offset); } + + return $rs; } }; diff --git a/lib/adodb/drivers/adodb-fbsql.inc.php b/lib/adodb/drivers/adodb-fbsql.inc.php index 459a8533a7..46a4460db8 100644 --- a/lib/adodb/drivers/adodb-fbsql.inc.php +++ b/lib/adodb/drivers/adodb-fbsql.inc.php @@ -1,6 +1,6 @@ =0) ? "SKIP $offset " : ''; $sql = preg_replace('/^[ \t]*select/i',$str,$sql); - return ($secs) ? - $this->CacheExecute($secs,$sql,$inputarr) - : - $this->Execute($sql,$inputarr); + if ($secs) + $rs =& $this->CacheExecute($secs,$sql,$inputarr); + else + $rs =& $this->Execute($sql,$inputarr); + + return $rs; } diff --git a/lib/adodb/drivers/adodb-ibase.inc.php b/lib/adodb/drivers/adodb-ibase.inc.php index 6a44559fe6..d42b1d7089 100644 --- a/lib/adodb/drivers/adodb-ibase.inc.php +++ b/lib/adodb/drivers/adodb-ibase.inc.php @@ -1,6 +1,6 @@ fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + $table = strtoupper($table); + $sql = "SELECT * FROM RDB\$INDICES WHERE RDB\$RELATION_NAME = '".$table."'"; + if (!$primary) { + $sql .= " AND RDB\$INDEX_NAME NOT LIKE 'RDB\$%'"; + } else { + $sql .= " AND RDB\$INDEX_NAME NOT LIKE 'RDB\$FOREIGN%'"; + } + // get index details + $rs = $this->Execute($sql); + if (!is_object($rs)) { + // restore fetchmode + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + return FALSE; + } + + $indexes = array (); + while ($row = $rs->FetchRow()) { + $index = $row[0]; + if (!isset($indexes[$index])) { + if (is_null($row[3])) {$row[3] = 0;} + $indexes[$index] = array( + 'unique' => ($row[3] == 1), + 'columns' => array() + ); + } + $sql = "SELECT * FROM RDB\$INDEX_SEGMENTS WHERE RDB\$INDEX_NAME = '".$name."' ORDER BY RDB\$FIELD_POSITION ASC"; + $rs1 = $this->Execute($sql); + while ($row1 = $rs1->FetchRow()) { + $indexes[$index]['columns'][$row1[2]] = $row1[1]; + } + } + // restore fetchmode + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + return $indexes; + } + + // See http://community.borland.com/article/0,1410,25844,00.html function RowLock($tables,$where,$col) { @@ -128,52 +184,7 @@ class ADODB_ibase extends ADOConnection { 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'))" )); @@ -228,6 +239,7 @@ class ADODB_ibase extends ADOConnection { // returns true or false function _connect($argHostname, $argUsername, $argPassword, $argDatabasename) { + if (!function_exists('ibase_pconnect')) return false; 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 @@ -244,6 +256,7 @@ class ADODB_ibase extends ADOConnection { // returns true or false function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) { + if (!function_exists('ibase_pconnect')) return false; 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 @@ -261,7 +274,7 @@ class ADODB_ibase extends ADOConnection { function Prepare($sql) { // return $sql; - $stmt = ibase_prepare($sql); + $stmt = ibase_prepare($this->_connectionID,$sql); if (!$stmt) return false; return array($sql,$stmt); } @@ -335,6 +348,101 @@ class ADODB_ibase extends ADOConnection { return @ibase_close($this->_connectionID); } + //OPN STUFF start + function _ConvertFieldType(&$fld, $ftype, $flen, $fscale, $fsubtype, $fprecision, $isInterbase6) + { + $fscale = abs($fscale); + $fld->max_length = $flen; + $fld->scale = null; + switch($ftype){ + case 7: + case 8: + if ($isInterbase6) { + switch($fsubtype){ + case 0: + $fld->type = ($ftype == 7 ? 'smallint' : 'integer'); + break; + case 1: + $fld->type = 'numeric'; + $fld->max_length = $fprecision; + $fld->scale = $fscale; + break; + case 2: + $fld->type = 'decimal'; + $fld->max_length = $fprecision; + $fld->scale = $fscale; + break; + } // switch + } else { + if ($fscale !=0) { + $fld->type = 'decimal'; + $fld->scale = $fscale; + $fld->max_length = ($ftype == 7 ? 4 : 9); + } else { + $fld->type = ($ftype == 7 ? 'smallint' : 'integer'); + } + } + break; + case 16: + if ($isInterbase6) { + switch($fsubtype){ + case 0: + $fld->type = 'decimal'; + $fld->max_length = 18; + $fld->scale = 0; + break; + case 1: + $fld->type = 'numeric'; + $fld->max_length = $fprecision; + $fld->scale = $fscale; + break; + case 2: + $fld->type = 'decimal'; + $fld->max_length = $fprecision; + $fld->scale = $fscale; + break; + } // switch + } + break; + case 10: + $fld->type = 'float'; + break; + case 14: + $fld->type = 'char'; + break; + case 27: + if ($fscale !=0) { + $fld->type = 'decimal'; + $fld->max_length = 15; + $fld->scale = 5; + } else { + $fld->type = 'double'; + } + break; + case 35: + if ($isInterbase6) { + $fld->type = 'timestamp'; + } else { + $fld->type = 'date'; + } + break; + case 12: + case 13: + $fld->type = 'date'; + break; + case 37: + $fld->type = 'varchar'; + break; + case 40: + $fld->type = 'cstring'; + break; + case 261: + $fld->type = 'blob'; + $fld->max_length = -1; + break; + } // switch + } + //OPN STUFF end // returns array of ADOFieldObjects for current table function &MetaColumns($table) { @@ -351,31 +459,41 @@ class ADODB_ibase extends ADOConnection { if ($rs === false) return false; $retarr = array(); + //OPN STUFF start + $isInterbase6 = ($this->dialect==3 ? true : false); + //OPN STUFF end 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; + //OPN STUFF start + $this->_ConvertFieldType($fld, $rs->fields[7], $rs->fields[3], $rs->fields[4], $rs->fields[5], $rs->fields[6], $isInterbase6); + if (isset($rs->fields[1]) && $rs->fields[1]) { + $fld->not_null = true; + } + if (isset($rs->fields[2])) { + + $fld->has_default = true; + $d = substr($rs->fields[2],strlen('default ')); + switch ($fld->type) + { + case 'smallint': + case 'integer': $fld->default_value = (int) $d; break; + case 'char': + case 'blob': + case 'text': + case 'varchar': $fld->default_value = (string) substr($d,1,strlen($d)-2); break; + case 'double': + case 'float': $fld->default_value = (float) $d; break; + default: $fld->default_value = $d; break; + } + // case 35:$tt = 'TIMESTAMP'; break; } - $fld->type = $tt; - $fld->max_length = $rs->fields[2]; - + if ((isset($rs->fields[5])) && ($fld->type == 'blob')) { + $fld->sub_type = $rs->fields[5]; + } else { + $fld->sub_type = null; + } + //OPN STUFF end if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; else $retarr[strtoupper($fld->name)] = $fld; @@ -517,6 +635,19 @@ class ADODB_ibase extends ADOConnection { case 'd': $s .= "(extract(day from $col))"; break; + case 'H': + case 'h': + $s .= "(extract(hour from $col))"; + break; + case 'I': + case 'i': + $s .= "(extract(minute from $col))"; + break; + case 'S': + case 's': + $s .= "CAST((extract(second from $col)) AS INTEGER)"; + break; + default: if ($ch == '\\') { $i++; @@ -593,7 +724,11 @@ class ADORecordset_ibase extends ADORecordSet } // OPN stuff start - optimized // fix missing nulls and decode blobs automatically - + + global $ADODB_ANSI_PADDING_OFF; + //$ADODB_ANSI_PADDING_OFF=1; + $rtrim = !empty($ADODB_ANSI_PADDING_OFF); + for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { if ($this->_cacheType[$i]=="BLOB") { if (isset($f[$i])) { @@ -604,7 +739,9 @@ class ADORecordset_ibase extends ADORecordSet } else { if (!isset($f[$i])) { $f[$i] = null; - } + } else if ($rtrim && is_string($f[$i])) { + $f[$i] = rtrim($f[$i]); + } } } // OPN stuff end diff --git a/lib/adodb/drivers/adodb-informix.inc.php b/lib/adodb/drivers/adodb-informix.inc.php index 7f3ed4ac04..0473f95002 100644 --- a/lib/adodb/drivers/adodb-informix.inc.php +++ b/lib/adodb/drivers/adodb-informix.inc.php @@ -1,6 +1,6 @@ _connectionID = ifx_connect($dbs,$argUsername,$argPassword); if ($this->_connectionID === false) return false; #if ($argDatabasename) return $this->SelectDB($argDatabasename); @@ -189,7 +196,10 @@ class ADODB_informix72 extends ADOConnection { // returns true or false function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) { + if (!function_exists('ifx_connect')) return false; + $dbs = $argDatabasename . "@" . $argHostname; + if ($argHostname) putenv("INFORMIXSERVER=$argHostname"); $this->_connectionID = ifx_pconnect($dbs,$argUsername,$argPassword); if ($this->_connectionID === false) return false; #if ($argDatabasename) return $this->SelectDB($argDatabasename); @@ -225,10 +235,10 @@ class ADODB_informix72 extends ADOConnection { // to be able to call "move", or "movefirst" statements if (!$ADODB_COUNTRECS && preg_match("/^\s*select/is", $sql)) { if ($inputarr) { - $this->lastQuery = ifx_query($sql,$this->_connectionID, IFX_SCROLL, $tab); + $this->lastQuery = ifx_query($sql,$this->_connectionID, $this->cursorType, $tab); } else { - $this->lastQuery = ifx_query($sql,$this->_connectionID, IFX_SCROLL); + $this->lastQuery = ifx_query($sql,$this->_connectionID, $this->cursorType); } } else { diff --git a/lib/adodb/drivers/adodb-mssql.inc.php b/lib/adodb/drivers/adodb-mssql.inc.php index 69fa7d4fb8..7a0247b649 100644 --- a/lib/adodb/drivers/adodb-mssql.inc.php +++ b/lib/adodb/drivers/adodb-mssql.inc.php @@ -1,6 +1,6 @@ 'master'"; @@ -100,6 +101,7 @@ class ADODB_mssql extends ADOConnection { var $uniqueOrderBy = true; var $_bindInputArray = true; + function ADODB_mssql() { $this->_has_mssql_init = (strnatcmp(PHP_VERSION,'4.1.0')>=0); @@ -197,11 +199,14 @@ class ADODB_mssql extends ADOConnection { if ($nrows > 0 && $offset <= 0) { $sql = preg_replace( '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop." $nrows ",$sql); - return $this->Execute($sql,$inputarr); + $rs =& $this->Execute($sql,$inputarr); } else - return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + + return $rs; } + // Format date column in sql string given an input format that understands Y M D function SQLDate($fmt, $col=false) { @@ -430,6 +435,7 @@ order by constraint_name, referenced_table_name, keyno"; // returns true or false function _connect($argHostname, $argUsername, $argPassword, $argDatabasename) { + if (!function_exists('mssql_pconnect')) return false; $this->_connectionID = mssql_connect($argHostname,$argUsername,$argPassword); if ($this->_connectionID === false) return false; if ($argDatabasename) return $this->SelectDB($argDatabasename); @@ -440,6 +446,7 @@ order by constraint_name, referenced_table_name, keyno"; // returns true or false function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) { + if (!function_exists('mssql_pconnect')) return false; $this->_connectionID = mssql_pconnect($argHostname,$argUsername,$argPassword); if ($this->_connectionID === false) return false; @@ -511,7 +518,9 @@ order by constraint_name, referenced_table_name, keyno"; } if ($this->debug) { - ADOConnection::outp( "Parameter(\$stmt, \$php_var='$var', \$name='$name'); (type=$type)"); + $prefix = ($isOutput) ? 'Out' : 'In'; + $ztype = (empty($type)) ? 'false' : $type; + ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);"); } /* See http://phplens.com/lens/lensforum/msgs.php?id=7231 diff --git a/lib/adodb/drivers/adodb-mssqlpo.inc.php b/lib/adodb/drivers/adodb-mssqlpo.inc.php index 747abdd95c..d727def5fe 100644 --- a/lib/adodb/drivers/adodb-mssqlpo.inc.php +++ b/lib/adodb/drivers/adodb-mssqlpo.inc.php @@ -1,6 +1,6 @@ GetOne("select version()"); + $arr['description'] = ADOConnection::GetOne("select version()"); $arr['version'] = ADOConnection::_findvers($arr['description']); return $arr; } @@ -69,6 +68,59 @@ class ADODB_mysql extends ADOConnection { return $ret; } + + function &MetaIndexes ($table, $primary = FALSE, $owner=false) + { + // save old fetch mode + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + // get index details + $rs = $this->Execute(sprintf('SHOW INDEXES FROM %s',$table)); + + // restore fetchmode + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + return FALSE; + } + + $indexes = array (); + + // parse index data into array + while ($row = $rs->FetchRow()) { + if ($primary == FALSE AND $row[2] == 'PRIMARY') { + continue; + } + + if (!isset($indexes[$row[2]])) { + $indexes[$row[2]] = array( + 'unique' => ($row[1] == 0), + 'columns' => array() + ); + } + + $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4]; + } + + // sort columns by order in the index + foreach ( array_keys ($indexes) as $index ) + { + ksort ($indexes[$index]['columns']); + } + + return $indexes; + } + + // if magic quotes disabled, use mysql_real_escape_string() function qstr($s,$magic_quotes=false) { @@ -128,14 +180,19 @@ class ADODB_mysql extends ADOConnection { return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); } + function GenID($seqname='adodbseq',$startID=1) { // post-nuke sets hasGenID to false if (!$this->hasGenID) return false; + $savelog = $this->_logsql; + $this->_logsql = false; $getnext = sprintf($this->_genIDSQL,$seqname); + $holdtransOK = $this->_transOK; // save the current status $rs = @$this->Execute($getnext); if (!$rs) { + if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset $u = strtoupper($seqname); $this->Execute(sprintf($this->_genSeqSQL,$seqname)); $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); @@ -145,6 +202,7 @@ class ADODB_mysql extends ADOConnection { if ($rs) $rs->Close(); + $this->_logsql = $savelog; return $this->genID; } @@ -240,14 +298,6 @@ class ADODB_mysql extends ADOConnection { { $s = ""; $arr = func_get_args(); - $first = true; - /* - foreach($arr as $a) { - if ($first) { - $s = $a; - $first = false; - } else $s .= ','.$a; - }*/ // suggestion by andrew005@mnogo.ru $s = implode(',',$arr); @@ -320,18 +370,34 @@ class ADODB_mysql extends ADOConnection { $fld->name = $rs->fields[0]; $type = $rs->fields[1]; + // split type into type(length): - if (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { + $fld->scale = null; + if (strpos($type,',') && preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; + $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1; + } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { $fld->type = $query_array[1]; $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; } else { $fld->max_length = -1; $fld->type = $type; } + /* + // split type into type(length): + if (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; + } else { + $fld->max_length = -1; + $fld->type = $type; + }*/ $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); + if (!$fld->binary) { $d = $rs->fields[4]; if ($d != "" && $d != "NULL") { @@ -366,9 +432,11 @@ class ADODB_mysql extends ADOConnection { { $offsetStr =($offset>=0) ? "$offset," : ''; - return ($secs) ? $this->CacheExecute($secs,$sql." LIMIT $offsetStr$nrows",$inputarr) - : $this->Execute($sql." LIMIT $offsetStr$nrows",$inputarr); - + if ($secs) + $rs =& $this->CacheExecute($secs,$sql." LIMIT $offsetStr$nrows",$inputarr); + else + $rs =& $this->Execute($sql." LIMIT $offsetStr$nrows",$inputarr); + return $rs; } @@ -484,7 +552,8 @@ class ADORecordSet_mysql extends ADORecordSet{ function &GetRowAssoc($upper=true) { if ($this->fetchMode == MYSQL_ASSOC && !$upper) return $this->fields; - return ADORecordSet::GetRowAssoc($upper); + $row =& ADORecordSet::GetRowAssoc($upper); + return $row; } /* Use associative array to get fields array */ @@ -575,6 +644,7 @@ class ADORecordSet_mysql extends ADORecordSet{ case 'BLOB': case 'MEDIUMBLOB': return !empty($fieldobj->binary) ? 'B' : 'X'; + case 'YEAR': case 'DATE': return 'D'; diff --git a/lib/adodb/drivers/adodb-mysqli.inc.php b/lib/adodb/drivers/adodb-mysqli.inc.php new file mode 100644 index 0000000000..a9daa02e48 --- /dev/null +++ b/lib/adodb/drivers/adodb-mysqli.inc.php @@ -0,0 +1,828 @@ +GetOne("select version()"); + $arr['version'] = ADOConnection::_findvers($arr['description']); + return $arr; + } + + + function BeginTrans() + { + if ($this->transOff) return true; + $this->transCnt += 1; + $this->Execute('SET AUTOCOMMIT=0'); + $this->Execute('BEGIN'); + return true; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) return true; + if (!$ok) return $this->RollbackTrans(); + + if ($this->transCnt) $this->transCnt -= 1; + $this->Execute('COMMIT'); + $this->Execute('SET AUTOCOMMIT=1'); + return true; + } + + function RollbackTrans() + { + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $this->Execute('ROLLBACK'); + $this->Execute('SET AUTOCOMMIT=1'); + return true; + } + + // if magic quotes disabled, use mysql_real_escape_string() + // From readme.htm: + // 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()); + function qstr($s, $magic_quotes = false) + { + if (!$magic_quotes) { + if (ADODB_PHPVER >= 0x5000) { + // $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID); + return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'"; + } + else + { + trigger_error("phpver < 5 not implemented", E_USER_ERROR); + } + + if ($this->replaceQuote[0] == '\\') + { + $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); + } + return "'".str_replace("'",$this->replaceQuote,$s)."'"; + } + // undo magic quotes for " + $s = str_replace('\\"','"',$s); + return "'$s'"; + } + + function _insertid() + { +// $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID); + $result = @mysqli_insert_id($this->_connectionID); + if ($result == -1){ + if ($this->debug) ADOConnection::outp("mysqli_insert_id() failed : " . $this->ErrorMsg()); + } + return $result; + } + + // Only works for INSERT, UPDATE and DELETE query's + function _affectedrows() + { + // $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID); + $result = @mysqli_affected_rows($this->_connectionID); + if ($result == -1) { + if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : " . $this->ErrorMsg()); + } + return $result; + } + + // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html + // Reference on Last_Insert_ID on the recommended way to simulate sequences + var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);"; + var $_genSeqSQL = "create table %s (id int not null)"; + var $_genSeq2SQL = "insert into %s values (%s)"; + var $_dropSeqSQL = "drop table %s"; + + function CreateSequence($seqname='adodbseq',$startID=1) + { + if (empty($this->_genSeqSQL)) return false; + $u = strtoupper($seqname); + + $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname)); + if (!$ok) return false; + return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); + } + + function GenID($seqname='adodbseq',$startID=1) + { + // post-nuke sets hasGenID to false + if (!$this->hasGenID) return false; + + $getnext = sprintf($this->_genIDSQL,$seqname); + $holdtransOK = $this->_transOK; // save the current status + $rs = @$this->Execute($getnext); + if (!$rs) { + if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset + $u = strtoupper($seqname); + $this->Execute(sprintf($this->_genSeqSQL,$seqname)); + $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); + $rs = $this->Execute($getnext); + } + $this->genID = mysqli_insert_id($this->_connectionID); + + if ($rs) $rs->Close(); + + return $this->genID; + } + + function &MetaDatabases() + { + $query = "SHOW DATABASES"; + $ret =& $this->Execute($query); + return $ret; + } + + + function &MetaIndexes ($table, $primary = FALSE) + { + // save old fetch mode + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + // get index details + $rs = $this->Execute(sprintf('SHOW INDEXES FROM %s',$table)); + + // restore fetchmode + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + return FALSE; + } + + $indexes = array (); + + // parse index data into array + while ($row = $rs->FetchRow()) { + if ($primary == FALSE AND $row[2] == 'PRIMARY') { + continue; + } + + if (!isset($indexes[$row[2]])) { + $indexes[$row[2]] = array( + 'unique' => ($row[1] == 0), + 'columns' => array() + ); + } + + $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4]; + } + + // sort columns by order in the index + foreach ( array_keys ($indexes) as $index ) + { + ksort ($indexes[$index]['columns']); + } + + return $indexes; + } + + + // Format date column in sql string given an input format that understands Y M D + function SQLDate($fmt, $col=false) + { + if (!$col) $col = $this->sysTimeStamp; + $s = 'DATE_FORMAT('.$col.",'"; + $concat = false; + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + $s .= '%Y'; + break; + case 'Q': + case 'q': + $s .= "'),Quarter($col)"; + + if ($len > $i+1) $s .= ",DATE_FORMAT($col,'"; + else $s .= ",('"; + $concat = true; + break; + case 'M': + $s .= '%b'; + break; + + case 'm': + $s .= '%m'; + break; + case 'D': + case 'd': + $s .= '%d'; + break; + + case 'H': + $s .= '%H'; + break; + + case 'h': + $s .= '%I'; + break; + + case 'i': + $s .= '%i'; + break; + + case 's': + $s .= '%s'; + break; + + case 'a': + case 'A': + $s .= '%p'; + break; + + default: + + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + $s .= $ch; + break; + } + } + $s.="')"; + if ($concat) $s = "CONCAT($s)"; + return $s; + } + + // returns concatenated string + // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator + function Concat() + { + $s = ""; + $arr = func_get_args(); + + // suggestion by andrew005@mnogo.ru + $s = implode(',',$arr); + if (strlen($s) > 0) return "CONCAT($s)"; + else return ''; + } + + // dayFraction is a day in floating point + function OffsetDate($dayFraction,$date=false) + { + if (!$date) + $date = $this->sysDate; + return "from_unixtime(unix_timestamp($date)+($dayFraction)*24*3600)"; + } + + // returns true or false + // To add: parameter int $port, + // parameter string $socket + function _connect($argHostname = NULL, + $argUsername = NULL, + $argPassword = NULL, + $argDatabasename = NULL) + { + // @ means: error surpression on + $this->_connectionID = @mysqli_init(); + + if (is_null($this->_connectionID)) + { + // mysqli_init only fails if insufficient memory + if ($this->debug) + ADOConnection::outp("mysqli_init() failed : " . $this->ErrorMsg()); + return false; + } + // Set connection options + // Not implemented now + // mysqli_options($this->_connection,,); + if (mysqli_real_connect($this->_connectionID, + $argHostname, + $argUsername, + $argPassword, + $argDatabasename)) + { + if ($argDatabasename) + { + return $this->SelectDB($argDatabasename); + } + + return true; + } + else + { + if ($this->debug) + ADOConnection::outp("Could't connect : " . $this->ErrorMsg()); + return false; + } + } + + // returns true or false + // How to force a persistent connection + function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + // not implemented in mysqli (yet)? + $this->_connectionID = mysqli_connect($argHostname, + $argUsername, + $argPassword, + $argDatabasename); + if ($this->_connectionID === false) return false; + // if ($this->autoRollback) $this->RollbackTrans(); + if ($argDatabasename) return $this->SelectDB($argDatabasename); + return true; + } + + // When is this used? Close old connection first? + // In _connect(), check $this->forceNewConnect? + function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + $this->forceNewConnect = true; + $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename); + } + + function &MetaColumns($table) + { + if ($this->metaColumnsSQL) { + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $rs = false; + switch($ADODB_FETCH_MODE) + { + case ADODB_FETCH_NUM: + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $rs = $this->Execute(sprintf($this->metaColumnsSQL, + $table)); + + $ADODB_FETCH_MODE = $save; + if ($rs === false) break; + $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); + if (!$fld->binary) + { + $d = $rs->fields[4]; + $d = $rs->fields['Default']; + if ($d != "" && $d != "NULL") + { + $fld->has_default = true; + $fld->default_value = $d; + } + else + { + $fld->has_default = false; + } + } + $retarr[strtoupper($fld->name)] = $fld; + $rs->MoveNext(); + } + break; + case ADODB_FETCH_ASSOC: + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH: + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + $rs = $this->Execute(sprintf($this->metaColumnsSQL, + $table)); + $ADODB_FETCH_MODE = $save; + if ($rs === false) break; + $retarr = array(); + while (!$rs->EOF){ + $fld = new ADOFieldObject(); + $fld->name = $rs->fields['Field']; + $fld->type = $rs->fields['Type']; + + // 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['Null'] != 'YES'); + $fld->primary_key = ($rs->fields['Key'] == 'PRI'); + $fld->auto_increment = (strpos($rs->fields['Extra'], 'auto_increment') !== false); + $fld->binary = (strpos($fld->type,'blob') !== false); + if (!$fld->binary) + { + $d = $rs->fields['Default']; + if ($d != "" && $d != "NULL") + { + $fld->has_default = true; + $fld->default_value = $d; + } + else + { + $fld->has_default = false; + } + } + $retarr[strtoupper($fld->name)] = $fld; + $rs->MoveNext(); + } + break; + default: + } + + if ($rs === false) return false; + $rs->Close(); + return $retarr; + } + return false; + } + + // returns true or false + function SelectDB($dbName) + { +// $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID); + $this->databaseName = $dbName; + if ($this->_connectionID) { + $result = @mysqli_select_db($this->_connectionID, $dbName); + if (!$result) { + ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->ErrorMsg()); + } + return $result; + } + return false; + } + + // parameters use PostgreSQL convention, not MySQL + function &SelectLimit($sql, + $nrows = -1, + $offset = -1, + $inputarr = false, + $arg3 = false, + $secs = 0) + { + $offsetStr = ($offset >= 0) ? "$offset," : ''; + + if ($secs) + $rs =& $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr , $arg3); + else + $rs =& $this->Execute($sql . " LIMIT $offsetStr$nrows" , $inputarr , $arg3); + + return $rs; + } + + + function Prepare($sql) + { + return $sql; + + $stmt = mysqli_prepare($this->_connectionID,$sql); + if (!$stmt) return false; + return array($sql,$stmt); + } + + + // returns queryID or false + function _query($sql, $inputarr) + { + global $ADODB_COUNTRECS; + + if (is_array($sql)) { + $stmt = $sql[1]; + foreach($inputarr as $k => $v) { + if (is_string($v)) $a[] = MYSQLI_BIND_STRING; + else if (is_integer($v)) $a[] = MYSQLI_BIND_INT; + else $a[] = MYSQLI_BIND_DOUBLE; + + $fnarr =& array_merge( array($stmt,$a) , $inputarr); + $ret = call_user_func_array('mysqli_bind_param',$fnarr); + } + $ret = mysqli_execute($stmt); + return $ret; + } + if (!$mysql_res = mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) { + if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg()); + return false; + } + + return $mysql_res; + } + + /* Returns: the last error message from previous database operation */ + function ErrorMsg() + { + if (empty($this->_connectionID)) + $this->_errorMsg = @mysqli_error(); + else + $this->_errorMsg = @mysqli_error($this->_connectionID); + return $this->_errorMsg; + } + + /* Returns: the last error number from previous database operation */ + function ErrorNo() + { + if (empty($this->_connectionID)) + return @mysqli_errno(); + else + return @mysqli_errno($this->_connectionID); + } + + // returns true or false + function _close() + { + @mysqli_close($this->_connectionID); + $this->_connectionID = false; + } + + /* + * Maximum size of C field + */ + function CharMax() + { + return 255; + } + + /* + * Maximum size of X field + */ + function TextMax() + { + return 4294967295; + } + + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordSet_mysqli extends ADORecordSet{ + + var $databaseType = "mysqli"; + var $canSeek = true; + + function ADORecordSet_mysqli($queryID, $mode = false) + { + if ($mode === false) + { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + switch ($mode) + { + case ADODB_FETCH_NUM: + $this->fetchMode = MYSQLI_NUM; + break; + case ADODB_FETCH_ASSOC: + $this->fetchMode = MYSQLI_ASSOC; + break; + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH: + default: + $this->fetchMode = MYSQLI_ASSOC; + break; + } + $this->ADORecordSet($queryID); + } + + function _initrs() + { + // mysqli_num_rows only return correct number, depens + // on the use of mysql_store_result and mysql_use_result + if (!$this->Connection->executeOnly) { + $this->_numOfRows = @mysqli_num_rows($this->_queryID); + $this->_numOfFields = @mysqli_num_fields($this->_queryID); + } + else { + $this->_numOfRows = 0; + $this->_numOfFields = 0; + } + } + + function &FetchField($fieldOffset = -1) + { + $fieldnr = $fieldOffset; + if ($fieldOffset != -1) { + $fieldOffset = mysqi_field_seek($this->_queryID, $fieldnr); + } + $o = mysqli_fetch_field($this->_queryID); + return $o; + } + + function &GetRowAssoc($upper = true) + { + if ($this->fetchMode == MYSQLI_ASSOC && !$upper) + return $this->fields; + $row =& ADORecordSet::GetRowAssoc($upper); + return $row; + } + + /* Use associative array to get fields array */ + function Fields($colname) + { + if ($this->fetchMode != MYSQLI_NUM) + 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 _seek($row) + { + if ($this->_numOfRows == 0) + return false; + + if ($row < 0) + return false; + + mysqli_data_seek($this->_queryID, $row); + $this->EOF = false; + return true; + } + + // 10% speedup to move MoveNext to child class + // This is the only implementation that works now (23-10-2003). + // Other functions return no or the wrong results. + function MoveNext() + { + if ($this->EOF) + return false; + $this->_currentRow++; + switch($this->fetchMode) + { + case MYSQLI_NUM: + $this->fields = mysqli_fetch_array($this->_queryID); + break; + case MYSQLI_ASSOC: + case MYSQLI_BOTH: + $this->fields = mysqli_fetch_assoc($this->_queryID); + break; + default: + } + if (is_array($this->fields)) + return true; + $this->EOF = true; + return false; + } + + function _fetch() + { + // mysqli_fetch_array($this->_queryID, MYSQLI_NUM) does not + // work (22-10-2003). But mysqli_fetch_array($this->_queryID) gives + // int resulttype should default to MYSQLI_BOTH,but give MYSQLI_NUM. + + // $this->fields = mysqli_fetch_fields($this->_queryID); + // $this->fields = mysqli_fetch_array($this->_queryID); //, $this->fetchMode); + + $this->fields = mysqli_fetch_assoc($this->_queryID); // $this->fetchMode); + return is_array($this->fields); + } + + function _close() + { + mysqli_free_result($this->_queryID); + $this->_queryID = false; + } + + function MetaType($t, $len = -1, $fieldobj = false) + { + if (is_object($t)) + { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + $len = -1; // mysql max_length is not accurate + switch (strtoupper($t)) { + case 'STRING': + case 'CHAR': + case 'VARCHAR': + case 'TINYBLOB': + case 'TINYTEXT': + case 'ENUM': + case 'SET': + if ($len <= $this->blobSize) return 'C'; + + case 'TEXT': + case 'LONGTEXT': + case 'MEDIUMTEXT': + return 'X'; + + // php_mysql extension always returns 'blob' even if 'text' + // so we have to check whether binary... + case 'IMAGE': + case 'LONGBLOB': + case 'BLOB': + case 'MEDIUMBLOB': + return !empty($fieldobj->binary) ? 'B' : 'X'; + case 'YEAR': + case 'DATE': + return 'D'; + + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': return 'T'; + + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'TINYINT': + case 'MEDIUMINT': + case 'SMALLINT': + + if (!empty($fieldobj->primary_key)) return 'R'; + else return 'I'; + // Added floating-point types + // Maybe not necessery. + case 'FLOAT': + case 'DOUBLE': + // case 'DOUBLE PRECISION': + case 'DECIMAL': + case 'DEC': + case 'FIXED': + default: + return 'N'; + } + } + + +} + +} + +?> \ No newline at end of file diff --git a/lib/adodb/drivers/adodb-mysqlt.inc.php b/lib/adodb/drivers/adodb-mysqlt.inc.php index 2c3dc95b5e..8b82ea50ba 100644 --- a/lib/adodb/drivers/adodb-mysqlt.inc.php +++ b/lib/adodb/drivers/adodb-mysqlt.inc.php @@ -1,7 +1,7 @@ _errorMsg = false; $this->_errorCode = false; @@ -207,6 +208,8 @@ NATSOFT.DOMAIN = return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,1); } + + // returns true or false function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename) { @@ -438,7 +441,9 @@ NATSOFT.DOMAIN = } // note that $nrows = 0 still has to work ==> no rows returned - return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + return $rs; + } else { // Algorithm by Tomas V V Cox, from PEAR DB oci8.php @@ -449,8 +454,7 @@ NATSOFT.DOMAIN = } if (is_array($inputarr)) { - reset($inputarr); - while (list($k,$v) = each($inputarr)) { + foreach($inputarr as $k => $v) { if (is_array($v)) { if (sizeof($v) == 2) // suggested by g.giunta@libero. OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]); @@ -498,8 +502,9 @@ NATSOFT.DOMAIN = $inputarr['adodb_nrows'] = $nrows; $inputarr['adodb_offset'] = $offset; - if ($secs2cache>0) return $this->CacheExecute($secs2cache, $sql,$inputarr); - else return $this->Execute($sql,$inputarr); + if ($secs2cache>0) $rs =& $this->CacheExecute($secs2cache, $sql,$inputarr); + else $rs =& $this->Execute($sql,$inputarr); + return $rs; } } @@ -589,7 +594,7 @@ NATSOFT.DOMAIN = $stmt = $this->Prepare('insert into emp (empno, ename) values (:empno, :ename)'); */ - function Prepare($sql) + function Prepare($sql,$cursor=false) { static $BINDNUM = 0; @@ -600,7 +605,7 @@ NATSOFT.DOMAIN = $BINDNUM += 1; if (@OCIStatementType($stmt) == 'BEGIN') { - return array($sql,$stmt,0,$BINDNUM,OCINewCursor($this->_connectionID)); + return array($sql,$stmt,0,$BINDNUM, ($cursor) ? false : OCINewCursor($this->_connectionID)); } return array($sql,$stmt,0,$BINDNUM); @@ -623,13 +628,12 @@ NATSOFT.DOMAIN = */ function &ExecuteCursor($sql,$cursorName='rs',$params=false) { - $stmt = ADODB_oci8::Prepare($sql); + $stmt = ADODB_oci8::Prepare($sql,true); # true to allocate OCINewCursor if (is_array($stmt) && sizeof($stmt) >= 5) { $this->Parameter($stmt, $ignoreCur, $cursorName, false, -1, OCI_B_CURSOR); if ($params) { - reset($params); - while (list($k,$v) = each($params)) { + foreach($params as $k => $v) { $this->Parameter($stmt,$params[$k], $k); } } @@ -711,7 +715,9 @@ NATSOFT.DOMAIN = function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) { if ($this->debug) { - ADOConnection::outp( "Parameter(\$stmt, \$php_var='$var', \$name='$name');"); + $prefix = ($isOutput) ? 'Out' : 'In'; + $ztype = (empty($type)) ? 'false' : $type; + ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);"); } return $this->Bind($stmt,$var,$maxLen,$type,$name); } @@ -747,8 +753,7 @@ NATSOFT.DOMAIN = } else { // one statement to bind them all $bindarr = array(); - reset($inputarr); - while(list($k,$v) = each($inputarr)) { + foreach($inputarr as $k => $v) { $bindarr[$k] = $v; OCIBindByName($stmt,":$k",$bindarr[$k],4000); } @@ -765,8 +770,7 @@ NATSOFT.DOMAIN = if (defined('ADODB_PREFETCH_ROWS')) @OCISetPrefetch($stmt,ADODB_PREFETCH_ROWS); if (is_array($inputarr)) { - reset($inputarr); - while(list($k,$v) = each($inputarr)) { + foreach($inputarr as $k => $v) { if (is_array($v)) { if (sizeof($v) == 2) // suggested by g.giunta@libero. OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]); @@ -795,17 +799,17 @@ NATSOFT.DOMAIN = return $stmt; case "BEGIN": - if (is_array($sql) && isset($sql[4])) { + if (is_array($sql) && !empty($sql[4])) { $cursor = $sql[4]; if (is_resource($cursor)) { - OCIExecute($cursor); + $ok = OCIExecute($cursor); return $cursor; } return $stmt; } else { if (is_resource($stmt)) { - OCIFreeStatement($stmt); - return true; + OCIFreeStatement($stmt); + return true; } return $stmt; } @@ -984,10 +988,10 @@ class ADORecordset_oci8 extends ADORecordSet { $this->_inited = true; if ($this->_queryID) { - + $this->_currentRow = 0; @$this->_initrs(); - $this->EOF = !$this->_fetch(); + $this->EOF = !$this->_fetch(); /* // based on idea by Gaetano Giunta to detect unusual oracle errors @@ -1065,7 +1069,10 @@ class ADORecordset_oci8 extends ADORecordSet { /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */ function &GetArrayLimit($nrows,$offset=-1) { - if ($offset <= 0) return $this->GetArray($nrows); + if ($offset <= 0) { + $arr =& $this->GetArray($nrows); + return $arr; + } for ($i=1; $i < $offset; $i++) if (!@OCIFetch($this->_queryID)) return array(); @@ -1139,7 +1146,7 @@ class ADORecordset_oci8 extends ADORecordSet { case 'NCLOB': case 'LONG': case 'LONG VARCHAR': - case 'CLOB'; + case 'CLOB': return 'X'; case 'LONG RAW': diff --git a/lib/adodb/drivers/adodb-oci805.inc.php b/lib/adodb/drivers/adodb-oci805.inc.php index 704de4175c..4dde2b363b 100644 --- a/lib/adodb/drivers/adodb-oci805.inc.php +++ b/lib/adodb/drivers/adodb-oci805.inc.php @@ -1,6 +1,6 @@ EOF) { $this->_currentRow++; if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) { + global $ADODB_ANSI_PADDING_OFF; + if ($this->fetchMode & OCI_ASSOC) $this->_updatefields(); + if (!empty($ADODB_ANSI_PADDING_OFF)) { + foreach($this->fields as $k => $v) { + if (is_string($v)) $this->fields[$k] = rtrim($v); + } + } return true; } $this->EOF = true; @@ -150,7 +158,7 @@ class ADORecordset_oci8po extends ADORecordset_oci8 { $arr = array(); $lowercase = (ADODB_ASSOC_CASE == 0); - foreach ($this->fields as $k => $v) { + foreach($this->fields as $k => $v) { if (is_integer($k)) $arr[$k] = $v; else { if ($lowercase) @@ -166,7 +174,14 @@ class ADORecordset_oci8po extends ADORecordset_oci8 { { $ret = @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode); if ($ret) { - if ($this->fetchMode & OCI_ASSOC) $this->_updatefields(); + global $ADODB_ANSI_PADDING_OFF; + + if ($this->fetchMode & OCI_ASSOC) $this->_updatefields(); + if (!empty($ADODB_ANSI_PADDING_OFF)) { + foreach($this->fields as $k => $v) { + if (is_string($v)) $this->fields[$k] = rtrim($v); + } + } } return $ret; } diff --git a/lib/adodb/drivers/adodb-odbc.inc.php b/lib/adodb/drivers/adodb-odbc.inc.php index b9b8ac01f5..aff3efa390 100644 --- a/lib/adodb/drivers/adodb-odbc.inc.php +++ b/lib/adodb/drivers/adodb-odbc.inc.php @@ -1,6 +1,6 @@ debug && $argDatabasename) { ADOConnection::outp("For odbc Connect(), $argDatabasename is not used. Place dsn in 1st parameter."); } @@ -173,6 +176,9 @@ class ADODB_odbc extends ADOConnection { function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename) { global $php_errormsg; + + if (!function_exists('odbc_connect')) return false; + $php_errormsg = ''; if ($this->debug && $argDatabasename) { ADOConnection::outp("For odbc PConnect(), $argDatabasename is not used. Place dsn in 1st parameter."); @@ -352,7 +358,9 @@ class ADODB_odbc extends ADOConnection { global $ADODB_FETCH_MODE; $table = strtoupper($table); - + $schema = false; + $this->_findschema($table,$schema); + $savem = $ADODB_FETCH_MODE; $ADODB_FETCH_MODE = ADODB_FETCH_NUM; @@ -394,7 +402,6 @@ class ADODB_odbc extends ADOConnection { 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(); @@ -415,8 +422,8 @@ class ADODB_odbc extends ADOConnection { 11 REMARKS */ while (!$rs->EOF) { - //print_r($rs->fields); - if (strtoupper($rs->fields[2]) == $table) { + //adodb_pr($rs->fields); + if (strtoupper($rs->fields[2]) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) { $fld = new ADOFieldObject(); $fld->name = $rs->fields[3]; $fld->type = $this->ODBCTypes($rs->fields[4]); @@ -632,7 +639,10 @@ class ADORecordSet_odbc extends ADORecordSet { // 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); + if ($offset <= 0) { + $rs =& $this->GetArray($nrows); + return $rs; + } $savem = $this->fetchMode; $this->fetchMode = ADODB_FETCH_NUM; $this->Move($offset); diff --git a/lib/adodb/drivers/adodb-odbc_mssql.inc.php b/lib/adodb/drivers/adodb-odbc_mssql.inc.php index 19a0b2cfef..435bd73465 100644 --- a/lib/adodb/drivers/adodb-odbc_mssql.inc.php +++ b/lib/adodb/drivers/adodb-odbc_mssql.inc.php @@ -1,6 +1,6 @@ 0 && $offset <= 0) { $sql = preg_replace( '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop." $nrows ",$sql); - return $this->Execute($sql,$inputarr); + $rs =& $this->Execute($sql,$inputarr); } else - return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + + return $rs; } // Format date column in sql string given an input format that understands Y M D diff --git a/lib/adodb/drivers/adodb-odbc_oracle.inc.php b/lib/adodb/drivers/adodb-odbc_oracle.inc.php index 8647b1baea..293af7653f 100644 --- a/lib/adodb/drivers/adodb-odbc_oracle.inc.php +++ b/lib/adodb/drivers/adodb-odbc_oracle.inc.php @@ -1,6 +1,6 @@ 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; + + var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum +FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n +WHERE relkind = 'r' AND (c.relname='%s' or c.relname = lower('%s')) + and c.relnamespace=n.oid and n.nspname='%s' + and a.attname not like '....%%' AND a.attnum > 0 + AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; + // get primary key etc -- from Freek Dijkstra - var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'"; + var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key + FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'"; var $hasAffectedRows = true; var $hasLimit = false; // set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10 @@ -85,8 +94,9 @@ AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum var $_genSeqSQL = "CREATE SEQUENCE %s START %s"; var $_dropSeqSQL = "DROP SEQUENCE %s"; var $metaDefaultsSQL = "SELECT d.adnum as num, d.adsrc as def from pg_attrdef d, pg_class c where d.adrelid=c.oid and c.relname='%s' order by d.adnum"; - var $upperCase = 'upper'; - var $substr = "substr"; + var $random = 'random()'; /// random function + var $autoRollback = true; // apparently pgsql does not autorollback properly before 4.3.4 + // http://bugs.php.net/bug.php?id=25404 // The last (fmtTimeStamp is not entirely correct: // PostgreSQL also has support for time zones, @@ -145,7 +155,7 @@ a different OID if a database must be reloaded. */ if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false; return pg_cmdtuples($this->_resultid); } - + // returns true/false function BeginTrans() @@ -348,6 +358,8 @@ select viewname,'V' from pg_views where viewname like $mask"; function BlobEncode($blob) { if (ADODB_PHPVER >= 0x4200) return pg_escape_bytea($blob); + + /*92=backslash, 0=null, 39=single-quote*/ $badch = array(chr(92),chr(0),chr(39)); # \ null ' $fixch = array('\\\\134','\\\\000','\\\\047'); return adodb_str_replace($badch,$fixch,$blob); @@ -357,8 +369,8 @@ select viewname,'V' from pg_views where viewname like $mask"; function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') { - return $this->Execute("UPDATE $table SET $column=? WHERE $where", - array($this->BlobEncode($val))) != false; + // do not use bind params which uses qstr(), as blobencode() already quotes data + return $this->Execute("UPDATE $table SET $column='".$this->BlobEncode($val)."'::bytea WHERE $where"); } function OffsetDate($dayFraction,$date=false) @@ -368,111 +380,177 @@ select viewname,'V' from pg_views where viewname like $mask"; } - // converts field names to lowercase - function &MetaColumns($table) + // for schema support, pass in the $table param "$schema.$tabname". + // converts field names to lowercase, $upper is ignored + function &MetaColumns($table,$upper=true) { global $ADODB_FETCH_MODE; - //if (strncmp(PHP_OS,'WIN',3) === 0); + $schema = false; + $this->_findschema($table,$schema); + $table = strtolower($table); - - if (!empty($this->metaColumnsSQL)) { - $save = $ADODB_FETCH_MODE; - $ADODB_FETCH_MODE = ADODB_FETCH_NUM; - if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); - $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table,$table)); + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema)); + else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table)); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) return false; + + if (!empty($this->metaKeySQL)) { + // If we want the primary keys, we have to issue a separate query + // Of course, a modified version of the metaColumnsSQL query using a + // LEFT JOIN would have been much more elegant, but postgres does + // not support OUTER JOINS. So here is the clumsy way. + + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + + $rskey = $this->Execute(sprintf($this->metaKeySQL,($table))); + // fetch all result in once for performance. + $keys =& $rskey->GetArray(); if (isset($savem)) $this->SetFetchMode($savem); $ADODB_FETCH_MODE = $save; - if ($rs === false) return false; - - if (!empty($this->metaKeySQL)) { - // If we want the primary keys, we have to issue a separate query - // Of course, a modified version of the metaColumnsSQL query using a - // LEFT JOIN would have been much more elegant, but postgres does - // not support OUTER JOINS. So here is the clumsy way. - - $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; - - $rskey = $this->Execute(sprintf($this->metaKeySQL,($table))); - // fetch all result in once for performance. - $keys =& $rskey->GetArray(); - if (isset($savem)) $this->SetFetchMode($savem); - $ADODB_FETCH_MODE = $save; - - $rskey->Close(); - unset($rskey); - } + $rskey->Close(); + unset($rskey); + } - $rsdefa = array(); - if (!empty($this->metaDefaultsSQL)) { - $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; - $sql = sprintf($this->metaDefaultsSQL, ($table)); - $rsdef = $this->Execute($sql); - if (isset($savem)) $this->SetFetchMode($savem); - $ADODB_FETCH_MODE = $save; - - if ($rsdef) { - while (!$rsdef->EOF) { - $num = $rsdef->fields['num']; - $s = $rsdef->fields['def']; - if (substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */ - $s = substr($s, 1); - $s = substr($s, 0, strlen($s) - 1); - } - - $rsdefa[$num] = $s; - $rsdef->MoveNext(); + $rsdefa = array(); + if (!empty($this->metaDefaultsSQL)) { + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + $sql = sprintf($this->metaDefaultsSQL, ($table)); + $rsdef = $this->Execute($sql); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rsdef) { + while (!$rsdef->EOF) { + $num = $rsdef->fields['num']; + $s = $rsdef->fields['def']; + if (substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */ + $s = substr($s, 1); + $s = substr($s, 0, strlen($s) - 1); } - } else { - ADOConnection::outp( "==> SQL => " . $sql); + + $rsdefa[$num] = $s; + $rsdef->MoveNext(); } - unset($rsdef); + } else { + ADOConnection::outp( "==> SQL => " . $sql); + } + unset($rsdef); + } + + $retarr = array(); + while (!$rs->EOF) { + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $fld->type = $rs->fields[1]; + $fld->max_length = $rs->fields[2]; + if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4; + if ($fld->max_length <= 0) $fld->max_length = -1; + + // dannym + // 5 hasdefault; 6 num-of-column + $fld->has_default = ($rs->fields[5] == 't'); + if ($fld->has_default) { + $fld->default_value = $rsdefa[$rs->fields[6]]; } - - $retarr = array(); - while (!$rs->EOF) { - $fld = new ADOFieldObject(); - $fld->name = $rs->fields[0]; - $fld->type = $rs->fields[1]; - $fld->max_length = $rs->fields[2]; - if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4; - if ($fld->max_length <= 0) $fld->max_length = -1; - - // dannym - // 5 hasdefault; 6 num-of-column - $fld->has_default = ($rs->fields[5] == 't'); - if ($fld->has_default) { - $fld->default_value = $rsdefa[$rs->fields[6]]; - } - //Freek - if ($rs->fields[4] == $this->true) { - $fld->not_null = true; - } - - // Freek - if (is_array($keys)) { - reset ($keys); - while (list($x,$key) = each($keys)) { - if ($fld->name == $key['column_name'] AND $key['primary_key'] == $this->true) - $fld->primary_key = true; - if ($fld->name == $key['column_name'] AND $key['unique_key'] == $this->true) - $fld->unique = true; // What name is more compatible? - } + //Freek + if ($rs->fields[4] == $this->true) { + $fld->not_null = true; + } + + // Freek + if (is_array($keys)) { + foreach($keys as $key) { + if ($fld->name == $key['column_name'] AND $key['primary_key'] == $this->true) + $fld->primary_key = true; + if ($fld->name == $key['column_name'] AND $key['unique_key'] == $this->true) + $fld->unique = true; // What name is more compatible? } - - if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; - else $retarr[strtoupper($fld->name)] = $fld; - - $rs->MoveNext(); } - $rs->Close(); - return $retarr; + + if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; + else $retarr[($upper) ? strtoupper($fld->name) : $fld->name] = $fld; + + $rs->MoveNext(); } - return false; + $rs->Close(); + return $retarr; + } + function &MetaIndexes ($table, $primary = FALSE) + { + global $ADODB_FETCH_MODE; + + $schema = false; + $this->_findschema($table,$schema); + + if ($schema) { // requires pgsql 7.3+ - pg_namespace used. + $sql = ' +SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" +FROM pg_catalog.pg_class c +JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid +JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid + ,pg_namespace n +WHERE c2.relname=\'%s\' and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\' AND i.indisprimary=false'; + } else { + $sql = ' +SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" +FROM pg_catalog.pg_class c +JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid +JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid +WHERE c2.relname=\'%s\''; + } + + if ($primary == FALSE) { + $sql .= ' AND i.indisprimary=false;'; + } + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + $rs = $this->Execute(sprintf($sql,$table,$schema)); + + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + return FALSE; + } + + $col_names = $this->MetaColumnNames($table); + $indexes = array(); + + while ($row = $rs->FetchRow()) { + $columns = array(); + + foreach (explode(' ', $row[2]) as $col) { + $columns[] = $col_names[$col - 1]; + } + + $indexes[$row[0]] = array( + 'unique' => ($row[1] == 't'), + 'columns' => $columns + ); + } + + return $indexes; + } + // returns true or false // // examples: @@ -480,6 +558,9 @@ select viewname,'V' from pg_views where viewname like $mask"; // $db->Connect('host1','user1','secret'); function _connect($str,$user='',$pwd='',$db='',$ctype=0) { + + if (!function_exists('pg_pconnect')) return false; + $this->_errorMsg = false; if ($user || $pwd || $db) { @@ -687,7 +768,8 @@ class ADORecordSet_postgres64 extends ADORecordSet{ function &GetRowAssoc($upper=true) { if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields; - return ADORecordSet::GetRowAssoc($upper); + $row =& ADORecordSet::GetRowAssoc($upper); + return $row; } function _initrs() @@ -746,14 +828,12 @@ class ADORecordSet_postgres64 extends ADORecordSet{ function _fixblobs() { if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) { - reset($this->_blobArr); - while(list($k,$v) = each($this->_blobArr)) { + foreach($this->_blobArr as $k => $v) { $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]); } } if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) { - reset($this->_blobArr); - while(list($k,$v) = each($this->_blobArr)) { + foreach($this->_blobArr as $k => $v) { $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]); } } @@ -766,9 +846,8 @@ class ADORecordSet_postgres64 extends ADORecordSet{ $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(); + if (is_array($this->fields) && $this->fields) { + if ($this->fields && isset($this->_blobArr)) $this->_fixblobs(); return true; } } @@ -780,11 +859,13 @@ class ADORecordSet_postgres64 extends ADORecordSet{ 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(); + + if ($this->fields && isset($this->_blobArr)) $this->_fixblobs(); return (is_array($this->fields)); } diff --git a/lib/adodb/drivers/adodb-postgres7.inc.php b/lib/adodb/drivers/adodb-postgres7.inc.php index 8e923eefd3..2b9eb235f0 100644 --- a/lib/adodb/drivers/adodb-postgres7.inc.php +++ b/lib/adodb/drivers/adodb-postgres7.inc.php @@ -1,6 +1,6 @@ = 0) ? " OFFSET $offset" : ''; - $limitStr = ($nrows >= 0) ? " LIMIT $nrows" : ''; - return $secs2cache ? - $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr) - : - $this->Execute($sql."$limitStr$offsetStr",$inputarr); + $offsetStr = ($offset >= 0) ? " OFFSET $offset" : ''; + $limitStr = ($nrows >= 0) ? " LIMIT $nrows" : ''; + if ($secs2cache) + $rs =& $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr); + else + $rs =& $this->Execute($sql."$limitStr$offsetStr",$inputarr); + + return $rs; } /* function Prepare($sql) @@ -135,7 +137,7 @@ class ADORecordSet_postgres7 extends ADORecordSet_postgres64{ $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode); if (is_array($this->fields)) { - if (isset($this->_blobArr)) $this->_fixblobs(); + if ($this->fields && isset($this->_blobArr)) $this->_fixblobs(); return true; } } diff --git a/lib/adodb/drivers/adodb-proxy.inc.php b/lib/adodb/drivers/adodb-proxy.inc.php index c53e057d65..c589ce96ad 100644 --- a/lib/adodb/drivers/adodb-proxy.inc.php +++ b/lib/adodb/drivers/adodb-proxy.inc.php @@ -1,6 +1,6 @@ _connectionID = sqlite_open($argHostname); if ($this->_connectionID === false) return false; $this->_createFunctions(); @@ -135,6 +137,8 @@ class ADODB_sqlite extends ADOConnection { // returns true or false function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) { + if (!function_exists('sqlite_open')) return false; + $this->_connectionID = sqlite_popen($argHostname); if ($this->_connectionID === false) return false; $this->_createFunctions(); @@ -156,10 +160,12 @@ class ADODB_sqlite extends ADOConnection { { $offsetStr = ($offset >= 0) ? " OFFSET $offset" : ''; $limitStr = ($nrows >= 0) ? " LIMIT $nrows" : ($offset >= 0 ? ' LIMIT 999999999' : ''); - return $secs2cache ? - $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr) - : - $this->Execute($sql."$limitStr$offsetStr",$inputarr); + if ($secs2cache) + $rs =& $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr); + else + $rs =& $this->Execute($sql."$limitStr$offsetStr",$inputarr); + + return $rs; } /* diff --git a/lib/adodb/drivers/adodb-sybase.inc.php b/lib/adodb/drivers/adodb-sybase.inc.php index 1291162ad1..b162667497 100644 --- a/lib/adodb/drivers/adodb-sybase.inc.php +++ b/lib/adodb/drivers/adodb-sybase.inc.php @@ -1,6 +1,6 @@ _connectionID = sybase_connect($argHostname,$argUsername,$argPassword); if ($this->_connectionID === false) return false; if ($argDatabasename) return $this->SelectDB($argDatabasename); @@ -123,6 +125,8 @@ class ADODB_sybase extends ADOConnection { // returns true or false function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) { + if (!function_exists('sybase_connect')) return false; + $this->_connectionID = sybase_pconnect($argHostname,$argUsername,$argPassword); if ($this->_connectionID === false) return false; if ($argDatabasename) return $this->SelectDB($argDatabasename); @@ -143,14 +147,15 @@ class ADODB_sybase extends ADOConnection { // See http://www.isug.com/Sybase_FAQ/ASE/section6.2.html#6.2.12 function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) { - if ($secs2cache > 0) // we do not cache rowcount, so we have to load entire recordset - return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); - + if ($secs2cache > 0) {// we do not cache rowcount, so we have to load entire recordset + $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + return $rs; + } $cnt = ($nrows > 0) ? $nrows : 0; if ($offset > 0 && $cnt) $cnt += $offset; $this->Execute("set rowcount $cnt"); - $rs = &ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); $this->Execute("set rowcount 0"); return $rs; diff --git a/lib/adodb/drivers/adodb-vfp.inc.php b/lib/adodb/drivers/adodb-vfp.inc.php index 42dddf9d16..86e1e752ab 100644 --- a/lib/adodb/drivers/adodb-vfp.inc.php +++ b/lib/adodb/drivers/adodb-vfp.inc.php @@ -1,6 +1,6 @@ 'ca', + DB_ERROR => 'error desconegut', + DB_ERROR_ALREADY_EXISTS => 'ja existeix', + DB_ERROR_CANNOT_CREATE => 'no es pot crear', + DB_ERROR_CANNOT_DELETE => 'no es pot esborrar', + DB_ERROR_CANNOT_DROP => 'no es pot eliminar', + DB_ERROR_CONSTRAINT => 'violació de constraint', + DB_ERROR_DIVZERO => 'divisió per zero', + DB_ERROR_INVALID => 'no és vàlid', + DB_ERROR_INVALID_DATE => 'la data o l\'hora no són vàlides', + DB_ERROR_INVALID_NUMBER => 'el nombre no és vàlid', + DB_ERROR_MISMATCH => 'no hi ha coincidència', + DB_ERROR_NODBSELECTED => 'cap base de dades seleccionada', + DB_ERROR_NOSUCHFIELD => 'camp inexistent', + DB_ERROR_NOSUCHTABLE => 'taula inexistent', + DB_ERROR_NOT_CAPABLE => 'l\'execució secundària de DB no pot', + DB_ERROR_NOT_FOUND => 'no trobat', + DB_ERROR_NOT_LOCKED => 'no blocat', + DB_ERROR_SYNTAX => 'error de sintaxi', + DB_ERROR_UNSUPPORTED => 'no suportat', + DB_ERROR_VALUE_COUNT_ON_ROW => 'el nombre de columnes no coincideix amb el nombre de valors en la fila', + DB_ERROR_INVALID_DSN => 'el DSN no és vàlid', + DB_ERROR_CONNECT_FAILED => 'connexió fallida', + 0 => 'cap error', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'les dades subministrades són insuficients', + DB_ERROR_EXTENSION_NOT_FOUND=> 'extensió no trobada', + DB_ERROR_NOSUCHDB => 'base de dades inexistent', + DB_ERROR_ACCESS_VIOLATION => 'permisos insuficients' +); +?> + \ No newline at end of file diff --git a/lib/adodb/lang/adodb-cn.inc.php b/lib/adodb/lang/adodb-cn.inc.php new file mode 100644 index 0000000000..eb8c7de55c --- /dev/null +++ b/lib/adodb/lang/adodb-cn.inc.php @@ -0,0 +1,35 @@ + 'cn', + DB_ERROR => 'δ֪´íÎó', + DB_ERROR_ALREADY_EXISTS => 'ÒѾ­´æÔÚ', + DB_ERROR_CANNOT_CREATE => '²»ÄÜ´´½¨', + DB_ERROR_CANNOT_DELETE => '²»ÄÜɾ³ý', + DB_ERROR_CANNOT_DROP => '²»ÄܶªÆú', + DB_ERROR_CONSTRAINT => 'Ô¼ÊøÏÞÖÆ', + DB_ERROR_DIVZERO => '±»0³ý', + DB_ERROR_INVALID => 'ÎÞЧ', + DB_ERROR_INVALID_DATE => 'ÎÞЧµÄÈÕÆÚ»òÕßʱ¼ä', + DB_ERROR_INVALID_NUMBER => 'ÎÞЧµÄÊý×Ö', + DB_ERROR_MISMATCH => '²»Æ¥Åä', + DB_ERROR_NODBSELECTED => 'ûÓÐÊý¾Ý¿â±»Ñ¡Ôñ', + DB_ERROR_NOSUCHFIELD => 'ûÓÐÏàÓ¦µÄ×Ö¶Î', + DB_ERROR_NOSUCHTABLE => 'ûÓÐÏàÓ¦µÄ±í', + DB_ERROR_NOT_CAPABLE => 'Êý¾Ý¿âºǫ́²»¼æÈÝ', + DB_ERROR_NOT_FOUND => 'ûÓз¢ÏÖ', + DB_ERROR_NOT_LOCKED => 'ûÓб»Ëø¶¨', + DB_ERROR_SYNTAX => 'Óï·¨´íÎó', + DB_ERROR_UNSUPPORTED => '²»Ö§³Ö', + DB_ERROR_VALUE_COUNT_ON_ROW => 'ÔÚÐÐÉÏÀÛ¼ÆÖµ', + DB_ERROR_INVALID_DSN => 'ÎÞЧµÄÊý¾ÝÔ´ (DSN)', + DB_ERROR_CONNECT_FAILED => 'Á¬½Óʧ°Ü', + 0 => 'ûÓдíÎó', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'ÌṩµÄÊý¾Ý²»ÄÜ·ûºÏÒªÇó', + DB_ERROR_EXTENSION_NOT_FOUND=> 'À©Õ¹Ã»Óб»·¢ÏÖ', + DB_ERROR_NOSUCHDB => 'ûÓÐÏàÓ¦µÄÊý¾Ý¿â', + DB_ERROR_ACCESS_VIOLATION => 'ûÓкÏÊʵÄȨÏÞ' +); +?> \ No newline at end of file diff --git a/lib/adodb/lang/adodb-de.inc.php b/lib/adodb/lang/adodb-de.inc.php new file mode 100644 index 0000000000..244cb2f66a --- /dev/null +++ b/lib/adodb/lang/adodb-de.inc.php @@ -0,0 +1,33 @@ + +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'de', + DB_ERROR => 'Unbekannter Fehler', + DB_ERROR_ALREADY_EXISTS => 'existiert bereits', + DB_ERROR_CANNOT_CREATE => 'kann nicht erstellen', + DB_ERROR_CANNOT_DELETE => 'kann nicht löschen', + DB_ERROR_CANNOT_DROP => 'Tabelle oder Index konnte nicht gelöscht werden', + DB_ERROR_CONSTRAINT => 'Constraint Verletzung', + DB_ERROR_DIVZERO => 'Division durch Null', + DB_ERROR_INVALID => 'ung¨ltig', + DB_ERROR_INVALID_DATE => 'ung¨ltiges Datum oder Zeit', + DB_ERROR_INVALID_NUMBER => 'ung¨ltige Zahl', + DB_ERROR_MISMATCH => 'Unverträglichkeit', + DB_ERROR_NODBSELECTED => 'keine Dantebank ausgewählt', + DB_ERROR_NOSUCHFIELD => 'Feld nicht vorhanden', + DB_ERROR_NOSUCHTABLE => 'Tabelle nicht vorhanden', + DB_ERROR_NOT_CAPABLE => 'Funktion nicht installiert', + DB_ERROR_NOT_FOUND => 'nicht gefunden', + DB_ERROR_NOT_LOCKED => 'nicht gesperrt', + DB_ERROR_SYNTAX => 'Syntaxfehler', + DB_ERROR_UNSUPPORTED => 'nicht Unterst¨tzt', + DB_ERROR_VALUE_COUNT_ON_ROW => 'Anzahl der zur¨ckgelieferten Felder entspricht nicht der Anzahl der Felder in der Abfrage', + DB_ERROR_INVALID_DSN => 'ung¨ltiger DSN', + DB_ERROR_CONNECT_FAILED => 'Verbindung konnte nicht hergestellt werden', + 0 => 'kein Fehler', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'Nicht gen¨gend Daten geliefert', + DB_ERROR_EXTENSION_NOT_FOUND=> 'erweiterung nicht gefunden', + DB_ERROR_NOSUCHDB => 'keine Datenbank', + DB_ERROR_ACCESS_VIOLATION => 'ungen¨gende Rechte' +); +?> \ No newline at end of file diff --git a/lib/adodb/lang/adodb-fr.inc.php b/lib/adodb/lang/adodb-fr.inc.php index 9d7e98f20b..066a2a5e5b 100644 --- a/lib/adodb/lang/adodb-fr.inc.php +++ b/lib/adodb/lang/adodb-fr.inc.php @@ -28,6 +28,6 @@ $ADODB_LANG_ARRAY = array ( DB_ERROR_NEED_MORE_DATA => 'données fournies insuffisantes', DB_ERROR_EXTENSION_NOT_FOUND=> 'extension non trouvée', DB_ERROR_NOSUCHDB => 'base de données inconnue', - DB_ERROR_ACCESS_VIOLATION => 'droits ynsuffisants' + DB_ERROR_ACCESS_VIOLATION => 'droits insuffisants' ); ?> \ No newline at end of file diff --git a/lib/adodb/lang/adodb-it.inc.php b/lib/adodb/lang/adodb-it.inc.php index 71dcb88599..20c5b93b63 100644 --- a/lib/adodb/lang/adodb-it.inc.php +++ b/lib/adodb/lang/adodb-it.inc.php @@ -8,10 +8,10 @@ $ADODB_LANG_ARRAY = array ( DB_ERROR_CANNOT_CREATE => 'non posso creare', DB_ERROR_CANNOT_DELETE => 'non posso cancellare', DB_ERROR_CANNOT_DROP => 'non posso eliminare', - DB_ERROR_CONSTRAINT => 'viiolazione constraint', + DB_ERROR_CONSTRAINT => 'violazione constraint', DB_ERROR_DIVZERO => 'divisione per zero', DB_ERROR_INVALID => 'non valido', - DB_ERROR_INVALID_DATE => 'date od ora non valido', + DB_ERROR_INVALID_DATE => 'data od ora non valida', DB_ERROR_INVALID_NUMBER => 'numero non valido', DB_ERROR_MISMATCH => 'diversi', DB_ERROR_NODBSELECTED => 'nessun database selezionato', @@ -26,9 +26,9 @@ $ADODB_LANG_ARRAY = array ( DB_ERROR_INVALID_DSN => 'DSN non valido', DB_ERROR_CONNECT_FAILED => 'connessione fallita', 0 => 'nessun errore', // DB_OK - DB_ERROR_NEED_MORE_DATA => 'dati inseriti insufficenti', + DB_ERROR_NEED_MORE_DATA => 'dati inseriti insufficienti', DB_ERROR_EXTENSION_NOT_FOUND=> 'estensione non trovata', DB_ERROR_NOSUCHDB => 'database non trovato', - DB_ERROR_ACCESS_VIOLATION => 'permessi insufficenti' + DB_ERROR_ACCESS_VIOLATION => 'permessi insufficienti' ); ?> \ No newline at end of file diff --git a/lib/adodb/license.txt b/lib/adodb/license.txt index b05750301b..65831629fa 100644 --- a/lib/adodb/license.txt +++ b/lib/adodb/license.txt @@ -13,12 +13,27 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -Neither the name of the John Lim nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this list +of conditions and the following disclaimer in the documentation and/or other materials +provided with the distribution. + +Neither the name of the John Lim nor the names of its contributors may be used to +endorse or promote products derived from this software without specific prior written +permission. DISCLAIMER: -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +JOHN LIM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ========================================================== GNU LESSER GENERAL PUBLIC LICENSE diff --git a/lib/adodb/perf/perf-db2.inc.php b/lib/adodb/perf/perf-db2.inc.php index bc73ab3a6f..64e26222d0 100644 --- a/lib/adodb/perf/perf-db2.inc.php +++ b/lib/adodb/perf/perf-db2.inc.php @@ -1,6 +1,6 @@ conn =& $conn; } - function Explain($sql) + function Explain($sql,$partial=false) { $save = $this->conn->LogSQL(false); + if ($partial) { + $sqlq = $this->conn->qstr($sql.'%'); + $arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq"); + if ($arr) { + foreach($arr as $row) { + $sql = reset($row); + if (crc32($sql) == $partial) break; + } + } + } $qno = rand(); $ok = $this->conn->Execute("EXPLAIN PLAN SET QUERYNO=$qno FOR $sql"); ob_start(); diff --git a/lib/adodb/perf/perf-informix.inc.php b/lib/adodb/perf/perf-informix.inc.php index 3ee4b923dc..2b2923b868 100644 --- a/lib/adodb/perf/perf-informix.inc.php +++ b/lib/adodb/perf/perf-informix.inc.php @@ -1,6 +1,6 @@ conn =& $conn; } - function Explain($sql) + function Explain($sql,$partial=false) { + + $save = $this->conn->LogSQL(false); + if ($partial) { + $sqlq = $this->conn->qstr($sql.'%'); + $arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq"); + if ($arr) { + foreach($arr as $row) { + $sql = reset($row); + if (crc32($sql) == $partial) break; + } + } + } + $s = '

    Explain: '.htmlspecialchars($sql).'

    '; $this->conn->Execute("SET SHOWPLAN_ALL ON;"); $sql = str_replace('?',"''",$sql); @@ -96,7 +109,7 @@ class perf_mssql extends adodb_perf{ } $this->conn->Execute("SET SHOWPLAN_ALL OFF;"); - + $this->conn->LogSQL($save); $s .= $this->Tracer($sql); return $s; } diff --git a/lib/adodb/perf/perf-mysql.inc.php b/lib/adodb/perf/perf-mysql.inc.php index 9e038c6dd4..bfa1883d4f 100644 --- a/lib/adodb/perf/perf-mysql.inc.php +++ b/lib/adodb/perf/perf-mysql.inc.php @@ -1,6 +1,6 @@ conn =& $conn; } - function Explain($sql) + function Explain($sql,$partial=false) { + if (strtoupper(substr(trim($sql),0,6)) !== 'SELECT') return '

    Unable to EXPLAIN non-select statement

    '; + $save = $this->conn->LogSQL(false); + if ($partial) { + $sqlq = $this->conn->qstr($sql.'%'); + $arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq"); + if ($arr) { + foreach($arr as $row) { + $sql = reset($row); + if (crc32($sql) == $partial) break; + } + } + } $sql = str_replace('?',"''",$sql); + + if ($partial) { + $sqlq = $this->conn->qstr($sql.'%'); + $sql = $this->conn->GetOne("select sql1 from adodb_logsql where sql1 like $sqlq"); + } + $s = '

    Explain: '.htmlspecialchars($sql).'

    '; $rs = $this->conn->Execute('EXPLAIN '.$sql); $s .= rs2html($rs,false,false,false,false); + $this->conn->LogSQL($save); $s .= $this->Tracer($sql); return $s; } @@ -207,7 +226,9 @@ class perf_mysql extends adodb_perf{ { global $HTTP_SESSION_VARS; - $stat = $this->conn->GetOne('show innodb status'); + $rs = $this->conn->Execute('show innodb status'); + if (!$rs || $rs->EOF) return 0; + $stat = $rs->fields[0]; $at = strpos($stat,'Buffer pool hit rate'); $stat = substr($stat,$at,200); if (preg_match('!Buffer pool hit rate\s*([0-9]*) / ([0-9]*)!',$stat,$arr)) { diff --git a/lib/adodb/perf/perf-oci8.inc.php b/lib/adodb/perf/perf-oci8.inc.php index e301a225c2..cc1151ea57 100644 --- a/lib/adodb/perf/perf-oci8.inc.php +++ b/lib/adodb/perf/perf-oci8.inc.php @@ -1,6 +1,6 @@ shared_pool_size
    if too ratio low'), + + 'memory sort ratio' => array('RATIOH', + "SELECT ROUND((100 * b.VALUE) /DECODE ((a.VALUE + b.VALUE), + 0,1,(a.VALUE + b.VALUE)),2) +FROM v\$sysstat a, + v\$sysstat b +WHERE a.name = 'sorts (disk)' +AND b.name = 'sorts (memory)'", + "% of memory sorts compared to disk sorts - should be over 95%"), 'IO', 'data reads' => array('IO', @@ -176,7 +185,7 @@ class perf_oci8 extends ADODB_perf{ return reset($rs->fields); } - function Explain($sql) + function Explain($sql,$partial=false) { $savelog = $this->conn->LogSQL(false); $rs =& $this->conn->SelectLimit("select ID FROM PLAN_TABLE"); @@ -216,6 +225,17 @@ CREATE TABLE PLAN_TABLE ( $rs->Close(); // $this->conn->debug=1; + if ($partial) { + $sqlq = $this->conn->qstr($sql.'%'); + $arr = $this->conn->GetArray("select distinct distinct sql1 from adodb_logsql where sql1 like $sqlq"); + if ($arr) { + foreach($arr as $row) { + $sql = reset($row); + if (crc32($sql) == $partial) break; + } + } + } + $s = "

    Explain: ".htmlspecialchars($sql)."

    "; $this->conn->BeginTrans(); @@ -239,7 +259,7 @@ CONNECT BY prior id=parent_id and statement_id='$id'"); $s .= rs2html($rs,false,false,false,false); $this->conn->RollbackTrans(); $this->conn->LogSQL($savelog); - $s .= $this->Tracer($sql); + $s .= $this->Tracer($sql,$partial); return $s; } @@ -256,17 +276,18 @@ select a.size_for_estimate as cache_mb_estimate, '- BETTER - ' else ' ' end as currsize, a.estd_physical_read_factor-b.estd_physical_read_factor as best_when_0 - from (select size_for_estimate,size_factor,estd_physical_read_factor,rownum r from v\$conn_cache_advice) a , - (select size_for_estimate,size_factor,estd_physical_read_factor,rownum r from v\$conn_cache_advice) b where a.r = b.r-1"); + from (select size_for_estimate,size_factor,estd_physical_read_factor,rownum r from v\$db_cache_advice) a , + (select size_for_estimate,size_factor,estd_physical_read_factor,rownum r from v\$db_cache_advice) b where a.r = b.r-1"); if (!$rs) return false; /* - The v$conn_cache_advice utility show the marginal changes in physical data block reads for different sizes of db_cache_size + The v$db_cache_advice utility show the marginal changes in physical data block reads for different sizes of db_cache_size */ $s = "

    Data Cache Estimate

    "; if ($rs->EOF) { $s .= "

    Cache that is 50% of current size is still too big

    "; } else { + $s .= "Ideal size of Data Cache is when \"best_when_0\" changes from a positive number and becomes zero."; $s .= rs2html($rs,false,false,false,false); } return $s; @@ -360,7 +381,8 @@ order by global $ADODB_CACHE_MODE,$HTTP_GET_VARS; if (isset($HTTP_GET_VARS['expsixora']) && isset($HTTP_GET_VARS['sql'])) { - echo "".$this->Explain($HTTP_GET_VARS['sql'])."\n"; + $partial = empty($HTTP_GET_VARS['part']); + echo "".$this->Explain($HTTP_GET_VARS['sql'],$partial)."\n"; } if (isset($HTTP_GET_VARS['sql'])) return $this->_SuspiciousSQL(); @@ -385,7 +407,7 @@ order by // code thanks to Ixora. // http://www.ixora.com.au/scripts/query_opt.htm // requires oracle 8.1.7 or later - function& ExpensiveSQL($numsql = 10) + function ExpensiveSQL($numsql = 10) { $sql = " select @@ -424,11 +446,14 @@ order by "; global $ADODB_CACHE_MODE,$HTTP_GET_VARS; if (isset($HTTP_GET_VARS['expeixora']) && isset($HTTP_GET_VARS['sql'])) { - echo "".$this->Explain($HTTP_GET_VARS['sql'])."\n"; + $partial = empty($HTTP_GET_VARS['part']); + echo "".$this->Explain($HTTP_GET_VARS['sql'],$partial)."\n"; } - if (isset($HTTP_GET_VARS['sql'])) return $this->_ExpensiveSQL(); - + if (isset($HTTP_GET_VARS['sql'])) { + $var =& $this->_ExpensiveSQL(); + return $var; + } $save = $ADODB_CACHE_MODE; $ADODB_CACHE_MODE = ADODB_FETCH_NUM; $savelog = $this->conn->LogSQL(false); diff --git a/lib/adodb/perf/perf-postgres.inc.php b/lib/adodb/perf/perf-postgres.inc.php index f0d97b1a5a..5ae20e4d2a 100644 --- a/lib/adodb/perf/perf-postgres.inc.php +++ b/lib/adodb/perf/perf-postgres.inc.php @@ -1,7 +1,7 @@ conn =& $conn; } - function Explain($sql) + function Explain($sql,$partial=false) { - $sql = str_replace('?',"''",$sql); $save = $this->conn->LogSQL(false); + + if ($partial) { + $sqlq = $this->conn->qstr($sql.'%'); + $arr = $this->conn->GetArray("select distinct distinct sql1 from adodb_logsql where sql1 like $sqlq"); + if ($arr) { + foreach($arr as $row) { + $sql = reset($row); + if (crc32($sql) == $partial) break; + } + } + } + $sql = str_replace('?',"''",$sql); $s = '

    Explain: '.htmlspecialchars($sql).'

    '; $rs = $this->conn->Execute('EXPLAIN '.$sql); $this->conn->LogSQL($save); @@ -102,7 +113,7 @@ class perf_postgres extends adodb_perf{ $rs->MoveNext(); } $s .= ''; - $s .= $this->Tracer($sql); + $s .= $this->Tracer($sql,$partial); return $s; } } diff --git a/lib/adodb/pivottable.inc.php b/lib/adodb/pivottable.inc.php index 96834f3723..f9c547f11b 100644 --- a/lib/adodb/pivottable.inc.php +++ b/lib/adodb/pivottable.inc.php @@ -1,6 +1,6 @@ _block_size; + } + + /** + */ + function setBlockSize($block_size) { + assert('$block_size >= 1'); + assert('$block_size <= 9'); + $this->_block_size = (int) $block_size; + } + + /** + */ + function getWorkLevel() { + return $this->_work_level; + } + + /** + */ + function setWorkLevel($work_level) { + assert('$work_level >= 0'); + assert('$work_level <= 250'); + $this->_work_level = (int) $work_level; + } + + /** + */ + function getMinLength() { + return $this->_min_length; + } + + /** + */ + function setMinLength($min_length) { + assert('$min_length >= 0'); + $this->_min_length = (int) $min_length; + } + + /** + */ + function ADODB_Compress_Bzip2($block_size = null, $work_level = null, $min_length = null) { + if (!is_null($block_size)) { + $this->setBlockSize($block_size); + } + + if (!is_null($work_level)) { + $this->setWorkLevel($work_level); + } + + if (!is_null($min_length)) { + $this->setMinLength($min_length); + } + } + + /** + */ + function write($data, $key) { + if (strlen($data) < $this->_min_length) { + return $data; + } + + if (!is_null($this->_block_size)) { + if (!is_null($this->_work_level)) { + return bzcompress($data, $this->_block_size, $this->_work_level); + } else { + return bzcompress($data, $this->_block_size); + } + } + + return bzcompress($data); + } + + /** + */ + function read($data, $key) { + return $data ? bzdecompress($data) : $data; + } + +} + +return 1; + +?> diff --git a/lib/adodb/session/adodb-compress-gzip.php b/lib/adodb/session/adodb-compress-gzip.php new file mode 100644 index 0000000000..c5e568e7e9 --- /dev/null +++ b/lib/adodb/session/adodb-compress-gzip.php @@ -0,0 +1,94 @@ +_level; + } + + /** + */ + function setLevel($level) { + assert('$level >= 0'); + assert('$level <= 9'); + $this->_level = (int) $level; + } + + /** + */ + function getMinLength() { + return $this->_min_length; + } + + /** + */ + function setMinLength($min_length) { + assert('$min_length >= 0'); + $this->_min_length = (int) $min_length; + } + + /** + */ + function ADODB_Compress_Gzip($level = null, $min_length = null) { + if (!is_null($level)) { + $this->setLevel($level); + } + + if (!is_null($min_length)) { + $this->setMinLength($min_length); + } + } + + /** + */ + function write($data, $key) { + if (strlen($data) < $this->_min_length) { + return $data; + } + + if (!is_null($this->_level)) { + return gzcompress($data, $this->_level); + } else { + return gzcompress($data); + } + } + + /** + */ + function read($data, $key) { + return $data ? gzuncompress($data) : $data; + } + +} + +return 1; + +?> \ No newline at end of file diff --git a/lib/adodb/session/adodb-cryptsession.php b/lib/adodb/session/adodb-cryptsession.php new file mode 100644 index 0000000000..c0ffc3c187 --- /dev/null +++ b/lib/adodb/session/adodb-cryptsession.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/lib/adodb/session/adodb-encrypt-mcrypt.php b/lib/adodb/session/adodb-encrypt-mcrypt.php new file mode 100644 index 0000000000..2083436392 --- /dev/null +++ b/lib/adodb/session/adodb-encrypt-mcrypt.php @@ -0,0 +1,110 @@ +_cipher; + } + + /** + */ + function setCipher($cipher) { + $this->_cipher = $cipher; + } + + /** + */ + function getMode() { + return $this->_mode; + } + + /** + */ + function setMode($mode) { + $this->_mode = $mode; + } + + /** + */ + function getSource() { + return $this->_source; + } + + /** + */ + function setSource($source) { + $this->_source = $source; + } + + /** + */ + function ADODB_Encrypt_MCrypt($cipher = null, $mode = null, $source = null) { + if (!$cipher) { + $cipher = MCRYPT_RIJNDAEL_256; + } + if (!$mode) { + $mode = MCRYPT_MODE_ECB; + } + if (!$source) { + $source = MCRYPT_RAND; + } + + $this->_cipher = $cipher; + $this->_mode = $mode; + $this->_source = $source; + } + + /** + */ + function write($data, $key) { + $iv_size = mcrypt_get_iv_size($this->_cipher, $this->_mode); + $iv = mcrypt_create_iv($iv_size, $this->_source); + return mcrypt_encrypt($this->_cipher, $key, $data, $this->_mode, $iv); + } + + /** + */ + function read($data, $key) { + $iv_size = mcrypt_get_iv_size($this->_cipher, $this->_mode); + $iv = mcrypt_create_iv($iv_size, $this->_source); + $rv = mcrypt_decrypt($this->_cipher, $key, $data, $this->_mode, $iv); + return rtrim($rv, "\0"); + } + +} + +return 1; + +?> diff --git a/lib/adodb/session/adodb-encrypt-md5.php b/lib/adodb/session/adodb-encrypt-md5.php new file mode 100644 index 0000000000..8a7e939539 --- /dev/null +++ b/lib/adodb/session/adodb-encrypt-md5.php @@ -0,0 +1,38 @@ +encrypt($data, $key); + } + + /** + */ + function read($data, $key) { + $md5crypt =& new MD5Crypt(); + return $md5crypt->decrypt($data, $key); + } + +} + +return 1; + +?> \ No newline at end of file diff --git a/lib/adodb/session/adodb-encrypt-secret.php b/lib/adodb/session/adodb-encrypt-secret.php new file mode 100644 index 0000000000..f979c7a0d0 --- /dev/null +++ b/lib/adodb/session/adodb-encrypt-secret.php @@ -0,0 +1,50 @@ + diff --git a/lib/adodb/session/adodb-sess.txt b/lib/adodb/session/adodb-sess.txt new file mode 100644 index 0000000000..d23dac42df --- /dev/null +++ b/lib/adodb/session/adodb-sess.txt @@ -0,0 +1,131 @@ +John, + +I have been an extremely satisfied ADODB user for several years now. + +To give you something back for all your hard work, I've spent the last 3 +days rewriting the adodb-session.php code. + +---------- +What's New +---------- + +Here's a list of the new code's benefits: + +* Combines the functionality of the three files: + +adodb-session.php +adodb-session-clob.php +adodb-cryptsession.php + +each with very similar functionality, into a single file adodb-session.php. +This will ease maintenance and support issues. + +* Supports multiple encryption and compression schemes. + Currently, we support: + + MD5Crypt (crypt.inc.php) + MCrypt + Secure (Horde's emulation of MCrypt, if MCrypt module is not available.) + GZip + BZip2 + +These can be stacked, so if you want to compress and then encrypt your +session data, it's easy. +Also, the built-in MCrypt functions will be *much* faster, and more secure, +than the MD5Crypt code. + +* adodb-session.php contains a single class ADODB_Session that encapsulates +all functionality. + This eliminates the use of global vars and defines (though they are +supported for backwards compatibility). + +* All user defined parameters are now static functions in the ADODB_Session +class. + +New parameters include: + +* encryptionKey(): Define the encryption key used to encrypt the session. +Originally, it was a hard coded string. + +* persist(): Define if the database will be opened in persistent mode. +Originally, the user had to call adodb_sess_open(). + +* dataFieldName(): Define the field name used to store the session data, as +'DATA' appears to be a reserved word in the following cases: + ANSI SQL + IBM DB2 + MS SQL Server + Postgres + SAP + +* filter(): Used to support multiple, simulataneous encryption/compression +schemes. + +* Debug support is improved thru _rsdump() function, which is called after +every database call. + +------------ +What's Fixed +------------ + +The new code includes several bug fixes and enhancements: + +* sesskey is compared in BINARY mode for MySQL, to avoid problems with +session keys that differ only by case. + Of course, the user should define the sesskey field as BINARY, to +correctly fix this problem, otherwise performance will suffer. + +* In ADODB_Session::gc(), if $expire_notify is true, the multiple DELETES in +the original code have been optimized to a single DELETE. + +* In ADODB_Session::destroy(), since "SELECT expireref, sesskey FROM $table +WHERE sesskey = $qkey" will only return a single value, we don't loop on the +result, we simply process the row, if any. + +* We close $rs after every use. + +--------------- +What's the Same +--------------- + +I know backwards compatibility is *very* important to you. Therefore, the +new code is 100% backwards compatible. + +If you like my code, but don't "trust" it's backwards compatible, maybe we +offer it as beta code, in a new directory for a release or two? + +------------ +What's To Do +------------ + +I've vascillated over whether to use a single function to get/set +parameters: + +$user = ADODB_Session::user(); // get +ADODB_Session::user($user); // set + +or to use separate functions (which is the PEAR/Java way): + +$user = ADODB_Session::getUser(); +ADODB_Session::setUser($user); + +I've chosen the former as it's makes for a simpler API, and reduces the +amount of code, but I'd be happy to change it to the latter. + +Also, do you think the class should be a singleton class, versus a static +class? + +Let me know if you find this code useful, and will be including it in the +next release of ADODB. + +If so, I will modify the current documentation to detail the new +functionality. To that end, what file(s) contain the documentation? Please +send them to me if they are not publically available. + +Also, if there is *anything* in the code that you like to see changed, let +me know. + +Thanks, + +Ross + diff --git a/lib/adodb/session/adodb-session-clob.php b/lib/adodb/session/adodb-session-clob.php new file mode 100644 index 0000000000..425adfb8f6 --- /dev/null +++ b/lib/adodb/session/adodb-session-clob.php @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/lib/adodb/session/adodb-session.php b/lib/adodb/session/adodb-session.php new file mode 100644 index 0000000000..7cba4f854e --- /dev/null +++ b/lib/adodb/session/adodb-session.php @@ -0,0 +1,817 @@ +Session Error: PHP.INI setting session.gc_maxlifetimenot set: $lifetime"; + $_lifetime = 1440; + } + } + + return $_lifetime; + } + + /*! + */ + function debug($debug = null) { + static $_debug = false; + static $set = false; + + if (!is_null($debug)) { + $_debug = (bool) $debug; + + $conn = ADODB_Session::_conn(); + if ($conn) { + $conn->debug = $_debug; + } + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESS_DEBUG'])) { + return $GLOBALS['ADODB_SESS_DEBUG']; + } + } + + return $_debug; + } + + /*! + */ + function expireNotify($expire_notify = null) { + static $_expire_notify; + static $set = false; + + if (!is_null($expire_notify)) { + $_expire_notify = $expire_notify; + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY'])) { + return $GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY']; + } + } + + return $_expire_notify; + } + + /*! + */ + function table($table = null) { + static $_table = 'sessions'; + static $set = false; + + if (!is_null($table)) { + $_table = trim($table); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_TBL'])) { + return $GLOBALS['ADODB_SESSION_TBL']; + } + } + + return $_table; + } + + /*! + */ + function optimize($optimize = null) { + static $_optimize = false; + static $set = false; + + if (!is_null($optimize)) { + $_optimize = (bool) $optimize; + $set = true; + } elseif (!$set) { + // backwards compatibility + if (defined('ADODB_SESSION_OPTIMIZE')) { + return true; + } + } + + return $_optimize; + } + + /*! + */ + function syncSeconds($sync_seconds = null) { + static $_sync_seconds = 60; + static $set = false; + + if (!is_null($sync_seconds)) { + $_sync_seconds = (int) $sync_seconds; + $set = true; + } elseif (!$set) { + // backwards compatibility + if (defined('ADODB_SESSION_SYNCH_SECS')) { + return ADODB_SESSION_SYNCH_SECS; + } + } + + return $_sync_seconds; + } + + /*! + */ + function clob($clob = null) { + static $_clob = false; + static $set = false; + + if (!is_null($clob)) { + $_clob = strtolower(trim($clob)); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_USE_LOBS'])) { + return $GLOBALS['ADODB_SESSION_USE_LOBS']; + } + } + + return $_clob; + } + + /*! + */ + function dataFieldName($data_field_name = null) { + static $_data_field_name = 'data'; + + if (!is_null($data_field_name)) { + $_data_field_name = trim($data_field_name); + } + + return $_data_field_name; + } + + /*! + */ + function filter($filter = null) { + static $_filter = array(); + + if (!is_null($filter)) { + if (!is_array($filter)) { + $filter = array($filter); + } + $_filter = $filter; + } + + return $_filter; + } + + /*! + */ + function encryptionKey($encryption_key = null) { + static $_encryption_key = 'CRYPTED ADODB SESSIONS ROCK!'; + + if (!is_null($encryption_key)) { + $_encryption_key = $encryption_key; + } + + return $_encryption_key; + } + + ///////////////////// + // private methods + ///////////////////// + + /*! + */ + function &_conn($conn=null) { + return $GLOBALS['ADODB_SESS_CONN']; + } + + /*! + */ + function _crc($crc = null) { + static $_crc = false; + + if (!is_null($crc)) { + $_crc = $crc; + } + + return $_crc; + } + + /*! + */ + function _init() { + session_module_name('user'); + session_set_save_handler( + array('ADODB_Session', 'open'), + array('ADODB_Session', 'close'), + array('ADODB_Session', 'read'), + array('ADODB_Session', 'write'), + array('ADODB_Session', 'destroy'), + array('ADODB_Session', 'gc') + ); + } + + + /*! + */ + function _sessionKey() { + // use this function to create the encryption key for crypted sessions + // crypt the used key, ADODB_Session::encryptionKey() as key and session_id() as salt + return crypt(ADODB_Session::encryptionKey(), session_id()); + } + + /*! + */ + function _dumprs($rs) { + $conn =& ADODB_Session::_conn(); + $debug = ADODB_Session::debug(); + + if (!$conn) { + return; + } + + if (!$debug) { + return; + } + + if (!$rs) { + echo "
    \$rs is null or false
    \n"; + return; + } + + //echo "
    \nAffected_Rows=",$conn->Affected_Rows(),"
    \n"; + + if (!is_object($rs)) { + return; + } + + require_once ADODB_SESSION.'/../tohtml.inc.php'; + rs2html($rs); + } + + ///////////////////// + // public methods + ///////////////////// + + /*! + Create the connection to the database. + + If $conn already exists, reuse that connection + */ + function open($save_path, $session_name, $persist = null) { + $conn =& ADODB_Session::_conn(); + + if ($conn) { + return true; + } + + $database = ADODB_Session::database(); + $debug = ADODB_Session::debug(); + $driver = ADODB_Session::driver(); + $host = ADODB_Session::host(); + $password = ADODB_Session::password(); + $user = ADODB_Session::user(); + + if (!is_null($persist)) { + $persist = (bool) $persist; + ADODB_Session::persist($persist); + } else { + $persist = ADODB_Session::persist(); + } + +# these can all be defaulted to in php.ini +# assert('$database'); +# assert('$driver'); +# assert('$host'); + + // cannot use =& below - do not know why... + $conn = ADONewConnection($driver); + + if ($debug) { + $conn->debug = true; +// ADOConnection::outp( " driver=$driver user=$user pwd=$password db=$database "); + } + + if ($persist) { + $ok = $conn->PConnect($host, $user, $password, $database); + } else { + $ok = $conn->Connect($host, $user, $password, $database); + } + + if ($ok) $GLOBALS['ADODB_SESS_CONN'] =& $conn; + else + ADOConnection::outp('

    Session: connection failed

    ', false); + + + return $ok; + } + + /*! + Close the connection + */ + function close() { + $conn =& ADODB_Session::_conn(); + + if ($conn) { + $conn->Close(); + } + + return true; + } + + /* + Slurp in the session variables and return the serialized string + */ + function read($key) { + $conn =& ADODB_Session::_conn(); + $data = ADODB_Session::dataFieldName(); + $filter = ADODB_Session::filter(); + $table = ADODB_Session::table(); + + if (!$conn) { + return ''; + } + + assert('$table'); + + $qkey = $conn->quote($key); + $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : ''; + + $sql = "SELECT $data FROM $table WHERE $binary sesskey = $qkey AND expiry >= " . time(); + $rs =& $conn->Execute($sql); + //ADODB_Session::_dumprs($rs); + if ($rs) { + if ($rs->EOF) { + $v = ''; + } else { + $v = reset($rs->fields); + $filter = array_reverse($filter); + foreach ($filter as $f) { + if (is_object($f)) { + $v = $f->read($v, ADODB_Session::_sessionKey()); + } + } + $v = rawurldecode($v); + } + + $rs->Close(); + + ADODB_Session::_crc(strlen($v) . crc32($v)); + return $v; + } + + return ''; + } + + /*! + Write the serialized data to a database. + + If the data has not been modified since the last read(), we do not write. + */ + function write($key, $val) { + $clob = ADODB_Session::clob(); + $conn =& ADODB_Session::_conn(); + $crc = ADODB_Session::_crc(); + $data = ADODB_Session::dataFieldName(); + $debug = ADODB_Session::debug(); + $driver = ADODB_Session::driver(); + $expire_notify = ADODB_Session::expireNotify(); + $filter = ADODB_Session::filter(); + $lifetime = ADODB_Session::lifetime(); + $table = ADODB_Session::table(); + + if (!$conn) { + return false; + } + + assert('$table'); + + $expiry = time() + $lifetime; + + $qkey = $conn->quote($key); + $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : ''; + + // crc32 optimization since adodb 2.1 + // now we only update expiry date, thx to sebastian thom in adodb 2.32 + if ($crc !== false && $crc == (strlen($val) . crc32($val))) { + if ($debug) { + echo '

    Session: Only updating date - crc32 not changed

    '; + } + $sql = "UPDATE $table SET expiry = $expiry WHERE $binary sesskey = $qkey AND expiry >= " . time(); + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + if ($rs) { + $rs->Close(); + } + return true; + } + $val = rawurlencode($val); + foreach ($filter as $f) { + if (is_object($f)) { + $val = $f->write($val, ADODB_Session::_sessionKey()); + } + } + + $arr = array('sesskey' => $key, 'expiry' => $expiry, $data => $val, 'expireref' => ''); + if ($expire_notify) { + $var = reset($expire_notify); + global $$var; + if (isset($$var)) { + $arr['expireref'] = $$var; + } + } + + if (!$clob) { // no lobs, simply use replace() + $rs = $conn->Replace($table, $arr, 'sesskey', $autoQuote = true); + ADODB_Session::_dumprs($rs); + } else { + // what value shall we insert/update for lob row? + switch ($driver) { + // empty_clob or empty_lob for oracle dbs + case 'oracle': + case 'oci8': + case 'oci8po': + case 'oci805': + $lob_value = sprintf('empty_%s()', strtolower($clob)); + break; + + // null for all other + default: + $lob_value = 'null'; + break; + } + + // do we insert or update? => as for sesskey + $rs =& $conn->Execute("SELECT COUNT(*) AS cnt FROM $table WHERE $binary sesskey = $qkey"); + ADODB_Session::_dumprs($rs); + if ($rs && reset($rs->fields) > 0) { + $sql = "UPDATE $table SET expiry = $expiry, $data = $lob_value WHERE sesskey = $qkey"; + } else { + $sql = "INSERT INTO $table (expiry, $data, sesskey) VALUES ($expiry, $lob_value, $qkey)"; + } + if ($rs) { + $rs->Close(); + } + + $err = ''; + $rs1 =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs1); + if (!$rs1) { + $err = $conn->ErrorMsg()."\n"; + } + $rs2 =& $conn->UpdateBlob($table, $data, $val, " sesskey=$qkey", strtoupper($clob)); + ADODB_Session::_dumprs($rs2); + if (!$rs2) { + $err .= $conn->ErrorMsg()."\n"; + } + $rs = ($rs && $rs2) ? true : false; + if ($rs1) { + $rs1->Close(); + } + if (is_object($rs2)) { + $rs2->Close(); + } + } + + if (!$rs) { + ADOConnection::outp('

    Session Replace: ' . $conn->ErrorMsg() . '

    ', false); + return false; + } else { + // bug in access driver (could be odbc?) means that info is not committed + // properly unless select statement executed in Win2000 + if ($conn->databaseType == 'access') { + $sql = "SELECT sesskey FROM $table WHERE $binary sesskey = $qkey"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + if ($rs) { + $rs->Close(); + } + } + } + return $rs ? true : false; + } + + /*! + */ + function destroy($key) { + $conn =& ADODB_Session::_conn(); + $table = ADODB_Session::table(); + $expire_notify = ADODB_Session::expireNotify(); + + if (!$conn) { + return false; + } + + assert('$table'); + + $qkey = $conn->quote($key); + $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : ''; + + if ($expire_notify) { + reset($expire_notify); + $fn = next($expire_notify); + $savem = $conn->SetFetchMode(ADODB_FETCH_NUM); + $sql = "SELECT expireref, sesskey FROM $table WHERE $binary sesskey = $qkey"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + $conn->SetFetchMode($savem); + if (!$rs) { + return false; + } + if (!$rs->EOF) { + $ref = $rs->fields[0]; + $key = $rs->fields[1]; + assert('$ref'); + assert('$key'); + $fn($ref, $key); + } + $rs->Close(); + } + + $sql = "DELETE FROM $table WHERE $binary sesskey = $qkey"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + if ($rs) { + $rs->Close(); + } + + return $rs ? true : false; + } + + /*! + */ + function gc($maxlifetime) { + $conn =& ADODB_Session::_conn(); + $debug = ADODB_Session::debug(); + $expire_notify = ADODB_Session::expireNotify(); + $optimize = ADODB_Session::optimize(); + $sync_seconds = ADODB_Session::syncSeconds(); + $table = ADODB_Session::table(); + + if (!$conn) { + return false; + } + + assert('$table'); + + $time = time(); + + $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : ''; + + if ($expire_notify) { + reset($expire_notify); + $fn = next($expire_notify); + $savem = $conn->SetFetchMode(ADODB_FETCH_NUM); + $sql = "SELECT expireref, sesskey FROM $table WHERE expiry < $time"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + $conn->SetFetchMode($savem); + if ($rs) { + $conn->BeginTrans(); + $keys = array(); + while (!$rs->EOF) { + $ref = $rs->fields[0]; + $key = $rs->fields[1]; + $fn($ref, $key); + $del = $conn->Execute("DELETE FROM $table WHERE sesskey='$key'"); + $rs->MoveNext(); + } + $rs->Close(); + + $conn->CommitTrans(); + } + } else { + $sql = "DELETE FROM $table WHERE expiry < $time"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + if ($rs) { + $rs->Close(); + } + if ($debug) { + ADOConnection::outp("

    Garbage Collection: $sql

    "); + } + } + + // suggested by Cameron, "GaM3R" + if ($optimize) { + $driver = ADODB_Session::driver(); + + if (preg_match('/mysql/i', $driver)) { + $sql = "OPTIMIZE TABLE $table"; + } + if (preg_match('/postgres/i', $driver)) { + $sql = "VACUUM $table"; + } + if (!empty($sql)) { + $conn->Execute($sql); + } + } + + if ($sync_seconds) { + $sql = 'SELECT '; + if ($conn->dataProvider === 'oci8') { + $sql .= "TO_CHAR({$conn->sysTimeStamp}, 'RRRR-MM-DD HH24:MI:SS')"; + } else { + $sql .= $conn->sysTimeStamp; + } + $sql .= " FROM $table"; + + $rs =& $conn->SelectLimit($sql, 1); + if ($rs && !$rs->EOF) { + $dbts = reset($rs->fields); + $rs->Close(); + $dbt = $conn->UnixTimeStamp($dbts); + $t = time(); + + if (abs($dbt - $t) >= $sync_seconds) { + global $HTTP_SERVER_VARS; + $msg = __FILE__ . + ": Server time for webserver {$HTTP_SERVER_VARS['HTTP_HOST']} not in synch with database: " . + " database=$dbt ($dbts), webserver=$t (diff=". (abs($dbt - $t) / 3600) . ' hours)'; + error_log($msg); + if ($debug) { + ADOConnection::outp("

    $msg

    "); + } + } + } + } + + return true; + } + +} + +ADODB_Session::_init(); + + +// for backwards compatability only +function adodb_sess_open($save_path, $session_name, $persist = true) { + return ADODB_Session::open($save_path, $session_name, $persist); +} + +// for backwards compatability only +function adodb_sess_gc($t) +{ + return ADODB_Session::gc($t); +} + +?> diff --git a/lib/adodb/session/adodb-sessions.mysql.sql b/lib/adodb/session/adodb-sessions.mysql.sql new file mode 100644 index 0000000000..f90de44931 --- /dev/null +++ b/lib/adodb/session/adodb-sessions.mysql.sql @@ -0,0 +1,16 @@ +-- $CVSHeader$ + +CREATE DATABASE /*! IF NOT EXISTS */ adodb_sessions; + +USE adodb_sessions; + +DROP TABLE /*! IF EXISTS */ sessions; + +CREATE TABLE /*! IF NOT EXISTS */ sessions ( + sesskey CHAR(32) /*! BINARY */ NOT NULL DEFAULT '', + expiry INT(11) /*! UNSIGNED */ NOT NULL DEFAULT 0, + expireref VARCHAR(64) DEFAULT '', + data LONGTEXT DEFAULT '', + PRIMARY KEY (sesskey), + INDEX expiry (expiry) +); diff --git a/lib/adodb/session/adodb-sessions.oracle.clob.sql b/lib/adodb/session/adodb-sessions.oracle.clob.sql new file mode 100644 index 0000000000..c5c4f2d070 --- /dev/null +++ b/lib/adodb/session/adodb-sessions.oracle.clob.sql @@ -0,0 +1,15 @@ +-- $CVSHeader$ + +DROP TABLE adodb_sessions; + +CREATE TABLE sessions ( + sesskey CHAR(32) DEFAULT '' NOT NULL, + expiry INT DEFAULT 0 NOT NULL, + expireref VARCHAR(64) DEFAULT '', + data CLOB DEFAULT '', + PRIMARY KEY (sesskey) +); + +CREATE INDEX ix_expiry ON sessions (expiry); + +QUIT; diff --git a/lib/adodb/session/adodb-sessions.oracle.sql b/lib/adodb/session/adodb-sessions.oracle.sql new file mode 100644 index 0000000000..8fd5a34232 --- /dev/null +++ b/lib/adodb/session/adodb-sessions.oracle.sql @@ -0,0 +1,16 @@ +-- $CVSHeader$ + +DROP TABLE adodb_sessions; + +CREATE TABLE sessions ( + sesskey CHAR(32) DEFAULT '' NOT NULL, + expiry INT DEFAULT 0 NOT NULL, + expireref VARCHAR(64) DEFAULT '', + data VARCHAR(4000) DEFAULT '', + PRIMARY KEY (sesskey), + INDEX expiry (expiry) +); + +CREATE INDEX ix_expiry ON sessions (expiry); + +QUIT; diff --git a/lib/adodb/session/crypt.inc.php b/lib/adodb/session/crypt.inc.php new file mode 100644 index 0000000000..7266ab619d --- /dev/null +++ b/lib/adodb/session/crypt.inc.php @@ -0,0 +1,64 @@ + +class MD5Crypt{ + function keyED($txt,$encrypt_key) + { + $encrypt_key = md5($encrypt_key); + $ctr=0; + $tmp = ""; + for ($i=0;$ikeyED($tmp,$key)); + } + + function Decrypt($txt,$key) + { + $txt = $this->keyED(base64_decode($txt),$key); + $tmp = ""; + for ($i=0;$i= 58 && $randnumber <= 64) || ($randnumber >= 91 && $randnumber <= 96)) + { + $randnumber = rand(48,120); + } + + $randomPassword .= chr($randnumber); + } + return $randomPassword; + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/tests/benchmark.php b/lib/adodb/tests/benchmark.php index 76db3c12a0..484b9cc78b 100644 --- a/lib/adodb/tests/benchmark.php +++ b/lib/adodb/tests/benchmark.php @@ -8,7 +8,7 @@ Connect('localhost','tester','test','test') || die("failed connection"); + +$enc = "GIF89a%01%00%01%00%80%FF%00%C0%C0%C0%00%00%00%21%F9%04%01%00%00%00%00%2C%00%00%00%00%01%00%01%00%00%01%012%00%3Bt_clear.gif%0D"; +$val = rawurldecode($enc); +$db->debug=1; + +### TEST BEGINS + +$db->Execute("insert into photos (id,name) values(9999,'dot.gif')"); +$db->UpdateBlob('photos','photo',$val,'id=9999'); +$v = $db->GetOne('select photo from photos where id=9999'); + + +### CLEANUP + +$db->Execute("delete from photos where id=9999"); + +### VALIDATION + +if ($v !== $val) echo "*** ERROR: Inserted value does not match downloaded val"; +else echo "*** OK: Passed"; + +echo "
    ";
    +echo "INSERTED: ", $enc;
    +echo "
    "; +echo"RETURNED: ", rawurlencode($v); +echo "

    "; +echo "INSERTED: ", $val; +echo "


    "; +echo "RETURNED: ", $v; + +?> \ No newline at end of file diff --git a/lib/adodb/tests/test-php5.php b/lib/adodb/tests/test-php5.php new file mode 100644 index 0000000000..033f667a24 --- /dev/null +++ b/lib/adodb/tests/test-php5.php @@ -0,0 +1,56 @@ +Connect('','scott','natsoft'); + break; +default: +case 'mysql': + $db = NewADOConnection("mysql"); + $db->Connect('localhost','root','','test'); + break; +} + +$db->debug=1; + +$cnt = $db->GetOne("select count(*) from adoxyz"); +$rs = $db->Execute("select * from adoxyz order by id"); + +$i = 0; +foreach($rs as $v) { + $i += 1; + echo "$i: "; adodb_pr($v); adodb_pr($rs->fields); + flush(); +} + +if ($i != $cnt) die("actual cnt is $i, cnt should be $cnt\n"); + + +$rs = $db->Execute("select bad from badder"); + +} catch (exception $e) { + adodb_pr($e); + $e = adodb_backtrace($e->trace); +} + +?> \ No newline at end of file diff --git a/lib/adodb/tests/test-xmlschema.php b/lib/adodb/tests/test-xmlschema.php index 80058f71b6..aa3b4e8be9 100644 --- a/lib/adodb/tests/test-xmlschema.php +++ b/lib/adodb/tests/test-xmlschema.php @@ -1,6 +1,6 @@ date1 (1969-02-20) = ".$db->DBDate('1969-2-20'); print "
    date1 (1999-02-20) = ".$db->DBDate('1999-2-20'); + print "
    date1.1 1999 = ".$db->DBDate("'1999'"); print "
    date2 (1970-1-2) = ".$db->DBDate(24*3600)."

    "; print "ts1 (1999-02-20 13:40:50) = ".$db->DBTimeStamp('1999-2-20 1:40:50 pm'); print "
    ts1.1 (1999-02-20 13:40:00) = ".$db->DBTimeStamp('1999-2-20 13:40'); @@ -126,6 +127,10 @@ FROM `nuke_stories` `t1`, `nuke_authors` `t2`, `nuke_stories_cat` `t3`, `nuke_to print "
    Fractional TS (1999-2-20 13:40:50.91): ".$db->DBTimeStamp($db->UnixTimeStamp('1999-2-20 13:40:50.91+1')); $dd = $db->UnixDate('1999-02-20'); print "
    unixdate 1999-02-20 = ".date('Y-m-d',$dd)."

    "; + print "
    ts4 =".($db->UnixTimeStamp("19700101000101")+8*3600); + print "
    ts5 =".$db->DBTimeStamp($db->UnixTimeStamp("20040110092123")); + print "
    ts6 =".$db->UserTimeStamp("20040110092123"); + print "
    ts6 =".$db->DBTimeStamp("20040110092123"); flush(); // mssql too slow in failing bad connection if (false && $db->databaseType != 'mssql') { @@ -260,8 +265,18 @@ FROM `nuke_stories` `t1`, `nuke_authors` `t2`, `nuke_stories_cat` `t3`, `nuke_to $a = $db->MetaColumns('ADOXYZ'); if ($a===false) print "MetaColumns not supported

    "; else { - print "

    Columns of ADOXYZ: "; - foreach($a as $v) print " ($v->name $v->type $v->max_length) "; + print "

    Columns of ADOXYZ:
    "; + foreach($a as $v) {print_r($v); echo "
    ";} + echo "
    "; + } + + print "

    Testing MetaIndexes

    "; + $a = $db->MetaIndexes('ADOXYZ',true); + if ($a===false) print "MetaIndexes not supported

    "; + else { + print "

    Indexes of ADOXYZ:
    "; + foreach($a as $v) {print_r($v); echo "
    ";} + echo "
    "; } print "

    Testing MetaPrimaryKeys

    "; $a = $db->MetaPrimaryKeys('ADOXYZ'); @@ -329,8 +344,8 @@ GO $yr = '1998'; $stmt = $db->PrepareSP('SalesByCategory'); - $db->Parameter($stmt,$cat,'CategoryName'); - $db->Parameter($stmt,$yr,'OrdYear'); + $db->InParameter($stmt,$cat,'CategoryName'); + $db->InParameter($stmt,$yr,'OrdYear'); $rs = $db->Execute($stmt); rs2html($rs); @@ -338,8 +353,8 @@ GO $yr = 1998; $stmt = $db->PrepareSP('SalesByCategory'); - $db->Parameter($stmt,$cat,'CategoryName'); - $db->Parameter($stmt,$yr,'OrdYear'); + $db->InParameter($stmt,$cat,'CategoryName'); + $db->InParameter($stmt,$yr,'OrdYear'); $rs = $db->Execute($stmt); rs2html($rs); @@ -362,9 +377,9 @@ GO $days = 10; $begin_date = ''; $end_date = ''; - $db->Parameter($stmt,$days,'days', false, 4, SQLINT4); - $db->Parameter($stmt,$begin_date,'start', 1, 20, SQLVARCHAR ); - $db->Parameter($stmt,$end_date,'end', 1, 20, SQLVARCHAR ); + $db->InParameter($stmt,$days,'days', 4, SQLINT4); + $db->OutParameter($stmt,$begin_date,'start', 20, SQLVARCHAR ); + $db->OutParameter($stmt,$end_date,'end', 20, SQLVARCHAR ); $db->Execute($stmt); if (empty($begin_date) or empty($end_date)) { Err("MSSQL SP Test for OUT Failed"); @@ -388,6 +403,7 @@ GO CREATE OR REPLACE PACKAGE adodb AS TYPE TabType IS REF CURSOR RETURN tab%ROWTYPE; PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames in varchar); +PROCEDURE data_out(input IN varchar, output OUT varchar); END adodb; / @@ -396,12 +412,16 @@ PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames in varchar) IS BEGIN OPEN tabcursor FOR SELECT * FROM tab where tname like tablenames; END open_tab; + +PROCEDURE data_out(input IN varchar, output OUT varchar) IS + BEGIN + output := 'Cinta Hati '||input; + END; END adodb; - / -*/ +*/ $stmt = $db->Prepare("BEGIN adodb.open_tab(:RS,'A%'); END;"); - $db->Parameter($stmt, $cur, 'RS', false, -1, OCI_B_CURSOR); + $db->InParameter($stmt, $cur, 'RS', -1, OCI_B_CURSOR); $rs = $db->Execute($stmt); if ($rs && !$rs->EOF) { @@ -410,15 +430,22 @@ END adodb; print "Error in using Cursor Variables 1

    "; } - $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2,:TAB); END;",'RS2',array('TAB'=>'A%')); - if ($rs && !$rs->EOF) { - print "Test 2 RowCount: ".$rs->RecordCount()."

    "; + + print "

    Testing Stored Procedures for oci8

    "; + + $stmt = $db->PrepareSP("BEGIN adodb.data_out(:a1, :a2); END;"); + $a1 = 'Malaysia'; + //$a2 = ''; # a2 doesn't even need to be defined! + $db->InParameter($stmt,$a1,'a1'); + $db->OutParameter($stmt,$a2,'a2'); + $rs = $db->Execute($stmt); + if ($rs) { + if ($a2 !== 'Cinta Hati Malaysia') print "Stored Procedure Error: a2 = $a2

    "; + else echo "OK: a2=$a2

    "; } else { - print "Error in using Cursor Variables 2

    "; + print "Error in using Stored Procedure IN/Out Variables

    "; } - print "

    Testing Stored Procedures for oci8

    "; - $tname = 'A%'; @@ -530,6 +557,7 @@ END adodb; $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+9,'Steven','Oey',$time )"); } // for if (1) { + $db->debug=1; $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; $cnt = $db->GetOne("select count(*) from ADOXYZ"); $rs = $db->Execute('update ADOXYZ set id=id+1'); @@ -555,23 +583,24 @@ END adodb; print "

    Error on RecordCount. Should be 0. Was ".$rs->RecordCount()."

    "; print_r($rs->fields); } - $rs = &$db->Execute("select id,firstname,lastname,created from ADOXYZ order by id"); - if ($rs) { - if ($rs->RecordCount() != 50) { - print "

    RecordCount returns ".$rs->RecordCount()."

    "; - $poc = $rs->PO_RecordCount('ADOXYZ'); - if ($poc == 50) print "

        PO_RecordCount passed

    "; - else print "

    PO_RecordCount returns wrong value: $poc

    "; - } else print "

    RecordCount() passed

    "; - if (isset($rs->fields['firstname'])) print '

    The fields columns can be indexed by column name.

    '; - else { - Err( '

    The fields columns cannot be indexed by column name.

    '); - print_r($rs->fields); + if ($db->databaseType !== 'odbc') { + $rs = &$db->Execute("select id,firstname,lastname,created,".$db->random." from ADOXYZ order by id"); + if ($rs) { + if ($rs->RecordCount() != 50) { + print "

    RecordCount returns ".$rs->RecordCount()."

    "; + $poc = $rs->PO_RecordCount('ADOXYZ'); + if ($poc == 50) print "

        PO_RecordCount passed

    "; + else print "

    PO_RecordCount returns wrong value: $poc

    "; + } else print "

    RecordCount() passed

    "; + if (isset($rs->fields['firstname'])) print '

    The fields columns can be indexed by column name.

    '; + else { + Err( '

    The fields columns cannot be indexed by column name.

    '); + print_r($rs->fields); + } + if (empty($HTTP_GET_VARS['hide'])) rs2html($rs); } - if (empty($HTTP_GET_VARS['hide'])) rs2html($rs); + else print "Error in Execute of SELECT with random

    "; } - else print "Error in Execute of SELECT

    "; - $val = $db->GetOne("select count(*) from ADOXYZ"); if ($val == 50) print "

    GetOne returns ok

    "; else print "

    Fail: GetOne returns $val

    "; @@ -1076,6 +1105,7 @@ END adodb; err('**** RSFilter failed'); print_r($rs->fields); } + rs2html($rs); $db->debug=1; @@ -1138,7 +1168,10 @@ END adodb; 'firstname', # row fields 'lastname', # column fields false, # join - 'ID' # sum + 'ID', # sum + 'Sum ', # label for sum + 'sum', # aggregate function + true ); $rs = $db->Execute($sql); if ($rs) rs2html($rs); @@ -1205,13 +1238,16 @@ END adodb; if ($ds != date("d m Y")) Err("Bad UserDate: ".$ds); else echo "Passed UserDate: $ds

    "; } - - $rs = $db->SelectLimit("select ".$db->sysTimeStamp." from adoxyz",1); + $db->debug=1; + if ($db->dataProvider == 'oci8') + $rs = $db->SelectLimit("select to_char(".$db->sysTimeStamp.",'YYYY-MM-DD HH24:MI:SS') from adoxyz",1); + else + $rs = $db->SelectLimit("select ".$db->sysTimeStamp." from adoxyz",1); $date = $rs->fields[0]; if (!$date) Err("Bad sysTimeStamp"); else { $ds = $db->UserTimeStamp($date,"H \\h\\r\\s-d m Y"); - if ($ds != date("H \\h\\r\\s-d m Y")) Err("Bad UserTimeStamp: ".$ds); + if ($ds != date("H \\h\\r\\s-d m Y")) Err("Bad UserTimeStamp: ".$ds.", correct is ".date("H \\h\\r\\s-d m Y")); else echo "Passed UserTimeStamp: $ds

    "; $date = 100; @@ -1408,6 +1444,6 @@ include('./testdatabases.inc.php'); include_once('../adodb-time.inc.php'); adodb_date_test(); ?> -

    ADODB Database Library (c) 2000-2003 John Lim. All rights reserved. Released under BSD and LGPL.

    +

    ADODB Database Library (c) 2000-2004 John Lim. All rights reserved. Released under BSD and LGPL.

    diff --git a/lib/adodb/tests/test2.php b/lib/adodb/tests/test2.php index 266fdd8259..177aa8e94e 100644 --- a/lib/adodb/tests/test2.php +++ b/lib/adodb/tests/test2.php @@ -8,7 +8,7 @@ PConnect("susetikus","tester","test","test")) - die("Cannot connect to database"); -# select * from last table in DB -$rs = $c1->Execute("select * from adoxyz order by 1"); +error_reporting(E_ALL); + +$path = dirname(__FILE__); + +include("$path/../adodb-exceptions.inc.php"); +include("$path/../adodb.inc.php"); + +try { +$db = NewADOConnection("oci8"); +$db->Connect('','scott','natsoft'); +$db->debug=1; + +$cnt = $db->GetOne("select count(*) from adoxyz"); +$rs = $db->Execute("select * from adoxyz order by id"); $i = 0; -$max = $rs->RecordCount(); -if ($max == -1) "RecordCount returns -1
    "; -while (!$rs->EOF and $i < $max) { - $rs->Move($i); - print_r( $rs->fields); - print '
    '; - $i++; +foreach($rs as $k => $v) { + $i += 1; + echo $k; adodb_pr($v); + flush(); } -?> - \ No newline at end of file + +if ($i != $cnt) die("actual cnt is $i, cnt should be $cnt\n"); + + + +$rs = $db->Execute("select bad from badder"); + +} catch (exception $e) { + adodb_pr($e); + $e = adodb_backtrace($e->trace); +} + +?> \ No newline at end of file diff --git a/lib/adodb/tests/test4.php b/lib/adodb/tests/test4.php index 7648ddd8bd..9a261b13a1 100644 --- a/lib/adodb/tests/test4.php +++ b/lib/adodb/tests/test4.php @@ -1,7 +1,7 @@ qstr($record['lastname']); $rs = $conn->Execute($sql); // Execute the query and get the existing record to update if (!$rs) print "

    No record found!

    "; + $record = array(); // Initialize an array to hold the record data to update // Set the values for the fields in the record diff --git a/lib/adodb/tests/test5.php b/lib/adodb/tests/test5.php index 3c1ef063db..5308f2b138 100644 --- a/lib/adodb/tests/test5.php +++ b/lib/adodb/tests/test5.php @@ -1,6 +1,6 @@ InitArray($array,$typearr); + +while (!$rs->EOF) { + print_r($rs->fields);echo "
    "; + $rs->MoveNext(); +} + +echo "
    1 Seek
    "; +$rs->Move(1); +while (!$rs->EOF) { + print_r($rs->fields);echo "
    "; + $rs->MoveNext(); +} + +echo "
    2 Seek
    "; +$rs->Move(2); +while (!$rs->EOF) { + print_r($rs->fields);echo "
    "; + $rs->MoveNext(); +} + +echo "
    3 Seek
    "; +$rs->Move(3); +while (!$rs->EOF) { + print_r($rs->fields);echo "
    "; + $rs->MoveNext(); +} + + + +die(); +?> \ No newline at end of file diff --git a/lib/adodb/tests/testcache.php b/lib/adodb/tests/testcache.php index 7881e836fe..c926a2a32e 100644 --- a/lib/adodb/tests/testcache.php +++ b/lib/adodb/tests/testcache.php @@ -2,7 +2,7 @@ debug=1; print "

    Connecting $db->databaseType...

    "; - $db->PConnect('tigress','adodb','natsoft','northwind'); - - if (true or @$db->PConnect("mangrove", "sa", "natsoft", "ai")) { + $ok = $db->PConnect('tigress','adodb','natsoft','northwind'); + //$rs = $db->Execute("exec sp_ddate"); + //print_r($rs->fields); + //die(); + + if ($ok or @$db->PConnect("mangrove", "sa", "natsoft", "ai")) { AutoDetect_MSSQL_Date_Order($db); // $db->Execute('drop table adoxyz'); testdb($db,"create table ADOXYZ (id int, firstname char(24) null, lastname char(24) null,created datetime null)"); @@ -271,7 +273,7 @@ if (!empty($testmssql) && !empty($testado)) { // ADO ACCESS MSSQL with OLEDB pro //$db->debug=1; $myDSN="SERVER=tigress;DATABASE=northwind;Trusted_Connection=yes"; //$myDSN='SERVER=(local)\NetSDK;DATABASE=northwind;'; - if ($db->PConnect($myDSN, "sa", "natsoft", 'SQLOLEDB')) + if ($db->PConnect($myDSN, "adodb", "natsoft", 'SQLOLEDB')) testdb($db,"create table ADOXYZ (id int, firstname char(24), lastname char(24),created datetime)"); else print "ERROR: MSSQL test 2 requires a MS SQL 7 on a server='mangrove', userid='sa', password='', database='ai'"; diff --git a/lib/adodb/tests/testgenid.php b/lib/adodb/tests/testgenid.php index f1f946349f..05554dd29d 100644 --- a/lib/adodb/tests/testgenid.php +++ b/lib/adodb/tests/testgenid.php @@ -1,6 +1,6 @@ PConnect('','scott','tiger'); - $db->debug = true; + $db->PConnect('','scott','natsoft'); + $db->debug = 99; +/* +-- TEST PACKAGE +CREATE OR REPLACE PACKAGE adodb AS +TYPE TabType IS REF CURSOR RETURN tab%ROWTYPE; +PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames in varchar); +PROCEDURE data_out(input IN varchar, output OUT varchar); +END adodb; +/ - #--------------------------------------------------------------- - # EXAMPLE 1 - # explicitly use Parameter function - #--------------------------------------------------------------- - $stmt = $db->Prepare("BEGIN adodb.open_tab(:RS,'%'); END;"); - $db->Parameter($stmt, $cur, 'RS', false, -1, OCI_B_CURSOR); - $rs = $db->Execute($stmt); +CREATE OR REPLACE PACKAGE BODY adodb AS +PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames in varchar) IS + BEGIN + OPEN tabcursor FOR SELECT * FROM tab where tname like tablenames; + END open_tab; +PROCEDURE data_out(input IN varchar, output OUT varchar) IS + BEGIN + output := 'Cinta Hati '||input; + END; +END adodb; +/ +*/ + $stmt = $db->Prepare("BEGIN adodb.open_tab(:RS,'A%'); END;"); + $db->InParameter($stmt, $cur, 'RS', -1, OCI_B_CURSOR); + $rs = $db->Execute($stmt); + if ($rs && !$rs->EOF) { print "Test 1 RowCount: ".$rs->RecordCount()."

    "; } else { print "Error in using Cursor Variables 1

    "; } - #--------------------------------------------------------------- - # EXAMPLE 2 - # Equivalent of above example 1 using ExecuteCursor($sql,$rsname) - #--------------------------------------------------------------- - $rs = $db->ExecuteCursor( - "BEGIN adodb.open_tab(:RS,'%'); END;", # pl/sql script - 'RS'); # cursor name - - if ($rs && !$rs->EOF) { - print "Test 2 RowCount: ".$rs->RecordCount()."

    "; - rs2html($rs); + + print "

    Testing Stored Procedures for oci8

    "; + + $stmt = $db->PrepareSP("BEGIN adodb.data_out(:a1, :a2); END;",true); + $a1 = 'Malaysia'; + //$a2 = ''; # a2 doesn't even need to be defined! + $db->InParameter($stmt,$a1,'a1'); + $db->OutParameter($stmt,$a2,'a2'); + $rs = $db->Execute($stmt); + if ($rs) { + if ($a2 !== 'Cinta Hati Malaysia') print "Stored Procedure Error: a2 = $a2

    "; + else echo "OK: a2=$a2

    "; } else { - print "Error in using Cursor Variables 2

    "; + print "Error in using Stored Procedure IN/Out Variables

    "; } + + + $tname = 'A%'; + + $stmt = $db->PrepareSP('select * from tab where tname like :tablename'); + $db->Parameter($stmt,$tname,'tablename'); + $rs = $db->Execute($stmt); + rs2html($rs); + ?> \ No newline at end of file diff --git a/lib/adodb/tests/testpaging.php b/lib/adodb/tests/testpaging.php index b0bbcfd2fc..3cf29aaf7d 100644 --- a/lib/adodb/tests/testpaging.php +++ b/lib/adodb/tests/testpaging.php @@ -1,6 +1,6 @@ PHP ".PHP_VERSION.""; - + + +### SETUP SESSION VARIABLES $HTTP_SESSION_VARS['MONKEY'] = array('1','abc',44.41); if (!isset($HTTP_GET_VARS['nochange'])) @$HTTP_SESSION_VARS['AVAR'] += 1; + +### START DISPLAY + print "

    PHP ".PHP_VERSION."

    "; print "

    \$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}

    "; + print "
    Cookies: "; + print_r($HTTP_COOKIE_VARS); + +### RANDOMLY PERFORM Garbage Collection if (rand() % 10 == 0) { - print "

    GC

    "; + print "

    Garbage Collection

    "; adodb_sess_gc(10); print "

    Random session destroy

    "; session_destroy(); } - print "
    "; - print_r($HTTP_COOKIE_VARS); ?> \ No newline at end of file diff --git a/lib/adodb/tests/tmssql.php b/lib/adodb/tests/tmssql.php index a3b743ca1f..e20db41ed2 100644 --- a/lib/adodb/tests/tmssql.php +++ b/lib/adodb/tests/tmssql.php @@ -1,65 +1,65 @@ -mssql"; - $db = mssql_connect('JAGUAR\vsdotnet','adodb','natsoft') or die('No Connection'); - mssql_select_db('northwind',$db); - - $rs = mssql_query('select getdate() as date',$db); - $o = mssql_fetch_row($rs); - print_r($o); - mssql_free_result($rs); - - print "

    Delete

    "; flush(); - $rs2 = mssql_query('delete from adoxyz',$db); - $p = mssql_num_rows($rs2); - mssql_free_result($rs2); - -} - -function tpear() -{ -include_once('DB.php'); - - print "

    PEAR

    "; - $username = 'adodb'; - $password = 'natsoft'; - $hostname = 'JAGUAR\vsdotnet'; - $databasename = 'northwind'; - - $dsn = "mssql://$username:$password@$hostname/$databasename"; - $conn = &DB::connect($dsn); - print "date=".$conn->GetOne('select getdate()')."
    "; - @$conn->query('create table tester (id integer)'); - print "

    Delete

    "; flush(); - $rs = $conn->query('delete from tester'); - print "date=".$conn->GetOne('select getdate()')."
    "; -} - -function tadodb() -{ -include_once('../adodb.inc.php'); - - print "

    ADOdb

    "; - $conn = NewADOConnection('mssql'); - $conn->Connect('JAGUAR\vsdotnet','adodb','natsoft','northwind'); -// $conn->debug=1; - print "date=".$conn->GetOne('select getdate()')."
    "; - $conn->Execute('create table tester (id integer)'); - print "

    Delete

    "; flush(); - $rs = $conn->Execute('delete from tester'); - print "date=".$conn->GetOne('select getdate()')."
    "; -} -?> -mssql -pear -adodb -mssql"; + $db = mssql_connect('JAGUAR\vsdotnet','adodb','natsoft') or die('No Connection'); + mssql_select_db('northwind',$db); + + $rs = mssql_query('select getdate() as date',$db); + $o = mssql_fetch_row($rs); + print_r($o); + mssql_free_result($rs); + + print "

    Delete

    "; flush(); + $rs2 = mssql_query('delete from adoxyz',$db); + $p = mssql_num_rows($rs2); + mssql_free_result($rs2); + +} + +function tpear() +{ +include_once('DB.php'); + + print "

    PEAR

    "; + $username = 'adodb'; + $password = 'natsoft'; + $hostname = 'JAGUAR\vsdotnet'; + $databasename = 'northwind'; + + $dsn = "mssql://$username:$password@$hostname/$databasename"; + $conn = &DB::connect($dsn); + print "date=".$conn->GetOne('select getdate()')."
    "; + @$conn->query('create table tester (id integer)'); + print "

    Delete

    "; flush(); + $rs = $conn->query('delete from tester'); + print "date=".$conn->GetOne('select getdate()')."
    "; +} + +function tadodb() +{ +include_once('../adodb.inc.php'); + + print "

    ADOdb

    "; + $conn = NewADOConnection('mssql'); + $conn->Connect('JAGUAR\vsdotnet','adodb','natsoft','northwind'); +// $conn->debug=1; + print "date=".$conn->GetOne('select getdate()')."
    "; + $conn->Execute('create table tester (id integer)'); + print "

    Delete

    "; flush(); + $rs = $conn->Execute('delete from tester'); + print "date=".$conn->GetOne('select getdate()')."
    "; +} +?> +mssql +pear +adodb + \ No newline at end of file diff --git a/lib/adodb/tips_portable_sql.htm b/lib/adodb/tips_portable_sql.htm index e0dd414914..fc438fb0ff 100644 --- a/lib/adodb/tips_portable_sql.htm +++ b/lib/adodb/tips_portable_sql.htm @@ -8,7 +8,9 @@

    Tips on Writing Portable SQL  

    - +

    Updated 18 Sep 2003. Added Portable Native SQL section. +

    + If you are writing an application that is used in multiple environments and operating systems, you need to plan to support multiple databases. This article is based on my experiences with multiple database systems, stretching from 4th @@ -166,17 +168,18 @@ the correct placeholder (available since ADOdb 3.92): $stmt = $DB->Prepare($sql); $stmt = $DB->Execute($stmt,array('one','two'));

    +

    Portable Native SQL

    ADOdb provides the following functions for portably generating SQL functions as strings to be merged into your SQL statements (some are only available since ADOdb 3.92):

    - +
    - + - + @@ -207,6 +210,26 @@ $stmt = $DB->Execute($stmt,array('one','two')); + + + + + + + + + + + + +
    FunctionFunction Description
    DBDate($date)DBDate($date) Pass in a UNIX timestamp or ISO date and it will convert it to a date string formatted for INSERT/UPDATE
    Param($name) Generates bind placeholders, using ? or named conventions as appropriate.
    $db->sysDateProperty that holds the SQL function that returns today's date
    $db->sysTimeStampProperty that holds the SQL function that returns the current +timestamp (date+time). +
    $db->concat_operatorProperty that holds the concatenation operator +
    $db->lengthProperty that holds the name of the SQL strlen function. +
    $db->upperCaseProperty that holds the name of the SQL strtoupper function. +
    $db->randomProperty that holds the SQL to generate a random number between 0.00 and 1.00. +
    $db->substrProperty that holds the name of the SQL substring function. +

     

    DDL and Tuning

    @@ -269,6 +292,9 @@ $conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1'); ambiguities when you use the ANY and EXISTS operators. However if your database has significant amounts of missing or unknown data, using nulls might be a good idea. +

    + ADOdb also supports a portable IfNull function, so you can define what to display + if the field contains a null.

    Stored Procedures

    Stored procedures are another problem area. Some databases allow recordsets to be returned in a stored procedure (Microsoft SQL Server and Sybase), and diff --git a/lib/adodb/toexport.inc.php b/lib/adodb/toexport.inc.php index 05fd2036f7..c5a63fc54e 100644 --- a/lib/adodb/toexport.inc.php +++ b/lib/adodb/toexport.inc.php @@ -1,7 +1,7 @@ FieldTypesArray(); - foreach($fieldTypes as $o) { + reset($fieldTypes); + while(list(,$o) = each($fieldTypes)) { $v = $o->name; if ($escquote) $v = str_replace($quote,$escquotequote,$v); diff --git a/lib/adodb/tohtml.inc.php b/lib/adodb/tohtml.inc.php index cf08639b5f..d42c7d8993 100644 --- a/lib/adodb/tohtml.inc.php +++ b/lib/adodb/tohtml.inc.php @@ -1,6 +1,6 @@ FieldCount(); - $hdr = "\n\n"; + $hdr = "
    \n\n"; for ($i=0; $i < $ncols; $i++) { $field = $rs->FetchField($i); if ($zheaderarray) $fname = $zheaderarray[$i]; @@ -60,7 +60,7 @@ GLOBAL $gSQLMaxRows,$gSQLBlockRows; if (strlen($fname)==0) $fname = ' '; $hdr .= ""; } - + $hdr .= "\n"; if ($echo) print $hdr."\n\n"; else $html = $hdr; diff --git a/lib/adodb/tute.htm b/lib/adodb/tute.htm index 3f2261e62d..b060a98513 100644 --- a/lib/adodb/tute.htm +++ b/lib/adodb/tute.htm @@ -1,290 +1,290 @@ - - - - - Tutorial: Moving from MySQL to ADODB - - - -

    Tutorial: Moving from MySQL to ADODB

    - -
    		You say eether and I say eyether, 
    -		You say neether and I say nyther; 
    -		Eether, eyether, neether, nyther - 
    -		Let's call the whole thing off ! 
    -
    - You like potato and I like po-tah-to, - You like tomato and I like to-mah-to; - Potato, po-tah-to, tomato, to-mah-to - - Let's call the whole thing off ! -
    -

    I love this song, especially the version with Louis Armstrong and Ella singing - duet. It is all about how hard it is for two people in love to be compatible - with each other. It's about compromise and finding a common ground, and that's - what this article is all about. -

    PHP is all about creating dynamic web-sites with the least fuss and the most - fun. To create these websites we need to use databases to retrieve login information, - to splash dynamic news onto the web page and store forum postings. So let's - say we were using the popular MySQL database for this. Your company has done - such a fantastic job that the Web site is more popular than your wildest dreams. - You find that MySQL cannot scale to handle the workload; time to switch databases. -

    Unfortunately in PHP every database is accessed slightly differently. To connect - to MySQL, you would use mysql_connect(); when you decide to upgrade to - Oracle or Microsoft SQL Server, you would use ocilogon() or mssql_connect() - respectively. What is worse is that the parameters you use for the different - connect functions are different also.. One database says po-tato, the other - database says pota-to. Oh-oh. -

    Let's NOT call the whole thing off

    -

    A database wrapper library such as ADODB comes in handy when you need to ensure portability. It provides - you with a common API to communicate with any supported database so you don't have to call things off.

    - -

    ADODB stands for Active Data Objects DataBase (sorry computer guys are sometimes - not very original). ADODB currently supports MySQL, PostgreSQL, Oracle, Interbase, - Microsoft SQL Server, Access, FoxPro, Sybase, ODBC and ADO. You can download - ADODB from http://php.weblogs.com/adodb. -

    MySQL Example

    -

    The most common database used with PHP is MySQL, so I guess you should be familiar - with the following code. It connects to a MySQL server at localhost, - database mydb, and executes an SQL select statement. The results are - printed, one line per row. -

    $db = mysql_connect("localhost", "root", "password");
    -mysql_select_db("mydb",$db);
    -$result = mysql_query("SELECT * FROM employees",$db);
    -if ($result === false) die("failed"); 
    -while ($fields = mysql_fetch_row($result)) {
    - for ($i=0, $max=sizeof($fields); $i < $max; $i++) {
    -		print $fields[$i].' ';
    - }
    - print "<br>\n";
    -} 
    -
    -

    The above code has been color-coded by section. The first section is the connection - phase. The second is the execution of the SQL, and the last section is displaying - the fields. The while loop scans the rows of the result, while the for - loop scans the fields in one row.

    -

    Here is the equivalent code in ADODB

    -
     include("adodb.inc.php");
    - $db = NewADOConnection('mysql');
    - $db->Connect("localhost", "root", "password", "mydb");
    - $result = $db->Execute("SELECT * FROM employees");
    - if ($result === false) die("failed");  
    - while (!$result->EOF) {
    -	for ($i=0, $max=$result->FieldCount(); $i < $max; $i++)
    -		   print $result->fields[$i].' ';
    -	$result->MoveNext();
    -	print "<br>\n";
    - } 
    -

    -

    Now porting to Oracle is as simple as changing the second line to NewADOConnection('oracle'). - Let's walk through the code...

    -

    Connecting to the Database

    -

    -
    include("adodb.inc.php");
    -$db = NewADOConnection('mysql');
    -$db->Connect("localhost", "root", "password", "mydb");
    -

    The connection code is a bit more sophisticated than MySQL's because our needs - are more sophisticated. In ADODB, we use an object-oriented approach to managing - the complexity of handling multiple databases. We have different classes to - handle different databases. If you aren't familiar with object-oriented programing, - don't worry -- the complexity is all hidden away in the NewADOConnection() - function.

    -

    To conserve memory, we only load the PHP code specific to the database you - are connecting to. We do this by calling NewADOConnection(databasedriver). - Legal database drivers include mysql, mssql, oracle, oci8, postgres, sybase, - vfp, access, ibase and many others.

    -

    Then we create a new instance of the connection class by calling NewADOConnection(). - Finally we connect to the database using $db->Connect().

    -

    Executing the SQL

    -

    $result = $db->Execute("SELECT * - FROM employees");
    - if ($result === false) die("failed")
    ; -
    -

    -

    Sending the SQL statement to the server is straight forward. Execute() will - return a recordset object on successful execution. You should check $result - as we do above. -

    An issue that confuses beginners is the fact that we have two types of objects - in ADODB, the connection object and the recordset object. When do we use each? -

    The connection object ($db) is responsible for connecting to the database, - formatting your SQL and querying the database server. The recordset object ($result) - is responsible for retrieving the results and formatting the reply as text or - as an array. -

    The only thing I need to add is that ADODB provides several helper functions - for making INSERT and UPDATE statements easier, which we will cover in the Advanced - section. -

    Retrieving the Data
    -

    -
    while (!$result->EOF) {
    -   for ($i=0, $max=$result->FieldCount(); $i < $max; $i++)
    -	   print $result->fields[$i].' ';
    -   $result->MoveNext();
    -   print "<br>\n";
    -}
    -

    The paradigm for getting the data is that it's like reading a file. For every - line, we check first whether we have reached the end-of-file (EOF). While not - end-of-file, loop through each field in the row. Then move to the next line - (MoveNext) and repeat. -

    The $result->fields[] array is generated by the PHP database - extension. Some database extensions do not index the array by field name. - To force indexing by name - that is associative arrays - - use the $ADODB_FETCH_MODE global variable. -

    -	$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().

    -

    ADOConnection

    -

    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.

    - -

    Other Useful Functions

    -

    $recordset->Move($pos) scrolls to that particular row. ADODB supports forward - scrolling for all databases. Some databases will not support backwards scrolling. - This is normally not a problem as you can always cache records to simulate backwards - scrolling. -

    $recordset->RecordCount() returns the number of records accessed by the - SQL statement. Some databases will return -1 because it is not supported. -

    $recordset->GetArray() returns the result as an array. -

    rs2html($recordset) is a function that is generates a HTML table based on the - $recordset passed to it. An example with the relevant lines in bold: -

       include('adodb.inc.php'); 
    -   include('tohtml.inc.php'); /* includes the rs2html function */
    -   $conn = &ADONewConnection('mysql'); 
    -   $conn->PConnect('localhost','userid','password','database');
    -   $rs = $conn->Execute('select * from table');
    -   rs2html($rs); /* recordset to html table */ 
    -

    There are many other helper functions that are listed in the documentation available at http://php.weblogs.com/adodb_manual. -

    Advanced Material

    -

    Inserts and Updates

    -

    Let's say you want to insert the following data into a database. -

    ID = 3
    - TheDate=mktime(0,0,0,8,31,2001) /* 31st August 2001 */
    - Note= sugar why don't we call it off -

    When you move to another database, your insert might no longer work.

    -

    The first problem is that each database has a different default date format. - MySQL expects YYYY-MM-DD format, while other databases have different defaults. - ADODB has a function called DBDate() that addresses this issue by converting - converting the date to the correct format.

    -

    The next problem is that the don't in the Note needs to be quoted. In - MySQL, we use don\'t but in some other databases (Sybase, Access, Microsoft - SQL Server) we use don''t. The qstr() function addresses this issue.

    -

    So how do we use the functions? Like this:

    -
    $sql = "INSERT INTO table (id, thedate,note) values (" 
    -   . $ID . ','
    -   . $db->DBDate($TheDate) .','
    -   . $db->qstr($Note).")";
    -$db->Execute($sql);
    -

    ADODB also supports $connection->Affected_Rows() (returns the - number of rows affected by last update or delete) and $recordset->Insert_ID() - (returns last autoincrement number generated by an insert statement). Be forewarned - that not all databases support the two functions.
    -

    -

    MetaTypes

    -

    You can find out more information about each of the fields (I use the words - fields and columns interchangebly) you are selecting by calling the recordset - method FetchField($fieldoffset). This will return an object with - 3 properties: name, type and max_length. -

    For example:
    -
    $recordset = $conn->Execute("select adate from table");
    $f0 = $recordset->FetchField(0); -
    -

    Then $f0->name will hold 'adata', $f0->type - will be set to 'date'. If the max_length is unknown, it will be set to - -1. -

    One problem with handling different databases is that each database often calls - the same type by a different name. For example a timestamp type is called - datetime in one database and time in another. So ADODB has a special - MetaType($type, $max_length) function that standardises the types - to the following: -

    C: character and varchar types
    - X: text or long character (eg. more than 255 bytes wide).
    - B: blob or binary image
    - D: date
    - T: timestamp
    - L: logical (boolean)
    - I: integer
    - N: numeric (float, double, money) -

    In the above date example, -

    $recordset = $conn->Execute("select adate from table");
    - $f0 = $recordset->FetchField(0);
    - $type = $recordset->MetaType($f0->type, $f0->max_length);
    - print $type; /* should print 'D'
    */ -

    -

    Select Limit and Top Support -

    ADODB has a function called $connection->SelectLimit($sql,$nrows,$offset) that allows -you to retrieve a subset of the recordset. This will take advantage of native -SELECT TOP on Microsoft products and SELECT ... LIMIT with PostgreSQL and MySQL, and -emulated if the database does not support it. -

    Caching Support -

    ADODB allows you to cache recordsets in your file system, and only requery the database -server after a certain timeout period with $connection->CacheExecute($secs2cache,$sql) and -$connection->CacheSelectLimit($secs2cache,$sql,$nrows,$offset). -

    PHP4 Session Handler Support -

    ADODB also supports PHP4 session handlers. You can store your session variables - in a database for true scalability using ADODB. For further information, visit - http://php.weblogs.com/adodb-sessions -

    Commercial Use Encouraged

    -

    If you plan to write commercial PHP applications that you want to resell, you should consider ADODB. It has been released using the lesser GPL, which means you can legally include it in commercial applications, while keeping your code proprietary. Commercial use of ADODB is strongly encouraged! We are using it internally for this reason.

    - -

    Conclusion

    -

    As a thank you for finishing this article, here are the complete lyrics for - let's call the whole thing off.
    -
    -

    -   Refrain 
    -
    - You say eether and I say eyether, - You say neether and I say nyther; - Eether, eyether, neether, nyther - - Let's call the whole thing off ! -
    - You like potato and I like po-tah-to, - You like tomato and I like to-mah-to; - Potato, po-tah-to, tomato, to-mah-to - - Let's call the whole thing off ! -
    -But oh, if we call the whole thing off, then we must part. -And oh, if we ever part, then that might break my heart. -
    - So, if you like pajamas and I like pa-jah-mas, - I'll wear pajamas and give up pa-jah-mas. - For we know we - Need each other, so we - Better call the calling off off. - Let's call the whole thing off ! -
    - Second Refrain -
    - You say laughter and I say lawfter, - You say after and I say awfter; - Laughter, lawfter, after, awfter - - Let's call the whole thing off ! -
    - You like vanilla and I like vanella, - You, sa's'parilla and I sa's'parella; - Vanilla, vanella, choc'late, strawb'ry - - Let's call the whole thing off ! -
    -But oh, if we call the whole thing off, then we must part. -And oh, if we ever part, then that might break my heart. -
    - So, if you go for oysters and I go for ersters, - I'll order oysters and cancel the ersters. - For we know we - Need each other, so we - Better call the calling off off. - Let's call the whole thing off ! -
    -

    Song and lyrics by George and Ira Gershwin, introduced by Fred Astaire and Ginger Rogers -in the film "Shall We Dance?"

    -

    -(c)2001-2002 John Lim. - - - + + + + + Tutorial: Moving from MySQL to ADODB + + + +

    Tutorial: Moving from MySQL to ADODB

    + +
    		You say eether and I say eyether, 
    +		You say neether and I say nyther; 
    +		Eether, eyether, neether, nyther - 
    +		Let's call the whole thing off ! 
    +
    + You like potato and I like po-tah-to, + You like tomato and I like to-mah-to; + Potato, po-tah-to, tomato, to-mah-to - + Let's call the whole thing off ! +
    +

    I love this song, especially the version with Louis Armstrong and Ella singing + duet. It is all about how hard it is for two people in love to be compatible + with each other. It's about compromise and finding a common ground, and that's + what this article is all about. +

    PHP is all about creating dynamic web-sites with the least fuss and the most + fun. To create these websites we need to use databases to retrieve login information, + to splash dynamic news onto the web page and store forum postings. So let's + say we were using the popular MySQL database for this. Your company has done + such a fantastic job that the Web site is more popular than your wildest dreams. + You find that MySQL cannot scale to handle the workload; time to switch databases. +

    Unfortunately in PHP every database is accessed slightly differently. To connect + to MySQL, you would use mysql_connect(); when you decide to upgrade to + Oracle or Microsoft SQL Server, you would use ocilogon() or mssql_connect() + respectively. What is worse is that the parameters you use for the different + connect functions are different also.. One database says po-tato, the other + database says pota-to. Oh-oh. +

    Let's NOT call the whole thing off

    +

    A database wrapper library such as ADODB comes in handy when you need to ensure portability. It provides + you with a common API to communicate with any supported database so you don't have to call things off.

    + +

    ADODB stands for Active Data Objects DataBase (sorry computer guys are sometimes + not very original). ADODB currently supports MySQL, PostgreSQL, Oracle, Interbase, + Microsoft SQL Server, Access, FoxPro, Sybase, ODBC and ADO. You can download + ADODB from http://php.weblogs.com/adodb. +

    MySQL Example

    +

    The most common database used with PHP is MySQL, so I guess you should be familiar + with the following code. It connects to a MySQL server at localhost, + database mydb, and executes an SQL select statement. The results are + printed, one line per row. +

    $db = mysql_connect("localhost", "root", "password");
    +mysql_select_db("mydb",$db);
    +$result = mysql_query("SELECT * FROM employees",$db);
    +if ($result === false) die("failed"); 
    +while ($fields = mysql_fetch_row($result)) {
    + for ($i=0, $max=sizeof($fields); $i < $max; $i++) {
    +		print $fields[$i].' ';
    + }
    + print "<br>\n";
    +} 
    +
    +

    The above code has been color-coded by section. The first section is the connection + phase. The second is the execution of the SQL, and the last section is displaying + the fields. The while loop scans the rows of the result, while the for + loop scans the fields in one row.

    +

    Here is the equivalent code in ADODB

    +
     include("adodb.inc.php");
    + $db = NewADOConnection('mysql');
    + $db->Connect("localhost", "root", "password", "mydb");
    + $result = $db->Execute("SELECT * FROM employees");
    + if ($result === false) die("failed");  
    + while (!$result->EOF) {
    +	for ($i=0, $max=$result->FieldCount(); $i < $max; $i++)
    +		   print $result->fields[$i].' ';
    +	$result->MoveNext();
    +	print "<br>\n";
    + } 
    +

    +

    Now porting to Oracle is as simple as changing the second line to NewADOConnection('oracle'). + Let's walk through the code...

    +

    Connecting to the Database

    +

    +
    include("adodb.inc.php");
    +$db = NewADOConnection('mysql');
    +$db->Connect("localhost", "root", "password", "mydb");
    +

    The connection code is a bit more sophisticated than MySQL's because our needs + are more sophisticated. In ADODB, we use an object-oriented approach to managing + the complexity of handling multiple databases. We have different classes to + handle different databases. If you aren't familiar with object-oriented programing, + don't worry -- the complexity is all hidden away in the NewADOConnection() + function.

    +

    To conserve memory, we only load the PHP code specific to the database you + are connecting to. We do this by calling NewADOConnection(databasedriver). + Legal database drivers include mysql, mssql, oracle, oci8, postgres, sybase, + vfp, access, ibase and many others.

    +

    Then we create a new instance of the connection class by calling NewADOConnection(). + Finally we connect to the database using $db->Connect().

    +

    Executing the SQL

    +

    $result = $db->Execute("SELECT * + FROM employees");
    + if ($result === false) die("failed")
    ; +
    +

    +

    Sending the SQL statement to the server is straight forward. Execute() will + return a recordset object on successful execution. You should check $result + as we do above. +

    An issue that confuses beginners is the fact that we have two types of objects + in ADODB, the connection object and the recordset object. When do we use each? +

    The connection object ($db) is responsible for connecting to the database, + formatting your SQL and querying the database server. The recordset object ($result) + is responsible for retrieving the results and formatting the reply as text or + as an array. +

    The only thing I need to add is that ADODB provides several helper functions + for making INSERT and UPDATE statements easier, which we will cover in the Advanced + section. +

    Retrieving the Data
    +

    +
    while (!$result->EOF) {
    +   for ($i=0, $max=$result->FieldCount(); $i < $max; $i++)
    +	   print $result->fields[$i].' ';
    +   $result->MoveNext();
    +   print "<br>\n";
    +}
    +

    The paradigm for getting the data is that it's like reading a file. For every + line, we check first whether we have reached the end-of-file (EOF). While not + end-of-file, loop through each field in the row. Then move to the next line + (MoveNext) and repeat. +

    The $result->fields[] array is generated by the PHP database + extension. Some database extensions do not index the array by field name. + To force indexing by name - that is associative arrays - + use the $ADODB_FETCH_MODE global variable. +

    +	$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().

    +

    ADOConnection

    +

    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.

    + +

    Other Useful Functions

    +

    $recordset->Move($pos) scrolls to that particular row. ADODB supports forward + scrolling for all databases. Some databases will not support backwards scrolling. + This is normally not a problem as you can always cache records to simulate backwards + scrolling. +

    $recordset->RecordCount() returns the number of records accessed by the + SQL statement. Some databases will return -1 because it is not supported. +

    $recordset->GetArray() returns the result as an array. +

    rs2html($recordset) is a function that is generates a HTML table based on the + $recordset passed to it. An example with the relevant lines in bold: +

       include('adodb.inc.php'); 
    +   include('tohtml.inc.php'); /* includes the rs2html function */
    +   $conn = &ADONewConnection('mysql'); 
    +   $conn->PConnect('localhost','userid','password','database');
    +   $rs = $conn->Execute('select * from table');
    +   rs2html($rs); /* recordset to html table */ 
    +

    There are many other helper functions that are listed in the documentation available at http://php.weblogs.com/adodb_manual. +

    Advanced Material

    +

    Inserts and Updates

    +

    Let's say you want to insert the following data into a database. +

    ID = 3
    + TheDate=mktime(0,0,0,8,31,2001) /* 31st August 2001 */
    + Note= sugar why don't we call it off +

    When you move to another database, your insert might no longer work.

    +

    The first problem is that each database has a different default date format. + MySQL expects YYYY-MM-DD format, while other databases have different defaults. + ADODB has a function called DBDate() that addresses this issue by converting + converting the date to the correct format.

    +

    The next problem is that the don't in the Note needs to be quoted. In + MySQL, we use don\'t but in some other databases (Sybase, Access, Microsoft + SQL Server) we use don''t. The qstr() function addresses this issue.

    +

    So how do we use the functions? Like this:

    +
    $sql = "INSERT INTO table (id, thedate,note) values (" 
    +   . $ID . ','
    +   . $db->DBDate($TheDate) .','
    +   . $db->qstr($Note).")";
    +$db->Execute($sql);
    +

    ADODB also supports $connection->Affected_Rows() (returns the + number of rows affected by last update or delete) and $recordset->Insert_ID() + (returns last autoincrement number generated by an insert statement). Be forewarned + that not all databases support the two functions.
    +

    +

    MetaTypes

    +

    You can find out more information about each of the fields (I use the words + fields and columns interchangebly) you are selecting by calling the recordset + method FetchField($fieldoffset). This will return an object with + 3 properties: name, type and max_length. +

    For example:
    +
    $recordset = $conn->Execute("select adate from table");
    $f0 = $recordset->FetchField(0); +
    +

    Then $f0->name will hold 'adata', $f0->type + will be set to 'date'. If the max_length is unknown, it will be set to + -1. +

    One problem with handling different databases is that each database often calls + the same type by a different name. For example a timestamp type is called + datetime in one database and time in another. So ADODB has a special + MetaType($type, $max_length) function that standardises the types + to the following: +

    C: character and varchar types
    + X: text or long character (eg. more than 255 bytes wide).
    + B: blob or binary image
    + D: date
    + T: timestamp
    + L: logical (boolean)
    + I: integer
    + N: numeric (float, double, money) +

    In the above date example, +

    $recordset = $conn->Execute("select adate from table");
    + $f0 = $recordset->FetchField(0);
    + $type = $recordset->MetaType($f0->type, $f0->max_length);
    + print $type; /* should print 'D'
    */ +

    +

    Select Limit and Top Support +

    ADODB has a function called $connection->SelectLimit($sql,$nrows,$offset) that allows +you to retrieve a subset of the recordset. This will take advantage of native +SELECT TOP on Microsoft products and SELECT ... LIMIT with PostgreSQL and MySQL, and +emulated if the database does not support it. +

    Caching Support +

    ADODB allows you to cache recordsets in your file system, and only requery the database +server after a certain timeout period with $connection->CacheExecute($secs2cache,$sql) and +$connection->CacheSelectLimit($secs2cache,$sql,$nrows,$offset). +

    PHP4 Session Handler Support +

    ADODB also supports PHP4 session handlers. You can store your session variables + in a database for true scalability using ADODB. For further information, visit + http://php.weblogs.com/adodb-sessions +

    Commercial Use Encouraged

    +

    If you plan to write commercial PHP applications that you want to resell, you should consider ADODB. It has been released using the lesser GPL, which means you can legally include it in commercial applications, while keeping your code proprietary. Commercial use of ADODB is strongly encouraged! We are using it internally for this reason.

    + +

    Conclusion

    +

    As a thank you for finishing this article, here are the complete lyrics for + let's call the whole thing off.
    +
    +

    +   Refrain 
    +
    + You say eether and I say eyether, + You say neether and I say nyther; + Eether, eyether, neether, nyther - + Let's call the whole thing off ! +
    + You like potato and I like po-tah-to, + You like tomato and I like to-mah-to; + Potato, po-tah-to, tomato, to-mah-to - + Let's call the whole thing off ! +
    +But oh, if we call the whole thing off, then we must part. +And oh, if we ever part, then that might break my heart. +
    + So, if you like pajamas and I like pa-jah-mas, + I'll wear pajamas and give up pa-jah-mas. + For we know we + Need each other, so we + Better call the calling off off. + Let's call the whole thing off ! +
    + Second Refrain +
    + You say laughter and I say lawfter, + You say after and I say awfter; + Laughter, lawfter, after, awfter - + Let's call the whole thing off ! +
    + You like vanilla and I like vanella, + You, sa's'parilla and I sa's'parella; + Vanilla, vanella, choc'late, strawb'ry - + Let's call the whole thing off ! +
    +But oh, if we call the whole thing off, then we must part. +And oh, if we ever part, then that might break my heart. +
    + So, if you go for oysters and I go for ersters, + I'll order oysters and cancel the ersters. + For we know we + Need each other, so we + Better call the calling off off. + Let's call the whole thing off ! +
    +

    Song and lyrics by George and Ira Gershwin, introduced by Fred Astaire and Ginger Rogers +in the film "Shall We Dance?"

    +

    +(c)2001-2002 John Lim. + + +

    $fname