New Upstream Release - libphp-adodb
Ready changes
Summary
Merged new upstream version: 5.22.6 (was: 5.22.4).
Resulting package
Built on 2023-07-10T00:56 (took 7m47s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases libphp-adodb
Lintian Result
Diff
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..5dad2ea
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,22 @@
+# EditorConfig file for ADOdb
+# https://editorconfig.org/
+
+root = true
+
+# Default file settings
+[*]
+indent_style = tab
+indent_size = 4
+end_of_line = lf
+trim_trailing_whitespace = true
+insert_final_newline = true
+charset = utf-8
+
+# Python build scripts
+[*.py]
+indent_style = space
+
+# Markdown files
+[*.md]
+indent_style = space
+trim_trailing_whitespace = false
diff --git a/README.md b/README.md
index e432b2f..96ac67b 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,9 @@
ADOdb Library for PHP
======================
-[![Join chat on Gitter](https://img.shields.io/gitter/room/form-data/form-data.svg)](https://gitter.im/adodb/adodb?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-[![Download ADOdb](https://img.shields.io/sourceforge/dm/adodb.svg)](https://sourceforge.net/projects/adodb/files/latest/download)
+[![Join chat on Gitter](https://img.shields.io/gitter/room/adodb/adodb?logo=gitter)](https://gitter.im/adodb/adodb?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![SourceForge Downloads Shield](https://img.shields.io/sourceforge/dm/adodb?label=SourceForge&logo=sourceforge&color=informational)](https://sourceforge.net/projects/adodb/files/latest/download)
+[![Packagist Downloads Shield](https://img.shields.io/packagist/dm/ADOdb/ADOdb-php?label=Packagist&logo=packagist&logoColor=white&color=informational)](https://packagist.org/packages/adodb/adodb-php)
(c) 2000-2013 John Lim (jlim@natsoft.com)
(c) 2014 Damien Regad, Mark Newnham and the
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..00670f2
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,45 @@
+# ADOdb Security Policy
+
+## Supported Versions
+
+The following releases of the library are currently being supported with
+security updates. Please refer to the [project's home page](https://adodb.org)
+for actual version numbers.
+
+- Stable
+- Legacy
+- Development (Git *master* branch)
+
+Older releases are no longer supported.
+
+
+## Reporting a Vulnerability
+
+If you discover a vulnerability in ADOdb, please contact
+the [project's maintainer](https://github.com/dregad)
+
+- by e-mail (look for it in the Git history)
+- via private chat on [Gitter](https://gitter.im/dregad)
+
+Kindly provide the following information in your report:
+
+- Affected ADOdb version(s) or Git revision
+- A clear and detailed description of the issue, including if possible a code
+ snippet to demonstrate or reproduce the vulnerability
+- A patch for the issue if you have one, preferably in *Git diff* format
+
+### CVE handling
+
+To ensure a comprehensive and detailed declaration of the issue, we generally
+prefer requesting CVE IDs ourselves, which usually happens after our analysis
+confirms the vulnerability.
+
+In case you have already obtained a CVE ID, do not forget to reference it in
+your report.
+
+### Credits
+
+Let us know if and how you wish to be credited for the finding.
+
+Your name, e-mail, company, etc. will be included as specified in the CVE
+report, as well as in the Git commit message patching the issue.
diff --git a/adodb-active-record.inc.php b/adodb-active-record.inc.php
index 8f3b005..5fbe7b9 100644
--- a/adodb-active-record.inc.php
+++ b/adodb-active-record.inc.php
@@ -281,7 +281,7 @@ class ADODB_Active_Record {
static function TableBelongsTo($table, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
{
- $ar = new ADOdb_Active_Record($table);
+ $ar = new ADODB_Active_Record($table);
$ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
}
@@ -290,7 +290,7 @@ class ADODB_Active_Record {
if (!is_array($tablePKey)) {
$tablePKey = array($tablePKey);
}
- $ar = new ADOdb_Active_Record($table, $tablePKey);
+ $ar = new ADODB_Active_Record($table, $tablePKey);
$ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
}
@@ -501,7 +501,8 @@ class ADODB_Active_Record {
}
break;
default:
- foreach($cols as $name => $fldobj) {
+ foreach($cols as $fldobj) {
+ $name = $fldobj->name;
if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
$this->$name = $fldobj->default_value;
diff --git a/adodb-csvlib.inc.php b/adodb-csvlib.inc.php
index c81254b..87efd94 100644
--- a/adodb-csvlib.inc.php
+++ b/adodb-csvlib.inc.php
@@ -29,11 +29,13 @@ global $ADODB_INCLUDED_CSV;
$ADODB_INCLUDED_CSV = 1;
/**
- * convert a recordset into special format
+ * Convert a recordset into special format
*
- * @param rs the recordset
+ * @param ADORecordSet $rs the recordset
+ * @param ADOConnection $conn
+ * @param string $sql
*
- * @return the CSV formatted data
+ * @return string the CSV formatted data
*/
function _rs2serialize(&$rs,$conn=false,$sql='')
{
@@ -74,28 +76,28 @@ $ADODB_INCLUDED_CSV = 1;
$savefetch = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
$class = $rs->connection->arrayClass;
- $rs2 = new $class();
+ /** @var ADORecordSet $rs2 */
+ $rs2 = new $class(ADORecordSet::DUMMY_QUERY_ID);
$rs2->timeCreated = $rs->timeCreated; # memcache fix
$rs2->sql = $rs->sql;
- $rs2->oldProvider = $rs->dataProvider;
$rs2->InitArrayFields($rows,$flds);
$rs2->fetchMode = $savefetch;
return $line.serialize($rs2);
}
-
-/**
-* Open CSV file and convert it into Data.
-*
-* @param url file/ftp/http url
-* @param err returns the error message
-* @param timeout dispose if recordset has been alive for $timeout secs
-*
-* @return recordset, or false if error occurred. If no
-* error occurred in sql INSERT/UPDATE/DELETE,
-* empty recordset is returned
-*/
- function csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
+ /**
+ * Open CSV file and convert it into Data.
+ *
+ * @param string $url file/ftp/http url
+ * @param string &$err returns the error message
+ * @param int $timeout dispose if recordset has been alive for $timeout secs
+ * @param string $rsclass RecordSet class to return
+ *
+ * @return ADORecordSet|false recordset, or false if error occurred.
+ * If no error occurred in sql INSERT/UPDATE/DELETE,
+ * empty recordset is returned.
+ */
+ function csv2rs($url, &$err, $timeout=0, $rsclass='ADORecordSet_array')
{
$false = false;
$err = false;
diff --git a/adodb-datadict.inc.php b/adodb-datadict.inc.php
index dbed95d..5156b1f 100644
--- a/adodb-datadict.inc.php
+++ b/adodb-datadict.inc.php
@@ -202,6 +202,12 @@ class ADODB_DataDict {
*/
public $blobAllowsDefaultValue;
+
+ /**
+ * @var string String to use to quote identifiers and names
+ */
+ public $quote;
+
function getCommentSQL($table,$col)
{
return false;
@@ -353,7 +359,7 @@ class ADODB_DataDict {
function nameQuote($name = NULL,$allowBrackets=false)
{
if (!is_string($name)) {
- return FALSE;
+ return false;
}
$name = trim($name);
@@ -427,6 +433,15 @@ class ADODB_DataDict {
function actualType($meta)
{
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
return $meta;
}
@@ -498,7 +513,7 @@ class ADODB_DataDict {
* @param string $tabname table-name
* @param string $flds column-name and type for the changed column
* @param string $tableflds='' complete definition of the new table, eg. for postgres, default ''
- * @param array/string $tableoptions='' options for the new table see createTableSQL, default ''
+ * @param array|string $tableoptions='' options for the new table see createTableSQL, default ''
* @return array with SQL strings
*/
function alterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
@@ -553,7 +568,7 @@ class ADODB_DataDict {
* @param string $tabname table-name
* @param string $flds column-name and type for the changed column
* @param string $tableflds='' complete definition of the new table, eg. for postgres, default ''
- * @param array/string $tableoptions='' options for the new table see createTableSQL, default ''
+ * @param array|string $tableoptions='' options for the new table see createTableSQL, default ''
* @return array with SQL strings
*/
function dropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
@@ -695,16 +710,25 @@ class ADODB_DataDict {
case '0':
case 'NAME': $fname = $v; break;
case '1':
- case 'TYPE': $ty = $v; $ftype = $this->actualType(strtoupper($v)); break;
+ case 'TYPE':
+
+ $ty = $v;
+ $ftype = $this->actualType(strtoupper($v));
+ break;
case 'SIZE':
- $dotat = strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,',');
- if ($dotat === false) $fsize = $v;
- else {
- $fsize = substr($v,0,$dotat);
- $fprec = substr($v,$dotat+1);
- }
- break;
+ $dotat = strpos($v,'.');
+ if ($dotat === false)
+ $dotat = strpos($v,',');
+ if ($dotat === false)
+ $fsize = $v;
+ else {
+
+ $fsize = substr($v,0,$dotat);
+ $fprec = substr($v,$dotat+1);
+
+ }
+ break;
case 'UNSIGNED': $funsigned = true; break;
case 'AUTOINCREMENT':
case 'AUTO': $fautoinc = true; $fnotnull = true; break;
@@ -989,11 +1013,17 @@ class ADODB_DataDict {
}
/**
- "Florian Buzin [ easywe ]" <florian.buzin#easywe.de>
-
- This function changes/adds new fields to your table. You don't
- have to know if the col is new or not. It will check on its own.
- */
+ * This function changes/adds new fields to your table.
+ *
+ * You don't have to know if the col is new or not. It will check on its own.
+ *
+ * @param string $tablename
+ * @param string $flds
+ * @param string[] $tableoptions
+ * @param bool $dropOldFlds
+ *
+ * @return string[] Array of SQL Commands
+ */
function changeTableSQL($tablename, $flds, $tableoptions = false, $dropOldFlds=false)
{
global $ADODB_FETCH_MODE;
@@ -1052,37 +1082,14 @@ class ADODB_DataDict {
$flds = $holdflds;
}
-
- // already exists, alter table instead
- list($lines,$pkey,$idxs) = $this->_genFields($flds);
- // genfields can return FALSE at times
- if ($lines == null) $lines = array();
- $alter = 'ALTER TABLE ' . $this->tableName($tablename);
- $sql = array();
-
- foreach ( $lines as $id => $v ) {
- if ( isset($cols[$id]) && is_object($cols[$id]) ) {
-
- $flds = lens_ParseArgs($v,',');
-
- // We are trying to change the size of the field, if not allowed, simply ignore the request.
- // $flds[1] holds the type, $flds[2] holds the size -postnuke addition
- if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)
- && (isset($flds[0][2]) && is_numeric($flds[0][2]))) {
- if ($this->debug) ADOConnection::outp(sprintf("<h3>%s cannot be changed to %s currently</h3>", $flds[0][0], $flds[0][1]));
- #echo "<h3>$this->alterCol cannot be changed to $flds currently</h3>";
- continue;
- }
- $sql[] = $alter . $this->alterCol . ' ' . $v;
- } else {
- $sql[] = $alter . $this->addCol . ' ' . $v;
- }
- }
+ $sql = $this->alterColumnSql($tablename, $flds);
if ($dropOldFlds) {
- foreach ( $cols as $id => $v )
- if ( !isset($lines[$id]) )
- $sql[] = $alter . $this->dropCol . ' ' . $v->name;
+ foreach ($cols as $id => $v) {
+ if (!isset($lines[$id])) {
+ $sql[] = $this->dropColumnSQL($tablename, $flds);
+ }
+ }
}
return $sql;
}
diff --git a/adodb-exceptions.inc.php b/adodb-exceptions.inc.php
index 9f1176f..e4fae81 100644
--- a/adodb-exceptions.inc.php
+++ b/adodb-exceptions.inc.php
@@ -30,6 +30,9 @@ var $params = '';
var $host = '';
var $database = '';
+ /** @var string A message text. */
+ var $msg = '';
+
function __construct($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection)
{
switch($fn) {
@@ -45,6 +48,9 @@ var $database = '';
$s = "$dbms error: [$errno: $errmsg] in $fn($p1, '$user', '****', $p2)";
break;
default:
+ //Prevent PHP warning if $p1 or $p2 are arrays.
+ $p1 = ( is_array($p1) ) ? 'Array' : $p1;
+ $p2 = ( is_array($p2) ) ? 'Array' : $p2;
$s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)";
break;
}
@@ -75,10 +81,18 @@ var $database = '';
function adodb_throw($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection)
{
-global $ADODB_EXCEPTION;
+ global $ADODB_EXCEPTION;
+
+ // Do not throw if errors are suppressed by @ operator
+ // error_reporting() value for suppressed errors changed in PHP 8.0.0
+ $suppressed = version_compare(PHP_VERSION, '8.0.0', '<')
+ ? 0
+ : E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE;
+ if (error_reporting() == $suppressed) {
+ return;
+ }
+
+ $errfn = is_string($ADODB_EXCEPTION) ? $ADODB_EXCEPTION : 'ADODB_EXCEPTION';
- if (error_reporting() == 0) return; // obey @ protocol
- if (is_string($ADODB_EXCEPTION)) $errfn = $ADODB_EXCEPTION;
- else $errfn = 'ADODB_EXCEPTION';
throw new $errfn($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection);
}
diff --git a/adodb-lib.inc.php b/adodb-lib.inc.php
index ced5e12..90b8b9d 100644
--- a/adodb-lib.inc.php
+++ b/adodb-lib.inc.php
@@ -27,44 +27,30 @@ if (!defined('ADODB_DIR')) die();
global $ADODB_INCLUDED_LIB;
$ADODB_INCLUDED_LIB = 1;
+/**
+ * Strip the ORDER BY clause from the outer SELECT.
+ *
+ * @param string $sql
+ *
+ * @return string
+ */
function adodb_strip_order_by($sql)
{
- $rez = preg_match_all('/(\sORDER\s+BY\s(?:[^)](?!LIMIT))*)/is', $sql, $arr);
- if ($arr)
- {
- $tmp = array_pop($arr);
- $arr = [1=>array_pop($tmp)];
- }
- if ($arr)
- if (strpos($arr[1], '(') !== false) {
- $at = strpos($sql, $arr[1]);
- $cntin = 0;
- for ($i=$at, $max=strlen($sql); $i < $max; $i++) {
- $ch = $sql[$i];
- if ($ch == '(') {
- $cntin += 1;
- } elseif($ch == ')') {
- $cntin -= 1;
- if ($cntin < 0) {
- break;
- }
- }
- }
- $sql = substr($sql,0,$at).substr($sql,$i);
- } else {
- $sql = str_replace($arr[1], '', $sql);
+ $num = preg_match_all('/(\sORDER\s+BY\s(?:[^)](?!LIMIT))*)/is', $sql, $matches, PREG_OFFSET_CAPTURE);
+ if ($num) {
+ // Get the last match
+ list($last_order_by, $offset) = array_pop($matches[1]);
+
+ // If we find a ')' after the last order by, then it belongs to a
+ // sub-query, not the outer SQL statement and should not be stripped
+ if (strpos($sql, ')', $offset) === false) {
+ $sql = str_replace($last_order_by, '', $sql);
}
-
+ }
return $sql;
}
-if (false) {
- $sql = 'select * from (select a from b order by a(b),b(c) desc)';
- $sql = '(select * from abc order by 1)';
- die(adodb_strip_order_by($sql));
-}
-
-function adodb_probetypes(&$array,&$types,$probe=8)
+function adodb_probetypes($array,&$types,$probe=8)
{
// probe and guess the type
$types = array();
@@ -96,7 +82,7 @@ function adodb_probetypes(&$array,&$types,$probe=8)
// that it is not an integer
if (strlen($v) == 0) $types[$i] = 'C';
if (strpos($v,'.') !== false) $types[$i] = 'N';
- else $types[$i] = 'I';
+ else $types[$i] = 'I';
continue;
}
@@ -107,7 +93,7 @@ function adodb_probetypes(&$array,&$types,$probe=8)
}
-function adodb_transpose(&$arr, &$newarr, &$hdr, &$fobjs)
+function adodb_transpose(&$arr, &$newarr, &$hdr, $fobjs)
{
$oldX = sizeof(reset($arr));
$oldY = sizeof($arr);
@@ -135,7 +121,7 @@ function adodb_transpose(&$arr, &$newarr, &$hdr, &$fobjs)
}
-function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc)
+function _adodb_replace($zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc)
{
// Add Quote around table name to support use of spaces / reserved keywords
$table=sprintf('%s%s%s', $zthis->nameQuote,$table,$zthis->nameQuote);
@@ -209,7 +195,7 @@ function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_
return ($rs) ? 2 : 0;
}
-function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
+function _adodb_getmenu($zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
$size=0, $selectAttr='',$compareFields0=true)
{
global $ADODB_FETCH_MODE;
@@ -242,6 +228,7 @@ function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=f
$value = 'value="' . htmlspecialchars($zval2) . '"';
}
+ /** @noinspection PhpUndefinedVariableInspection */
$s .= _adodb_getmenu_option($defstr, $compareFields0 ? $zval : $zval2, $value, $zval);
$zthis->MoveNext();
@@ -250,7 +237,7 @@ function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=f
return $s ."\n</select>\n";
}
-function _adodb_getmenu_gp(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
+function _adodb_getmenu_gp($zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
$size=0, $selectAttr='',$compareFields0=true)
{
global $ADODB_FETCH_MODE;
@@ -304,6 +291,7 @@ function _adodb_getmenu_gp(&$zthis, $name,$defstr='',$blank1stItem=true,$multipl
$s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
}
+ /** @noinspection PhpUndefinedVariableInspection */
$s .= _adodb_getmenu_option($defstr, $compareFields0 ? $zval : $zval2, $value, $zval);
$zthis->MoveNext();
@@ -349,7 +337,7 @@ function _adodb_getmenu_select($name, $defstr = '', $blank1stItem = true,
$html = '<select name="' . $name . '"' . $attr . ' ' . $selectAttr . '>';
if ($blank1stItem) {
- if (is_string($blank1stItem)) {
+ if (is_string($blank1stItem)) {
$barr = explode(':',$blank1stItem);
if (sizeof($barr) == 1) {
$barr[] = '';
@@ -400,7 +388,7 @@ function _adodb_getmenu_option($defstr, $compare, $value, $display)
$cnt = _adodb_getcount($conn, $sql);
*/
-function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
+function _adodb_getcount($zthis, $sql,$inputarr=false,$secs2cache=0)
{
$qryRecs = 0;
@@ -456,7 +444,7 @@ function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
continue;
}
// Exit loop if 'FROM' keyword was found
- if (strtoupper(substr($sql, $pos, 4)) == 'FROM') {
+ if (strtoupper(substr($sql, $pos, 4)) == 'FROM') {
break;
}
}
@@ -491,7 +479,7 @@ function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
if (preg_match('/\s*UNION\s*/is', $sql)) {
$rewritesql = $sql;
} else {
- $rewritesql = $rewritesql = adodb_strip_order_by($sql);
+ $rewritesql = adodb_strip_order_by($sql);
}
if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) {
@@ -520,37 +508,38 @@ function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
return $qryRecs;
}
-/*
- Code originally from "Cornel G" <conyg@fx.ro>
-
- This code might not work with SQL that has UNION in it
-
- Also if you are using CachePageExecute(), there is a strong possibility that
- data will get out of synch. use CachePageExecute() only with tables that
- rarely change.
-*/
-function _adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page,
- $inputarr=false, $secs2cache=0)
+/**
+ * Execute query with pagination including record count.
+ *
+ * This code might not work with SQL that has UNION in it.
+ * Also if you are using cachePageExecute(), there is a strong possibility that
+ * data will get out of sync. cachePageExecute() should only be used with
+ * tables that rarely change.
+ *
+ * @param ADOConnection $zthis Connection
+ * @param string $sql Query to execute
+ * @param int $nrows Number of rows per page
+ * @param int $page Page number to retrieve (1-based)
+ * @param array $inputarr Array of bind variables
+ * @param int $secs2cache Time-to-live of the cache (in seconds), 0 to force query execution
+ *
+ * @return ADORecordSet|bool
+ *
+ * @author Cornel G <conyg@fx.ro>
+ */
+function _adodb_pageexecute_all_rows($zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0)
{
$atfirstpage = false;
$atlastpage = false;
- $lastpageno=1;
- // If an invalid nrows is supplied,
- // we assume a default value of 10 rows per page
+ // If an invalid nrows is supplied, assume a default value of 10 rows per page
if (!isset($nrows) || $nrows <= 0) $nrows = 10;
- $qryRecs = false; //count records for no offset
-
$qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache);
$lastpageno = (int) ceil($qryRecs / $nrows);
- $zthis->_maxRecordCount = $qryRecs;
-
-
- // ***** Here we check whether $page is the last page or
- // whether we are trying to retrieve
- // a page number greater than the last page number.
+ // Check whether $page is the last page or if we are trying to retrieve
+ // a page number greater than the last one.
if ($page >= $lastpageno) {
$page = $lastpageno;
$atlastpage = true;
@@ -582,10 +571,27 @@ function _adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page,
return $rsreturn;
}
-// Iván Oliva version
-function _adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0)
+/**
+ * Execute query with pagination without last page information.
+ *
+ * This code might not work with SQL that has UNION in it.
+ * Also if you are using cachePageExecute(), there is a strong possibility that
+ * data will get out of sync. cachePageExecute() should only be used with
+ * tables that rarely change.
+ *
+ * @param ADOConnection $zthis Connection
+ * @param string $sql Query to execute
+ * @param int $nrows Number of rows per page
+ * @param int $page Page number to retrieve (1-based)
+ * @param array $inputarr Array of bind variables
+ * @param int $secs2cache Time-to-live of the cache (in seconds), 0 to force query execution
+ *
+ * @return ADORecordSet|bool
+ *
+ * @author Iván Oliva
+ */
+function _adodb_pageexecute_no_last_page($zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0)
{
-
$atfirstpage = false;
$atlastpage = false;
@@ -623,7 +629,6 @@ function _adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr
// page and return it. Revert to original method and loop through pages
// until we find some data...
$pagecounter = $page + 1;
- $pagecounteroffset = ($pagecounter * $nrows) - $nrows;
$rstest = $rsreturn;
if ($rstest) {
@@ -715,7 +720,7 @@ function _adodb_quote_fieldname($zthis, $fieldName)
}
}
-function _adodb_getupdatesql(&$zthis, &$rs, $arrFields, $forceUpdate=false, $force=2)
+function _adodb_getupdatesql(&$zthis, $rs, $arrFields, $forceUpdate=false, $force=2)
{
if (!$rs) {
printf(ADODB_BAD_RS,'GetUpdateSQL');
@@ -746,11 +751,11 @@ function _adodb_getupdatesql(&$zthis, &$rs, $arrFields, $forceUpdate=false, $for
if ($hasnumeric) $val = $rs->fields[$i];
else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname];
- else if (isset($rs->fields[$field->name])) $val = $rs->fields[$field->name];
- else if (isset($rs->fields[strtolower($upperfname)])) $val = $rs->fields[strtolower($upperfname)];
+ else if (isset($rs->fields[$field->name])) $val = $rs->fields[$field->name];
+ else if (isset($rs->fields[strtolower($upperfname)])) $val = $rs->fields[strtolower($upperfname)];
else $val = '';
- if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) {
+ if ($forceUpdate || $val !== $arrFields[$upperfname]) {
// Set the counter for the number of fields that will be updated.
$fieldUpdatedCount++;
@@ -840,7 +845,6 @@ function _adodb_getupdatesql(&$zthis, &$rs, $arrFields, $forceUpdate=false, $for
$discard = false;
// not a good hack, improvements?
if ($whereClause) {
- #var_dump($whereClause);
if (preg_match('/\s(ORDER\s.*)/is', $whereClause[1], $discard));
else if (preg_match('/\s(LIMIT\s.*)/is', $whereClause[1], $discard));
else if (preg_match('/\s(FOR UPDATE.*)/is', $whereClause[1], $discard));
@@ -863,14 +867,14 @@ function _adodb_getupdatesql(&$zthis, &$rs, $arrFields, $forceUpdate=false, $for
}
}
-function adodb_key_exists($key, &$arr,$force=2)
+function adodb_key_exists($key, $arr,$force=2)
{
if ($force<=0) {
// the following is the old behaviour where null or empty fields are ignored
return (!empty($arr[$key])) || (isset($arr[$key]) && strlen($arr[$key])>0);
}
- if (isset($arr[$key]))
+ if (isset($arr[$key]))
return true;
## null check below
return array_key_exists($key,$arr);
@@ -883,7 +887,7 @@ function adodb_key_exists($key, &$arr,$force=2)
*
*
*/
-function _adodb_getinsertsql(&$zthis, &$rs, $arrFields, $force=2)
+function _adodb_getinsertsql(&$zthis, $rs, $arrFields, $force=2)
{
static $cacheRS = false;
static $cacheSig = 0;
@@ -892,7 +896,6 @@ static $cacheCols;
$tableName = '';
$values = '';
$fields = '';
- $recordSet = null;
if (is_array($arrFields))
$arrFields = array_change_key_case($arrFields,CASE_UPPER);
$fieldInsertedCount = 0;
@@ -906,7 +909,7 @@ static $cacheCols;
//because we have to call MetaType.
//php can't do a $rsclass::MetaType()
$rsclass = $zthis->rsPrefix.$zthis->databaseType;
- $recordSet = new $rsclass(-1,$zthis->fetchMode);
+ $recordSet = new $rsclass(ADORecordSet::DUMMY_QUERY_ID, $zthis->fetchMode);
$recordSet->connection = $zthis;
if (is_string($cacheRS) && $cacheRS == $rs) {
@@ -920,6 +923,7 @@ static $cacheCols;
if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS == $rs->insertSig) {
$columns = $cacheCols;
} else {
+ $columns = [];
for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++)
$columns[] = $rs->FetchField($i);
$cacheRS = $cacheSig;
@@ -936,60 +940,58 @@ static $cacheCols;
// Loop through all of the fields in the recordset
foreach( $columns as $field ) {
$upperfname = strtoupper($field->name);
- if (adodb_key_exists($upperfname,$arrFields,$force)) {
+ if (adodb_key_exists($upperfname, $arrFields, $force)) {
$bad = false;
$fnameq = _adodb_quote_fieldname($zthis, $field->name);
$type = $recordSet->MetaType($field->type);
- /********************************************************/
- if (is_null($arrFields[$upperfname])
- || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
- || $arrFields[$upperfname] === $zthis->null2null
- )
- {
- switch ($force) {
+ /********************************************************/
+ if (is_null($arrFields[$upperfname])
+ || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
+ || $arrFields[$upperfname] === $zthis->null2null
+ ) {
+ switch ($force) {
- case ADODB_FORCE_IGNORE: // we must always set null if missing
- $bad = true;
- break;
+ case ADODB_FORCE_IGNORE: // we must always set null if missing
+ $bad = true;
+ break;
- case ADODB_FORCE_NULL:
- $values .= "null, ";
- break;
+ case ADODB_FORCE_NULL:
+ $values .= "null, ";
+ break;
- case ADODB_FORCE_EMPTY:
- //Set empty
- $arrFields[$upperfname] = "";
- $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields);
- break;
+ case ADODB_FORCE_EMPTY:
+ //Set empty
+ $arrFields[$upperfname] = "";
+ $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields);
+ break;
- default:
- case ADODB_FORCE_VALUE:
- //Set the value that was given in array, so you can give both null and empty values
- if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
- $values .= "null, ";
- } else {
- $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields);
- }
- break;
+ default:
+ case ADODB_FORCE_VALUE:
+ //Set the value that was given in array, so you can give both null and empty values
+ if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
+ $values .= "null, ";
+ } else {
+ $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields);
+ }
+ break;
- case ADODB_FORCE_NULL_AND_ZERO:
- switch ($type)
- {
- case 'N':
- case 'I':
- case 'L':
- $values .= '0, ';
- break;
- default:
- $values .= "null, ";
- break;
- }
+ case ADODB_FORCE_NULL_AND_ZERO:
+ switch ($type) {
+ case 'N':
+ case 'I':
+ case 'L':
+ $values .= '0, ';
+ break;
+ default:
+ $values .= "null, ";
+ break;
+ }
break;
- } // switch
+ } // switch
- /*********************************************************/
+ /*********************************************************/
} else {
//we do this so each driver can customize the sql for
//DB specific column types.
@@ -998,11 +1000,12 @@ static $cacheCols;
$values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields);
}
- if ($bad) continue;
+ if ($bad) {
+ continue;
+ }
// Set the counter for the number of fields that will be inserted.
$fieldInsertedCount++;
-
// Get the name of the fields to insert
$fields .= $fnameq . ", ";
}
@@ -1010,7 +1013,7 @@ static $cacheCols;
// If there were any inserted fields then build the rest of the insert query.
- if ($fieldInsertedCount <= 0) return false;
+ if ($fieldInsertedCount <= 0) return false;
// Get the table name from the existing query.
if (!$tableName) {
@@ -1048,76 +1051,76 @@ static $cacheCols;
*/
function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFields)
{
- $sql = '';
-
- // Based on the datatype of the field
- // Format the value properly for the database
- switch($type) {
- case 'B':
- //in order to handle Blobs correctly, we need
- //to do some magic for Oracle
-
- //we need to create a new descriptor to handle
- //this properly
- if (!empty($zthis->hasReturningInto)) {
- if ($action == 'I') {
- $sql = 'empty_blob(), ';
- } else {
- $sql = $fnameq. '=empty_blob(), ';
- }
- //add the variable to the returning clause array
- //so the user can build this later in
- //case they want to add more to it
- $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
- } else if (empty($arrFields[$fname])){
- if ($action == 'I') {
- $sql = 'empty_blob(), ';
- } else {
- $sql = $fnameq. '=empty_blob(), ';
- }
- } else {
- //this is to maintain compatibility
- //with older adodb versions.
- $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, false);
- }
- break;
-
- case "X":
- //we need to do some more magic here for long variables
- //to handle these correctly in oracle.
-
- //create a safe bind var name
- //to avoid conflicts w/ dupes.
- if (!empty($zthis->hasReturningInto)) {
- if ($action == 'I') {
- $sql = ':xx'.$fname.'xx, ';
- } else {
- $sql = $fnameq.'=:xx'.$fname.'xx, ';
- }
- //add the variable to the returning clause array
- //so the user can build this later in
- //case they want to add more to it
- $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
- } else {
- //this is to maintain compatibility
- //with older adodb versions.
- $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, false);
- }
- break;
+ // Based on the datatype of the field
+ // Format the value properly for the database
+ switch ($type) {
+ case 'B':
+ //in order to handle Blobs correctly, we need
+ //to do some magic for Oracle
+
+ //we need to create a new descriptor to handle
+ //this properly
+ if (!empty($zthis->hasReturningInto)) {
+ if ($action == 'I') {
+ $sql = 'empty_blob(), ';
+ } else {
+ $sql = $fnameq . '=empty_blob(), ';
+ }
+ //add the variable to the returning clause array
+ //so the user can build this later in
+ //case they want to add more to it
+ $zthis->_returningArray[$fname] = ':xx' . $fname . 'xx';
+ } else {
+ if (empty($arrFields[$fname])) {
+ if ($action == 'I') {
+ $sql = 'empty_blob(), ';
+ } else {
+ $sql = $fnameq . '=empty_blob(), ';
+ }
+ } else {
+ //this is to maintain compatibility
+ //with older adodb versions.
+ $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, false);
+ }
+ }
+ break;
+
+ case "X":
+ //we need to do some more magic here for long variables
+ //to handle these correctly in oracle.
+
+ //create a safe bind var name
+ //to avoid conflicts w/ dupes.
+ if (!empty($zthis->hasReturningInto)) {
+ if ($action == 'I') {
+ $sql = ':xx' . $fname . 'xx, ';
+ } else {
+ $sql = $fnameq . '=:xx' . $fname . 'xx, ';
+ }
+ //add the variable to the returning clause array
+ //so the user can build this later in
+ //case they want to add more to it
+ $zthis->_returningArray[$fname] = ':xx' . $fname . 'xx';
+ } else {
+ //this is to maintain compatibility
+ //with older adodb versions.
+ $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, false);
+ }
+ break;
- default:
- $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, false);
- break;
- }
+ default:
+ $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, false);
+ break;
+ }
- return $sql;
+ return $sql;
}
function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields, $recurse=true)
{
if ($recurse) {
- switch($zthis->dataProvider) {
+ switch($zthis->dataProvider) {
case 'postgres':
if ($type == 'L') $type = 'C';
break;
@@ -1143,15 +1146,15 @@ function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields,
break;
case "N":
- $val = $arrFields[$fname];
+ $val = $arrFields[$fname];
if (!is_numeric($val)) $val = str_replace(',', '.', (float)$val);
- break;
+ break;
case "I":
case "R":
- $val = $arrFields[$fname];
+ $val = $arrFields[$fname];
if (!is_numeric($val)) $val = (integer) $val;
- break;
+ break;
default:
$val = str_replace(array("'"," ","("),"",$arrFields[$fname]); // basic sql injection defence
@@ -1161,178 +1164,225 @@ function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields,
if ($action == 'I') return $val . ", ";
- return $fnameq . "=" . $val . ", ";
+ return $fnameq . "=" . $val . ", ";
}
-
-function _adodb_debug_execute(&$zthis, $sql, $inputarr)
+/**
+* Replaces standard _execute when debug mode is enabled
+*
+* @param ADOConnection $zthis An ADOConnection object
+* @param string|string[] $sql A string or array of SQL statements
+* @param string[]|null $inputarr An optional array of bind parameters
+*
+* @return handle|void A handle to the executed query
+*/
+function _adodb_debug_execute($zthis, $sql, $inputarr)
{
+ // Unpack the bind parameters
$ss = '';
if ($inputarr) {
- foreach($inputarr as $kk=>$vv) {
- if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
- if (is_null($vv)) $ss .= "($kk=>null) ";
- else
- {
- if (is_array($vv))
- {
- $vv = sprintf("Array Of Values: [%s]", implode(',',$vv));
+ foreach ($inputarr as $kk => $vv) {
+ if (is_string($vv) && strlen($vv) > 64) {
+ $vv = substr($vv, 0, 64) . '...';
+ }
+ if (is_null($vv)) {
+ $ss .= "($kk=>null) ";
+ } else {
+ if (is_array($vv)) {
+ $vv = sprintf("Array Of Values: [%s]", implode(',', $vv));
}
$ss .= "($kk=>'$vv') ";
}
}
-
$ss = "[ $ss ]";
}
+
$sqlTxt = is_array($sql) ? $sql[0] : $sql;
- /*str_replace(', ','##1#__^LF',is_array($sql) ? $sql[0] : $sql);
- $sqlTxt = str_replace(',',', ',$sqlTxt);
- $sqlTxt = str_replace('##1#__^LF', ', ' ,$sqlTxt);
- */
+
+ // Remove newlines and tabs, compress repeating spaces
+ $sqlTxt = preg_replace('/\s+/', ' ', $sqlTxt);
+
// check if running from browser or command-line
$inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
- $dbt = $zthis->databaseType;
- if (isset($zthis->dsnType)) $dbt .= '-'.$zthis->dsnType;
+ $myDatabaseType = $zthis->databaseType;
+ if (!isset($zthis->dsnType)) {
+ // Append the PDO driver name
+ $myDatabaseType .= '-' . $zthis->dsnType;
+ }
+
if ($inBrowser) {
if ($ss) {
- $ss = '<code>'.htmlspecialchars($ss).'</code>';
+ // Default formatting for passed parameter
+ $ss = sprintf('<code class="adodb-debug">%s</code>', htmlspecialchars($ss));
+ }
+ if ($zthis->debug === -1) {
+ $outString = "<br class='adodb-debug'>(%s): %s %s<br class='adodb-debug'>";
+ ADOConnection::outp(sprintf($outString, $myDatabaseType, htmlspecialchars($sqlTxt), $ss), false);
+ } elseif ($zthis->debug !== -99) {
+ $outString = "<hr class='adodb-debug'>(%s): %s %s<hr class='adodb-debug'>";
+ ADOConnection::outp(sprintf($outString, $myDatabaseType, htmlspecialchars($sqlTxt), $ss), false);
}
- if ($zthis->debug === -1)
- ADOConnection::outp( "<br>\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<br>\n",false);
- else if ($zthis->debug !== -99)
- ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<hr>\n",false);
} else {
- $ss = "\n ".$ss;
- if ($zthis->debug !== -99)
- ADOConnection::outp("-----<hr>\n($dbt): ".$sqlTxt." $ss\n-----<hr>\n",false);
+ // CLI output
+ if ($zthis->debug !== -99) {
+ $outString = sprintf("%s\n%s\n %s %s \n%s\n", str_repeat('-', 78), $myDatabaseType, $sqlTxt, $ss, str_repeat('-', 78));
+ ADOConnection::outp($outString, false);
+ }
}
- $qID = $zthis->_query($sql,$inputarr);
+ // Now execute the query
+ $qID = $zthis->_query($sql, $inputarr);
- /*
- Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
- because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion
- */
+ // Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
+ // because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion
if ($zthis->databaseType == 'mssql') {
- // ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6
-
- if($emsg = $zthis->ErrorMsg()) {
+ // ErrorNo is a slow function call in mssql
+ if ($emsg = $zthis->ErrorMsg()) {
if ($err = $zthis->ErrorNo()) {
- if ($zthis->debug === -99)
- ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<hr>\n",false);
+ if ($zthis->debug === -99) {
+ ADOConnection::outp("<hr>\n($myDatabaseType): " . htmlspecialchars($sqlTxt) . " $ss\n<hr>\n", false);
+ }
- ADOConnection::outp($err.': '.$emsg);
+ ADOConnection::outp($err . ': ' . $emsg);
}
}
- } else if (!$qID) {
-
- if ($zthis->debug === -99)
- if ($inBrowser) ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<hr>\n",false);
- else ADOConnection::outp("-----<hr>\n($dbt): ".$sqlTxt."$ss\n-----<hr>\n",false);
+ } else {
+ if (!$qID) {
+ // Statement execution has failed
+ if ($zthis->debug === -99) {
+ if ($inBrowser) {
+ $outString = "<hr class='adodb-debug'>(%s): %s %s<hr class='adodb-debug'>";
+ ADOConnection::outp(sprintf($outString, $myDatabaseType, htmlspecialchars($sqlTxt), $ss), false);
+ } else {
+ $outString = sprintf("%s\n%s\n %s %s \n%s\n",str_repeat('-',78),$myDatabaseType,$sqlTxt,$ss,str_repeat('-',78));
+ ADOConnection::outp($outString, false);
+ }
+ }
- ADOConnection::outp($zthis->ErrorNo() .': '. $zthis->ErrorMsg());
+ // Send last error to output
+ $errno = $zthis->ErrorNo();
+ if ($errno) {
+ ADOConnection::outp($errno . ': ' . $zthis->ErrorMsg());
+ }
+ }
}
- if ($zthis->debug === 99) _adodb_backtrace(true,9999,2);
+ if ($qID === false || $zthis->debug === 99) {
+ _adodb_backtrace();
+ }
return $qID;
}
-# pretty print the debug_backtrace function
-function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0,$ishtml=null)
+/**
+ * Pretty print the debug_backtrace function
+ *
+ * @param string[]|bool $printOrArr Whether to print the result directly or return the result
+ * @param int $maximumDepth The maximum depth of the array to traverse
+ * @param int $elementsToIgnore The backtrace array indexes to ignore
+ * @param null|bool $ishtml True if we are in a CGI environment, false for CLI,
+ * null to auto detect
+ *
+ * @return string Formatted backtrace
+ */
+function _adodb_backtrace($printOrArr=true, $maximumDepth=9999, $elementsToIgnore=0, $ishtml=null)
{
- if (!function_exists('debug_backtrace')) return '';
+ if (!function_exists('debug_backtrace')) {
+ return '';
+ }
- if ($ishtml === null) $html = (isset($_SERVER['HTTP_USER_AGENT']));
- else $html = $ishtml;
+ if ($ishtml === null) {
+ // Auto determine if we in a CGI enviroment
+ $html = (isset($_SERVER['HTTP_USER_AGENT']));
+ } else {
+ $html = $ishtml;
+ }
- $fmt = ($html) ? "</font><font color=#808080 size=-1> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s";
+ $cgiString = "</font><font color=#808080 size=-1> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>";
+ $cliString = "%% line %4d, file: %s";
+ $fmt = ($html) ? $cgiString : $cliString;
$MAXSTRLEN = 128;
$s = ($html) ? '<pre align=left>' : '';
- if (is_array($printOrArr)) $traceArr = $printOrArr;
- else $traceArr = debug_backtrace();
+ if (is_array($printOrArr)) {
+ $traceArr = $printOrArr;
+ } else {
+ $traceArr = debug_backtrace();
+ }
+
+ // Remove first 2 elements that just show calls to adodb_backtrace
array_shift($traceArr);
array_shift($traceArr);
- $tabs = sizeof($traceArr)-2;
+
+ // We want last element to have no indent
+ $tabs = sizeof($traceArr) - 1;
foreach ($traceArr as $arr) {
- if ($skippy) {$skippy -= 1; continue;}
- $levels -= 1;
- if ($levels < 0) break;
+ if ($elementsToIgnore) {
+ // Ignore array element at start of array
+ $elementsToIgnore--;
+ $tabs--;
+ continue;
+ }
+ $maximumDepth--;
+ if ($maximumDepth < 0) {
+ break;
+ }
$args = array();
- for ($i=0; $i < $tabs; $i++) $s .= ($html) ? ' ' : "\t";
- $tabs -= 1;
- if ($html) $s .= '<font face="Courier New,Courier">';
- 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(str_replace(array("\r","\n"),' ',substr($v,0,$MAXSTRLEN)));
- if (strlen($v) > $MAXSTRLEN) $str .= '...';
- $args[] = $str;
- }
+
+ if ($tabs) {
+ $s .= str_repeat($html ? ' ' : "\t", $tabs);
+ $tabs--;
+ }
+ if ($html) {
+ $s .= '<font face="Courier New,Courier">';
}
- $s .= $arr['function'].'('.implode(', ',$args).')';
+ if (isset($arr['class'])) {
+ $s .= $arr['class'] . '.';
+ }
- $s .= @sprintf($fmt, $arr['line'],$arr['file'],basename($arr['file']));
+ if (isset($arr['args'])) {
+ foreach ($arr['args'] as $v) {
+ if (is_null($v)) {
+ $args[] = 'null';
+ } elseif (is_array($v)) {
+ $args[] = 'Array[' . sizeof($v) . ']';
+ } elseif (is_object($v)) {
+ $args[] = 'Object:' . get_class($v);
+ } elseif (is_bool($v)) {
+ $args[] = $v ? 'true' : 'false';
+ } else {
+ $v = (string)@$v;
+ // Truncate
+ $v = substr($v, 0, $MAXSTRLEN);
+ // Remove newlines and tabs, compress repeating spaces
+ $v = preg_replace('/\s+/', ' ', $v);
+ // Convert htmlchars (not sure why we do this in CLI)
+ $str = htmlspecialchars($v);
+
+ if (strlen($v) > $MAXSTRLEN) {
+ $str .= '...';
+ }
+ $args[] = $str;
+ }
+ }
+ }
+ $s .= $arr['function'] . '(' . implode(', ', $args) . ')';
+ $s .= @sprintf($fmt, $arr['line'], $arr['file'], basename($arr['file']));
$s .= "\n";
}
- if ($html) $s .= '</pre>';
- if ($printOrArr) print $s;
+ if ($html) {
+ $s .= '</pre>';
+ }
+ if ($printOrArr) {
+ print $s;
+ }
return $s;
}
-/*
-function _adodb_find_from($sql)
-{
-
- $sql = str_replace(array("\n","\r"), ' ', $sql);
- $charCount = strlen($sql);
-
- $inString = false;
- $quote = '';
- $parentheseCount = 0;
- $prevChars = '';
- $nextChars = '';
-
-
- for($i = 0; $i < $charCount; $i++) {
-
- $char = substr($sql,$i,1);
- $prevChars = substr($sql,0,$i);
- $nextChars = substr($sql,$i+1);
-
- if((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === false) {
- $quote = $char;
- $inString = true;
- }
-
- elseif((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === true && $quote == $char) {
- $quote = "";
- $inString = false;
- }
-
- elseif($char == "(" && $inString === false)
- $parentheseCount++;
-
- elseif($char == ")" && $inString === false && $parentheseCount > 0)
- $parentheseCount--;
-
- elseif($parentheseCount <= 0 && $inString === false && $char == " " && strtoupper(substr($prevChars,-5,5)) == " FROM")
- return $i;
-
- }
-}
-*/
diff --git a/adodb-loadbalancer.inc.php b/adodb-loadbalancer.inc.php
index 2e4f392..de06780 100644
--- a/adodb-loadbalancer.inc.php
+++ b/adodb-loadbalancer.inc.php
@@ -38,17 +38,17 @@ class ADOdbLoadBalancer
/**
* @var bool|array All connections to each database.
*/
- protected $connections = false;
+ protected $connections = [];
/**
* @var bool|array Just connections to the write capable database.
*/
- protected $connections_write = false;
+ protected $connections_write = [];
/**
* @var bool|array Just connections to the readonly database.
*/
- protected $connections_readonly = false;
+ protected $connections_readonly = [];
/**
* @var array Counts of all connections and their types.
@@ -73,12 +73,12 @@ class ADOdbLoadBalancer
/**
* @var bool Session variables that must be maintained across all connections, ie: SET TIME ZONE.
*/
- protected $session_variables = false;
+ protected $session_variables = [];
/**
* @var bool Called immediately after connecting to any DB.
*/
- protected $user_defined_session_init_sql = false;
+ protected $user_defined_session_init_sql = [];
/**
@@ -174,7 +174,7 @@ class ADOdbLoadBalancer
* @param string $type Type of database connection, either: 'write' capable or 'readonly'
* @return bool|int|string
*/
- private function getConnectionByWeight($type)
+ public function getConnectionByWeight($type)
{
if ($type == 'readonly') {
$total_weight = $this->total_connection_weights['all'];
@@ -233,7 +233,7 @@ class ADOdbLoadBalancer
* @return bool|ADOConnection
* @throws Exception
*/
- private function _getConnection($connection_id)
+ public function getConnectionById($connection_id)
{
if (isset($this->connections[$connection_id])) {
$connection_obj = $this->connections[$connection_id];
@@ -261,6 +261,15 @@ class ADOdbLoadBalancer
throw $e; // No connections left, reThrow exception so application can catch it.
}
+ // Check to see if a connection test callback was defined, and if so execute it.
+ // This is useful for testing replication lag and such to ensure the connection is suitable to be used.
+ $test_connection_callback = $connection_obj->getConnectionTestCallback();
+ if (is_callable($test_connection_callback)
+ && $test_connection_callback($connection_obj, $adodb_obj) !== TRUE
+ ) {
+ return false;
+ }
+
if (is_array($this->user_defined_session_init_sql)) {
foreach ($this->user_defined_session_init_sql as $session_init_sql) {
$adodb_obj->Execute($session_init_sql);
@@ -298,9 +307,12 @@ class ADOdbLoadBalancer
if ($connection_id !== false) {
try {
- $adodb_obj = $this->_getConnection($connection_id);
- // $connection_obj = $this->connections[$connection_id];
- break;
+ $adodb_obj = $this->getConnectionById($connection_id);
+ if (is_object($adodb_obj)) {
+ break; //Found valid connection, continue with it.
+ } else {
+ throw new Exception('ADODB Connection Object does not exist. Perhaps LoadBalancer Database Connection Test Failed?');
+ }
} catch (Exception $e) {
// Connection error, see if there are other connections to try still.
$this->removeConnection($connection_id);
@@ -315,6 +327,10 @@ class ADOdbLoadBalancer
}
}
+ if (!isset($connection_id)) {
+ throw new Exception('No connection available to use at this time! Type: ' . $type);
+ }
+
$this->last_connection_id[$type] = $connection_id;
if ($pin_connection === true) {
@@ -387,7 +403,7 @@ class ADOdbLoadBalancer
*/
private function executeSessionVariables($adodb_obj = false)
{
- if (is_array($this->session_variables)) {
+ if (is_array($this->session_variables) && count($this->session_variables) > 0) {
$sql = '';
foreach ($this->session_variables as $name => $value) {
// $sql .= 'SET SESSION '. $name .' '. $value;
@@ -432,7 +448,7 @@ class ADOdbLoadBalancer
&& $connection_obj->getADOdbObject()->_connectionID !== false
)
) {
- $adodb_obj = $this->_getConnection($key);
+ $adodb_obj = $this->getConnectionById($key);
if (is_object($adodb_obj)) {
$result_arr[] = $adodb_obj->Execute($sql, $inputarr);
}
@@ -595,6 +611,7 @@ class ADOdbLoadBalancer
case 'binddate':
case 'bindtimestamp':
case 'setfetchmode':
+ case 'setcustommetatype':
$type = false; // No connection necessary.
break;
@@ -686,6 +703,11 @@ class ADOdbLoadBalancerConnection
*/
protected $adodb_obj = false;
+ /**
+ * @var callable Closure
+ */
+ protected $connection_test_callback = NULL;
+
/**
* @var string Type of connection, either 'write' capable or 'readonly'
*/
@@ -761,6 +783,24 @@ class ADOdbLoadBalancerConnection
return true;
}
+ /**
+ * Anonymous function that is called and must return TRUE for the connection to be usable.*
+ * The first argument is the type of connection to test.
+ * Useful to check things like replication lag.
+ * @param callable $callback
+ * @return void
+ */
+ function setConnectionTestCallback($callback) {
+ $this->connection_test_callback = $callback;
+ }
+
+ /**
+ * @return callable|null
+ */
+ function getConnectionTestCallback() {
+ return $this->connection_test_callback;
+ }
+
/**
* Returns the ADODB object for this connection.
*
diff --git a/adodb-memcache.lib.inc.php b/adodb-memcache.lib.inc.php
index 7f110e7..a251c9c 100644
--- a/adodb-memcache.lib.inc.php
+++ b/adodb-memcache.lib.inc.php
@@ -17,6 +17,8 @@
*
* @copyright 2000-2013 John Lim
* @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
+ *
+ * @noinspection PhpUnused
*/
// security - hide paths
@@ -26,183 +28,393 @@ global $ADODB_INCLUDED_MEMCACHE;
$ADODB_INCLUDED_MEMCACHE = 1;
global $ADODB_INCLUDED_CSV;
-if (empty($ADODB_INCLUDED_CSV)) include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
-
- class ADODB_Cache_MemCache {
- var $createdir = false; // create caching directory structure?
-
- // $library will be populated with the proper library on connect
- // and is used later when there are differences in specific calls
- // between memcache and memcached
- var $library = false;
-
- //-----------------------------
- // memcache specific variables
-
- var $hosts; // array of hosts
- var $port = 11211;
- var $compress = false; // memcache compression with zlib
-
- var $_connected = false;
- var $_memcache = false;
-
- function __construct(&$obj)
- {
- $this->hosts = $obj->memCacheHost;
- $this->port = $obj->memCachePort;
- $this->compress = $obj->memCacheCompress;
- }
-
- // implement as lazy connection. The connection only occurs on CacheExecute call
- function connect(&$err)
- {
- // do we have memcache or memcached?
- if (class_exists('Memcache')) {
- $this->library='Memcache';
- $memcache = new MemCache;
- } elseif (class_exists('Memcached')) {
- $this->library='Memcached';
- $memcache = new MemCached;
- } else {
- $err = 'Neither the Memcache nor Memcached PECL extensions were found!';
- return false;
- }
+if (empty($ADODB_INCLUDED_CSV)) {
+ include_once(ADODB_DIR . '/adodb-csvlib.inc.php');
+}
- if (!is_array($this->hosts)) $this->hosts = array($this->hosts);
+class ADODB_Cache_MemCache
+{
+ /**
+ * @var bool Prevents parent class calling non-existant function
+ */
+ public $createdir = false;
- $failcnt = 0;
- foreach($this->hosts as $host) {
- if (!@$memcache->addServer($host,$this->port)) {
- $failcnt += 1;
- }
- }
- if ($failcnt == sizeof($this->hosts)) {
- $err = 'Can\'t connect to any memcache server';
+ /**
+ * @var array of hosts
+ */
+ private $hosts;
+
+ /**
+ * @var int Connection Port, uses default
+ */
+ private $port;
+
+ /**
+ * @var bool memcache compression with zlib
+ */
+ private $compress;
+
+ /**
+ * @var array of options for memcached only
+ */
+ private $options;
+
+ /**
+ * @var bool Internal flag indicating successful connection
+ */
+ private $isConnected = false;
+
+ /**
+ * @var Memcache|Memcached Handle for the Memcache library
+ *
+ * Populated with the proper library on connect, used later when
+ * there are differences in specific calls between memcache and memcached
+ */
+ private $memcacheLibrary = false;
+
+ /**
+ * @var array New server feature controller lists available servers
+ */
+ private $serverControllers = array();
+
+ /**
+ * @var array New server feature template uses granular server controller
+ */
+ private $serverControllerTemplate = array(
+ 'host' => '',
+ 'port' => 11211,
+ 'weight' => 0,
+ );
+
+ /**
+ * An integer index into the libraries
+ * @see $libraries
+ */
+ const MCLIB = 1;
+ const MCLIBD = 2;
+
+ /**
+ * @var array Xrefs the library flag to the actual class name
+ */
+ private $libraries = array(
+ self::MCLIB => 'Memcache',
+ self::MCLIBD => 'Memcached'
+ );
+
+ /**
+ * @var int An indicator of which library we are using
+ */
+ private $libraryFlag;
+
+ /**
+ * Class Constructor.
+ *
+ * @param ADOConnection $db
+ */
+ public function __construct($db)
+ {
+ $this->hosts = $db->memCacheHost;
+ $this->port = $this->serverControllerTemplate['port'] = $db->memCachePort;
+ $this->compress = $db->memCacheCompress;
+ $this->options = $db->memCacheOptions;
+ }
+
+ /**
+ * Return true if the current library is Memcached.
+ * @return bool
+ */
+ public function isLibMemcached(): bool
+ {
+ return $this->libraryFlag == self::MCLIBD;
+ }
+
+ /**
+ * Lazy connection.
+ *
+ * The connection only occurs on CacheExecute call.
+ *
+ * @param string $err
+ *
+ * @return bool success of connecting to a server
+ */
+ public function connect(&$err)
+ {
+ // do we have memcache or memcached? see the note at adodb.org on memcache
+ if (class_exists('Memcache')) {
+ $this->libraryFlag = self::MCLIB;
+ } elseif (class_exists('Memcached')) {
+ $this->libraryFlag = self::MCLIBD;
+ } else {
+ $err = 'Neither the Memcache nor Memcached PECL extensions were found!';
+ return false;
+ }
+
+ $usedLibrary = $this->libraries[$this->libraryFlag];
+
+ /** @var Memcache|Memcached $memCache */
+ $memCache = new $usedLibrary;
+ if (!$memCache) {
+ $err = 'Memcache library failed to initialize';
+ return false;
+ }
+
+ // Convert simple compression flag for memcached
+ if ($this->isLibMemcached()) {
+ $this->options[Memcached::OPT_COMPRESSION] = $this->compress;
+ }
+
+ // Are there any options available for memcached
+ if ($this->isLibMemcached() && count($this->options) > 0) {
+ $optionSuccess = $memCache->setOptions($this->options);
+ if (!$optionSuccess) {
+ $err = 'Invalid option parameters passed to Memcached';
return false;
}
- $this->_connected = true;
- $this->_memcache = $memcache;
- return true;
}
- // returns true or false. true if successful save
- function writecache($filename, $contents, $debug, $secs2cache)
- {
- if (!$this->_connected) {
- $err = '';
- if (!$this->connect($err) && $debug) ADOConnection::outp($err);
- }
- if (!$this->_memcache) return false;
+ // Have we passed a controller array
+ if (!is_array($this->hosts)) {
+ $this->hosts = array($this->hosts);
+ }
- $failed=false;
- switch ($this->library) {
- case 'Memcache':
- if (!$this->_memcache->set($filename, $contents, $this->compress ? MEMCACHE_COMPRESSED : 0, $secs2cache)) {
- $failed=true;
- }
- break;
- case 'Memcached':
- if (!$this->_memcache->set($filename, $contents, $secs2cache)) {
- $failed=true;
- }
- break;
- default:
- $failed=true;
- break;
+ if (!is_array($this->hosts[0])) {
+ // Old way, convert to controller
+ foreach ($this->hosts as $ipAddress) {
+ $connector = $this->serverControllerTemplate;
+ $connector['host'] = $ipAddress;
+ $connector['port'] = $this->port;
+
+ $this->serverControllers[] = $connector;
}
+ } else {
+ // New way, must validate port, etc
+ foreach ($this->hosts as $controller) {
+ $connector = array_merge($this->serverControllerTemplate, $controller);
+ if ($this->isLibMemcached()) {
+ $connector['weight'] = (int)$connector['weight'];
+ } else {
+ // Cannot use weight in memcache, simply discard
+ $connector['weight'] = 0;
+ }
- if($failed) {
- if ($debug) ADOConnection::outp(" Failed to save data at the memcache server!<br>\n");
- return false;
+ $this->serverControllers[] = $connector;
}
+ }
+ // Checks for existing connections ( but only for memcached )
+ if ($this->isLibMemcached() && !empty($memCache->getServerList())) {
+ // Use the existing configuration
+ $this->isConnected = true;
+ $this->memcacheLibrary = $memCache;
return true;
}
- // returns a recordset
- function readcache($filename, &$err, $secs2cache, $rsClass)
- {
- $false = false;
- if (!$this->_connected) $this->connect($err);
- if (!$this->_memcache) return $false;
-
- $rs = $this->_memcache->get($filename);
- if (!$rs) {
- $err = 'Item with such key doesn\'t exist on the memcache server.';
- return $false;
+ $failcnt = 0;
+ foreach ($this->serverControllers as $controller) {
+ if ($this->isLibMemcached()) {
+ if (!@$memCache->addServer($controller['host'], $controller['port'], $controller['weight'])) {
+ $failcnt++;
+ }
+ } else {
+ if (!@$memCache->addServer($controller['host'], $controller['port'])) {
+ $failcnt++;
+ }
}
+ }
+ if ($failcnt == sizeof($this->serverControllers)) {
+ $err = 'Can\'t connect to any memcache server';
+ return false;
+ }
+
+ $this->memcacheLibrary = $memCache;
- // hack, should actually use _csv2rs
- $rs = explode("\n", $rs);
- unset($rs[0]);
- $rs = join("\n", $rs);
- $rs = unserialize($rs);
- if (! is_object($rs)) {
- $err = 'Unable to unserialize $rs';
- return $false;
+ // A valid memcache connection is available
+ $this->isConnected = true;
+ return true;
+ }
+
+ /**
+ * Writes a cached query to the server
+ *
+ * @param string $filename The MD5 of the query to cache
+ * @param string $contents The query results
+ * @param bool $debug
+ * @param int $secs2cache
+ *
+ * @return bool true or false. true if successful save
+ */
+ public function writeCache($filename, $contents, $debug, $secs2cache)
+ {
+ $err = '';
+ if (!$this->isConnected && $debug) {
+ // Call to writeCache() before connect(), try to connect
+ if (!$this->connect($err)) {
+ ADOConnection::outp($err);
}
- if ($rs->timeCreated == 0) return $rs; // apparently have been reports that timeCreated was set to 0 somewhere
-
- $tdiff = intval($rs->timeCreated+$secs2cache - time());
- if ($tdiff <= 2) {
- switch($tdiff) {
- case 2:
- if ((rand() & 15) == 0) {
- $err = "Timeout 2";
- return $false;
- }
- break;
- case 1:
- if ((rand() & 3) == 0) {
- $err = "Timeout 1";
- return $false;
- }
- break;
- default:
- $err = "Timeout 0";
- return $false;
- }
+ } else {
+ if (!$this->isConnected) {
+ $this->connect($err);
}
- return $rs;
}
- function flushall($debug=false)
- {
- if (!$this->_connected) {
- $err = '';
- if (!$this->connect($err) && $debug) ADOConnection::outp($err);
+ if (!$this->memcacheLibrary) {
+ return false;
+ }
+
+ $failed = false;
+ switch ($this->libraryFlag) {
+ case self::MCLIB:
+ if (!$this->memcacheLibrary->set($filename, $contents, $this->compress ? MEMCACHE_COMPRESSED : 0,
+ $secs2cache)) {
+ $failed = true;
+ }
+ break;
+ case self::MCLIBD:
+ if (!$this->memcacheLibrary->set($filename, $contents, $secs2cache)) {
+ $failed = true;
+ }
+ break;
+ default:
+ $failed = true;
+ break;
+ }
+
+ if ($failed) {
+ if ($debug) {
+ ADOConnection::outp(" Failed to save data at the memcache server!<br>\n");
}
- if (!$this->_memcache) return false;
+ return false;
+ }
- $del = $this->_memcache->flush();
+ return true;
+ }
- if ($debug)
- if (!$del) ADOConnection::outp("flushall: failed!<br>\n");
- else ADOConnection::outp("flushall: succeeded!<br>\n");
+ /**
+ * Reads a cached query from the server.
+ *
+ * @param string $filename The MD5 of the query to read
+ * @param string $err The query results
+ * @param int $secs2cache
+ * @param object $rsClass **UNUSED**
+ *
+ * @return object|bool record or false.
+ *
+ * @noinspection PhpUnusedParameterInspection
+ */
+ public function readCache($filename, &$err, $secs2cache, $rsClass)
+ {
+ if (!$this->isConnected) {
+ $this->connect($err);
+ }
+ if (!$this->memcacheLibrary) {
+ return false;
+ }
+
+ $rs = $this->memcacheLibrary->get($filename);
+ if (!$rs) {
+ $err = 'Item with such key doesn\'t exist on the memcache server.';
+ return false;
+ }
+
+ // hack, should actually use _csv2rs
+ $rs = explode("\n", $rs);
+ unset($rs[0]);
+ $rs = join("\n", $rs);
+ $rs = unserialize($rs);
+ if (!is_object($rs)) {
+ $err = 'Unable to unserialize $rs';
+ return false;
+ }
+ if ($rs->timeCreated == 0) {
+ return $rs;
+ } // apparently have been reports that timeCreated was set to 0 somewhere
- return $del;
+ $tdiff = intval($rs->timeCreated + $secs2cache - time());
+ if ($tdiff <= 2) {
+ switch ($tdiff) {
+ case 2:
+ if ((rand() & 15) == 0) {
+ $err = "Timeout 2";
+ return false;
+ }
+ break;
+ case 1:
+ if ((rand() & 3) == 0) {
+ $err = "Timeout 1";
+ return false;
+ }
+ break;
+ default:
+ $err = "Timeout 0";
+ return false;
+ }
}
+ return $rs;
+ }
- function flushcache($filename, $debug=false)
- {
- if (!$this->_connected) {
- $err = '';
- if (!$this->connect($err) && $debug) ADOConnection::outp($err);
+ /**
+ * Flushes all of the stored memcache data
+ *
+ * @param bool $debug
+ *
+ * @return bool The response from the memcache server
+ */
+ public function flushAll($debug = false)
+ {
+ if (!$this->isConnected) {
+ $err = '';
+ if (!$this->connect($err) && $debug) {
+ ADOConnection::outp($err);
}
- if (!$this->_memcache) return false;
+ }
+ if (!$this->memcacheLibrary) {
+ return false;
+ }
- $del = $this->_memcache->delete($filename);
+ $del = $this->memcacheLibrary->flush();
+
+ if ($debug) {
+ if (!$del) {
+ ADOConnection::outp("flushall: failed!<br>\n");
+ } else {
+ ADOConnection::outp("flushall: succeeded!<br>\n");
+ }
+ }
- if ($debug)
- if (!$del) ADOConnection::outp("flushcache: $key entry doesn't exist on memcache server!<br>\n");
- else ADOConnection::outp("flushcache: $key entry flushed from memcache server!<br>\n");
+ return $del;
+ }
- return $del;
+ /**
+ * Flushes the contents of a specified query
+ *
+ * @param string $filename The MD5 of the query to flush
+ * @param bool $debug
+ *
+ * @return bool The response from the memcache server
+ */
+ public function flushCache($filename, $debug = false)
+ {
+ if (!$this->isConnected) {
+ $err = '';
+ if (!$this->connect($err) && $debug) {
+ ADOConnection::outp($err);
+ }
+ }
+ if (!$this->memcacheLibrary) {
+ return false;
}
- // not used for memcache
- function createdir($dir, $hash)
- {
- return true;
+ $del = $this->memcacheLibrary->delete($filename);
+
+ if ($debug) {
+ if (!$del) {
+ ADOConnection::outp("flushcache: $filename entry doesn't exist on memcache server!<br>\n");
+ } else {
+ ADOConnection::outp("flushcache: $filename entry flushed from memcache server!<br>\n");
+ }
}
+
+ return $del;
}
+
+}
diff --git a/adodb-perf.inc.php b/adodb-perf.inc.php
index d9d8a99..9161053 100644
--- a/adodb-perf.inc.php
+++ b/adodb-perf.inc.php
@@ -237,6 +237,9 @@ class adodb_perf {
var $createTableSQL = false;
var $maxLength = 2000;
+ /** @var array Settings data. */
+ var $settings = [];
+
// Sets the tablename to be used
static function table($newtable = false)
{
@@ -1014,7 +1017,7 @@ Committed_AS: 348732 kB
* <code>ADODB_OPT_LOW</code> for CPU-less optimization
* Default is LOW <code>ADODB_OPT_LOW</code>
* @author Markus Staab
- * @return Returns <code>true</code> on success and <code>false</code> on error
+ * @return bool true on success, false on error
*/
function OptimizeTables()
{
@@ -1045,7 +1048,7 @@ Committed_AS: 348732 kB
* <code>ADODB_OPT_LOW</code> for CPU-less optimization
* Default is LOW <code>ADODB_OPT_LOW</code>
* @author Markus Staab
- * @return Returns <code>true</code> on success and <code>false</code> on error
+ * @return bool true on success, false on error
*/
function OptimizeTable( $table, $mode = ADODB_OPT_LOW)
{
@@ -1059,7 +1062,7 @@ Committed_AS: 348732 kB
* optimize each using <code>optmizeTable()</code>
*
* @author Markus Staab
- * @return Returns <code>true</code> on success and <code>false</code> on error
+ * @return bool true on success, false on error
*/
function optimizeDatabase()
{
diff --git a/adodb-time.inc.php b/adodb-time.inc.php
index cfbdc6a..0c3dd11 100644
--- a/adodb-time.inc.php
+++ b/adodb-time.inc.php
@@ -2,6 +2,8 @@
/**
* ADOdb Date Library.
*
+ * @deprecated 5.22.6 Use 64-bit PHP native functions instead.
+ *
* PHP native date functions use integer timestamps for computations.
* Because of this, dates are restricted to the years 1901-2038 on Unix
* and 1970-2038 on Windows due to integer overflow for dates beyond
diff --git a/adodb-xmlschema.inc.php b/adodb-xmlschema.inc.php
index 58e3aff..662e2aa 100644
--- a/adodb-xmlschema.inc.php
+++ b/adodb-xmlschema.inc.php
@@ -26,133 +26,119 @@
* @author Dan Cech
*/
-function _file_get_contents($file)
-{
- if (function_exists('file_get_contents')) return file_get_contents($file);
-
- $f = fopen($file,'r');
- if (!$f) return '';
- $t = '';
-
- while ($s = fread($f,100000)) $t .= $s;
- fclose($f);
- return $t;
-}
-
-
/**
-* Debug on or off
-*/
+ * Debug on or off
+ */
if( !defined( 'XMLS_DEBUG' ) ) {
define( 'XMLS_DEBUG', FALSE );
}
/**
-* Default prefix key
-*/
+ * Default prefix key
+ */
if( !defined( 'XMLS_PREFIX' ) ) {
define( 'XMLS_PREFIX', '%%P' );
}
/**
-* Maximum length allowed for object prefix
-*/
+ * Maximum length allowed for object prefix
+ */
if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) {
define( 'XMLS_PREFIX_MAXLEN', 10 );
}
/**
-* Execute SQL inline as it is generated
-*/
+ * Execute SQL inline as it is generated
+ */
if( !defined( 'XMLS_EXECUTE_INLINE' ) ) {
define( 'XMLS_EXECUTE_INLINE', FALSE );
}
/**
-* Continue SQL Execution if an error occurs?
-*/
+ * Continue SQL Execution if an error occurs?
+ */
if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) {
define( 'XMLS_CONTINUE_ON_ERROR', FALSE );
}
/**
-* Current Schema Version
-*/
+ * Current Schema Version
+ */
if( !defined( 'XMLS_SCHEMA_VERSION' ) ) {
define( 'XMLS_SCHEMA_VERSION', '0.2' );
}
/**
-* Default Schema Version. Used for Schemas without an explicit version set.
-*/
+ * Default Schema Version. Used for Schemas without an explicit version set.
+ */
if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) {
define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' );
}
/**
-* Default Schema Version. Used for Schemas without an explicit version set.
-*/
+ * Default Schema Version. Used for Schemas without an explicit version set.
+ */
if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) {
define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' );
}
/**
-* Include the main ADODB library
-*/
+ * Include the main ADODB library
+ */
if( !defined( '_ADODB_LAYER' ) ) {
require( 'adodb.inc.php' );
require( 'adodb-datadict.inc.php' );
}
/**
-* Abstract DB Object. This class provides basic methods for database objects, such
-* as tables and indexes.
-*
-* @package axmls
-* @access private
-*/
+ * Abstract DB Object. This class provides basic methods for database objects, such
+ * as tables and indexes.
+ *
+ * @package axmls
+ * @access private
+ */
class dbObject {
/**
- * var object Parent
- */
+ * var object Parent
+ */
var $parent;
/**
- * var string current element
- */
+ * var string current element
+ */
var $currentElement;
/**
- * NOP
- */
- function __construct( &$parent, $attributes = NULL ) {
+ * NOP
+ */
+ function __construct( $parent, $attributes = NULL ) {
$this->parent = $parent;
}
/**
- * XML Callback to process start elements
- *
- * @access private
- */
+ * XML Callback to process start elements
+ *
+ * @access private
+ */
function _tag_open( &$parser, $tag, $attributes ) {
}
/**
- * XML Callback to process CDATA elements
- *
- * @access private
- */
+ * XML Callback to process CDATA elements
+ *
+ * @access private
+ */
function _tag_cdata( &$parser, $cdata ) {
}
/**
- * XML Callback to process end elements
- *
- * @access private
- */
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
function _tag_close( &$parser, $tag ) {
}
@@ -162,110 +148,119 @@ class dbObject {
}
/**
- * Destroys the object
- */
+ * Destroys the object
+ */
function destroy() {
}
/**
- * Checks whether the specified RDBMS is supported by the current
- * database object or its ranking ancestor.
- *
- * @param string $platform RDBMS platform name (from ADODB platform list).
- * @return boolean TRUE if RDBMS is supported; otherwise returns FALSE.
- */
+ * Checks whether the specified RDBMS is supported by the current
+ * database object or its ranking ancestor.
+ *
+ * @param string $platform RDBMS platform name (from ADODB platform list).
+ * @return boolean TRUE if RDBMS is supported; otherwise returns FALSE.
+ */
function supportedPlatform( $platform = NULL ) {
return is_object( $this->parent ) ? $this->parent->supportedPlatform( $platform ) : TRUE;
}
/**
- * Returns the prefix set by the ranking ancestor of the database object.
- *
- * @param string $name Prefix string.
- * @return string Prefix.
- */
+ * Returns the prefix set by the ranking ancestor of the database object.
+ *
+ * @param string $name Prefix string.
+ * @return string Prefix.
+ */
function prefix( $name = '' ) {
return is_object( $this->parent ) ? $this->parent->prefix( $name ) : $name;
}
/**
- * Extracts a field ID from the specified field.
- *
- * @param string $field Field.
- * @return string Field ID.
- */
+ * Extracts a field ID from the specified field.
+ *
+ * @param string $field Field.
+ * @return string Field ID.
+ */
function FieldID( $field ) {
return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) );
}
}
/**
-* Creates a table object in ADOdb's datadict format
-*
-* This class stores information about a database table. As charactaristics
-* of the table are loaded from the external source, methods and properties
-* of this class are used to build up the table description in ADOdb's
-* datadict format.
-*
-* @package axmls
-* @access private
-*/
+ * Creates a table object in ADOdb's datadict format
+ *
+ * This class stores information about a database table. As charactaristics
+ * of the table are loaded from the external source, methods and properties
+ * of this class are used to build up the table description in ADOdb's
+ * datadict format.
+ *
+ * @package axmls
+ * @access private
+ */
class dbTable extends dbObject {
/**
- * @var string Table name
- */
+ * @var string Table name
+ */
var $name;
/**
- * @var array Field specifier: Meta-information about each field
- */
+ * @var array Field specifier: Meta-information about each field
+ */
var $fields = array();
/**
- * @var array List of table indexes.
- */
+ * @var array List of table indexes.
+ */
var $indexes = array();
/**
- * @var array Table options: Table-level options
- */
+ * @var array Table options: Table-level options
+ */
var $opts = array();
/**
- * @var string Field index: Keeps track of which field is currently being processed
- */
+ * @var string Field index: Keeps track of which field is currently being processed
+ */
var $current_field;
/**
- * @var boolean Mark table for destruction
- * @access private
- */
+ * @var boolean Mark table for destruction
+ * @access private
+ */
var $drop_table;
/**
- * @var boolean Mark field for destruction (not yet implemented)
- * @access private
- */
+ * @var boolean Mark field for destruction (not yet implemented)
+ * @access private
+ */
var $drop_field = array();
/**
- * Iniitializes a new table object.
- *
- * @param string $prefix DB Object prefix
- * @param array $attributes Array of table attributes.
- */
- function __construct( &$parent, $attributes = NULL ) {
+ * @var array Platform-specific options
+ * @access private
+ */
+ var $currentPlatform = true;
+
+ /** @var dbData Stores information about table data. */
+ var $data;
+
+ /**
+ * Iniitializes a new table object.
+ *
+ * @param string $prefix DB Object prefix
+ * @param array $attributes Array of table attributes.
+ */
+ function __construct( $parent, $attributes = NULL ) {
$this->parent = $parent;
$this->name = $this->prefix($attributes['NAME']);
}
/**
- * XML Callback to process start elements. Elements currently
- * processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & DEFAULT.
- *
- * @access private
- */
+ * XML Callback to process start elements. Elements currently
+ * processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & DEFAULT.
+ *
+ * @access private
+ */
function _tag_open( &$parser, $tag, $attributes ) {
$this->currentElement = strtoupper( $tag );
@@ -321,10 +316,10 @@ class dbTable extends dbObject {
}
/**
- * XML Callback to process CDATA elements
- *
- * @access private
- */
+ * XML Callback to process CDATA elements
+ *
+ * @access private
+ */
function _tag_cdata( &$parser, $cdata ) {
switch( $this->currentElement ) {
// Table constraint
@@ -345,10 +340,10 @@ class dbTable extends dbObject {
}
/**
- * XML Callback to process end elements
- *
- * @access private
- */
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
function _tag_close( &$parser, $tag ) {
$this->currentElement = '';
@@ -366,11 +361,11 @@ class dbTable extends dbObject {
}
/**
- * Adds an index to a table object
- *
- * @param array $attributes Index attributes
- * @return object dbIndex object
- */
+ * Adds an index to a table object
+ *
+ * @param array $attributes Index attributes
+ * @return object dbIndex object
+ */
function addIndex( $attributes ) {
$name = strtoupper( $attributes['NAME'] );
$this->indexes[$name] = new dbIndex( $this, $attributes );
@@ -378,11 +373,11 @@ class dbTable extends dbObject {
}
/**
- * Adds data to a table object
- *
- * @param array $attributes Data attributes
- * @return object dbData object
- */
+ * Adds data to a table object
+ *
+ * @param array $attributes Data attributes
+ * @return object dbData object
+ */
function addData( $attributes ) {
if( !isset( $this->data ) ) {
$this->data = new dbData( $this, $attributes );
@@ -391,34 +386,34 @@ class dbTable extends dbObject {
}
/**
- * Adds a field to a table object
- *
- * $name is the name of the table to which the field should be added.
- * $type is an ADODB datadict field type. The following field types
- * are supported as of ADODB 3.40:
- * - C: varchar
- * - X: CLOB (character large object) or largest varchar size
- * if CLOB is not supported
- * - C2: Multibyte varchar
- * - X2: Multibyte CLOB
- * - B: BLOB (binary large object)
- * - D: Date (some databases do not support this, and we return a datetime type)
- * - T: Datetime or Timestamp
- * - L: Integer field suitable for storing booleans (0 or 1)
- * - I: Integer (mapped to I4)
- * - I1: 1-byte integer
- * - I2: 2-byte integer
- * - I4: 4-byte integer
- * - I8: 8-byte integer
- * - F: Floating point number
- * - N: Numeric or decimal number
- *
- * @param string $name Name of the table to which the field will be added.
- * @param string $type ADODB datadict field type.
- * @param string $size Field size
- * @param array $opts Field options array
- * @return array Field specifier array
- */
+ * Adds a field to a table object
+ *
+ * $name is the name of the table to which the field should be added.
+ * $type is an ADODB datadict field type. The following field types
+ * are supported as of ADODB 3.40:
+ * - C: varchar
+ * - X: CLOB (character large object) or largest varchar size
+ * if CLOB is not supported
+ * - C2: Multibyte varchar
+ * - X2: Multibyte CLOB
+ * - B: BLOB (binary large object)
+ * - D: Date (some databases do not support this, and we return a datetime type)
+ * - T: Datetime or Timestamp
+ * - L: Integer field suitable for storing booleans (0 or 1)
+ * - I: Integer (mapped to I4)
+ * - I1: 1-byte integer
+ * - I2: 2-byte integer
+ * - I4: 4-byte integer
+ * - I8: 8-byte integer
+ * - F: Floating point number
+ * - N: Numeric or decimal number
+ *
+ * @param string $name Name of the table to which the field will be added.
+ * @param string $type ADODB datadict field type.
+ * @param string $size Field size
+ * @param array $opts Field options array
+ * @return void
+ */
function addField( $name, $type, $size = NULL, $opts = NULL ) {
$field_id = $this->FieldID( $name );
@@ -443,16 +438,16 @@ class dbTable extends dbObject {
}
/**
- * Adds a field option to the current field specifier
- *
- * This method adds a field option allowed by the ADOdb datadict
- * and appends it to the given field.
- *
- * @param string $field Field name
- * @param string $opt ADOdb field option
- * @param mixed $value Field option value
- * @return array Field specifier array
- */
+ * Adds a field option to the current field specifier
+ *
+ * This method adds a field option allowed by the ADOdb datadict
+ * and appends it to the given field.
+ *
+ * @param string $field Field name
+ * @param string $opt ADOdb field option
+ * @param mixed $value Field option value
+ * @return void
+ */
function addFieldOpt( $field, $opt, $value = NULL ) {
if( !isset( $value ) ) {
$this->fields[$this->FieldID( $field )]['OPTS'][] = $opt;
@@ -463,14 +458,14 @@ class dbTable extends dbObject {
}
/**
- * Adds an option to the table
- *
- * This method takes a comma-separated list of table-level options
- * and appends them to the table object.
- *
- * @param string $opt Table option
- * @return array Options
- */
+ * Adds an option to the table
+ *
+ * This method takes a comma-separated list of table-level options
+ * and appends them to the table object.
+ *
+ * @param string $opt Table option
+ * @return array Options
+ */
function addTableOpt( $opt ) {
if(isset($this->currentPlatform)) {
$this->opts[$this->parent->db->databaseType] = $opt;
@@ -480,11 +475,11 @@ class dbTable extends dbObject {
/**
- * Generates the SQL that will create the table in the database
- *
- * @param object $xmls adoSchema object
- * @return array Array containing table creation SQL
- */
+ * Generates the SQL that will create the table in the database
+ *
+ * @param object $xmls adoSchema object
+ * @return array Array containing table creation SQL
+ */
function create( &$xmls ) {
$sql = array();
@@ -592,8 +587,8 @@ class dbTable extends dbObject {
}
/**
- * Marks a field or table for destruction
- */
+ * Marks a field or table for destruction
+ */
function drop() {
if( isset( $this->current_field ) ) {
// Drop the current field
@@ -610,61 +605,61 @@ class dbTable extends dbObject {
}
/**
-* Creates an index object in ADOdb's datadict format
-*
-* This class stores information about a database index. As charactaristics
-* of the index are loaded from the external source, methods and properties
-* of this class are used to build up the index description in ADOdb's
-* datadict format.
-*
-* @package axmls
-* @access private
-*/
+ * Creates an index object in ADOdb's datadict format
+ *
+ * This class stores information about a database index. As charactaristics
+ * of the index are loaded from the external source, methods and properties
+ * of this class are used to build up the index description in ADOdb's
+ * datadict format.
+ *
+ * @package axmls
+ * @access private
+ */
class dbIndex extends dbObject {
/**
- * @var string Index name
- */
+ * @var string Index name
+ */
var $name;
/**
- * @var array Index options: Index-level options
- */
+ * @var array Index options: Index-level options
+ */
var $opts = array();
/**
- * @var array Indexed fields: Table columns included in this index
- */
+ * @var array Indexed fields: Table columns included in this index
+ */
var $columns = array();
/**
- * @var boolean Mark index for destruction
- * @access private
- */
+ * @var boolean Mark index for destruction
+ * @access private
+ */
var $drop = FALSE;
/**
- * Initializes the new dbIndex object.
- *
- * @param object $parent Parent object
- * @param array $attributes Attributes
- *
- * @internal
- */
- function __construct( &$parent, $attributes = NULL ) {
+ * Initializes the new dbIndex object.
+ *
+ * @param object $parent Parent object
+ * @param array $attributes Attributes
+ *
+ * @internal
+ */
+ function __construct( $parent, $attributes = NULL ) {
$this->parent = $parent;
$this->name = $this->prefix ($attributes['NAME']);
}
/**
- * XML Callback to process start elements
- *
- * Processes XML opening tags.
- * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH.
- *
- * @access private
- */
+ * XML Callback to process start elements
+ *
+ * Processes XML opening tags.
+ * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH.
+ *
+ * @access private
+ */
function _tag_open( &$parser, $tag, $attributes ) {
$this->currentElement = strtoupper( $tag );
@@ -686,12 +681,12 @@ class dbIndex extends dbObject {
}
/**
- * XML Callback to process CDATA elements
- *
- * Processes XML cdata.
- *
- * @access private
- */
+ * XML Callback to process CDATA elements
+ *
+ * Processes XML cdata.
+ *
+ * @access private
+ */
function _tag_cdata( &$parser, $cdata ) {
switch( $this->currentElement ) {
// Index field name
@@ -704,10 +699,10 @@ class dbIndex extends dbObject {
}
/**
- * XML Callback to process end elements
- *
- * @access private
- */
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
function _tag_close( &$parser, $tag ) {
$this->currentElement = '';
@@ -719,11 +714,11 @@ class dbIndex extends dbObject {
}
/**
- * Adds a field to the index
- *
- * @param string $name Field name
- * @return string Field list
- */
+ * Adds a field to the index
+ *
+ * @param string $name Field name
+ * @return string Field list
+ */
function addField( $name ) {
$this->columns[$this->FieldID( $name )] = $name;
@@ -732,11 +727,11 @@ class dbIndex extends dbObject {
}
/**
- * Adds options to the index
- *
- * @param string $opt Comma-separated list of index options.
- * @return string Option list
- */
+ * Adds options to the index
+ *
+ * @param string $opt Comma-separated list of index options.
+ * @return string Option list
+ */
function addIndexOpt( $opt ) {
$this->opts[] = $opt;
@@ -745,11 +740,11 @@ class dbIndex extends dbObject {
}
/**
- * Generates the SQL that will create the index in the database
- *
- * @param object $xmls adoSchema object
- * @return array Array containing index creation SQL
- */
+ * Generates the SQL that will create the index in the database
+ *
+ * @param object $xmls adoSchema object
+ * @return array Array containing index creation SQL
+ */
function create( &$xmls ) {
if( $this->drop ) {
return NULL;
@@ -766,47 +761,50 @@ class dbIndex extends dbObject {
}
/**
- * Marks an index for destruction
- */
+ * Marks an index for destruction
+ */
function drop() {
$this->drop = TRUE;
}
}
/**
-* Creates a data object in ADOdb's datadict format
-*
-* This class stores information about table data.
-*
-* @package axmls
-* @access private
-*/
+ * Creates a data object in ADOdb's datadict format
+ *
+ * This class stores information about table data.
+ *
+ * @package axmls
+ * @access private
+ */
class dbData extends dbObject {
var $data = array();
var $row;
+ /** @var string Field name */
+ var $current_field;
+
/**
- * Initializes the new dbIndex object.
- *
- * @param object $parent Parent object
- * @param array $attributes Attributes
- *
- * @internal
- */
- function __construct( &$parent, $attributes = NULL ) {
+ * Initializes the new dbIndex object.
+ *
+ * @param object $parent Parent object
+ * @param array $attributes Attributes
+ *
+ * @internal
+ */
+ function __construct( $parent, $attributes = NULL ) {
$this->parent = $parent;
}
/**
- * XML Callback to process start elements
- *
- * Processes XML opening tags.
- * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH.
- *
- * @access private
- */
+ * XML Callback to process start elements
+ *
+ * Processes XML opening tags.
+ * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH.
+ *
+ * @access private
+ */
function _tag_open( &$parser, $tag, $attributes ) {
$this->currentElement = strtoupper( $tag );
@@ -823,12 +821,12 @@ class dbData extends dbObject {
}
/**
- * XML Callback to process CDATA elements
- *
- * Processes XML cdata.
- *
- * @access private
- */
+ * XML Callback to process CDATA elements
+ *
+ * Processes XML cdata.
+ *
+ * @access private
+ */
function _tag_cdata( &$parser, $cdata ) {
switch( $this->currentElement ) {
// Index field name
@@ -841,10 +839,10 @@ class dbData extends dbObject {
}
/**
- * XML Callback to process end elements
- *
- * @access private
- */
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
function _tag_close( &$parser, $tag ) {
$this->currentElement = '';
@@ -856,11 +854,11 @@ class dbData extends dbObject {
}
/**
- * Adds a field to the index
- *
- * @param string $name Field name
- * @return string Field list
- */
+ * Adds a field to the index
+ *
+ * @param string $name Field name
+ * @return string Field list
+ */
function addField( $attributes ) {
if( isset( $attributes['NAME'] ) ) {
$name = $attributes['NAME'];
@@ -873,11 +871,11 @@ class dbData extends dbObject {
}
/**
- * Adds options to the index
- *
- * @param string $opt Comma-separated list of index options.
- * @return string Option list
- */
+ * Adds options to the index
+ *
+ * @param string $opt Comma-separated list of index options.
+ * @return string Option list
+ */
function addData( $cdata ) {
if( !isset( $this->data[$this->row] ) ) {
$this->data[$this->row] = array();
@@ -891,11 +889,11 @@ class dbData extends dbObject {
}
/**
- * Generates the SQL that will create the index in the database
- *
- * @param object $xmls adoSchema object
- * @return array Array containing index creation SQL
- */
+ * Generates the SQL that will create the index in the database
+ *
+ * @param object $xmls adoSchema object
+ * @return array Array containing index creation SQL
+ */
function create( &$xmls ) {
$table = $xmls->dict->TableName($this->parent->name);
$table_field_count = count($this->parent->fields);
@@ -909,7 +907,8 @@ class dbData extends dbObject {
foreach( $row as $field_id => $field_data ) {
if( !array_key_exists( $field_id, $table_fields ) ) {
if( is_numeric( $field_id ) ) {
- $field_id = reset( array_keys( $table_fields ) );
+ $keys = array_keys($table_fields);
+ $field_id = reset($keys);
} else {
continue;
}
@@ -961,40 +960,40 @@ class dbData extends dbObject {
}
/**
-* Creates the SQL to execute a list of provided SQL queries
-*
-* @package axmls
-* @access private
-*/
+ * Creates the SQL to execute a list of provided SQL queries
+ *
+ * @package axmls
+ * @access private
+ */
class dbQuerySet extends dbObject {
/**
- * @var array List of SQL queries
- */
+ * @var array List of SQL queries
+ */
var $queries = array();
/**
- * @var string String used to build of a query line by line
- */
+ * @var string String used to build of a query line by line
+ */
var $query;
/**
- * @var string Query prefix key
- */
+ * @var string Query prefix key
+ */
var $prefixKey = '';
/**
- * @var boolean Auto prefix enable (TRUE)
- */
+ * @var boolean Auto prefix enable (TRUE)
+ */
var $prefixMethod = 'AUTO';
/**
- * Initializes the query set.
- *
- * @param object $parent Parent object
- * @param array $attributes Attributes
- */
- function __construct( &$parent, $attributes = NULL ) {
+ * Initializes the query set.
+ *
+ * @param object $parent Parent object
+ * @param array $attributes Attributes
+ */
+ function __construct( $parent, $attributes = NULL ) {
$this->parent = $parent;
// Overrides the manual prefix key
@@ -1019,11 +1018,11 @@ class dbQuerySet extends dbObject {
}
/**
- * XML Callback to process start elements. Elements currently
- * processed are: QUERY.
- *
- * @access private
- */
+ * XML Callback to process start elements. Elements currently
+ * processed are: QUERY.
+ *
+ * @access private
+ */
function _tag_open( &$parser, $tag, $attributes ) {
$this->currentElement = strtoupper( $tag );
@@ -1044,8 +1043,8 @@ class dbQuerySet extends dbObject {
}
/**
- * XML Callback to process CDATA elements
- */
+ * XML Callback to process CDATA elements
+ */
function _tag_cdata( &$parser, $cdata ) {
switch( $this->currentElement ) {
// Line of queryset SQL data
@@ -1058,10 +1057,10 @@ class dbQuerySet extends dbObject {
}
/**
- * XML Callback to process end elements
- *
- * @access private
- */
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
function _tag_close( &$parser, $tag ) {
$this->currentElement = '';
@@ -1081,10 +1080,10 @@ class dbQuerySet extends dbObject {
}
/**
- * Re-initializes the query.
- *
- * @return boolean TRUE
- */
+ * Re-initializes the query.
+ *
+ * @return boolean TRUE
+ */
function newQuery() {
$this->query = '';
@@ -1092,10 +1091,10 @@ class dbQuerySet extends dbObject {
}
/**
- * Discards the existing query.
- *
- * @return boolean TRUE
- */
+ * Discards the existing query.
+ *
+ * @return boolean TRUE
+ */
function discardQuery() {
unset( $this->query );
@@ -1103,11 +1102,11 @@ class dbQuerySet extends dbObject {
}
/**
- * Appends a line to a query that is being built line by line
- *
- * @param string $data Line of SQL data or NULL to initialize a new query
- * @return string SQL query string.
- */
+ * Appends a line to a query that is being built line by line
+ *
+ * @param string $data Line of SQL data or NULL to initialize a new query
+ * @return string SQL query string.
+ */
function buildQuery( $sql = NULL ) {
if( !isset( $this->query ) OR empty( $sql ) ) {
return FALSE;
@@ -1119,10 +1118,10 @@ class dbQuerySet extends dbObject {
}
/**
- * Adds a completed query to the query list
- *
- * @return string SQL of added query
- */
+ * Adds a completed query to the query list
+ *
+ * @return string SQL of added query
+ */
function addQuery() {
if( !isset( $this->query ) ) {
return FALSE;
@@ -1136,11 +1135,11 @@ class dbQuerySet extends dbObject {
}
/**
- * Creates and returns the current query set
- *
- * @param object $xmls adoSchema object
- * @return array Query set
- */
+ * Creates and returns the current query set
+ *
+ * @param object $xmls adoSchema object
+ * @return array Query set
+ */
function create( &$xmls ) {
foreach( $this->queries as $id => $query ) {
switch( $this->prefixMethod ) {
@@ -1176,13 +1175,13 @@ class dbQuerySet extends dbObject {
}
/**
- * Rebuilds the query with the prefix attached to any objects
- *
- * @param string $regex Regex used to add prefix
- * @param string $query SQL query string
- * @param string $prefix Prefix to be appended to tables, indices, etc.
- * @return string Prefixed SQL query string.
- */
+ * Rebuilds the query with the prefix attached to any objects
+ *
+ * @param string $regex Regex used to add prefix
+ * @param string $query SQL query string
+ * @param string $prefix Prefix to be appended to tables, indices, etc.
+ * @return string Prefixed SQL query string.
+ */
function prefixQuery( $regex, $query, $prefix = NULL ) {
if( !isset( $prefix ) ) {
return $query;
@@ -1212,98 +1211,101 @@ class dbQuerySet extends dbObject {
}
/**
-* Loads and parses an XML file, creating an array of "ready-to-run" SQL statements
-*
-* This class is used to load and parse the XML file, to create an array of SQL statements
-* that can be used to build a database, and to build the database using the SQL array.
-*
-* @tutorial getting_started.pkg
-*
-* @author Richard Tango-Lowy & Dan Cech
-* @version $Revision: 1.12 $
-*
-* @package axmls
-*/
+ * Loads and parses an XML file, creating an array of "ready-to-run" SQL statements
+ *
+ * This class is used to load and parse the XML file, to create an array of SQL statements
+ * that can be used to build a database, and to build the database using the SQL array.
+ *
+ * @tutorial getting_started.pkg
+ *
+ * @author Richard Tango-Lowy & Dan Cech
+ * @version 1.12
+ *
+ * @package axmls
+ */
class adoSchema {
/**
- * @var array Array containing SQL queries to generate all objects
- * @access private
- */
+ * @var array Array containing SQL queries to generate all objects
+ * @access private
+ */
var $sqlArray;
/**
- * @var object ADOdb connection object
- * @access private
- */
+ * @var object ADOdb connection object
+ * @access private
+ */
var $db;
/**
- * @var object ADOdb Data Dictionary
- * @access private
- */
+ * @var object ADOdb Data Dictionary
+ * @access private
+ */
var $dict;
/**
- * @var string Current XML element
- * @access private
- */
+ * @var string Current XML element
+ * @access private
+ */
var $currentElement = '';
/**
- * @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing database
- * @access private
- */
+ * @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing database
+ * @access private
+ */
var $upgrade = '';
/**
- * @var string Optional object prefix
- * @access private
- */
+ * @var string Optional object prefix
+ * @access private
+ */
var $objectPrefix = '';
/**
- * @var long System debug
- * @access private
- */
+ * @var long System debug
+ * @access private
+ */
var $debug;
/**
- * @var string Regular expression to find schema version
- * @access private
- */
+ * @var string Regular expression to find schema version
+ * @access private
+ */
var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
/**
- * @var string Current schema version
- * @access private
- */
+ * @var string Current schema version
+ * @access private
+ */
var $schemaVersion;
/**
- * @var int Success of last Schema execution
- */
+ * @var int Success of last Schema execution
+ */
var $success;
/**
- * @var bool Execute SQL inline as it is generated
- */
+ * @var bool Execute SQL inline as it is generated
+ */
var $executeInline;
/**
- * @var bool Continue SQL execution if errors occur
- */
+ * @var bool Continue SQL execution if errors occur
+ */
var $continueOnError;
+ /** @var dbTable A table object. */
+ var $obj;
+
/**
- * Creates an adoSchema object
- *
- * Creating an adoSchema object is the first step in processing an XML schema.
- * The only parameter is an ADOdb database connection object, which must already
- * have been created.
- *
- * @param object $db ADOdb database connection object.
- */
+ * Creates an adoSchema object
+ *
+ * Creating an adoSchema object is the first step in processing an XML schema.
+ * The only parameter is an ADOdb database connection object, which must already
+ * have been created.
+ *
+ * @param object $db ADOdb database connection object.
+ */
function __construct( $db ) {
$this->db = $db;
$this->debug = $this->db->debug;
@@ -1316,21 +1318,21 @@ class adoSchema {
}
/**
- * Sets the method to be used for upgrading an existing database
- *
- * Use this method to specify how existing database objects should be upgraded.
- * The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER attempts to
- * alter each database object directly, REPLACE attempts to rebuild each object
- * from scratch, BEST attempts to determine the best upgrade method for each
- * object, and NONE disables upgrading.
- *
- * This method is not yet used by AXMLS, but exists for backward compatibility.
- * The ALTER method is automatically assumed when the adoSchema object is
- * instantiated; other upgrade methods are not currently supported.
- *
- * @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE)
- * @returns string Upgrade method used
- */
+ * Sets the method to be used for upgrading an existing database
+ *
+ * Use this method to specify how existing database objects should be upgraded.
+ * The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER attempts to
+ * alter each database object directly, REPLACE attempts to rebuild each object
+ * from scratch, BEST attempts to determine the best upgrade method for each
+ * object, and NONE disables upgrading.
+ *
+ * This method is not yet used by AXMLS, but exists for backward compatibility.
+ * The ALTER method is automatically assumed when the adoSchema object is
+ * instantiated; other upgrade methods are not currently supported.
+ *
+ * @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE)
+ * @returns string Upgrade method used
+ */
function SetUpgradeMethod( $method = '' ) {
if( !is_string( $method ) ) {
return FALSE;
@@ -1361,18 +1363,19 @@ class adoSchema {
}
/**
- * Enables/disables inline SQL execution.
- *
- * Call this method to enable or disable inline execution of the schema. If the mode is set to TRUE (inline execution),
- * AXMLS applies the SQL to the database immediately as each schema entity is parsed. If the mode
- * is set to FALSE (post execution), AXMLS parses the entire schema and you will need to call adoSchema::ExecuteSchema()
- * to apply the schema to the database.
- *
- * @param bool $mode execute
- * @return bool current execution mode
- *
- * @see ParseSchema(), ExecuteSchema()
- */
+ * Enables/disables inline SQL execution.
+ *
+ * Call this method to enable or disable inline execution of the schema. If the mode is set to TRUE (inline execution),
+ * AXMLS applies the SQL to the database immediately as each schema entity is parsed. If the mode
+ * is set to FALSE (post execution), AXMLS parses the entire schema and you will need to call adoSchema::ExecuteSchema()
+ * to apply the schema to the database.
+ *
+ * @param bool $mode execute
+ * @return bool current execution mode
+ *
+ * @see ParseSchema()
+ * @see ExecuteSchema()
+ */
function ExecuteInline( $mode = NULL ) {
if( is_bool( $mode ) ) {
$this->executeInline = $mode;
@@ -1382,18 +1385,19 @@ class adoSchema {
}
/**
- * Enables/disables SQL continue on error.
- *
- * Call this method to enable or disable continuation of SQL execution if an error occurs.
- * If the mode is set to TRUE (continue), AXMLS will continue to apply SQL to the database, even if an error occurs.
- * If the mode is set to FALSE (halt), AXMLS will halt execution of generated sql if an error occurs, though parsing
- * of the schema will continue.
- *
- * @param bool $mode execute
- * @return bool current continueOnError mode
- *
- * @see addSQL(), ExecuteSchema()
- */
+ * Enables/disables SQL continue on error.
+ *
+ * Call this method to enable or disable continuation of SQL execution if an error occurs.
+ * If the mode is set to TRUE (continue), AXMLS will continue to apply SQL to the database, even if an error occurs.
+ * If the mode is set to FALSE (halt), AXMLS will halt execution of generated sql if an error occurs, though parsing
+ * of the schema will continue.
+ *
+ * @param bool $mode execute
+ * @return bool current continueOnError mode
+ *
+ * @see addSQL()
+ * @see ExecuteSchema()
+ */
function ContinueOnError( $mode = NULL ) {
if( is_bool( $mode ) ) {
$this->continueOnError = $mode;
@@ -1403,33 +1407,34 @@ class adoSchema {
}
/**
- * Loads an XML schema from a file and converts it to SQL.
- *
- * Call this method to load the specified schema (see the DTD for the proper format) from
- * the filesystem and generate the SQL necessary to create the database described.
- * @see ParseSchemaString()
- *
- * @param string $file Name of XML schema file.
- * @param bool $returnSchema Return schema rather than parsing.
- * @return array Array of SQL queries, ready to execute
- */
+ * Loads an XML schema from a file and converts it to SQL.
+ *
+ * Call this method to load the specified schema (see the DTD for the proper format) from
+ * the filesystem and generate the SQL necessary to create the database described.
+ * @see ParseSchemaString()
+ *
+ * @param string $file Name of XML schema file.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute
+ */
function ParseSchema( $filename, $returnSchema = FALSE ) {
return $this->ParseSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
}
/**
- * Loads an XML schema from a file and converts it to SQL.
- *
- * Call this method to load the specified schema from a file (see the DTD for the proper format)
- * and generate the SQL necessary to create the database described by the schema.
- *
- * @param string $file Name of XML schema file.
- * @param bool $returnSchema Return schema rather than parsing.
- * @return array Array of SQL queries, ready to execute.
- *
- * @deprecated Replaced by adoSchema::ParseSchema() and adoSchema::ParseSchemaString()
- * @see ParseSchema(), ParseSchemaString()
- */
+ * Loads an XML schema from a file and converts it to SQL.
+ *
+ * Call this method to load the specified schema from a file (see the DTD for the proper format)
+ * and generate the SQL necessary to create the database described by the schema.
+ *
+ * @param string $file Name of XML schema file.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute.
+ *
+ * @deprecated Replaced by adoSchema::ParseSchema() and adoSchema::ParseSchemaString()
+ * @see ParseSchema()
+ * @see ParseSchemaString()
+ */
function ParseSchemaFile( $filename, $returnSchema = FALSE ) {
// Open the file
if( !($fp = fopen( $filename, 'r' )) ) {
@@ -1472,16 +1477,16 @@ class adoSchema {
}
/**
- * Converts an XML schema string to SQL.
- *
- * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
- * and generate the SQL necessary to create the database described by the schema.
- * @see ParseSchema()
- *
- * @param string $xmlstring XML schema string.
- * @param bool $returnSchema Return schema rather than parsing.
- * @return array Array of SQL queries, ready to execute.
- */
+ * Converts an XML schema string to SQL.
+ *
+ * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
+ * and generate the SQL necessary to create the database described by the schema.
+ * @see ParseSchema()
+ *
+ * @param string $xmlstring XML schema string.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute.
+ */
function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) {
if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
return FALSE;
@@ -1515,31 +1520,31 @@ class adoSchema {
}
/**
- * Loads an XML schema from a file and converts it to uninstallation SQL.
- *
- * Call this method to load the specified schema (see the DTD for the proper format) from
- * the filesystem and generate the SQL necessary to remove the database described.
- * @see RemoveSchemaString()
- *
- * @param string $file Name of XML schema file.
- * @param bool $returnSchema Return schema rather than parsing.
- * @return array Array of SQL queries, ready to execute
- */
+ * Loads an XML schema from a file and converts it to uninstallation SQL.
+ *
+ * Call this method to load the specified schema (see the DTD for the proper format) from
+ * the filesystem and generate the SQL necessary to remove the database described.
+ * @see RemoveSchemaString()
+ *
+ * @param string $file Name of XML schema file.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute
+ */
function RemoveSchema( $filename, $returnSchema = FALSE ) {
return $this->RemoveSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
}
/**
- * Converts an XML schema string to uninstallation SQL.
- *
- * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
- * and generate the SQL necessary to uninstall the database described by the schema.
- * @see RemoveSchema()
- *
- * @param string $schema XML schema string.
- * @param bool $returnSchema Return schema rather than parsing.
- * @return array Array of SQL queries, ready to execute.
- */
+ * Converts an XML schema string to uninstallation SQL.
+ *
+ * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
+ * and generate the SQL necessary to uninstall the database described by the schema.
+ * @see RemoveSchema()
+ *
+ * @param string $schema XML schema string.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute.
+ */
function RemoveSchemaString( $schema, $returnSchema = FALSE ) {
// grab current version
@@ -1551,18 +1556,20 @@ class adoSchema {
}
/**
- * Applies the current XML schema to the database (post execution).
- *
- * Call this method to apply the current schema (generally created by calling
- * ParseSchema() or ParseSchemaString() ) to the database (creating the tables, indexes,
- * and executing other SQL specified in the schema) after parsing.
- * @see ParseSchema(), ParseSchemaString(), ExecuteInline()
- *
- * @param array $sqlArray Array of SQL statements that will be applied rather than
- * the current schema.
- * @param boolean $continueOnErr Continue to apply the schema even if an error occurs.
- * @returns integer 0 if failure, 1 if errors, 2 if successful.
- */
+ * Applies the current XML schema to the database (post execution).
+ *
+ * Call this method to apply the current schema (generally created by calling
+ * ParseSchema() or ParseSchemaString() ) to the database (creating the tables, indexes,
+ * and executing other SQL specified in the schema) after parsing.
+ * @see ParseSchema()
+ * @see ParseSchemaString()
+ * @see ExecuteInline()
+ *
+ * @param array $sqlArray Array of SQL statements that will be applied rather than
+ * the current schema.
+ * @param boolean $continueOnErr Continue to apply the schema even if an error occurs.
+ * @returns integer 0 if failure, 1 if errors, 2 if successful.
+ */
function ExecuteSchema( $sqlArray = NULL, $continueOnErr = NULL ) {
if( !is_bool( $continueOnErr ) ) {
$continueOnErr = $this->ContinueOnError();
@@ -1582,28 +1589,28 @@ class adoSchema {
}
/**
- * Returns the current SQL array.
- *
- * Call this method to fetch the array of SQL queries resulting from
- * ParseSchema() or ParseSchemaString().
- *
- * @param string $format Format: HTML, TEXT, or NONE (PHP array)
- * @return array Array of SQL statements or FALSE if an error occurs
- */
+ * Returns the current SQL array.
+ *
+ * Call this method to fetch the array of SQL queries resulting from
+ * ParseSchema() or ParseSchemaString().
+ *
+ * @param string $format Format: HTML, TEXT, or NONE (PHP array)
+ * @return array Array of SQL statements or FALSE if an error occurs
+ */
function PrintSQL( $format = 'NONE' ) {
$sqlArray = null;
return $this->getSQL( $format, $sqlArray );
}
/**
- * Saves the current SQL array to the local filesystem as a list of SQL queries.
- *
- * Call this method to save the array of SQL queries (generally resulting from a
- * parsed XML schema) to the filesystem.
- *
- * @param string $filename Path and name where the file should be saved.
- * @return boolean TRUE if save is successful, else FALSE.
- */
+ * Saves the current SQL array to the local filesystem as a list of SQL queries.
+ *
+ * Call this method to save the array of SQL queries (generally resulting from a
+ * parsed XML schema) to the filesystem.
+ *
+ * @param string $filename Path and name where the file should be saved.
+ * @return boolean TRUE if save is successful, else FALSE.
+ */
function SaveSQL( $filename = './schema.sql' ) {
if( !isset( $sqlArray ) ) {
@@ -1622,12 +1629,12 @@ class adoSchema {
}
/**
- * Create an xml parser
- *
- * @return object PHP XML parser object
- *
- * @access private
- */
+ * Create an xml parser
+ *
+ * @return object PHP XML parser object
+ *
+ * @access private
+ */
function create_parser() {
// Create the parser
$xmlParser = xml_parser_create();
@@ -1641,10 +1648,10 @@ class adoSchema {
}
/**
- * XML Callback to process start elements
- *
- * @access private
- */
+ * XML Callback to process start elements
+ *
+ * @access private
+ */
function _tag_open( &$parser, $tag, $attributes ) {
switch( strtoupper( $tag ) ) {
case 'TABLE':
@@ -1664,39 +1671,39 @@ class adoSchema {
}
/**
- * XML Callback to process CDATA elements
- *
- * @access private
- */
+ * XML Callback to process CDATA elements
+ *
+ * @access private
+ */
function _tag_cdata( &$parser, $cdata ) {
}
/**
- * XML Callback to process end elements
- *
- * @access private
- * @internal
- */
+ * XML Callback to process end elements
+ *
+ * @access private
+ * @internal
+ */
function _tag_close( &$parser, $tag ) {
}
/**
- * Converts an XML schema string to the specified DTD version.
- *
- * Call this method to convert a string containing an XML schema to a different AXMLS
- * DTD version. For instance, to convert a schema created for an pre-1.0 version for
- * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
- * parameter is specified, the schema will be converted to the current DTD version.
- * If the newFile parameter is provided, the converted schema will be written to the specified
- * file.
- * @see ConvertSchemaFile()
- *
- * @param string $schema String containing XML schema that will be converted.
- * @param string $newVersion DTD version to convert to.
- * @param string $newFile File name of (converted) output file.
- * @return string Converted XML schema or FALSE if an error occurs.
- */
+ * Converts an XML schema string to the specified DTD version.
+ *
+ * Call this method to convert a string containing an XML schema to a different AXMLS
+ * DTD version. For instance, to convert a schema created for an pre-1.0 version for
+ * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
+ * parameter is specified, the schema will be converted to the current DTD version.
+ * If the newFile parameter is provided, the converted schema will be written to the specified
+ * file.
+ * @see ConvertSchemaFile()
+ *
+ * @param string $schema String containing XML schema that will be converted.
+ * @param string $newVersion DTD version to convert to.
+ * @param string $newFile File name of (converted) output file.
+ * @return string Converted XML schema or FALSE if an error occurs.
+ */
function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = NULL ) {
// grab current version
@@ -1722,29 +1729,22 @@ class adoSchema {
return $result;
}
- // compat for pre-4.3 - jlim
- function _file_get_contents($path)
- {
- if (function_exists('file_get_contents')) return file_get_contents($path);
- return join('',file($path));
- }
-
- /**
- * Converts an XML schema file to the specified DTD version.
- *
- * Call this method to convert the specified XML schema file to a different AXMLS
- * DTD version. For instance, to convert a schema created for an pre-1.0 version for
- * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
- * parameter is specified, the schema will be converted to the current DTD version.
- * If the newFile parameter is provided, the converted schema will be written to the specified
- * file.
- * @see ConvertSchemaString()
- *
- * @param string $filename Name of XML schema file that will be converted.
- * @param string $newVersion DTD version to convert to.
- * @param string $newFile File name of (converted) output file.
- * @return string Converted XML schema or FALSE if an error occurs.
- */
+ /**
+ * Converts an XML schema file to the specified DTD version.
+ *
+ * Call this method to convert the specified XML schema file to a different AXMLS
+ * DTD version. For instance, to convert a schema created for an pre-1.0 version for
+ * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
+ * parameter is specified, the schema will be converted to the current DTD version.
+ * If the newFile parameter is provided, the converted schema will be written to the specified
+ * file.
+ * @see ConvertSchemaString()
+ *
+ * @param string $filename Name of XML schema file that will be converted.
+ * @param string $newVersion DTD version to convert to.
+ * @param string $newFile File name of (converted) output file.
+ * @return string Converted XML schema or FALSE if an error occurs.
+ */
function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = NULL ) {
// grab current version
@@ -1757,7 +1757,7 @@ class adoSchema {
}
if( $version == $newVersion ) {
- $result = _file_get_contents( $filename );
+ $result = file_get_contents( $filename );
// remove unicode BOM if present
if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 187, 191 ) ) {
@@ -1796,7 +1796,7 @@ class adoSchema {
return FALSE;
}
- $schema = _file_get_contents( $schema );
+ $schema = file_get_contents( $schema );
break;
case 'string':
default:
@@ -1807,14 +1807,14 @@ class adoSchema {
$arguments = array (
'/_xml' => $schema,
- '/_xsl' => _file_get_contents( $xsl_file )
+ '/_xsl' => file_get_contents( $xsl_file )
);
// create an XSLT processor
$xh = xslt_create ();
// set error handler
- xslt_set_error_handler ($xh, array (&$this, 'xslt_error_handler'));
+ xslt_set_error_handler ($xh, array ($this, 'xslt_error_handler'));
// process the schema
$result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments);
@@ -1825,15 +1825,15 @@ class adoSchema {
}
/**
- * Processes XSLT transformation errors
- *
- * @param object $parser XML parser object
- * @param integer $errno Error number
- * @param integer $level Error level
- * @param array $fields Error information fields
- *
- * @access private
- */
+ * Processes XSLT transformation errors
+ *
+ * @param object $parser XML parser object
+ * @param integer $errno Error number
+ * @param integer $level Error level
+ * @param array $fields Error information fields
+ *
+ * @access private
+ */
function xslt_error_handler( $parser, $errno, $level, $fields ) {
if( is_array( $fields ) ) {
$msg = array(
@@ -1878,14 +1878,14 @@ class adoSchema {
}
/**
- * Returns the AXMLS Schema Version of the requested XML schema file.
- *
- * Call this method to obtain the AXMLS DTD version of the requested XML schema file.
- * @see SchemaStringVersion()
- *
- * @param string $filename AXMLS schema file
- * @return string Schema version number or FALSE on error
- */
+ * Returns the AXMLS Schema Version of the requested XML schema file.
+ *
+ * Call this method to obtain the AXMLS DTD version of the requested XML schema file.
+ * @see SchemaStringVersion()
+ *
+ * @param string $filename AXMLS schema file
+ * @return string Schema version number or FALSE on error
+ */
function SchemaFileVersion( $filename ) {
// Open the file
if( !($fp = fopen( $filename, 'r' )) ) {
@@ -1904,14 +1904,14 @@ class adoSchema {
}
/**
- * Returns the AXMLS Schema Version of the provided XML schema string.
- *
- * Call this method to obtain the AXMLS DTD version of the provided XML schema string.
- * @see SchemaFileVersion()
- *
- * @param string $xmlstring XML schema string
- * @return string Schema version number or FALSE on error
- */
+ * Returns the AXMLS Schema Version of the provided XML schema string.
+ *
+ * Call this method to obtain the AXMLS DTD version of the provided XML schema string.
+ * @see SchemaFileVersion()
+ *
+ * @param string $xmlstring XML schema string
+ * @return string Schema version number or FALSE on error
+ */
function SchemaStringVersion( $xmlstring ) {
if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
return FALSE;
@@ -1925,15 +1925,15 @@ class adoSchema {
}
/**
- * Extracts an XML schema from an existing database.
- *
- * Call this method to create an XML schema string from an existing database.
- * If the data parameter is set to TRUE, AXMLS will include the data from the database
- * in the schema.
- *
- * @param boolean $data Include data in schema dump
- * @return string Generated XML schema
- */
+ * Extracts an XML schema from an existing database.
+ *
+ * Call this method to create an XML schema string from an existing database.
+ * If the data parameter is set to TRUE, AXMLS will include the data from the database
+ * in the schema.
+ *
+ * @param boolean $data Include data in schema dump
+ * @return string Generated XML schema
+ */
function ExtractSchema( $data = FALSE ) {
$old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM );
@@ -2032,15 +2032,15 @@ class adoSchema {
}
/**
- * Sets a prefix for database objects
- *
- * Call this method to set a standard prefix that will be prepended to all database tables
- * and indices when the schema is parsed. Calling setPrefix with no arguments clears the prefix.
- *
- * @param string $prefix Prefix that will be prepended.
- * @param boolean $underscore If TRUE, automatically append an underscore character to the prefix.
- * @return boolean TRUE if successful, else FALSE
- */
+ * Sets a prefix for database objects
+ *
+ * Call this method to set a standard prefix that will be prepended to all database tables
+ * and indices when the schema is parsed. Calling setPrefix with no arguments clears the prefix.
+ *
+ * @param string $prefix Prefix that will be prepended.
+ * @param boolean $underscore If TRUE, automatically append an underscore character to the prefix.
+ * @return boolean TRUE if successful, else FALSE
+ */
function SetPrefix( $prefix = '', $underscore = TRUE ) {
switch( TRUE ) {
// clear prefix
@@ -2067,13 +2067,13 @@ class adoSchema {
}
/**
- * Returns an object name with the current prefix prepended.
- *
- * @param string $name Name
- * @return string Prefixed name
- *
- * @access private
- */
+ * Returns an object name with the current prefix prepended.
+ *
+ * @param string $name Name
+ * @return string Prefixed name
+ *
+ * @access private
+ */
function prefix( $name = '' ) {
// if prefix is set
if( !empty( $this->objectPrefix ) ) {
@@ -2087,13 +2087,13 @@ class adoSchema {
}
/**
- * Checks if element references a specific platform
- *
- * @param string $platform Requested platform
- * @returns boolean TRUE if platform check succeeds
- *
- * @access private
- */
+ * Checks if element references a specific platform
+ *
+ * @param string $platform Requested platform
+ * @returns boolean TRUE if platform check succeeds
+ *
+ * @access private
+ */
function supportedPlatform( $platform = NULL ) {
$regex = '/^(\w*\|)*' . $this->db->databaseType . '(\|\w*)*$/';
@@ -2107,22 +2107,22 @@ class adoSchema {
}
/**
- * Clears the array of generated SQL.
- *
- * @access private
- */
+ * Clears the array of generated SQL.
+ *
+ * @access private
+ */
function clearSQL() {
$this->sqlArray = array();
}
/**
- * Adds SQL into the SQL array.
- *
- * @param mixed $sql SQL to Add
- * @return boolean TRUE if successful, else FALSE.
- *
- * @access private
- */
+ * Adds SQL into the SQL array.
+ *
+ * @param mixed $sql SQL to Add
+ * @return boolean TRUE if successful, else FALSE.
+ *
+ * @access private
+ */
function addSQL( $sql = NULL ) {
if( is_array( $sql ) ) {
foreach( $sql as $line ) {
@@ -2158,13 +2158,13 @@ class adoSchema {
}
/**
- * Gets the SQL array in the specified format.
- *
- * @param string $format Format
- * @return mixed SQL
- *
- * @access private
- */
+ * Gets the SQL array in the specified format.
+ *
+ * @param string $format Format
+ * @return mixed SQL
+ *
+ * @access private
+ */
function getSQL( $format = NULL, $sqlArray = NULL ) {
if( !is_array( $sqlArray ) ) {
$sqlArray = $this->sqlArray;
@@ -2186,19 +2186,19 @@ class adoSchema {
}
/**
- * Destroys an adoSchema object.
- *
- * Call this method to clean up after an adoSchema object that is no longer in use.
- * @deprecated adoSchema now cleans up automatically.
- */
+ * Destroys an adoSchema object.
+ *
+ * Call this method to clean up after an adoSchema object that is no longer in use.
+ * @deprecated adoSchema now cleans up automatically.
+ */
function Destroy() {}
}
/**
-* Message logging function
-*
-* @access private
-*/
+ * Message logging function
+ *
+ * @access private
+ */
function logMsg( $msg, $title = NULL, $force = FALSE ) {
if( XMLS_DEBUG or $force ) {
echo '<pre>';
diff --git a/adodb-xmlschema03.inc.php b/adodb-xmlschema03.inc.php
index de1ea26..3c8bce5 100644
--- a/adodb-xmlschema03.inc.php
+++ b/adodb-xmlschema03.inc.php
@@ -26,74 +26,60 @@
* @author Dan Cech
*/
-function _file_get_contents($file)
-{
- if (function_exists('file_get_contents')) return file_get_contents($file);
-
- $f = fopen($file,'r');
- if (!$f) return '';
- $t = '';
-
- while ($s = fread($f,100000)) $t .= $s;
- fclose($f);
- return $t;
-}
-
-
/**
-* Debug on or off
-*/
+ * Debug on or off
+ */
if( !defined( 'XMLS_DEBUG' ) ) {
define( 'XMLS_DEBUG', FALSE );
}
/**
-* Default prefix key
-*/
+ * Default prefix key
+ */
if( !defined( 'XMLS_PREFIX' ) ) {
define( 'XMLS_PREFIX', '%%P' );
}
/**
-* Maximum length allowed for object prefix
-*/
+ * Maximum length allowed for object prefix
+ */
if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) {
define( 'XMLS_PREFIX_MAXLEN', 10 );
}
/**
-* Execute SQL inline as it is generated
-*/
+ * Execute SQL inline as it is generated
+ */
if( !defined( 'XMLS_EXECUTE_INLINE' ) ) {
define( 'XMLS_EXECUTE_INLINE', FALSE );
}
/**
-* Continue SQL Execution if an error occurs?
-*/
+ * Continue SQL Execution if an error occurs?
+ */
if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) {
define( 'XMLS_CONTINUE_ON_ERROR', FALSE );
}
/**
-* Current Schema Version
-*/
+ * Current Schema Version
+ */
if( !defined( 'XMLS_SCHEMA_VERSION' ) ) {
define( 'XMLS_SCHEMA_VERSION', '0.3' );
}
/**
-* Default Schema Version. Used for Schemas without an explicit version set.
-*/
+ * Default Schema Version. Used for Schemas without an explicit version set.
+ */
if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) {
define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' );
}
/**
-* How to handle data rows that already exist in a database during and upgrade.
-* Options are INSERT (attempts to insert duplicate rows), UPDATE (updates existing
-* rows) and IGNORE (ignores existing rows).
-*/
+ * How to handle data rows that already exist in a database during and upgrade.
+ * Options are INSERT (attempts to insert duplicate rows), UPDATE (updates existing
+ * rows) and IGNORE (ignores existing rows).
+ */
if( !defined( 'XMLS_MODE_INSERT' ) ) {
define( 'XMLS_MODE_INSERT', 0 );
}
@@ -108,69 +94,69 @@ if( !defined( 'XMLS_EXISTING_DATA' ) ) {
}
/**
-* Default Schema Version. Used for Schemas without an explicit version set.
-*/
+ * Default Schema Version. Used for Schemas without an explicit version set.
+ */
if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) {
define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' );
}
/**
-* Include the main ADODB library
-*/
+ * Include the main ADODB library
+ */
if( !defined( '_ADODB_LAYER' ) ) {
require( 'adodb.inc.php' );
require( 'adodb-datadict.inc.php' );
}
/**
-* Abstract DB Object. This class provides basic methods for database objects, such
-* as tables and indexes.
-*
-* @package axmls
-* @access private
-*/
+ * Abstract DB Object. This class provides basic methods for database objects, such
+ * as tables and indexes.
+ *
+ * @package axmls
+ * @access private
+ */
class dbObject {
/**
- * var object Parent
- */
+ * var object Parent
+ */
var $parent;
/**
- * var string current element
- */
+ * var string current element
+ */
var $currentElement;
/**
- * NOP
- */
- function __construct( &$parent, $attributes = NULL ) {
+ * NOP
+ */
+ function __construct( $parent, $attributes = NULL ) {
$this->parent = $parent;
}
/**
- * XML Callback to process start elements
- *
- * @access private
- */
+ * XML Callback to process start elements
+ *
+ * @access private
+ */
function _tag_open( $parser, $tag, $attributes ) {
}
/**
- * XML Callback to process CDATA elements
- *
- * @access private
- */
+ * XML Callback to process CDATA elements
+ *
+ * @access private
+ */
function _tag_cdata( $parser, $cdata ) {
}
/**
- * XML Callback to process end elements
- *
- * @access private
- */
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
function _tag_close( $parser, $tag ) {
}
@@ -180,117 +166,119 @@ class dbObject {
}
/**
- * Destroys the object
- */
+ * Destroys the object
+ */
function destroy() {
}
/**
- * Checks whether the specified RDBMS is supported by the current
- * database object or its ranking ancestor.
- *
- * @param string $platform RDBMS platform name (from ADODB platform list).
- * @return boolean TRUE if RDBMS is supported; otherwise returns FALSE.
- */
+ * Checks whether the specified RDBMS is supported by the current
+ * database object or its ranking ancestor.
+ *
+ * @param string $platform RDBMS platform name (from ADODB platform list).
+ * @return boolean TRUE if RDBMS is supported; otherwise returns FALSE.
+ */
function supportedPlatform( $platform = NULL ) {
return is_object( $this->parent ) ? $this->parent->supportedPlatform( $platform ) : TRUE;
}
/**
- * Returns the prefix set by the ranking ancestor of the database object.
- *
- * @param string $name Prefix string.
- * @return string Prefix.
- */
+ * Returns the prefix set by the ranking ancestor of the database object.
+ *
+ * @param string $name Prefix string.
+ * @return string Prefix.
+ */
function prefix( $name = '' ) {
return is_object( $this->parent ) ? $this->parent->prefix( $name ) : $name;
}
/**
- * Extracts a field ID from the specified field.
- *
- * @param string $field Field.
- * @return string Field ID.
- */
+ * Extracts a field ID from the specified field.
+ *
+ * @param string $field Field.
+ * @return string Field ID.
+ */
function fieldID( $field ) {
return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) );
}
}
/**
-* Creates a table object in ADOdb's datadict format
-*
-* This class stores information about a database table. As charactaristics
-* of the table are loaded from the external source, methods and properties
-* of this class are used to build up the table description in ADOdb's
-* datadict format.
-*
-* @package axmls
-* @access private
-*/
+ * Creates a table object in ADOdb's datadict format
+ *
+ * This class stores information about a database table. As charactaristics
+ * of the table are loaded from the external source, methods and properties
+ * of this class are used to build up the table description in ADOdb's
+ * datadict format.
+ *
+ * @package axmls
+ * @access private
+ */
class dbTable extends dbObject {
/**
- * @var string Table name
- */
+ * @var string Table name
+ */
var $name;
/**
- * @var array Field specifier: Meta-information about each field
- */
+ * @var array Field specifier: Meta-information about each field
+ */
var $fields = array();
/**
- * @var array List of table indexes.
- */
+ * @var array List of table indexes.
+ */
var $indexes = array();
/**
- * @var array Table options: Table-level options
- */
+ * @var array Table options: Table-level options
+ */
var $opts = array();
/**
- * @var string Field index: Keeps track of which field is currently being processed
- */
+ * @var string Field index: Keeps track of which field is currently being processed
+ */
var $current_field;
/**
- * @var boolean Mark table for destruction
- * @access private
- */
+ * @var boolean Mark table for destruction
+ * @access private
+ */
var $drop_table;
/**
- * @var boolean Mark field for destruction (not yet implemented)
- * @access private
- */
+ * @var boolean Mark field for destruction (not yet implemented)
+ * @access private
+ */
var $drop_field = array();
/**
- * @var array Platform-specific options
- * @access private
- */
+ * @var array Platform-specific options
+ * @access private
+ */
var $currentPlatform = true;
+ /** @var dbData Stores information about table data. */
+ var $data;
/**
- * Iniitializes a new table object.
- *
- * @param string $prefix DB Object prefix
- * @param array $attributes Array of table attributes.
- */
- function __construct( &$parent, $attributes = NULL ) {
+ * Iniitializes a new table object.
+ *
+ * @param string $prefix DB Object prefix
+ * @param array $attributes Array of table attributes.
+ */
+ function __construct( $parent, $attributes = NULL ) {
$this->parent = $parent;
$this->name = $this->prefix($attributes['NAME']);
}
/**
- * XML Callback to process start elements. Elements currently
- * processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & DEFAULT.
- *
- * @access private
- */
+ * XML Callback to process start elements. Elements currently
+ * processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & DEFAULT.
+ *
+ * @access private
+ */
function _tag_open( $parser, $tag, $attributes ) {
$this->currentElement = strtoupper( $tag );
@@ -349,10 +337,10 @@ class dbTable extends dbObject {
}
/**
- * XML Callback to process CDATA elements
- *
- * @access private
- */
+ * XML Callback to process CDATA elements
+ *
+ * @access private
+ */
function _tag_cdata( $parser, $cdata ) {
switch( $this->currentElement ) {
// Table or field comment
@@ -385,10 +373,10 @@ class dbTable extends dbObject {
}
/**
- * XML Callback to process end elements
- *
- * @access private
- */
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
function _tag_close( $parser, $tag ) {
$this->currentElement = '';
@@ -411,11 +399,11 @@ class dbTable extends dbObject {
}
/**
- * Adds an index to a table object
- *
- * @param array $attributes Index attributes
- * @return object dbIndex object
- */
+ * Adds an index to a table object
+ *
+ * @param array $attributes Index attributes
+ * @return object dbIndex object
+ */
function addIndex( $attributes ) {
$name = strtoupper( $attributes['NAME'] );
$this->indexes[$name] = new dbIndex( $this, $attributes );
@@ -423,11 +411,11 @@ class dbTable extends dbObject {
}
/**
- * Adds data to a table object
- *
- * @param array $attributes Data attributes
- * @return object dbData object
- */
+ * Adds data to a table object
+ *
+ * @param array $attributes Data attributes
+ * @return object dbData object
+ */
function addData( $attributes ) {
if( !isset( $this->data ) ) {
$this->data = new dbData( $this, $attributes );
@@ -436,34 +424,34 @@ class dbTable extends dbObject {
}
/**
- * Adds a field to a table object
- *
- * $name is the name of the table to which the field should be added.
- * $type is an ADODB datadict field type. The following field types
- * are supported as of ADODB 3.40:
- * - C: varchar
- * - X: CLOB (character large object) or largest varchar size
- * if CLOB is not supported
- * - C2: Multibyte varchar
- * - X2: Multibyte CLOB
- * - B: BLOB (binary large object)
- * - D: Date (some databases do not support this, and we return a datetime type)
- * - T: Datetime or Timestamp
- * - L: Integer field suitable for storing booleans (0 or 1)
- * - I: Integer (mapped to I4)
- * - I1: 1-byte integer
- * - I2: 2-byte integer
- * - I4: 4-byte integer
- * - I8: 8-byte integer
- * - F: Floating point number
- * - N: Numeric or decimal number
- *
- * @param string $name Name of the table to which the field will be added.
- * @param string $type ADODB datadict field type.
- * @param string $size Field size
- * @param array $opts Field options array
- * @return array Field specifier array
- */
+ * Adds a field to a table object
+ *
+ * $name is the name of the table to which the field should be added.
+ * $type is an ADODB datadict field type. The following field types
+ * are supported as of ADODB 3.40:
+ * - C: varchar
+ * - X: CLOB (character large object) or largest varchar size
+ * if CLOB is not supported
+ * - C2: Multibyte varchar
+ * - X2: Multibyte CLOB
+ * - B: BLOB (binary large object)
+ * - D: Date (some databases do not support this, and we return a datetime type)
+ * - T: Datetime or Timestamp
+ * - L: Integer field suitable for storing booleans (0 or 1)
+ * - I: Integer (mapped to I4)
+ * - I1: 1-byte integer
+ * - I2: 2-byte integer
+ * - I4: 4-byte integer
+ * - I8: 8-byte integer
+ * - F: Floating point number
+ * - N: Numeric or decimal number
+ *
+ * @param string $name Name of the table to which the field will be added.
+ * @param string $type ADODB datadict field type.
+ * @param string $size Field size
+ * @param array $opts Field options array
+ * @return void
+ */
function addField( $name, $type, $size = NULL, $opts = NULL ) {
$field_id = $this->fieldID( $name );
@@ -490,16 +478,16 @@ class dbTable extends dbObject {
}
/**
- * Adds a field option to the current field specifier
- *
- * This method adds a field option allowed by the ADOdb datadict
- * and appends it to the given field.
- *
- * @param string $field Field name
- * @param string $opt ADOdb field option
- * @param mixed $value Field option value
- * @return array Field specifier array
- */
+ * Adds a field option to the current field specifier
+ *
+ * This method adds a field option allowed by the ADOdb datadict
+ * and appends it to the given field.
+ *
+ * @param string $field Field name
+ * @param string $opt ADOdb field option
+ * @param mixed $value Field option value
+ * @return void
+ */
function addFieldOpt( $field, $opt, $value = NULL ) {
if( $this->currentPlatform ) {
if( !isset( $value ) ) {
@@ -512,14 +500,14 @@ class dbTable extends dbObject {
}
/**
- * Adds an option to the table
- *
- * This method takes a comma-separated list of table-level options
- * and appends them to the table object.
- *
- * @param string $opt Table option
- * @return array Options
- */
+ * Adds an option to the table
+ *
+ * This method takes a comma-separated list of table-level options
+ * and appends them to the table object.
+ *
+ * @param string $opt Table option
+ * @return array Options
+ */
function addTableOpt( $opt ) {
if(isset($this->currentPlatform)) {
$this->opts[$this->parent->db->dataProvider] = $opt;
@@ -533,11 +521,11 @@ class dbTable extends dbObject {
}
/**
- * Generates the SQL that will create the table in the database
- *
- * @param object $xmls adoSchema object
- * @return array Array containing table creation SQL
- */
+ * Generates the SQL that will create the table in the database
+ *
+ * @param object $xmls adoSchema object
+ * @return array Array containing table creation SQL
+ */
function create( &$xmls ) {
$sql = array();
@@ -599,8 +587,11 @@ class dbTable extends dbObject {
// Option has an argument.
if( is_array( $opt ) ) {
$key = key( $opt );
- $value = $opt[key( $opt )];
- @$fldarray[$field_id][$key] .= $value;
+ $value = $opt[$key];
+ if(!isset($fldarray[$field_id][$key])) {
+ $fldarray[$field_id][$key] = "";
+ }
+ $fldarray[$field_id][$key] .= $value;
// Option doesn't have arguments
} else {
$fldarray[$field_id][$opt] = $opt;
@@ -645,8 +636,8 @@ class dbTable extends dbObject {
}
/**
- * Marks a field or table for destruction
- */
+ * Marks a field or table for destruction
+ */
function drop() {
if( isset( $this->current_field ) ) {
// Drop the current field
@@ -663,61 +654,61 @@ class dbTable extends dbObject {
}
/**
-* Creates an index object in ADOdb's datadict format
-*
-* This class stores information about a database index. As charactaristics
-* of the index are loaded from the external source, methods and properties
-* of this class are used to build up the index description in ADOdb's
-* datadict format.
-*
-* @package axmls
-* @access private
-*/
+ * Creates an index object in ADOdb's datadict format
+ *
+ * This class stores information about a database index. As charactaristics
+ * of the index are loaded from the external source, methods and properties
+ * of this class are used to build up the index description in ADOdb's
+ * datadict format.
+ *
+ * @package axmls
+ * @access private
+ */
class dbIndex extends dbObject {
/**
- * @var string Index name
- */
+ * @var string Index name
+ */
var $name;
/**
- * @var array Index options: Index-level options
- */
+ * @var array Index options: Index-level options
+ */
var $opts = array();
/**
- * @var array Indexed fields: Table columns included in this index
- */
+ * @var array Indexed fields: Table columns included in this index
+ */
var $columns = array();
/**
- * @var boolean Mark index for destruction
- * @access private
- */
+ * @var boolean Mark index for destruction
+ * @access private
+ */
var $drop = FALSE;
/**
- * Initializes the new dbIndex object.
- *
- * @param object $parent Parent object
- * @param array $attributes Attributes
- *
- * @internal
- */
- function __construct( &$parent, $attributes = NULL ) {
+ * Initializes the new dbIndex object.
+ *
+ * @param object $parent Parent object
+ * @param array $attributes Attributes
+ *
+ * @internal
+ */
+ function __construct( $parent, $attributes = NULL ) {
$this->parent = $parent;
$this->name = $this->prefix ($attributes['NAME']);
}
/**
- * XML Callback to process start elements
- *
- * Processes XML opening tags.
- * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH.
- *
- * @access private
- */
+ * XML Callback to process start elements
+ *
+ * Processes XML opening tags.
+ * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH.
+ *
+ * @access private
+ */
function _tag_open( $parser, $tag, $attributes ) {
$this->currentElement = strtoupper( $tag );
@@ -739,12 +730,12 @@ class dbIndex extends dbObject {
}
/**
- * XML Callback to process CDATA elements
- *
- * Processes XML cdata.
- *
- * @access private
- */
+ * XML Callback to process CDATA elements
+ *
+ * Processes XML cdata.
+ *
+ * @access private
+ */
function _tag_cdata( $parser, $cdata ) {
switch( $this->currentElement ) {
// Index field name
@@ -757,10 +748,10 @@ class dbIndex extends dbObject {
}
/**
- * XML Callback to process end elements
- *
- * @access private
- */
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
function _tag_close( $parser, $tag ) {
$this->currentElement = '';
@@ -772,11 +763,11 @@ class dbIndex extends dbObject {
}
/**
- * Adds a field to the index
- *
- * @param string $name Field name
- * @return string Field list
- */
+ * Adds a field to the index
+ *
+ * @param string $name Field name
+ * @return string[] Field list
+ */
function addField( $name ) {
$this->columns[$this->fieldID( $name )] = $name;
@@ -785,11 +776,11 @@ class dbIndex extends dbObject {
}
/**
- * Adds options to the index
- *
- * @param string $opt Comma-separated list of index options.
- * @return string Option list
- */
+ * Adds options to the index
+ *
+ * @param string $opt Comma-separated list of index options.
+ * @return string[] Option list
+ */
function addIndexOpt( $opt ) {
$this->opts[] = $opt;
@@ -798,11 +789,11 @@ class dbIndex extends dbObject {
}
/**
- * Generates the SQL that will create the index in the database
- *
- * @param object $xmls adoSchema object
- * @return array Array containing index creation SQL
- */
+ * Generates the SQL that will create the index in the database
+ *
+ * @param object $xmls adoSchema object
+ * @return array Array containing index creation SQL
+ */
function create( &$xmls ) {
if( $this->drop ) {
return NULL;
@@ -819,48 +810,51 @@ class dbIndex extends dbObject {
}
/**
- * Marks an index for destruction
- */
+ * Marks an index for destruction
+ */
function drop() {
$this->drop = TRUE;
}
}
/**
-* Creates a data object in ADOdb's datadict format
-*
-* This class stores information about table data, and is called
-* when we need to load field data into a table.
-*
-* @package axmls
-* @access private
-*/
+ * Creates a data object in ADOdb's datadict format
+ *
+ * This class stores information about table data, and is called
+ * when we need to load field data into a table.
+ *
+ * @package axmls
+ * @access private
+ */
class dbData extends dbObject {
var $data = array();
var $row;
+ /** @var string Field name */
+ var $current_field;
+
/**
- * Initializes the new dbData object.
- *
- * @param object $parent Parent object
- * @param array $attributes Attributes
- *
- * @internal
- */
- function __construct( &$parent, $attributes = NULL ) {
+ * Initializes the new dbData object.
+ *
+ * @param object $parent Parent object
+ * @param array $attributes Attributes
+ *
+ * @internal
+ */
+ function __construct( $parent, $attributes = NULL ) {
$this->parent = $parent;
}
/**
- * XML Callback to process start elements
- *
- * Processes XML opening tags.
- * Elements currently processed are: ROW and F (field).
- *
- * @access private
- */
+ * XML Callback to process start elements
+ *
+ * Processes XML opening tags.
+ * Elements currently processed are: ROW and F (field).
+ *
+ * @access private
+ */
function _tag_open( $parser, $tag, $attributes ) {
$this->currentElement = strtoupper( $tag );
@@ -877,12 +871,12 @@ class dbData extends dbObject {
}
/**
- * XML Callback to process CDATA elements
- *
- * Processes XML cdata.
- *
- * @access private
- */
+ * XML Callback to process CDATA elements
+ *
+ * Processes XML cdata.
+ *
+ * @access private
+ */
function _tag_cdata( $parser, $cdata ) {
switch( $this->currentElement ) {
// Index field name
@@ -895,10 +889,10 @@ class dbData extends dbObject {
}
/**
- * XML Callback to process end elements
- *
- * @access private
- */
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
function _tag_close( $parser, $tag ) {
$this->currentElement = '';
@@ -910,11 +904,11 @@ class dbData extends dbObject {
}
/**
- * Adds a field to the insert
- *
- * @param string $name Field name
- * @return string Field list
- */
+ * Adds a field to the insert
+ *
+ * @param string $name Field name
+ * @return string Field list
+ */
function addField( $attributes ) {
// check we're in a valid row
if( !isset( $this->row ) || !isset( $this->data[$this->row] ) ) {
@@ -935,11 +929,11 @@ class dbData extends dbObject {
}
/**
- * Adds options to the index
- *
- * @param string $opt Comma-separated list of index options.
- * @return string Option list
- */
+ * Adds data.
+ *
+ * @param string $cdata Data to add
+ * @return void
+ */
function addData( $cdata ) {
// check we're in a valid field
if ( isset( $this->data[$this->row][$this->current_field] ) ) {
@@ -949,11 +943,11 @@ class dbData extends dbObject {
}
/**
- * Generates the SQL that will add/update the data in the database
- *
- * @param object $xmls adoSchema object
- * @return array Array containing index creation SQL
- */
+ * Generates the SQL that will add/update the data in the database
+ *
+ * @param object $xmls adoSchema object
+ * @return array Array containing index creation SQL
+ */
function create( &$xmls ) {
$table = $xmls->dict->tableName($this->parent->name);
$table_field_count = count($this->parent->fields);
@@ -976,7 +970,8 @@ class dbData extends dbObject {
foreach( $row as $field_id => $field_data ) {
if( !array_key_exists( $field_id, $table_fields ) ) {
if( is_numeric( $field_id ) ) {
- $field_id = reset( array_keys( $table_fields ) );
+ $keys = array_keys($table_fields);
+ $field_id = reset($keys);
} else {
continue;
}
@@ -1072,40 +1067,40 @@ class dbData extends dbObject {
}
/**
-* Creates the SQL to execute a list of provided SQL queries
-*
-* @package axmls
-* @access private
-*/
+ * Creates the SQL to execute a list of provided SQL queries
+ *
+ * @package axmls
+ * @access private
+ */
class dbQuerySet extends dbObject {
/**
- * @var array List of SQL queries
- */
+ * @var array List of SQL queries
+ */
var $queries = array();
/**
- * @var string String used to build of a query line by line
- */
+ * @var string String used to build of a query line by line
+ */
var $query;
/**
- * @var string Query prefix key
- */
+ * @var string Query prefix key
+ */
var $prefixKey = '';
/**
- * @var boolean Auto prefix enable (TRUE)
- */
+ * @var boolean Auto prefix enable (TRUE)
+ */
var $prefixMethod = 'AUTO';
/**
- * Initializes the query set.
- *
- * @param object $parent Parent object
- * @param array $attributes Attributes
- */
- function __construct( &$parent, $attributes = NULL ) {
+ * Initializes the query set.
+ *
+ * @param object $parent Parent object
+ * @param array $attributes Attributes
+ */
+ function __construct( $parent, $attributes = NULL ) {
$this->parent = $parent;
// Overrides the manual prefix key
@@ -1130,11 +1125,11 @@ class dbQuerySet extends dbObject {
}
/**
- * XML Callback to process start elements. Elements currently
- * processed are: QUERY.
- *
- * @access private
- */
+ * XML Callback to process start elements. Elements currently
+ * processed are: QUERY.
+ *
+ * @access private
+ */
function _tag_open( $parser, $tag, $attributes ) {
$this->currentElement = strtoupper( $tag );
@@ -1155,8 +1150,8 @@ class dbQuerySet extends dbObject {
}
/**
- * XML Callback to process CDATA elements
- */
+ * XML Callback to process CDATA elements
+ */
function _tag_cdata( $parser, $cdata ) {
switch( $this->currentElement ) {
// Line of queryset SQL data
@@ -1169,10 +1164,10 @@ class dbQuerySet extends dbObject {
}
/**
- * XML Callback to process end elements
- *
- * @access private
- */
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
function _tag_close( $parser, $tag ) {
$this->currentElement = '';
@@ -1192,10 +1187,10 @@ class dbQuerySet extends dbObject {
}
/**
- * Re-initializes the query.
- *
- * @return boolean TRUE
- */
+ * Re-initializes the query.
+ *
+ * @return boolean TRUE
+ */
function newQuery() {
$this->query = '';
@@ -1203,10 +1198,10 @@ class dbQuerySet extends dbObject {
}
/**
- * Discards the existing query.
- *
- * @return boolean TRUE
- */
+ * Discards the existing query.
+ *
+ * @return boolean TRUE
+ */
function discardQuery() {
unset( $this->query );
@@ -1214,11 +1209,11 @@ class dbQuerySet extends dbObject {
}
/**
- * Appends a line to a query that is being built line by line
- *
- * @param string $data Line of SQL data or NULL to initialize a new query
- * @return string SQL query string.
- */
+ * Appends a line to a query that is being built line by line
+ *
+ * @param string $data Line of SQL data or NULL to initialize a new query
+ * @return string SQL query string.
+ */
function buildQuery( $sql = NULL ) {
if( !isset( $this->query ) OR empty( $sql ) ) {
return FALSE;
@@ -1230,10 +1225,10 @@ class dbQuerySet extends dbObject {
}
/**
- * Adds a completed query to the query list
- *
- * @return string SQL of added query
- */
+ * Adds a completed query to the query list
+ *
+ * @return string SQL of added query
+ */
function addQuery() {
if( !isset( $this->query ) ) {
return FALSE;
@@ -1247,11 +1242,11 @@ class dbQuerySet extends dbObject {
}
/**
- * Creates and returns the current query set
- *
- * @param object $xmls adoSchema object
- * @return array Query set
- */
+ * Creates and returns the current query set
+ *
+ * @param object $xmls adoSchema object
+ * @return array Query set
+ */
function create( &$xmls ) {
foreach( $this->queries as $id => $query ) {
switch( $this->prefixMethod ) {
@@ -1287,13 +1282,13 @@ class dbQuerySet extends dbObject {
}
/**
- * Rebuilds the query with the prefix attached to any objects
- *
- * @param string $regex Regex used to add prefix
- * @param string $query SQL query string
- * @param string $prefix Prefix to be appended to tables, indices, etc.
- * @return string Prefixed SQL query string.
- */
+ * Rebuilds the query with the prefix attached to any objects
+ *
+ * @param string $regex Regex used to add prefix
+ * @param string $query SQL query string
+ * @param string $prefix Prefix to be appended to tables, indices, etc.
+ * @return string Prefixed SQL query string.
+ */
function prefixQuery( $regex, $query, $prefix = NULL ) {
if( !isset( $prefix ) ) {
return $query;
@@ -1323,103 +1318,106 @@ class dbQuerySet extends dbObject {
}
/**
-* Loads and parses an XML file, creating an array of "ready-to-run" SQL statements
-*
-* This class is used to load and parse the XML file, to create an array of SQL statements
-* that can be used to build a database, and to build the database using the SQL array.
-*
-* @tutorial getting_started.pkg
-*
-* @author Richard Tango-Lowy & Dan Cech
-* @version $Revision: 1.62 $
-*
-* @package axmls
-*/
+ * Loads and parses an XML file, creating an array of "ready-to-run" SQL statements
+ *
+ * This class is used to load and parse the XML file, to create an array of SQL statements
+ * that can be used to build a database, and to build the database using the SQL array.
+ *
+ * @tutorial getting_started.pkg
+ *
+ * @author Richard Tango-Lowy & Dan Cech
+ * @version 1.62
+ *
+ * @package axmls
+ */
class adoSchema {
/**
- * @var array Array containing SQL queries to generate all objects
- * @access private
- */
+ * @var array Array containing SQL queries to generate all objects
+ * @access private
+ */
var $sqlArray;
/**
- * @var object ADOdb connection object
- * @access private
- */
+ * @var object ADOdb connection object
+ * @access private
+ */
var $db;
/**
- * @var object ADOdb Data Dictionary
- * @access private
- */
+ * @var object ADOdb Data Dictionary
+ * @access private
+ */
var $dict;
/**
- * @var string Current XML element
- * @access private
- */
+ * @var string Current XML element
+ * @access private
+ */
var $currentElement = '';
/**
- * @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing database
- * @access private
- */
+ * @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing database
+ * @access private
+ */
var $upgrade = '';
/**
- * @var string Optional object prefix
- * @access private
- */
+ * @var string Optional object prefix
+ * @access private
+ */
var $objectPrefix = '';
/**
- * @var long System debug
- * @access private
- */
+ * @var long System debug
+ * @access private
+ */
var $debug;
/**
- * @var string Regular expression to find schema version
- * @access private
- */
+ * @var string Regular expression to find schema version
+ * @access private
+ */
var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
/**
- * @var string Current schema version
- * @access private
- */
+ * @var string Current schema version
+ * @access private
+ */
var $schemaVersion;
/**
- * @var int Success of last Schema execution
- */
+ * @var int Success of last Schema execution
+ */
var $success;
/**
- * @var bool Execute SQL inline as it is generated
- */
+ * @var bool Execute SQL inline as it is generated
+ */
var $executeInline;
/**
- * @var bool Continue SQL execution if errors occur
- */
+ * @var bool Continue SQL execution if errors occur
+ */
var $continueOnError;
/**
- * @var int How to handle existing data rows (insert, update, or ignore)
- */
+ * @var int How to handle existing data rows (insert, update, or ignore)
+ */
var $existingData;
+ /** @var dbTable A table object. */
+ var $obj;
+
/**
- * Creates an adoSchema object
- *
- * Creating an adoSchema object is the first step in processing an XML schema.
- * The only parameter is an ADOdb database connection object, which must already
- * have been created.
- *
- * @param object $db ADOdb database connection object.
- */
+ * Creates an adoSchema object
+ *
+ * Creating an adoSchema object is the first step in processing an XML schema.
+ * The only parameter is an ADOdb database connection object, which must already
+ * have been created.
+ *
+ * @param object $db ADOdb database connection object.
+ */
function __construct( $db ) {
$this->db = $db;
$this->debug = $this->db->debug;
@@ -1433,21 +1431,21 @@ class adoSchema {
}
/**
- * Sets the method to be used for upgrading an existing database
- *
- * Use this method to specify how existing database objects should be upgraded.
- * The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER attempts to
- * alter each database object directly, REPLACE attempts to rebuild each object
- * from scratch, BEST attempts to determine the best upgrade method for each
- * object, and NONE disables upgrading.
- *
- * This method is not yet used by AXMLS, but exists for backward compatibility.
- * The ALTER method is automatically assumed when the adoSchema object is
- * instantiated; other upgrade methods are not currently supported.
- *
- * @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE)
- * @returns string Upgrade method used
- */
+ * Sets the method to be used for upgrading an existing database
+ *
+ * Use this method to specify how existing database objects should be upgraded.
+ * The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER attempts to
+ * alter each database object directly, REPLACE attempts to rebuild each object
+ * from scratch, BEST attempts to determine the best upgrade method for each
+ * object, and NONE disables upgrading.
+ *
+ * This method is not yet used by AXMLS, but exists for backward compatibility.
+ * The ALTER method is automatically assumed when the adoSchema object is
+ * instantiated; other upgrade methods are not currently supported.
+ *
+ * @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE)
+ * @returns string Upgrade method used
+ */
function setUpgradeMethod( $method = '' ) {
if( !is_string( $method ) ) {
return FALSE;
@@ -1478,24 +1476,24 @@ class adoSchema {
}
/**
- * Specifies how to handle existing data row when there is a unique key conflict.
- *
- * The existingData setting specifies how the parser should handle existing rows
- * when a unique key violation occurs during the insert. This can happen when inserting
- * data into an existing table with one or more primary keys or unique indexes.
- * The existingData method takes one of three options: XMLS_MODE_INSERT attempts
- * to always insert the data as a new row. In the event of a unique key violation,
- * the database will generate an error. XMLS_MODE_UPDATE attempts to update the
- * any existing rows with the new data based upon primary or unique key fields in
- * the schema. If the data row in the schema specifies no unique fields, the row
- * data will be inserted as a new row. XMLS_MODE_IGNORE specifies that any data rows
- * that would result in a unique key violation be ignored; no inserts or updates will
- * take place. For backward compatibility, the default setting is XMLS_MODE_INSERT,
- * but XMLS_MODE_UPDATE will generally be the most appropriate setting.
- *
- * @param int $mode XMLS_MODE_INSERT, XMLS_MODE_UPDATE, or XMLS_MODE_IGNORE
- * @return int current mode
- */
+ * Specifies how to handle existing data row when there is a unique key conflict.
+ *
+ * The existingData setting specifies how the parser should handle existing rows
+ * when a unique key violation occurs during the insert. This can happen when inserting
+ * data into an existing table with one or more primary keys or unique indexes.
+ * The existingData method takes one of three options: XMLS_MODE_INSERT attempts
+ * to always insert the data as a new row. In the event of a unique key violation,
+ * the database will generate an error. XMLS_MODE_UPDATE attempts to update the
+ * any existing rows with the new data based upon primary or unique key fields in
+ * the schema. If the data row in the schema specifies no unique fields, the row
+ * data will be inserted as a new row. XMLS_MODE_IGNORE specifies that any data rows
+ * that would result in a unique key violation be ignored; no inserts or updates will
+ * take place. For backward compatibility, the default setting is XMLS_MODE_INSERT,
+ * but XMLS_MODE_UPDATE will generally be the most appropriate setting.
+ *
+ * @param int $mode XMLS_MODE_INSERT, XMLS_MODE_UPDATE, or XMLS_MODE_IGNORE
+ * @return int current mode
+ */
function existingData( $mode = NULL ) {
if( is_int( $mode ) ) {
switch( $mode ) {
@@ -1519,18 +1517,19 @@ class adoSchema {
}
/**
- * Enables/disables inline SQL execution.
- *
- * Call this method to enable or disable inline execution of the schema. If the mode is set to TRUE (inline execution),
- * AXMLS applies the SQL to the database immediately as each schema entity is parsed. If the mode
- * is set to FALSE (post execution), AXMLS parses the entire schema and you will need to call adoSchema::ExecuteSchema()
- * to apply the schema to the database.
- *
- * @param bool $mode execute
- * @return bool current execution mode
- *
- * @see ParseSchema(), ExecuteSchema()
- */
+ * Enables/disables inline SQL execution.
+ *
+ * Call this method to enable or disable inline execution of the schema. If the mode is set to TRUE (inline execution),
+ * AXMLS applies the SQL to the database immediately as each schema entity is parsed. If the mode
+ * is set to FALSE (post execution), AXMLS parses the entire schema and you will need to call adoSchema::ExecuteSchema()
+ * to apply the schema to the database.
+ *
+ * @param bool $mode execute
+ * @return bool current execution mode
+ *
+ * @see ParseSchema()
+ * @see ExecuteSchema()
+ */
function executeInline( $mode = NULL ) {
if( is_bool( $mode ) ) {
$this->executeInline = $mode;
@@ -1540,18 +1539,19 @@ class adoSchema {
}
/**
- * Enables/disables SQL continue on error.
- *
- * Call this method to enable or disable continuation of SQL execution if an error occurs.
- * If the mode is set to TRUE (continue), AXMLS will continue to apply SQL to the database, even if an error occurs.
- * If the mode is set to FALSE (halt), AXMLS will halt execution of generated sql if an error occurs, though parsing
- * of the schema will continue.
- *
- * @param bool $mode execute
- * @return bool current continueOnError mode
- *
- * @see addSQL(), ExecuteSchema()
- */
+ * Enables/disables SQL continue on error.
+ *
+ * Call this method to enable or disable continuation of SQL execution if an error occurs.
+ * If the mode is set to TRUE (continue), AXMLS will continue to apply SQL to the database, even if an error occurs.
+ * If the mode is set to FALSE (halt), AXMLS will halt execution of generated sql if an error occurs, though parsing
+ * of the schema will continue.
+ *
+ * @param bool $mode execute
+ * @return bool current continueOnError mode
+ *
+ * @see addSQL()
+ * @see ExecuteSchema()
+ */
function continueOnError( $mode = NULL ) {
if( is_bool( $mode ) ) {
$this->continueOnError = $mode;
@@ -1561,43 +1561,44 @@ class adoSchema {
}
/**
- * Loads an XML schema from a file and converts it to SQL.
- *
- * Call this method to load the specified schema (see the DTD for the proper format) from
- * the filesystem and generate the SQL necessary to create the database
- * described. This method automatically converts the schema to the latest
- * axmls schema version.
- * @see ParseSchemaString()
- *
- * @param string $file Name of XML schema file.
- * @param bool $returnSchema Return schema rather than parsing.
- * @return array Array of SQL queries, ready to execute
- */
+ * Loads an XML schema from a file and converts it to SQL.
+ *
+ * Call this method to load the specified schema (see the DTD for the proper format) from
+ * the filesystem and generate the SQL necessary to create the database
+ * described. This method automatically converts the schema to the latest
+ * axmls schema version.
+ * @see ParseSchemaString()
+ *
+ * @param string $file Name of XML schema file.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute
+ */
function parseSchema( $filename, $returnSchema = FALSE ) {
return $this->parseSchemaString( $this->convertSchemaFile( $filename ), $returnSchema );
}
/**
- * Loads an XML schema from a file and converts it to SQL.
- *
- * Call this method to load the specified schema directly from a file (see
- * the DTD for the proper format) and generate the SQL necessary to create
- * the database described by the schema. Use this method when you are dealing
- * with large schema files. Otherwise, parseSchema() is faster.
- * This method does not automatically convert the schema to the latest axmls
- * schema version. You must convert the schema manually using either the
- * convertSchemaFile() or convertSchemaString() method.
- * @see parseSchema()
- * @see convertSchemaFile()
- * @see convertSchemaString()
- *
- * @param string $file Name of XML schema file.
- * @param bool $returnSchema Return schema rather than parsing.
- * @return array Array of SQL queries, ready to execute.
- *
- * @deprecated Replaced by adoSchema::parseSchema() and adoSchema::parseSchemaString()
- * @see parseSchema(), parseSchemaString()
- */
+ * Loads an XML schema from a file and converts it to SQL.
+ *
+ * Call this method to load the specified schema directly from a file (see
+ * the DTD for the proper format) and generate the SQL necessary to create
+ * the database described by the schema. Use this method when you are dealing
+ * with large schema files. Otherwise, parseSchema() is faster.
+ * This method does not automatically convert the schema to the latest axmls
+ * schema version. You must convert the schema manually using either the
+ * convertSchemaFile() or convertSchemaString() method.
+ * @see parseSchema()
+ * @see convertSchemaFile()
+ * @see convertSchemaString()
+ *
+ * @param string $file Name of XML schema file.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute.
+ *
+ * @deprecated Replaced by adoSchema::parseSchema() and adoSchema::parseSchemaString()
+ * @see parseSchema()
+ * @see parseSchemaString()
+ */
function parseSchemaFile( $filename, $returnSchema = FALSE ) {
// Open the file
if( !($fp = fopen( $filename, 'r' )) ) {
@@ -1640,16 +1641,16 @@ class adoSchema {
}
/**
- * Converts an XML schema string to SQL.
- *
- * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
- * and generate the SQL necessary to create the database described by the schema.
- * @see parseSchema()
- *
- * @param string $xmlstring XML schema string.
- * @param bool $returnSchema Return schema rather than parsing.
- * @return array Array of SQL queries, ready to execute.
- */
+ * Converts an XML schema string to SQL.
+ *
+ * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
+ * and generate the SQL necessary to create the database described by the schema.
+ * @see parseSchema()
+ *
+ * @param string $xmlstring XML schema string.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute.
+ */
function parseSchemaString( $xmlstring, $returnSchema = FALSE ) {
if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
logMsg( 'Empty or Invalid Schema' );
@@ -1684,31 +1685,31 @@ class adoSchema {
}
/**
- * Loads an XML schema from a file and converts it to uninstallation SQL.
- *
- * Call this method to load the specified schema (see the DTD for the proper format) from
- * the filesystem and generate the SQL necessary to remove the database described.
- * @see RemoveSchemaString()
- *
- * @param string $file Name of XML schema file.
- * @param bool $returnSchema Return schema rather than parsing.
- * @return array Array of SQL queries, ready to execute
- */
+ * Loads an XML schema from a file and converts it to uninstallation SQL.
+ *
+ * Call this method to load the specified schema (see the DTD for the proper format) from
+ * the filesystem and generate the SQL necessary to remove the database described.
+ * @see RemoveSchemaString()
+ *
+ * @param string $file Name of XML schema file.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute
+ */
function removeSchema( $filename, $returnSchema = FALSE ) {
return $this->removeSchemaString( $this->convertSchemaFile( $filename ), $returnSchema );
}
/**
- * Converts an XML schema string to uninstallation SQL.
- *
- * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
- * and generate the SQL necessary to uninstall the database described by the schema.
- * @see removeSchema()
- *
- * @param string $schema XML schema string.
- * @param bool $returnSchema Return schema rather than parsing.
- * @return array Array of SQL queries, ready to execute.
- */
+ * Converts an XML schema string to uninstallation SQL.
+ *
+ * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
+ * and generate the SQL necessary to uninstall the database described by the schema.
+ * @see removeSchema()
+ *
+ * @param string $schema XML schema string.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute.
+ */
function removeSchemaString( $schema, $returnSchema = FALSE ) {
// grab current version
@@ -1720,18 +1721,20 @@ class adoSchema {
}
/**
- * Applies the current XML schema to the database (post execution).
- *
- * Call this method to apply the current schema (generally created by calling
- * parseSchema() or parseSchemaString() ) to the database (creating the tables, indexes,
- * and executing other SQL specified in the schema) after parsing.
- * @see parseSchema(), parseSchemaString(), executeInline()
- *
- * @param array $sqlArray Array of SQL statements that will be applied rather than
- * the current schema.
- * @param boolean $continueOnErr Continue to apply the schema even if an error occurs.
- * @returns integer 0 if failure, 1 if errors, 2 if successful.
- */
+ * Applies the current XML schema to the database (post execution).
+ *
+ * Call this method to apply the current schema (generally created by calling
+ * parseSchema() or parseSchemaString() ) to the database (creating the tables, indexes,
+ * and executing other SQL specified in the schema) after parsing.
+ * @see parseSchema()
+ * @see parseSchemaString()
+ * @see executeInline()
+ *
+ * @param array $sqlArray Array of SQL statements that will be applied rather than
+ * the current schema.
+ * @param boolean $continueOnErr Continue to apply the schema even if an error occurs.
+ * @returns integer 0 if failure, 1 if errors, 2 if successful.
+ */
function executeSchema( $sqlArray = NULL, $continueOnErr = NULL ) {
if( !is_bool( $continueOnErr ) ) {
$continueOnErr = $this->continueOnError();
@@ -1751,35 +1754,35 @@ class adoSchema {
}
/**
- * Returns the current SQL array.
- *
- * Call this method to fetch the array of SQL queries resulting from
- * parseSchema() or parseSchemaString().
- *
- * @param string $format Format: HTML, TEXT, or NONE (PHP array)
- * @return array Array of SQL statements or FALSE if an error occurs
- */
+ * Returns the current SQL array.
+ *
+ * Call this method to fetch the array of SQL queries resulting from
+ * parseSchema() or parseSchemaString().
+ *
+ * @param string $format Format: HTML, TEXT, or NONE (PHP array)
+ * @return array Array of SQL statements or FALSE if an error occurs
+ */
function printSQL( $format = 'NONE' ) {
$sqlArray = null;
return $this->getSQL( $format, $sqlArray );
}
/**
- * Saves the current SQL array to the local filesystem as a list of SQL queries.
- *
- * Call this method to save the array of SQL queries (generally resulting from a
- * parsed XML schema) to the filesystem.
- *
- * @param string $filename Path and name where the file should be saved.
- * @return boolean TRUE if save is successful, else FALSE.
- */
+ * Saves the current SQL array to the local filesystem as a list of SQL queries.
+ *
+ * Call this method to save the array of SQL queries (generally resulting from a
+ * parsed XML schema) to the filesystem.
+ *
+ * @param string $filename Path and name where the file should be saved.
+ * @return boolean TRUE if save is successful, else FALSE.
+ */
function saveSQL( $filename = './schema.sql' ) {
if( !isset( $sqlArray ) ) {
$sqlArray = $this->sqlArray;
}
if( !isset( $sqlArray ) ) {
- return FALSE;
+ return false;
}
$fp = fopen( $filename, "w" );
@@ -1791,12 +1794,12 @@ class adoSchema {
}
/**
- * Create an xml parser
- *
- * @return object PHP XML parser object
- *
- * @access private
- */
+ * Create an xml parser
+ *
+ * @return object PHP XML parser object
+ *
+ * @access private
+ */
function create_parser() {
// Create the parser
$xmlParser = xml_parser_create();
@@ -1810,10 +1813,10 @@ class adoSchema {
}
/**
- * XML Callback to process start elements
- *
- * @access private
- */
+ * XML Callback to process start elements
+ *
+ * @access private
+ */
function _tag_open( $parser, $tag, $attributes ) {
switch( strtoupper( $tag ) ) {
case 'TABLE':
@@ -1835,39 +1838,39 @@ class adoSchema {
}
/**
- * XML Callback to process CDATA elements
- *
- * @access private
- */
+ * XML Callback to process CDATA elements
+ *
+ * @access private
+ */
function _tag_cdata( $parser, $cdata ) {
}
/**
- * XML Callback to process end elements
- *
- * @access private
- * @internal
- */
+ * XML Callback to process end elements
+ *
+ * @access private
+ * @internal
+ */
function _tag_close( $parser, $tag ) {
}
/**
- * Converts an XML schema string to the specified DTD version.
- *
- * Call this method to convert a string containing an XML schema to a different AXMLS
- * DTD version. For instance, to convert a schema created for an pre-1.0 version for
- * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
- * parameter is specified, the schema will be converted to the current DTD version.
- * If the newFile parameter is provided, the converted schema will be written to the specified
- * file.
- * @see convertSchemaFile()
- *
- * @param string $schema String containing XML schema that will be converted.
- * @param string $newVersion DTD version to convert to.
- * @param string $newFile File name of (converted) output file.
- * @return string Converted XML schema or FALSE if an error occurs.
- */
+ * Converts an XML schema string to the specified DTD version.
+ *
+ * Call this method to convert a string containing an XML schema to a different AXMLS
+ * DTD version. For instance, to convert a schema created for an pre-1.0 version for
+ * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
+ * parameter is specified, the schema will be converted to the current DTD version.
+ * If the newFile parameter is provided, the converted schema will be written to the specified
+ * file.
+ * @see convertSchemaFile()
+ *
+ * @param string $schema String containing XML schema that will be converted.
+ * @param string $newVersion DTD version to convert to.
+ * @param string $newFile File name of (converted) output file.
+ * @return string Converted XML schema or FALSE if an error occurs.
+ */
function convertSchemaString( $schema, $newVersion = NULL, $newFile = NULL ) {
// grab current version
@@ -1893,30 +1896,22 @@ class adoSchema {
return $result;
}
- /*
- // compat for pre-4.3 - jlim
- function _file_get_contents($path)
- {
- if (function_exists('file_get_contents')) return file_get_contents($path);
- return join('',file($path));
- }*/
-
- /**
- * Converts an XML schema file to the specified DTD version.
- *
- * Call this method to convert the specified XML schema file to a different AXMLS
- * DTD version. For instance, to convert a schema created for an pre-1.0 version for
- * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
- * parameter is specified, the schema will be converted to the current DTD version.
- * If the newFile parameter is provided, the converted schema will be written to the specified
- * file.
- * @see convertSchemaString()
- *
- * @param string $filename Name of XML schema file that will be converted.
- * @param string $newVersion DTD version to convert to.
- * @param string $newFile File name of (converted) output file.
- * @return string Converted XML schema or FALSE if an error occurs.
- */
+ /**
+ * Converts an XML schema file to the specified DTD version.
+ *
+ * Call this method to convert the specified XML schema file to a different AXMLS
+ * DTD version. For instance, to convert a schema created for an pre-1.0 version for
+ * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
+ * parameter is specified, the schema will be converted to the current DTD version.
+ * If the newFile parameter is provided, the converted schema will be written to the specified
+ * file.
+ * @see convertSchemaString()
+ *
+ * @param string $filename Name of XML schema file that will be converted.
+ * @param string $newVersion DTD version to convert to.
+ * @param string $newFile File name of (converted) output file.
+ * @return string Converted XML schema or FALSE if an error occurs.
+ */
function convertSchemaFile( $filename, $newVersion = NULL, $newFile = NULL ) {
// grab current version
@@ -1929,7 +1924,7 @@ class adoSchema {
}
if( $version == $newVersion ) {
- $result = _file_get_contents( $filename );
+ $result = file_get_contents( $filename );
// remove unicode BOM if present
if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 187, 191 ) ) {
@@ -1968,7 +1963,7 @@ class adoSchema {
return FALSE;
}
- $schema = _file_get_contents( $schema );
+ $schema = file_get_contents( $schema );
break;
case 'string':
default:
@@ -1979,14 +1974,14 @@ class adoSchema {
$arguments = array (
'/_xml' => $schema,
- '/_xsl' => _file_get_contents( $xsl_file )
+ '/_xsl' => file_get_contents( $xsl_file )
);
// create an XSLT processor
$xh = xslt_create ();
// set error handler
- xslt_set_error_handler ($xh, array (&$this, 'xslt_error_handler'));
+ xslt_set_error_handler ($xh, array ($this, 'xslt_error_handler'));
// process the schema
$result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments);
@@ -1997,15 +1992,15 @@ class adoSchema {
}
/**
- * Processes XSLT transformation errors
- *
- * @param object $parser XML parser object
- * @param integer $errno Error number
- * @param integer $level Error level
- * @param array $fields Error information fields
- *
- * @access private
- */
+ * Processes XSLT transformation errors
+ *
+ * @param object $parser XML parser object
+ * @param integer $errno Error number
+ * @param integer $level Error level
+ * @param array $fields Error information fields
+ *
+ * @access private
+ */
function xslt_error_handler( $parser, $errno, $level, $fields ) {
if( is_array( $fields ) ) {
$msg = array(
@@ -2050,14 +2045,14 @@ class adoSchema {
}
/**
- * Returns the AXMLS Schema Version of the requested XML schema file.
- *
- * Call this method to obtain the AXMLS DTD version of the requested XML schema file.
- * @see SchemaStringVersion()
- *
- * @param string $filename AXMLS schema file
- * @return string Schema version number or FALSE on error
- */
+ * Returns the AXMLS Schema Version of the requested XML schema file.
+ *
+ * Call this method to obtain the AXMLS DTD version of the requested XML schema file.
+ * @see SchemaStringVersion()
+ *
+ * @param string $filename AXMLS schema file
+ * @return string Schema version number or FALSE on error
+ */
function schemaFileVersion( $filename ) {
// Open the file
if( !($fp = fopen( $filename, 'r' )) ) {
@@ -2076,14 +2071,14 @@ class adoSchema {
}
/**
- * Returns the AXMLS Schema Version of the provided XML schema string.
- *
- * Call this method to obtain the AXMLS DTD version of the provided XML schema string.
- * @see SchemaFileVersion()
- *
- * @param string $xmlstring XML schema string
- * @return string Schema version number or FALSE on error
- */
+ * Returns the AXMLS Schema Version of the provided XML schema string.
+ *
+ * Call this method to obtain the AXMLS DTD version of the provided XML schema string.
+ * @see SchemaFileVersion()
+ *
+ * @param string $xmlstring XML schema string
+ * @return string Schema version number or FALSE on error
+ */
function schemaStringVersion( $xmlstring ) {
if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
return FALSE;
@@ -2097,18 +2092,18 @@ class adoSchema {
}
/**
- * Extracts an XML schema from an existing database.
- *
- * Call this method to create an XML schema string from an existing database.
- * If the data parameter is set to TRUE, AXMLS will include the data from the database
- * tables in the schema.
- *
- * @param boolean $data include data in schema dump
- * @param string $indent indentation to use
- * @param string $prefix extract only tables with given prefix
- * @param boolean $stripprefix strip prefix string when storing in XML schema
- * @return string Generated XML schema
- */
+ * Extracts an XML schema from an existing database.
+ *
+ * Call this method to create an XML schema string from an existing database.
+ * If the data parameter is set to TRUE, AXMLS will include the data from the database
+ * tables in the schema.
+ *
+ * @param boolean $data include data in schema dump
+ * @param string $indent indentation to use
+ * @param string $prefix extract only tables with given prefix
+ * @param boolean $stripprefix strip prefix string when storing in XML schema
+ * @return string Generated XML schema
+ */
function extractSchema( $data = FALSE, $indent = ' ', $prefix = '' , $stripprefix=false) {
$old_mode = $this->db->setFetchMode( ADODB_FETCH_NUM );
@@ -2217,15 +2212,15 @@ class adoSchema {
}
/**
- * Sets a prefix for database objects
- *
- * Call this method to set a standard prefix that will be prepended to all database tables
- * and indices when the schema is parsed. Calling setPrefix with no arguments clears the prefix.
- *
- * @param string $prefix Prefix that will be prepended.
- * @param boolean $underscore If TRUE, automatically append an underscore character to the prefix.
- * @return boolean TRUE if successful, else FALSE
- */
+ * Sets a prefix for database objects
+ *
+ * Call this method to set a standard prefix that will be prepended to all database tables
+ * and indices when the schema is parsed. Calling setPrefix with no arguments clears the prefix.
+ *
+ * @param string $prefix Prefix that will be prepended.
+ * @param boolean $underscore If TRUE, automatically append an underscore character to the prefix.
+ * @return boolean TRUE if successful, else FALSE
+ */
function setPrefix( $prefix = '', $underscore = TRUE ) {
switch( TRUE ) {
// clear prefix
@@ -2252,13 +2247,13 @@ class adoSchema {
}
/**
- * Returns an object name with the current prefix prepended.
- *
- * @param string $name Name
- * @return string Prefixed name
- *
- * @access private
- */
+ * Returns an object name with the current prefix prepended.
+ *
+ * @param string $name Name
+ * @return string Prefixed name
+ *
+ * @access private
+ */
function prefix( $name = '' ) {
// if prefix is set
if( !empty( $this->objectPrefix ) ) {
@@ -2272,13 +2267,13 @@ class adoSchema {
}
/**
- * Checks if element references a specific platform
- *
- * @param string $platform Requested platform
- * @returns boolean TRUE if platform check succeeds
- *
- * @access private
- */
+ * Checks if element references a specific platform
+ *
+ * @param string $platform Requested platform
+ * @returns boolean TRUE if platform check succeeds
+ *
+ * @access private
+ */
function supportedPlatform( $platform = NULL ) {
if( !empty( $platform ) ) {
$regex = '/(^|\|)' . $this->db->databaseType . '(\||$)/i';
@@ -2301,22 +2296,22 @@ class adoSchema {
}
/**
- * Clears the array of generated SQL.
- *
- * @access private
- */
+ * Clears the array of generated SQL.
+ *
+ * @access private
+ */
function clearSQL() {
$this->sqlArray = array();
}
/**
- * Adds SQL into the SQL array.
- *
- * @param mixed $sql SQL to Add
- * @return boolean TRUE if successful, else FALSE.
- *
- * @access private
- */
+ * Adds SQL into the SQL array.
+ *
+ * @param mixed $sql SQL to Add
+ * @return boolean TRUE if successful, else FALSE.
+ *
+ * @access private
+ */
function addSQL( $sql = NULL ) {
if( is_array( $sql ) ) {
foreach( $sql as $line ) {
@@ -2352,13 +2347,13 @@ class adoSchema {
}
/**
- * Gets the SQL array in the specified format.
- *
- * @param string $format Format
- * @return mixed SQL
- *
- * @access private
- */
+ * Gets the SQL array in the specified format.
+ *
+ * @param string $format Format
+ * @return mixed SQL
+ *
+ * @access private
+ */
function getSQL( $format = NULL, $sqlArray = NULL ) {
if( !is_array( $sqlArray ) ) {
$sqlArray = $this->sqlArray;
@@ -2380,20 +2375,20 @@ class adoSchema {
}
/**
- * Destroys an adoSchema object.
- *
- * Call this method to clean up after an adoSchema object that is no longer in use.
- * @deprecated adoSchema now cleans up automatically.
- */
+ * Destroys an adoSchema object.
+ *
+ * Call this method to clean up after an adoSchema object that is no longer in use.
+ * @deprecated adoSchema now cleans up automatically.
+ */
function destroy() {
}
}
/**
-* Message logging function
-*
-* @access private
-*/
+ * Message logging function
+ *
+ * @access private
+ */
function logMsg( $msg, $title = NULL, $force = FALSE ) {
if( XMLS_DEBUG or $force ) {
echo '<pre>';
diff --git a/adodb.inc.php b/adodb.inc.php
index 3d5d1ad..0eb42d9 100644
--- a/adodb.inc.php
+++ b/adodb.inc.php
@@ -70,19 +70,19 @@ if (!defined('_ADODB_LAYER')) {
//==============================================================================================
/*********************************************************
- * Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).
- * Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi
- * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:adodb_force_type
- *
- * 0 = ignore empty fields. All empty fields in array are ignored.
- * 1 = force null. All empty, php null and string 'null' fields are
- * changed to sql NULL values.
- * 2 = force empty. All empty, php null and string 'null' fields are
- * changed to sql empty '' or 0 values.
- * 3 = force value. Value is left as it is. Php null and string 'null'
- * are set to sql NULL values and empty fields '' are set to empty '' sql values.
- * 4 = force value. Like 1 but numeric empty fields are set to zero.
- */
+ * Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).
+ * Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi
+ * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:adodb_force_type
+ *
+ * 0 = ignore empty fields. All empty fields in array are ignored.
+ * 1 = force null. All empty, php null and string 'null' fields are
+ * changed to sql NULL values.
+ * 2 = force empty. All empty, php null and string 'null' fields are
+ * changed to sql empty '' or 0 values.
+ * 3 = force value. Value is left as it is. Php null and string 'null'
+ * are set to sql NULL values and empty fields '' are set to empty '' sql values.
+ * 4 = force value. Like 1 but numeric empty fields are set to zero.
+ */
define('ADODB_FORCE_IGNORE',0);
define('ADODB_FORCE_NULL',1);
define('ADODB_FORCE_EMPTY',2);
@@ -99,10 +99,10 @@ if (!defined('_ADODB_LAYER')) {
define ('ADODB_STRINGMAX_NOLIMIT',-2);
/*
- * Defines the the default meta type returned
- * when ADOdb encounters a type that it is not
- * defined in the metaTypes.
- */
+ * Defines the the default meta type returned
+ * when ADOdb encounters a type that it is not
+ * defined in the metaTypes.
+ */
if (!defined('ADODB_DEFAULT_METATYPE'))
define ('ADODB_DEFAULT_METATYPE','N');
@@ -198,7 +198,7 @@ if (!defined('_ADODB_LAYER')) {
/**
* ADODB version as a string.
*/
- $ADODB_vers = 'v5.21.4 2022-01-22';
+ $ADODB_vers = 'v5.22.6 2023-06-11';
/**
* Determines whether recordset->RecordCount() is used.
@@ -221,8 +221,12 @@ if (!defined('_ADODB_LAYER')) {
// CLASS ADOFieldObject
//==============================================================================================
/**
- * Helper class for FetchFields -- holds info on a column
+ * Helper class for FetchFields -- holds info on a column.
+ *
+ * Note: Dynamic properties are required here, as some drivers may require
+ * the object to hold database-specific field metadata.
*/
+ #[\AllowDynamicProperties]
class ADOFieldObject {
var $name = '';
var $max_length=0;
@@ -240,12 +244,25 @@ if (!defined('_ADODB_LAYER')) {
}
+ /**
+ * Parse date string to prevent injection attack.
+ *
+ * @param string $s
+ *
+ * @return string
+ */
function _adodb_safedate($s) {
return str_replace(array("'", '\\'), '', $s);
}
- // parse date string to prevent injection attack
- // date string will have one quote at beginning e.g. '3434343'
+ /**
+ * Parse date string to prevent injection attack.
+ * Date string will have one quote at beginning e.g. '3434343'
+ *
+ * @param string $s
+ *
+ * @return string
+ */
function _adodb_safedateq($s) {
$len = strlen($s);
if ($s[0] !== "'") {
@@ -269,9 +286,17 @@ if (!defined('_ADODB_LAYER')) {
return strlen($s2) == 0 ? 'null' : $s2;
}
-
- // for transaction handling
-
+ /**
+ * For transaction handling.
+ *
+ * @param $dbms
+ * @param $fn
+ * @param $errno
+ * @param $errmsg
+ * @param $p1
+ * @param $p2
+ * @param $thisConnection
+ */
function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection) {
//print "Errorno ($fn errno=$errno m=$errmsg) ";
$thisConnection->_transOK = false;
@@ -281,8 +306,9 @@ if (!defined('_ADODB_LAYER')) {
}
}
- //------------------
- // class for caching
+ /**
+ * Class ADODB_Cache_File
+ */
class ADODB_Cache_File {
var $createdir = true; // requires creation of temp dirs
@@ -294,18 +320,42 @@ if (!defined('_ADODB_LAYER')) {
}
}
- // write serialised recordset to cache item/file
- function writecache($filename, $contents, $debug, $secs2cache) {
+ /**
+ * Write serialised RecordSet to cache item/file.
+ *
+ * @param $filename
+ * @param $contents
+ * @param $debug
+ * @param $secs2cache
+ *
+ * @return bool|int
+ */
+ function writecache($filename, $contents, $debug, $secs2cache) {
return adodb_write_file($filename, $contents,$debug);
}
- // load serialised recordset and unserialise it
+ /**
+ * load serialised RecordSet and unserialise it
+ *
+ * @param $filename
+ * @param $err
+ * @param $secs2cache
+ * @param $rsClass
+ *
+ * @return ADORecordSet
+ */
function &readcache($filename, &$err, $secs2cache, $rsClass) {
$rs = csv2rs($filename,$err,$secs2cache,$rsClass);
return $rs;
}
- // flush all items in cache
+ /**
+ * Flush all items in cache.
+ *
+ * @param bool $debug
+ *
+ * @return bool|void
+ */
function flushall($debug=false) {
global $ADODB_CACHE_DIR;
@@ -320,7 +370,12 @@ if (!defined('_ADODB_LAYER')) {
return $rez;
}
- // flush one file in cache
+ /**
+ * Flush one file in cache.
+ *
+ * @param string $f
+ * @param bool $debug
+ */
function flushcache($f, $debug=false) {
if (!@unlink($f)) {
if ($debug) {
@@ -329,20 +384,29 @@ if (!defined('_ADODB_LAYER')) {
}
}
+ /**
+ * @param string $hash
+ *
+ * @return string
+ */
function getdirname($hash) {
global $ADODB_CACHE_DIR;
- if (!isset($this->notSafeMode)) {
- $this->notSafeMode = !ini_get('safe_mode');
- }
- return ($this->notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($hash,0,2) : $ADODB_CACHE_DIR;
+ return $ADODB_CACHE_DIR . '/' . substr($hash, 0, 2);
}
- // create temp directories
+ /**
+ * Create temp directories.
+ *
+ * @param string $hash
+ * @param bool $debug
+ *
+ * @return string
+ */
function createdir($hash, $debug) {
global $ADODB_CACHE_PERMS;
$dir = $this->getdirname($hash);
- if ($this->notSafeMode && !file_exists($dir)) {
+ if (!file_exists($dir)) {
$oldu = umask(0);
if (!@mkdir($dir, empty($ADODB_CACHE_PERMS) ? 0771 : $ADODB_CACHE_PERMS)) {
if(!is_dir($dir) && $debug) {
@@ -395,7 +459,20 @@ if (!defined('_ADODB_LAYER')) {
//
var $dataProvider = 'native';
var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql
- var $database = ''; /// Name of database to be used.
+
+ /**
+ * @var string Current database name.
+ *
+ * This used to be stored in the $databaseName property, which was marked
+ * as deprecated in 4.66 and removed in 5.22.5.
+ */
+ public $database = '';
+
+ /**
+ * @var string If the driver is PDO, then the dsnType is e.g. sqlsrv, otherwise empty
+ */
+ public $dsnType = '';
+
var $host = ''; /// The hostname of the database server
var $port = ''; /// The port of the database server
var $user = ''; /// The username which is used to connect to the database server.
@@ -416,8 +493,33 @@ if (!defined('_ADODB_LAYER')) {
var $leftBracket = '['; /// left square bracked for t-sql styled column names
var $rightBracket = ']'; /// right square bracked for t-sql styled column names
var $charSet=false; /// character set to use - only for interbase, postgres and oci8
+
+ /** @var string SQL statement to get databases */
var $metaDatabasesSQL = '';
+
+ /** @var string SQL statement to get database tables */
var $metaTablesSQL = '';
+
+ /** @var string SQL statement to get table columns. */
+ var $metaColumnsSQL;
+
+ /**
+ * SQL statement to get the last IDENTITY value inserted into an IDENTITY
+ * column in the same scope.
+ * @see https://learn.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql
+ * @var string
+ */
+ var $identitySQL;
+
+ /** @var string SQL statement to create a Sequence . */
+ var $_genSeqSQL;
+
+ /** @var string SQL statement to drop a Sequence. */
+ var $_dropSeqSQL;
+
+ /** @var string SQL statement to generate a Sequence ID. */
+ var $_genIDSQL;
+
var $uniqueOrderBy = false; /// All order by columns have to be unique
var $emptyDate = ' ';
var $emptyTimeStamp = ' ';
@@ -440,11 +542,47 @@ if (!defined('_ADODB_LAYER')) {
var $isoDates = false; /// accepts dates in ISO format
var $cacheSecs = 3600; /// cache for 1 hour
- // memcache
- var $memCache = false; /// should we use memCache instead of caching in files
- var $memCacheHost; /// memCache host
- var $memCachePort = 11211; /// memCache port
- var $memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib, not supported w/memcached library)
+ /*****************************************
+ * memcached server options
+ ******************************************/
+
+ /**
+ * Use memCache library instead of caching in files.
+ * @var bool $memCache
+ */
+ public $memCache = false;
+
+ /**
+ * The memcache server(s) to connect to. Can be defined as:
+ * - a single host name/ip address
+ * - a list of hosts/ip addresses
+ * - an array of server connection data (weighted server groups).
+ * @link https://adodb.org/dokuwiki/doku.php?id=v5:userguide:memcached
+ * @var string|array $memCacheHost
+ */
+ public $memCacheHost;
+
+ /**
+ * Default port number.
+ * The default port can be overridden if memcache server connection data
+ * is provided as an array {@see $memCacheHost}.
+ * @var int $memCachePort
+ */
+ public $memCachePort = 11211;
+
+ /**
+ * Enable compression of stored items.
+ * @var bool $memCacheCompress
+ */
+ public $memCacheCompress = false;
+
+ /**
+ * An array of memcached options.
+ * Only used with memcached; memcache ignores this setting.
+ * @link https://www.php.net/manual/en/memcached.constants.php
+ * @var array $memCacheOptions
+ */
+ public $memCacheOptions = array();
var $sysDate = false; /// name of function that returns the current date
var $sysTimeStamp = false; /// name of function that returns the current timestamp
@@ -479,6 +617,10 @@ if (!defined('_ADODB_LAYER')) {
var $null2null = 'null'; // in autoexecute/getinsertsql/getupdatesql, this value will be converted to a null
var $bulkBind = false; // enable 2D Execute array
+
+ /** @var string SQL statement executed by some drivers after successful connection. */
+ public $connectStmt = '';
+
//
// PRIVATE VARS
//
@@ -486,14 +628,34 @@ if (!defined('_ADODB_LAYER')) {
var $_transOK = null;
/** @var resource Identifier for the native database connection */
var $_connectionID = false;
- var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will
- /// then returned by the errorMsg() function
- var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8
+
+ /**
+ * Stores the last returned error message.
+ * @see ADOConnection::errorMsg()
+ * @var string|false
+ */
+ var $_errorMsg = false;
+
+ /**
+ * Stores the last returned error code.
+ * Not guaranteed to be used. Only some drivers actually populate it.
+ * @var int|false
+ */
+ var $_errorCode = false;
+
var $_queryID = false; /// This variable keeps the last created result link identifier
var $_isPersistentConnection = false; /// A boolean variable to state whether its a persistent connection or normal connection. */
var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.
- var $_evalAll = false;
+
+ /**
+ * Eval string used to filter data.
+ * Only used in the deprecated Text driver.
+ * @see https://adodb.org/dokuwiki/doku.php?id=v5:database:text#workaround
+ * @var string
+ */
+ var $evalAll = false;
+
var $_affected = false;
var $_logsql = false;
var $_transmode = ''; // transaction mode
@@ -512,6 +674,29 @@ if (!defined('_ADODB_LAYER')) {
*/
protected $connectionParameters = array();
+ /*
+ * A simple associative array of user-defined custom actual/meta types
+ */
+ public $customActualTypes = array();
+
+ /*
+ * An array of user-defined custom meta/actual types.
+ * $this->customMetaTypes[$meta] = array(
+ * 'actual'=>'',
+ * 'dictionary'=>'',
+ * 'handler'=>'',
+ * 'callback'=>''
+ * );
+ */
+ public $customMetaTypes = array();
+
+ /** @var ADORecordSet Recordset used to retrieve MetaType information */
+ var $_metars;
+
+ /** @var string a specified locale. */
+ var $locale;
+
+
/**
* Default Constructor.
* We define it even though it does not actually do anything. This avoids
@@ -572,11 +757,54 @@ if (!defined('_ADODB_LAYER')) {
return $matches[1];
}
+ /**
+ * Set a custom meta type with a corresponding actual
+ *
+ * @param string $metaType The Custom ADOdb metatype
+ * @param string $dictionaryType The database dictionary type
+ * @param string $actualType The database actual type
+ * @param bool $handleAsType handle like an existing Metatype
+ * @param mixed $callBack A pre-processing function
+ *
+ * @return bool success if the actual exists
+ */
+ final public function setCustomMetaType(
+ $metaType,
+ $dictionaryType,
+ $actualType,
+ $handleAsType=false,
+ $callback=false){
+
+ $this->customMetaTypes[strtoupper($metaType)] = array(
+ 'actual'=>$actualType,
+ 'dictionary'=>strtoupper($dictionaryType),
+ 'handler'=>$handleAsType,
+ 'callback'=>$callback
+ );
+
+ /*
+ * Create a reverse lookup for the actualType
+ */
+ $this->customActualTypes[$actualType] = $metaType;
+
+ return true;
+ }
+
+ /**
+ * Get a list of custom meta types.
+ *
+ * @return string[]
+ */
+ final public function getCustomMetaTypes()
+ {
+ return $this->customMetaTypes;
+ }
+
+
/**
* Get server version info.
*
- * @return string[] An array with 2 elements: $arr['string'] is the description string,
- * and $arr[version] is the version (also a string).
+ * @return string[] Array with 2 string elements: version and description
*/
function ServerInfo() {
return array('description' => '', 'version' => '');
@@ -591,6 +819,13 @@ if (!defined('_ADODB_LAYER')) {
return !empty($this->_connectionID);
}
+ /**
+ * Find version string.
+ *
+ * @param string $str
+ *
+ * @return string
+ */
function _findvers($str) {
if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) {
return $arr[1];
@@ -729,6 +964,16 @@ if (!defined('_ADODB_LAYER')) {
return false;
}
+ /**
+ * Always force a new connection to database.
+ *
+ * @param string $argHostname Host to connect to
+ * @param string $argUsername Userid to login
+ * @param string $argPassword Associated password
+ * @param string $argDatabaseName Database name
+ *
+ * @return bool
+ */
function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) {
return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
}
@@ -807,7 +1052,13 @@ if (!defined('_ADODB_LAYER')) {
return $ret;
}
- function outp_throw($msg,$src='WARN',$sql='') {
+ /**
+ * Throw an exception if the handler is defined or prints the message if not.
+ * @param string $msg Message
+ * @param string $src the name of the calling function (in uppercase)
+ * @param string $sql Optional offending SQL statement
+ */
+ function outp_throw($msg, $src='WARN', $sql='') {
if (defined('ADODB_ERROR_HANDLER') && ADODB_ERROR_HANDLER == 'adodb_throw') {
adodb_throw($this->databaseType,$src,-9999,$msg,$sql,false,$this);
return;
@@ -843,6 +1094,8 @@ if (!defined('_ADODB_LAYER')) {
*
* @param string $fmt Format string
* @param string $col Date column; use system date if not specified.
+ *
+ * @return string
*/
function SQLDate($fmt, $col = '') {
if (!$col) {
@@ -852,14 +1105,14 @@ if (!defined('_ADODB_LAYER')) {
}
/**
- * Prepare an sql statement and return the statement resource.
+ * Prepare an SQL statement and return the statement resource.
*
- * For databases that do not support this, we return the $sql. To ensure
- * compatibility with databases that do not support prepare:
+ * For databases that do not support prepared statements, we return the
+ * provided SQL statement as-is, to ensure compatibility:
*
- * $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
- * $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
- * $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
+ * $stmt = $db->prepare("insert into table (id, name) values (?,?)");
+ * $db->execute($stmt, array(1,'Jill')) or die('insert failed');
+ * $db->execute($stmt, array(2,'Joe')) or die('insert failed');
*
* @param string $sql SQL to send to database
*
@@ -870,6 +1123,17 @@ if (!defined('_ADODB_LAYER')) {
return $sql;
}
+ /**
+ * Releases a previously prepared statement.
+ *
+ * @param mixed $stmt Statement resource, as returned by {@see prepare()}
+ *
+ * @return bool
+ */
+ function releaseStatement(&$stmt) {
+ return true;
+ }
+
/**
* Prepare a Stored Procedure and return the statement resource.
*
@@ -897,6 +1161,12 @@ if (!defined('_ADODB_LAYER')) {
return $this->qstr($s);
}
+ /**
+ * Quotes a string so that all strings are escaped.
+ * Wrapper for qstr with magic_quotes = false.
+ *
+ * @param string &$s
+ */
function q(&$s) {
//if (!empty($this->qNull && $s == 'null') {
// return $s;
@@ -905,8 +1175,9 @@ if (!defined('_ADODB_LAYER')) {
}
/**
- * PEAR DB Compat - do not use internally.
- */
+ * PEAR DB Compat - do not use internally.
+ * @return int
+ */
function ErrorNative() {
return $this->ErrorNo();
}
@@ -914,18 +1185,23 @@ if (!defined('_ADODB_LAYER')) {
/**
* PEAR DB Compat - do not use internally.
+ * @param string $seq_name
+ * @return int
*/
function nextId($seq_name) {
return $this->GenID($seq_name);
}
/**
- * Lock a row, will escalate and lock the table if row locking not supported
- * will normally free the lock at the end of the transaction
+ * Lock a row.
+ * Will escalate and lock the table if row locking is not supported.
+ * Will normally free the lock at the end of the transaction.
*
- * @param string $table name of table to lock
- * @param string $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
- * @param string $col
+ * @param string $table name of table to lock
+ * @param string $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
+ * @param string $col
+ *
+ * @return bool
*/
function RowLock($table,$where,$col='1 as adodbignore') {
return false;
@@ -948,15 +1224,15 @@ if (!defined('_ADODB_LAYER')) {
}
/**
- * PEAR DB Compat - do not use internally.
- *
- * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
- * for easy porting :-)
- *
- * @param int $mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
- *
- * @return int Previous fetch mode
- */
+ * PEAR DB Compat - do not use internally.
+ *
+ * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
+ * for easy porting :-)
+ *
+ * @param int $mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
+ *
+ * @return int Previous fetch mode
+ */
function SetFetchMode($mode) {
$old = $this->fetchMode;
$this->fetchMode = $mode;
@@ -968,15 +1244,14 @@ if (!defined('_ADODB_LAYER')) {
return $old;
}
-
/**
- * PEAR DB Compat - do not use internally.
+ * PEAR DB Compat - do not use internally.
*
* @param string $sql
* @param array|bool $inputarr
*
* @return ADORecordSet|bool
- */
+ */
function Query($sql, $inputarr=false) {
$rs = $this->Execute($sql, $inputarr);
if (!$rs && defined('ADODB_PEAR')) {
@@ -985,7 +1260,6 @@ if (!defined('_ADODB_LAYER')) {
return $rs;
}
-
/**
* PEAR DB Compat - do not use internally
*/
@@ -1026,36 +1300,54 @@ if (!defined('_ADODB_LAYER')) {
return '?';
}
- /*
- InParameter and OutParameter are self-documenting versions of Parameter().
- */
- function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {
+ /**
+ * Self-documenting version of Parameter().
+ *
+ * @param $stmt
+ * @param &$var
+ * @param $name
+ * @param int $maxLen
+ * @param bool $type
+ *
+ * @return bool
+ */
+ function InParameter(&$stmt, &$var, $name, $maxLen=4000, $type=false) {
return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
}
- /*
- */
+ /**
+ * Self-documenting version of Parameter().
+ *
+ * @param $stmt
+ * @param $var
+ * @param $name
+ * @param int $maxLen
+ * @param bool $type
+ *
+ * @return bool
+ */
function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {
return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);
}
-
- /*
- Usage in oracle
- $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
- $db->Parameter($stmt,$id,'myid');
- $db->Parameter($stmt,$group,'group',64);
- $db->Execute();
-
- @param $stmt Statement returned by Prepare() or PrepareSP().
- @param $var PHP variable to bind to
- @param $name Name of stored procedure variable name to bind to.
- @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
- @param [$maxLen] Holds an maximum length of the variable.
- @param [$type] The data type of $var. Legal values depend on driver.
-
- */
+ /**
+ *
+ * Usage in oracle
+ * $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
+ * $db->Parameter($stmt,$id,'myid');
+ * $db->Parameter($stmt,$group,'group',64);
+ * $db->Execute();
+ *
+ * @param mixed &$stmt Statement returned by Prepare() or PrepareSP().
+ * @param mixed &$var PHP variable to bind to
+ * @param string $name Name of stored procedure variable name to bind to.
+ * @param int|bool $isOutput Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
+ * @param int $maxLen Holds an maximum length of the variable.
+ * @param mixed $type The data type of $var. Legal values depend on driver.
+ *
+ * @return bool
+ */
function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) {
return false;
}
@@ -1102,13 +1394,16 @@ if (!defined('_ADODB_LAYER')) {
/**
- Used together with StartTrans() to end a transaction. Monitors connection
- for sql errors, and will commit or rollback as appropriate.
-
- @autoComplete if true, monitor sql errors and commit and rollback as appropriate,
- and if set to false force rollback even if no SQL error detected.
- @returns true on commit, false on rollback.
- */
+ * Complete a transation.
+ *
+ * Used together with StartTrans() to end a transaction. Monitors connection
+ * for sql errors, and will commit or rollback as appropriate.
+ *
+ * @param bool autoComplete if true, monitor sql errors and commit and
+ * rollback as appropriate, and if set to false
+ * force rollback even if no SQL error detected.
+ * @returns true on commit, false on rollback.
+ */
function CompleteTrans($autoComplete = true) {
if ($this->transOff > 1) {
$this->transOff -= 1;
@@ -1132,16 +1427,16 @@ if (!defined('_ADODB_LAYER')) {
$this->_transOK = false;
$this->RollbackTrans();
if ($this->debug) {
- ADOCOnnection::outp("Smart Rollback occurred");
+ ADOConnection::outp("Smart Rollback occurred");
}
}
return $this->_transOK;
}
- /*
- At the end of a StartTrans/CompleteTrans block, perform a rollback.
- */
+ /**
+ * At the end of a StartTrans/CompleteTrans block, perform a rollback.
+ */
function FailTrans() {
if ($this->debug)
if ($this->transOff == 0) {
@@ -1154,8 +1449,8 @@ if (!defined('_ADODB_LAYER')) {
}
/**
- Check if transaction has failed, only for Smart Transactions.
- */
+ * Check if transaction has failed, only for Smart Transactions.
+ */
function HasFailedTrans() {
if ($this->transOff > 0) {
return $this->_transOK == false;
@@ -1171,7 +1466,7 @@ if (!defined('_ADODB_LAYER')) {
* @param array|bool $inputarr holds the input data to bind to.
* Null elements will be set to null.
*
- * @return ADORecordSet|bool
+ * @return ADORecordSet|false
*/
public function Execute($sql, $inputarr = false) {
if ($this->fnExecute) {
@@ -1324,9 +1619,6 @@ if (!defined('_ADODB_LAYER')) {
// error handling if query fails
if ($this->_queryID === false) {
- if ($this->debug == 99) {
- adodb_backtrace(true,5);
- }
$fn = $this->raiseErrorFn;
if ($fn) {
$fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
@@ -1374,6 +1666,18 @@ if (!defined('_ADODB_LAYER')) {
return $rs;
}
+ /**
+ * Execute a query.
+ *
+ * @param string|array $sql Query to execute.
+ * @param array $inputarr An optional array of parameters.
+ *
+ * @return mixed|bool Query identifier or true if execution successful, false if failed.
+ */
+ function _query($sql, $inputarr = false) {
+ return false;
+ }
+
function CreateSequence($seqname='adodbseq',$startID=1) {
if (empty($this->_genSeqSQL)) {
return false;
@@ -1496,8 +1800,8 @@ if (!defined('_ADODB_LAYER')) {
}
/**
- * @return # rows affected by UPDATE/DELETE
- */
+ * @return int|false Number of rows affected by UPDATE/DELETE
+ */
function Affected_Rows() {
if ($this->hasAffectedRows) {
if ($this->fnExecute === 'adodb_log_sql') {
@@ -1572,11 +1876,24 @@ if (!defined('_ADODB_LAYER')) {
}
/**
- * @returns assoc array where keys are tables, and values are foreign keys
+ * Returns a list of Foreign Keys associated with a specific table.
+ *
+ * If there are no foreign keys then the function returns false.
+ *
+ * @param string $table The name of the table to get the foreign keys for.
+ * @param string $owner Table owner/schema.
+ * @param bool $upper If true, only matches the table with the uppercase name.
+ * @param bool $associative Returns the result in associative mode;
+ * if ADODB_FETCH_MODE is already associative, then
+ * this parameter is discarded.
+ *
+ * @return string[]|false An array where keys are tables, and values are foreign keys;
+ * false if no foreign keys could be found.
*/
- function MetaForeignKeys($table, $owner=false, $upper=false) {
+ function metaForeignKeys($table, $owner = '', $upper = false, $associative = false) {
return false;
}
+
/**
* Choose a database to connect to. Many databases do not support this.
*
@@ -1693,12 +2010,12 @@ if (!defined('_ADODB_LAYER')) {
}
/**
- * Create serializable recordset. Breaks rs link to connection.
- *
- * @param ADORecordSet $rs the recordset to serialize
+ * Create serializable recordset. Breaks rs link to connection.
+ *
+ * @param ADORecordSet $rs the recordset to serialize
*
- * @return ADORecordSet_array|bool the new recordset
- */
+ * @return ADORecordSet_array|bool the new recordset
+ */
function SerializableRS(&$rs) {
$rs2 = $this->_rs2rs($rs);
$ignore = false;
@@ -1708,17 +2025,17 @@ if (!defined('_ADODB_LAYER')) {
}
/**
- * Convert a database recordset to an array recordset.
+ * Convert a database recordset to an array recordset.
+ *
+ * Input recordset's cursor should be at beginning, and old $rs will be closed.
*
- * Input recordset's cursor should be at beginning, and old $rs will be closed.
- *
* @param ADORecordSet $rs the recordset to copy
* @param int $nrows number of rows to retrieve (optional)
* @param int $offset offset by number of rows (optional)
* @param bool $close
*
* @return ADORecordSet_array|ADORecordSet|bool the new recordset
- */
+ */
function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true) {
if (! $rs) {
$ret = false;
@@ -1747,7 +2064,7 @@ if (!defined('_ADODB_LAYER')) {
$arrayClass = $this->arrayClass;
- $rs2 = new $arrayClass();
+ $rs2 = new $arrayClass($fakeQueryId=1);
$rs2->connection = $this;
$rs2->sql = $rs->sql;
$rs2->dataProvider = $this->dataProvider;
@@ -1756,7 +2073,7 @@ if (!defined('_ADODB_LAYER')) {
return $rs2;
}
- /*
+ /**
* Return all rows.
*
* Compat with PEAR DB.
@@ -1765,9 +2082,9 @@ if (!defined('_ADODB_LAYER')) {
* @param array|bool $inputarr Input bind array
*
* @return array|false
- */
+ */
function GetAll($sql, $inputarr=false) {
- return $this->GetArray($sql,$inputarr);
+ return $this->GetArray($sql,$inputarr);
}
/**
@@ -1941,23 +2258,17 @@ if (!defined('_ADODB_LAYER')) {
return $rv;
}
- function Transpose(&$rs,$addfieldnames=true) {
- $rs2 = $this->_rs2rs($rs);
- if (!$rs2) {
- return false;
- }
-
- $rs2->_transpose($addfieldnames);
- return $rs2;
- }
-
- /*
- Calculate the offset of a date for a particular database and generate
- appropriate SQL. Useful for calculating future/past dates and storing
- in a database.
-
- If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
- */
+ /**
+ * Calculate the offset of a date for a particular database
+ * and generate appropriate SQL.
+ *
+ * Useful for calculating future/past dates and storing in a database.
+ *
+ * @param double $dayFraction 1.5 means 1.5 days from now, 1.0/24 for 1 hour
+ * @param string|false $date Reference date, false for system time
+ *
+ * @return string
+ */
function OffsetDate($dayFraction,$date=false) {
if (!$date) {
$date = $this->sysDate;
@@ -2029,14 +2340,14 @@ if (!defined('_ADODB_LAYER')) {
}
/**
- * Return one row of sql statement. Recordset is disposed for you.
- * Note that SelectLimit should not be called.
- *
- * @param string $sql SQL statement
- * @param array|bool $inputarr input bind array
+ * Return one row of sql statement. Recordset is disposed for you.
+ * Note that SelectLimit should not be called.
+ *
+ * @param string $sql SQL statement
+ * @param array|bool $inputarr input bind array
*
- * @return array|false Array containing the first row of the query
- */
+ * @return array|false Array containing the first row of the query
+ */
function GetRow($sql,$inputarr=false) {
global $ADODB_COUNTRECS;
@@ -2083,24 +2394,24 @@ if (!defined('_ADODB_LAYER')) {
}
/**
- * Insert or replace a single record. Note: this is not the same as MySQL's replace.
- * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
- * Also note that no table locking is done currently, so it is possible that the
- * record be inserted twice by two programs...
- *
- * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
- *
- * $table table name
- * $fieldArray associative array of data (you must quote strings yourself).
- * $keyCol the primary key field name or if compound key, array of field names
- * autoQuote set to true to use a heuristic to quote strings. Works with nulls and numbers
- * but does not work with dates nor SQL functions.
- * has_autoinc the primary key is an auto-inc field, so skip in insert.
- *
- * Currently blob replace not supported
- *
- * returns 0 = fail, 1 = update, 2 = insert
- */
+ * Insert or replace a single record. Note: this is not the same as MySQL's replace.
+ * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
+ * Also note that no table locking is done currently, so it is possible that the
+ * record be inserted twice by two programs...
+ *
+ * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
+ *
+ * $table table name
+ * $fieldArray associative array of data (you must quote strings yourself).
+ * $keyCol the primary key field name or if compound key, array of field names
+ * autoQuote set to true to use a heuristic to quote strings. Works with nulls and numbers
+ * but does not work with dates nor SQL functions.
+ * has_autoinc the primary key is an auto-inc field, so skip in insert.
+ *
+ * Currently blob replace not supported
+ *
+ * returns 0 = fail, 1 = update, 2 = insert
+ */
function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false) {
global $ADODB_INCLUDED_LIB;
@@ -2182,7 +2493,7 @@ if (!defined('_ADODB_LAYER')) {
* - userid
* - setFetchMode (adodb 4.23)
*
- * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
+ * We create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
* Assuming that we can have 50,000 files per directory with good performance,
* then we can scale to 12.8 million unique cached recordsets. Wow!
*/
@@ -2323,34 +2634,32 @@ if (!defined('_ADODB_LAYER')) {
}
- /*
-
-
- $forceUpdate .
- */
/**
- * Similar to PEAR DB's autoExecute(), except that $mode can be 'INSERT'
- * or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE.
- * If $mode == 'UPDATE', then $where is compulsory as a safety measure.
+ * Simple interface to insert and update records.
*
- * @param $table
- * @param $fields_values
- * @param string $mode
- * @param false $where
- * @param bool $forceUpdate If true, perform update even if the data has not changed.
- * @param bool $magic_quotes This param is not used since 5.21.0.
- * It remains for backwards compatibility.
+ * Automatically generate and execute INSERT and UPDATE statements
+ * on a given table, similar to PEAR DB's autoExecute().
+ *
+ * @param string $table Name of the table to process.
+ * @param array $fields_values Associative array of field names => values.
+ * @param string|int $mode Execution mode: 'INSERT' (default), 'UPDATE' or
+ * one of the DB_AUTOQUERY_xx constants.
+ * @param string $where SQL where clause (mandatory in UPDATE mode as a safety measure)
+ * @param bool $forceUpdate If true, update all provided fields, even if they have not changed;
+ * otherwise only modified fields are updated.
+ * @param bool $magic_quotes This param is not used since 5.21.0.
+ * It remains for backwards compatibility.
*
* @return bool
*
* @noinspection PhpUnusedParameterInspection
*/
- function AutoExecute($table, $fields_values, $mode = 'INSERT', $where = false, $forceUpdate = true, $magic_quotes = false) {
+ function autoExecute($table, $fields_values, $mode = 'INSERT', $where = '', $forceUpdate = true, $magic_quotes = false) {
if (empty($fields_values)) {
$this->outp_throw('AutoExecute: Empty fields array', 'AutoExecute');
return false;
}
- if ($where === false && ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) ) {
+ if (empty($where) && ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */)) {
$this->outp_throw('AutoExecute: Illegal mode=UPDATE with empty WHERE clause', 'AutoExecute');
return false;
}
@@ -2362,7 +2671,7 @@ if (!defined('_ADODB_LAYER')) {
}
$rs->tableName = $table;
- if ($where !== false) {
+ if (!empty($where)) {
$sql .= " WHERE $where";
}
$rs->sql = $sql;
@@ -2457,37 +2766,47 @@ if (!defined('_ADODB_LAYER')) {
/**
- * Update a blob column, given a where clause. There are more sophisticated
- * blob handling functions that we could have implemented, but all require
- * a very complex API. Instead we have chosen something that is extremely
- * simple to understand and use.
- *
- * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
- *
- * Usage to update a $blobvalue which has a primary key blob_id=1 into a
- * field blobtable.blobcolumn:
- *
- * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
- *
- * Insert example:
- *
- * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
- * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
- */
- function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') {
+ * Update a BLOB column, given a where clause.
+ *
+ * There are more sophisticated blob handling functions that we could have
+ * implemented, but all require a very complex API. Instead we have chosen
+ * something that is extremely simple to understand and use.
+ *
+ * Sample usage:
+ * - update a BLOB in field table.blob_col with value $blobValue, for a
+ * record having primary key id=1
+ * $conn->updateBlob('table', 'blob_col', $blobValue, 'id=1');
+ * - insert example:
+ * $conn->execute('INSERT INTO table (id, blob_col) VALUES (1, null)');
+ * $conn->updateBlob('table', 'blob_col', $blobValue, 'id=1');
+ *
+ * @param string $table
+ * @param string $column
+ * @param string $val Filename containing blob data
+ * @param mixed $where {@see updateBlob()}
+ * @param string $blobtype supports 'BLOB' (default) and 'CLOB'
+ *
+ * @return bool success
+ */
+ function updateBlob($table, $column, $val, $where, $blobtype='BLOB') {
return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
}
/**
- * Usage:
- * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
- *
- * $blobtype supports 'BLOB' and 'CLOB'
- *
- * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
- * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
- */
- function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') {
+ * Update a BLOB from a file.
+ *
+ * Usage example:
+ * $conn->updateBlobFile('table', 'blob_col', '/path/to/file', 'id=1');
+ *
+ * @param string $table
+ * @param string $column
+ * @param string $path Filename containing blob data
+ * @param mixed $where {@see updateBlob()}
+ * @param string $blobtype supports 'BLOB' and 'CLOB'
+ *
+ * @return bool success
+ */
+ function updateBlobFile($table, $column, $path, $where, $blobtype='BLOB') {
$fd = fopen($path,'rb');
if ($fd === false) {
return false;
@@ -2551,12 +2870,12 @@ if (!defined('_ADODB_LAYER')) {
}
/**
- * Usage:
- * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
- *
- * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
- * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
- */
+ * Usage:
+ * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
+ *
+ * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
+ * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
+ */
function UpdateClob($table,$column,$val,$where) {
return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
}
@@ -2575,9 +2894,9 @@ if (!defined('_ADODB_LAYER')) {
/**
- * Change the SQL connection locale to a specified locale.
- * This is used to get the date formats written depending on the client locale.
- */
+ * Change the SQL connection locale to a specified locale.
+ * This is used to get the date formats written depending on the client locale.
+ */
function SetDateLocale($locale = 'En') {
$this->locale = $locale;
switch (strtoupper($locale))
@@ -2656,7 +2975,9 @@ if (!defined('_ADODB_LAYER')) {
}
/**
- * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
+ * Begin a Transaction.
+ *
+ * Must be followed by CommitTrans() or RollbackTrans().
*
* @return bool true if succeeded or false if database does not support transactions
*/
@@ -2718,11 +3039,14 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
}
/**
- * If database does not support transactions, always return true as data always committed
+ * Commits a transaction.
*
- * @param bool $ok set to false to rollback transaction, true to commit
+ * If database does not support transactions, return true as data is
+ * always committed.
*
- * @return true/false.
+ * @param bool $ok True to commit, false to rollback the transaction.
+ *
+ * @return bool true if successful
*/
function CommitTrans($ok=true) {
return true;
@@ -2730,9 +3054,12 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
/**
- * If database does not support transactions, rollbacks always fail, so return false
+ * Rolls back a transaction.
*
- * @return bool
+ * If database does not support transactions, return false as rollbacks
+ * always fail.
+ *
+ * @return bool true if successful
*/
function RollbackTrans() {
return false;
@@ -3239,20 +3566,21 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
/**
- * Will select the supplied $page number from a recordset, given that it is paginated in pages of
- * $nrows rows per page. It also saves two boolean values saying if the given page is the first
- * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
+ * Execute query with pagination.
*
- * See docs-adodb.htm#ex8 for an example of usage.
- * NOTE: phpLens uses a different algorithm and does not use PageExecute().
+ * Will select the supplied $page number from a recordset, divided in
+ * pages of $nrows rows each. It also saves two boolean values saying
+ * if the given page is the first and/or last one of the recordset.
*
- * @param string $sql
- * @param int $nrows Number of rows per page to get
- * @param int $page Page number to get (1-based)
- * @param mixed[]|bool $inputarr Array of bind variables
- * @param int $secs2cache Private parameter only used by jlim
+ * @param string $sql Query to execute
+ * @param int $nrows Number of rows per page
+ * @param int $page Page number to retrieve (1-based)
+ * @param array|bool $inputarr Array of bind variables
+ * @param int $secs2cache Time-to-live of the cache (in seconds), 0 to force query execution
+ *
+ * @return ADORecordSet|bool the recordset ($rs->databaseType == 'array')
*
- * @return mixed the recordset ($rs->databaseType == 'array')
+ * @author Iván Oliva
*/
function PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0) {
global $ADODB_INCLUDED_LIB;
@@ -3269,17 +3597,17 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
/**
- * Will select the supplied $page number from a recordset, given that it is paginated in pages of
- * $nrows rows per page. It also saves two boolean values saying if the given page is the first
- * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
- *
- * @param int $secs2cache seconds to cache data, set to 0 to force query
- * @param string $sql
- * @param int $nrows is the number of rows per page to get
- * @param int $page is the page number to get (1-based)
- * @param mixed[]|bool $inputarr array of bind variables
- * @return mixed the recordset ($rs->databaseType == 'array')
- */
+ * Will select the supplied $page number from a recordset, given that it is paginated in pages of
+ * $nrows rows per page. It also saves two boolean values saying if the given page is the first
+ * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
+ *
+ * @param int $secs2cache seconds to cache data, set to 0 to force query
+ * @param string $sql
+ * @param int $nrows is the number of rows per page to get
+ * @param int $page is the page number to get (1-based)
+ * @param mixed[]|bool $inputarr array of bind variables
+ * @return mixed the recordset ($rs->databaseType == 'array')
+ */
function CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false) {
/*switch($this->dataProvider) {
case 'postgres':
@@ -3291,37 +3619,37 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
}
/**
- * Returns the maximum size of a MetaType C field. If the method
- * is not defined in the driver returns ADODB_STRINGMAX_NOTSET
- *
- * @return int
- */
+ * Returns the maximum size of a MetaType C field. If the method
+ * is not defined in the driver returns ADODB_STRINGMAX_NOTSET
+ *
+ * @return int
+ */
function charMax() {
return ADODB_STRINGMAX_NOTSET;
}
/**
- * Returns the maximum size of a MetaType X field. If the method
- * is not defined in the driver returns ADODB_STRINGMAX_NOTSET
- *
- * @return int
- */
+ * Returns the maximum size of a MetaType X field. If the method
+ * is not defined in the driver returns ADODB_STRINGMAX_NOTSET
+ *
+ * @return int
+ */
function textMax() {
return ADODB_STRINGMAX_NOTSET;
}
/**
- * Returns a substring of a varchar type field
- *
- * Some databases have variations of the parameters, which is why
- * we have an ADOdb function for it
- *
- * @param string $fld The field to sub-string
- * @param int $start The start point
- * @param int $length An optional length
- *
- * @return string The SQL text
- */
+ * Returns a substring of a varchar type field
+ *
+ * Some databases have variations of the parameters, which is why
+ * we have an ADOdb function for it
+ *
+ * @param string $fld The field to sub-string
+ * @param int $start The start point
+ * @param int $length An optional length
+ *
+ * @return string The SQL text
+ */
function substr($fld,$start,$length=0) {
$text = "{$this->substr}($fld,$start";
if ($length > 0)
@@ -3426,15 +3754,15 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
//==============================================================================================
/**
- * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
- */
+ * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
+ */
+ #[\AllowDynamicProperties]
class ADOFetchObj {
};
- //==============================================================================================
- // CLASS ADORecordSet_empty
- //==============================================================================================
-
+ /**
+ * Class ADODB_Iterator_empty
+ */
class ADODB_Iterator_empty implements Iterator {
private $rs;
@@ -3477,8 +3805,8 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
/**
- * Lightweight recordset when there are no records to be returned
- */
+ * Lightweight recordset when there are no records to be returned
+ */
class ADORecordSet_empty implements IteratorAggregate
{
var $dataProvider = 'empty';
@@ -3564,10 +3892,9 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
include_once(ADODB_DIR.'/adodb-time.inc.php');
}
- //==============================================================================================
- // CLASS ADORecordSet
- //==============================================================================================
-
+ /**
+ * Class ADODB_Iterator
+ */
class ADODB_Iterator implements Iterator {
private $rs;
@@ -3612,18 +3939,29 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
}
+/**
+ * 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 implements IteratorAggregate {
/**
- * 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).
+ * Used for cases when a recordset object is not created by executing a query.
*/
- class ADORecordSet implements IteratorAggregate {
+ const DUMMY_QUERY_ID = -1;
/**
* public variables
*/
var $dataProvider = "native";
+
+ /**
+ * @var string Table name (used in _adodb_getupdatesql() and _adodb_getinsertsql())-
+ */
+ public $tableName = '';
+
/** @var bool|array */
var $fields = false; /// holds the current row data
var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob
@@ -3639,41 +3977,66 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
var $bind = false; /// used by Fields() to hold array - should be private?
var $fetchMode; /// default fetch mode
- var $connection = false; /// the parent connection
-
+ /** @var ADOConnection The parent connection */
+ var $connection = false;
/**
* private variables
*/
var $_numOfRows = -1; /** number of rows, or -1 */
var $_numOfFields = -1; /** number of fields in recordset */
- /** @var resource result link identifier */
- var $_queryID = -1;
+
+ /**
+ * @var resource|int|false result link identifier
+ */
+ var $_queryID = self::DUMMY_QUERY_ID;
+
var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */
var $_closed = false; /** has recordset been closed */
var $_inited = false; /** Init() should only be called once */
var $_obj; /** Used by FetchObj */
var $_names; /** Used by FetchObj */
- var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */
- var $_atFirstPage = false; /** Added by Iván Oliva to implement recordset pagination */
- var $_atLastPage = false; /** Added by Iván Oliva to implement recordset pagination */
+ // Recordset pagination
+ /** @var int Number of rows per page */
+ var $rowsPerPage;
+ /** @var int Current page number */
+ var $_currentPage = -1;
+ /** @var bool True if current page is the first page */
+ var $_atFirstPage = false;
+ /** @var bool True if current page is the last page */
+ var $_atLastPage = false;
+ /** @var int Last page number */
var $_lastPageNo = -1;
+ /** @var int Total number of rows in recordset */
var $_maxRecordCount = 0;
+
var $datetime = false;
+ public $customActualTypes;
+ public $customMetaTypes;
+
+ /** @var int Only used in _adodb_getinsertsql() */
+ public $insertSig;
+
/**
* @var ADOFieldObject[] Field metadata cache
* @see fieldTypesArray()
*/
protected $fieldObjectsCache;
+ /**
+ * @var int Defines the Fetch Mode for a recordset
+ * See the ADODB_FETCH_* constants
+ */
+ public $adodbFetchMode;
+
/**
* Constructor
*
- * @param resource|int queryID this is the queryID returned by ADOConnection->_query()
- *
+ * @param resource|int $queryID Query ID returned by ADOConnection->_query()
+ * @param int|bool $mode The ADODB_FETCH_MODE value
*/
- function __construct($queryID) {
+ function __construct($queryID,$mode=false) {
$this->_queryID = $queryID;
}
@@ -3698,7 +4061,7 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
}
$this->_inited = true;
if ($this->_queryID) {
- @$this->_initrs();
+ @$this->_initRS();
} else {
$this->_numOfRows = 0;
$this->_numOfFields = 0;
@@ -3713,6 +4076,16 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
}
}
+ /**
+ * Recordset initialization stub
+ */
+ protected function _initRS() {}
+
+ /**
+ * Row fetch stub
+ * @return bool
+ */
+ protected function _fetch() {}
/**
* Generate a SELECT tag from a recordset, and return the HTML markup.
@@ -3851,24 +4224,28 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
return $this->GetArray($nRows);
}
- /*
- * Some databases allow multiple recordsets to be returned. This function
- * will return true if there is a next recordset, or false if no more.
- */
+ /**
+ * Checks if there is another available recordset.
+ *
+ * Some databases allow multiple recordsets to be returned.
+ *
+ * @return boolean true if there is a next recordset, or false if no more
+ */
function NextRecordSet() {
return false;
}
/**
- * return recordset as a 2-dimensional array.
+ * Return recordset as a 2-dimensional array.
+ *
* Helper function for ADOConnection->SelectLimit()
*
- * @param offset is the row to start calculations from (1-based)
- * @param [nrows] is the number of rows to return
+ * @param int $nrows Number of rows to return
+ * @param int $offset Starting row (1-based)
*
* @return array an array indexed by the rows (0-based) from the recordset
*/
- function GetArrayLimit($nrows,$offset=-1) {
+ function getArrayLimit($nrows, $offset=-1) {
if ($offset <= 0) {
return $this->GetArray($nrows);
}
@@ -3889,11 +4266,11 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
/**
* Synonym for GetArray() for compatibility with ADO.
*
- * @param [nRows] is the number of rows to return. -1 means every row.
+ * @param int $nRows Number of rows to return. -1 means every row.
*
* @return array an array indexed by the rows (0-based) from the recordset
*/
- function GetRows($nRows = -1) {
+ function getRows($nRows = -1) {
return $this->GetArray($nRows);
}
@@ -3994,9 +4371,7 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
switch ($showArrayMethod) {
case 0:
- if ($fetchMode == ADODB_FETCH_ASSOC
- || $fetchMode == ADODB_FETCH_BOTH)
- {
+ if ($fetchMode != ADODB_FETCH_NUM) {
/*
* The driver should have already handled the key
* casing, but in case it did not. We will check and force
@@ -4106,8 +4481,8 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
/**
- * PEAR DB Compat - do not use internally
- */
+ * PEAR DB Compat - do not use internally
+ */
function Free() {
return $this->Close();
}
@@ -4152,13 +4527,13 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
/**
- * Fetch a row, returning PEAR_Error if no more rows.
- * This is PEAR DB compat mode.
- *
- * @param mixed[]|false $arr
- *
- * @return mixed DB_OK or error object
- */
+ * Fetch a row, returning PEAR_Error if no more rows.
+ * This is PEAR DB compat mode.
+ *
+ * @param mixed[]|false $arr
+ *
+ * @return mixed DB_OK or error object
+ */
function FetchInto(&$arr) {
if ($this->EOF) {
return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false;
@@ -4281,6 +4656,14 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
return false;
}
+ /**
+ * Adjusts the result pointer to an arbitrary row in the result.
+ *
+ * @param int $row The row to seek to.
+ *
+ * @return bool False if the recordset contains no rows, otherwise true.
+ */
+ function _seek($row) {}
/**
* Get the value of a field in the current row by column name.
@@ -4354,8 +4737,9 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
* Use associative array to get fields array for databases that do not support
* associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it
*
- * @param int [$upper] Case for the array keys, defaults to uppercase
+ * @param int $upper Case for the array keys, defaults to uppercase
* (see ADODB_ASSOC_CASE_xxx constants)
+ * @return array
*/
function GetRowAssoc($upper = ADODB_ASSOC_CASE) {
$record = array();
@@ -4391,15 +4775,14 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
}
/**
- * Synonyms RecordCount and RowCount
+ * Number of rows in recordset.
*
* @return int Number of rows or -1 if this is not supported
*/
- function RecordCount() {
+ function recordCount() {
return $this->_numOfRows;
}
-
/**
* If we are using PageExecute(), this will return the maximum possible rows
* that can be returned when paging a recordset.
@@ -4407,26 +4790,32 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
* @return int
*/
function MaxRecordCount() {
- return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();
+ return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->recordCount();
}
/**
- * synonyms RecordCount and RowCount
+ * Number of rows in recordset.
+ * Alias for {@see recordCount()}
*
- * @return the number of rows or -1 if this is not supported
+ * @return int Number of rows or -1 if this is not supported
*/
- function RowCount() {
- return $this->_numOfRows;
+ function rowCount() {
+ return $this->recordCount();
}
-
- /**
- * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
+ /**
+ * Portable RecordCount.
+ *
+ * Be aware of possible problems in multiuser environments.
+ * For better speed the table must be indexed by the condition.
+ * Heavy test this before deploying.
*
- * @return the number of records from a previous SELECT. All databases support this.
+ * @param string $table
+ * @param string $condition
+ *
+ * @return int Number of records from a previous SELECT. All databases support this.
*
- * But aware possible problems in multiuser environments. For better speed the table
- * must be indexed by the condition. Heavy test this before deploying.
+ * @author Pablo Roca <pabloroca@mvps.org>
*/
function PO_RecordCount($table="", $condition="") {
@@ -4500,24 +4889,24 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
}
/**
- * Return the fields array of the current row as an object for convenience.
- * The default case is lowercase field names.
- *
- * @return the object with the properties set to the fields of the current row
- */
+ * Return the fields array of the current row as an object for convenience.
+ * The default case is lowercase field names.
+ *
+ * @return the object with the properties set to the fields of the current row
+ */
function FetchObj() {
return $this->FetchObject(false);
}
/**
- * Return the fields array of the current row as an object for convenience.
- * The default case is uppercase.
- *
- * @param $isupper to set the object property names to uppercase
- *
- * @return the object with the properties set to the fields of the current row
- */
- function FetchObject($isupper=true) {
+ * Return the fields array of the current row as an object for convenience.
+ * The default case is uppercase.
+ *
+ * @param bool $isUpper to set the object property names to uppercase
+ *
+ * @return ADOFetchObj The object with properties set to the fields of the current row
+ */
+ function FetchObject($isUpper=true) {
if (empty($this->_obj)) {
$this->_obj = new ADOFetchObj();
$this->_names = array();
@@ -4526,12 +4915,11 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
$this->_names[] = $f->name;
}
}
- $i = 0;
$o = clone($this->_obj);
for ($i=0; $i <$this->_numOfFields; $i++) {
$name = $this->_names[$i];
- if ($isupper) {
+ if ($isUpper) {
$n = strtoupper($name);
} else {
$n = $name;
@@ -4543,34 +4931,34 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
}
/**
- * Return the fields array of the current row as an object for convenience.
- * The default is lower-case field names.
- *
- * @return the object with the properties set to the fields of the current row,
- * or false if EOF
- *
- * Fixed bug reported by tim@orotech.net
- */
+ * Return the fields array of the current row as an object for convenience.
+ * The default is lower-case field names.
+ *
+ * @return ADOFetchObj|false The object with properties set to the fields of the current row
+ * or false if EOF.
+ *
+ * Fixed bug reported by tim@orotech.net
+ */
function FetchNextObj() {
return $this->FetchNextObject(false);
}
/**
- * Return the fields array of the current row as an object for convenience.
- * The default is upper case field names.
- *
- * @param $isupper to set the object property names to uppercase
- *
- * @return the object with the properties set to the fields of the current row,
- * or false if EOF
- *
- * Fixed bug reported by tim@orotech.net
- */
- function FetchNextObject($isupper=true) {
+ * Return the fields array of the current row as an object for convenience.
+ * The default is upper case field names.
+ *
+ * @param bool $isUpper to set the object property names to uppercase
+ *
+ * @return ADOFetchObj|false The object with properties set to the fields of the current row
+ * or false if EOF.
+ *
+ * Fixed bug reported by tim@orotech.net
+ */
+ function FetchNextObject($isUpper=true) {
$o = false;
if ($this->_numOfRows != 0 && !$this->EOF) {
- $o = $this->FetchObject($isupper);
+ $o = $this->FetchObject($isUpper);
$this->_currentRow++;
if ($this->_fetch()) {
return $o;
@@ -4581,37 +4969,29 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
}
/**
- * Get the metatype of the column. This is used for formatting. This is because
- * many databases use different names for the same type, so we transform the original
- * type to our standardised version which uses 1 character codes:
- *
- * @param t is the type passed in. Normally is ADOFieldObject->type.
- * @param len is the maximum length of that field. This is because we treat character
- * fields bigger than a certain size as a 'B' (blob).
- * @param fieldobj is the field object returned by the database driver. Can hold
- * additional info (eg. primary_key for mysql).
+ * Get the ADOdb metatype.
*
- * @return the general type of the data:
- * C for character < 250 chars
- * X for teXt (>= 250 chars)
- * B for Binary
- * N for numeric or floating point
- * D for date
- * T for timestamp
- * L for logical/Boolean
- * I for integer
- * R for autoincrement counter/integer
+ * Many databases use different names for the same type, so we transform
+ * the native type to our standardised one, which uses 1 character codes.
+ * @see https://adodb.org/dokuwiki/doku.php?id=v5:dictionary:dictionary_index#portable_data_types
*
+ * @param string|ADOFieldObject $t Native type (usually ADOFieldObject->type)
+ * It is also possible to provide an
+ * ADOFieldObject here.
+ * @param int $len The field's maximum length. This is because we treat
+ * character fields bigger than a certain size as a 'B' (blob).
+ * @param ADOFieldObject $fieldObj Field object returned by the database driver;
+ * can hold additional info (eg. primary_key for mysql).
*
- */
- function MetaType($t,$len=-1,$fieldobj=false) {
- if (is_object($t)) {
- $fieldobj = $t;
- $t = $fieldobj->type;
- $len = $fieldobj->max_length;
+ * @return string The ADOdb Standard type
+ */
+ function metaType($t, $len = -1, $fieldObj = false) {
+ if ($t instanceof ADOFieldObject) {
+ $fieldObj = $t;
+ $t = $fieldObj->type;
+ $len = $fieldObj->max_length;
}
-
// changed in 2.32 to hashing instead of switch stmt for speed...
static $typeMap = array(
'VARCHAR' => 'C',
@@ -4718,8 +5098,6 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
"SQLBOOL" => 'L'
);
-
- $tmap = false;
$t = strtoupper($t);
$tmap = (isset($typeMap[$t])) ? $typeMap[$t] : ADODB_DEFAULT_METATYPE;
switch ($tmap) {
@@ -4735,7 +5113,7 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
return 'C';
case 'I':
- if (!empty($fieldobj->primary_key)) {
+ if (!empty($fieldObj->primary_key)) {
return 'R';
}
return 'I';
@@ -4744,8 +5122,8 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
return 'N';
case 'B':
- if (isset($fieldobj->binary)) {
- return ($fieldobj->binary) ? 'B' : 'X';
+ if (isset($fieldObj->binary)) {
+ return ($fieldObj->binary) ? 'B' : 'X';
}
return 'B';
@@ -4796,8 +5174,10 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
/**
* set/returns the current recordset page when paginating
+ * @param int $page
+ * @return int
*/
- function AbsolutePage($page=-1) {
+ function absolutePage($page=-1) {
if ($page != -1) {
$this->_currentPage = $page;
}
@@ -4806,6 +5186,8 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
/**
* set/returns the status of the atFirstPage flag when paginating
+ * @param bool $status
+ * @return bool
*/
function AtFirstPage($status=false) {
if ($status != false) {
@@ -4814,6 +5196,10 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
return $this->_atFirstPage;
}
+ /**
+ * @param bool $page
+ * @return bool
+ */
function LastPageNo($page = false) {
if ($page != false) {
$this->_lastPageNo = $page;
@@ -4823,6 +5209,8 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
/**
* set/returns the status of the atLastPage flag when paginating
+ * @param bool $status
+ * @return bool
*/
function AtLastPage($status=false) {
if ($status != false) {
@@ -4860,48 +5248,22 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
/**
* Constructor
+ *
+ * The parameters passed to this recordset are always fake because
+ * this class does not use the queryID
+ *
+ * @param resource|int $queryID Ignored
+ * @param int|bool $mode The ADODB_FETCH_MODE value
*/
- function __construct($fakeid=1) {
+ function __construct($queryID, $mode=false) {
global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;
// fetch() on EOF does not delete $this->fields
$this->compat = !empty($ADODB_COMPAT_FETCH);
- parent::__construct($fakeid); // fake queryID
+ parent::__construct($queryID); // fake queryID
$this->fetchMode = $ADODB_FETCH_MODE;
}
- function _transpose($addfieldnames=true) {
- global $ADODB_INCLUDED_LIB;
-
- if (empty($ADODB_INCLUDED_LIB)) {
- include_once(ADODB_DIR.'/adodb-lib.inc.php');
- }
- $hdr = true;
-
- $fobjs = $addfieldnames ? $this->_fieldobjects : false;
- adodb_transpose($this->_array, $newarr, $hdr, $fobjs);
- //adodb_pr($newarr);
-
- $this->_skiprow1 = false;
- $this->_array = $newarr;
- $this->_colnames = $hdr;
-
- adodb_probetypes($newarr,$this->_types);
-
- $this->_fieldobjects = array();
-
- foreach($hdr as $k => $name) {
- $f = new ADOFieldObject();
- $f->name = $name;
- $f->type = $this->_types[$k];
- $f->max_length = -1;
- $this->_fieldobjects[] = $f;
- }
- $this->fields = reset($this->_array);
-
- $this->_initrs();
-
- }
/**
* Setup the array.
@@ -5115,12 +5477,8 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
break;
case 'mysql':
- // mysql driver deprecated since 5.5, removed in 7.0
- // automatically switch to mysqli
- if(version_compare(PHP_VERSION, '7.0.0', '>=')) {
- $db = 'mysqli';
- }
- $class = $db;
+ // mysql extension removed in PHP 7.0 - automatically switch to mysqli
+ $class = $db = 'mysqli';
break;
default:
@@ -5485,6 +5843,7 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
}
include_once($path);
$class = "ADODB2_$drivername";
+ /** @var ADODB_DataDict $dict */
$dict = new $class();
$dict->dataProvider = $conn->dataProvider;
$dict->connection = $conn;
@@ -5497,9 +5856,9 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
return $dict;
}
- /*
- Perform a print_r, with pre tags for better formatting.
- */
+ /**
+ * Perform a print_r, with pre tags for better formatting.
+ */
function adodb_pr($var,$as_string=false) {
if ($as_string) {
ob_start();
@@ -5518,12 +5877,15 @@ http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_1
}
}
- /*
- 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
- */
+ /**
+ * Perform a stack-crawl and pretty print it.
+ *
+ * @param bool $printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then).
+ * @param int $levels Number of levels to display
+ * @param mixed $ishtml
+ *
+ * @return string
+ */
function adodb_backtrace($printOrArr=true,$levels=9999,$ishtml=null) {
global $ADODB_INCLUDED_LIB;
if (empty($ADODB_INCLUDED_LIB)) {
diff --git a/composer.json b/composer.json
index 807866b..cd97e9d 100644
--- a/composer.json
+++ b/composer.json
@@ -27,7 +27,7 @@
},
"require" : {
- "php" : "^5.5.9 || ^7.0 || ^8.0"
+ "php" : "^7.0 || ^8.0"
},
"require-dev" : {
diff --git a/datadict/datadict-access.inc.php b/datadict/datadict-access.inc.php
index 7a7d4cb..b3f9fad 100644
--- a/datadict/datadict-access.inc.php
+++ b/datadict/datadict-access.inc.php
@@ -30,6 +30,15 @@ class ADODB2_access extends ADODB_DataDict {
function ActualType($meta)
{
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
switch($meta) {
case 'C': return 'TEXT';
case 'XL':
@@ -41,18 +50,19 @@ class ADODB2_access extends ADODB_DataDict {
case 'B': return 'BINARY';
case 'TS':
- case 'D': return 'DATETIME';
+ case 'D':
+ return 'DATETIME';
case 'T': return 'DATETIME';
- case 'L': return 'BYTE';
- case 'I': return 'INTEGER';
+ case 'L': return 'BYTE';
+ case 'I': return 'INTEGER';
case 'I1': return 'BYTE';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'INTEGER';
- case 'F': return 'DOUBLE';
- case 'N': return 'NUMERIC';
+ case 'F': return 'DOUBLE';
+ case 'N': return 'NUMERIC';
default:
return $meta;
}
diff --git a/datadict/datadict-db2.inc.php b/datadict/datadict-db2.inc.php
index c5dda09..9ac106b 100644
--- a/datadict/datadict-db2.inc.php
+++ b/datadict/datadict-db2.inc.php
@@ -34,6 +34,15 @@ class ADODB2_db2 extends ADODB_DataDict {
function ActualType($meta)
{
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL': return 'CLOB';
diff --git a/datadict/datadict-firebird.inc.php b/datadict/datadict-firebird.inc.php
index 0020a0a..79d0a8f 100644
--- a/datadict/datadict-firebird.inc.php
+++ b/datadict/datadict-firebird.inc.php
@@ -22,8 +22,8 @@
// security - hide paths
if (!defined('ADODB_DIR')) die();
-class ADODB2_firebird extends ADODB_DataDict {
-
+class ADODB2_firebird extends ADODB_DataDict
+{
var $databaseType = 'firebird';
var $seqField = false;
var $seqPrefix = 's_';
@@ -32,69 +32,92 @@ class ADODB2_firebird extends ADODB_DataDict {
var $alterCol = ' ALTER';
var $dropCol = ' DROP';
- function ActualType($meta)
+ function actualType($meta)
{
- switch($meta) {
- case 'C': return 'VARCHAR';
- case 'XL':
- case 'X': return 'BLOB SUB_TYPE TEXT';
-
- case 'C2': return 'VARCHAR(32765)'; // up to 32K
- case 'X2': return 'VARCHAR(4096)';
-
- case 'V': return 'CHAR';
- case 'C1': return 'CHAR(1)';
- case 'B': return 'BLOB';
+ $meta = strtoupper($meta);
- case 'D': return 'DATE';
- case 'TS':
- case 'T': return 'TIMESTAMP';
-
- case 'L': return 'SMALLINT';
- case 'I': return 'INTEGER';
- case 'I1': return 'SMALLINT';
- case 'I2': return 'SMALLINT';
- case 'I4': return 'INTEGER';
- case 'I8': return 'BIGINT';
+ // Add support for custom meta types.
+ // We do this first, that allows us to override existing types
+ if (isset($this->connection->customMetaTypes[$meta])) {
+ return $this->connection->customMetaTypes[$meta]['actual'];
+ }
- case 'F': return 'DOUBLE PRECISION';
- case 'N': return 'DECIMAL';
- default:
- return $meta;
+ switch($meta) {
+ case 'C':
+ return 'VARCHAR';
+ case 'XL':
+ return 'BLOB SUB_TYPE BINARY';
+ case 'X':
+ return 'BLOB SUB_TYPE TEXT';
+
+ case 'C2':
+ return 'VARCHAR(32765)'; // up to 32K
+ case 'X2':
+ return 'VARCHAR(4096)';
+
+ case 'V':
+ return 'CHAR';
+ case 'C1':
+ return 'CHAR(1)';
+
+ case 'B':
+ return 'BLOB';
+
+ case 'D':
+ return 'DATE';
+ case 'TS':
+ case 'T':
+ return 'TIMESTAMP';
+
+ case 'L':
+ case 'I1':
+ case 'I2':
+ return 'SMALLINT';
+ case 'I':
+ case 'I4':
+ return 'INTEGER';
+ case 'I8':
+ return 'BIGINT';
+
+ case 'F':
+ return 'DOUBLE PRECISION';
+ case 'N':
+ return 'DECIMAL';
+ default:
+ return $meta;
}
}
- function NameQuote($name = NULL,$allowBrackets=false)
+ function nameQuote($name = null, $allowBrackets = false)
{
if (!is_string($name)) {
- return FALSE;
+ return false;
}
$name = trim($name);
- if ( !is_object($this->connection) ) {
+ if (!is_object($this->connection)) {
return $name;
}
$quote = $this->connection->nameQuote;
// if name is of the form `name`, quote it
- if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
+ if (preg_match('/^`(.+)`$/', $name, $matches)) {
return $quote . $matches[1] . $quote;
}
// if name contains special characters, quote it
- if ( !preg_match('/^[' . $this->nameRegex . ']+$/', $name) ) {
+ if (!preg_match('/^[' . $this->nameRegex . ']+$/', $name)) {
return $quote . $name . $quote;
}
return $quote . $name . $quote;
}
- function CreateDatabase($dbname, $options=false)
+ function createDatabase($dbname, $options = false)
{
- $options = $this->_Options($options);
$sql = array();
$sql[] = "DECLARE EXTERNAL FUNCTION LOWER CSTRING(80) RETURNS CSTRING(80) FREE_IT ENTRY_POINT 'IB_UDF_lower' MODULE_NAME 'ib_udf'";
@@ -102,50 +125,62 @@ class ADODB2_firebird extends ADODB_DataDict {
return $sql;
}
- function _DropAutoIncrement($t)
+ function _dropAutoIncrement($tabname)
{
- if (strpos($t,'.') !== false) {
- $tarr = explode('.',$t);
- return 'DROP GENERATOR '.$tarr[0].'."s_'.$tarr[1].'"';
+ if (strpos($tabname, '.') !== false) {
+ $tarr = explode('.', $tabname);
+ return 'DROP SEQUENCE ' . $tarr[0] . '."s_' . $tarr[1] . '"';
}
- return 'DROP GENERATOR s_'.$t;
+ return 'DROP SEQUENCE s_' . $tabname;
}
- function _CreateSuffix($fname,&$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
+ function _createSuffix($fname, &$ftype, $fnotnull, $fdefault, $fautoinc, $fconstraint, $funsigned)
{
$suffix = '';
- if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
- if ($fnotnull) $suffix .= ' NOT NULL';
- if ($fautoinc) $this->seqField = $fname;
+ if (strlen($fdefault)) {
+ $suffix .= " DEFAULT $fdefault";
+ }
+ if ($fnotnull) {
+ $suffix .= ' NOT NULL';
+ }
+ if ($fautoinc) {
+ $this->seqField = $fname;
+ }
$fconstraint = preg_replace("/``/", "\"", $fconstraint);
- if ($fconstraint) $suffix .= ' '.$fconstraint;
+ if ($fconstraint) {
+ $suffix .= ' ' . $fconstraint;
+ }
return $suffix;
}
/**
- Generate the SQL to create table. Returns an array of sql strings.
- */
- function CreateTableSQL($tabname, $flds, $tableoptions=array())
+ * Generate the SQL to create table. Returns an array of sql strings.
+ */
+ function createTableSQL($tabname, $flds, $tableoptions = array())
{
- list($lines,$pkey,$idxs) = $this->_GenFields($flds, true);
+ list($lines, $pkey, $idxs) = $this->_GenFields($flds, true);
// genfields can return FALSE at times
- if ($lines == null) $lines = array();
+ if ($lines == null) {
+ $lines = array();
+ }
$taboptions = $this->_Options($tableoptions);
- $tabname = $this->TableName ($tabname);
- $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
+ $tabname = $this->TableName($tabname);
+ $sql = $this->_TableSQL($tabname, $lines, $pkey, $taboptions);
- if ($this->autoIncrement && !isset($taboptions['DROP']))
- { $tsql = $this->_Triggers($tabname,$taboptions);
- foreach($tsql as $s) $sql[] = $s;
+ if ($this->autoIncrement && !isset($taboptions['DROP'])) {
+ $tsql = $this->_Triggers($tabname, $taboptions);
+ foreach ($tsql as $s) {
+ $sql[] = $s;
+ }
}
if (is_array($idxs)) {
- foreach($idxs as $idx => $idxdef) {
- $sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
+ foreach ($idxs as $idx => $idxdef) {
+ $sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
$sql = array_merge($sql, $sql_idxs);
}
}
@@ -154,44 +189,47 @@ class ADODB2_firebird extends ADODB_DataDict {
}
-/*
-CREATE or replace TRIGGER jaddress_insert
-before insert on jaddress
-for each row
-begin
-IF ( NEW."seqField" IS NULL OR NEW."seqField" = 0 ) THEN
- NEW."seqField" = GEN_ID("GEN_tabname", 1);
-end;
-*/
- function _Triggers($tabname,$tableoptions)
+ /*
+ CREATE or replace TRIGGER jaddress_insert
+ before insert on jaddress
+ for each row
+ begin
+ IF ( NEW."seqField" IS NULL OR NEW."seqField" = 0 ) THEN
+ NEW."seqField" = GEN_ID("GEN_tabname", 1);
+ end;
+ */
+ function _triggers($tabname, $taboptions)
{
- if (!$this->seqField) return array();
+ if (!$this->seqField) {
+ return array();
+ }
- $tab1 = preg_replace( '/"/', '', $tabname );
+ $tab1 = preg_replace('/"/', '', $tabname);
if ($this->schema) {
- $t = strpos($tab1,'.');
- if ($t !== false) $tab = substr($tab1,$t+1);
- else $tab = $tab1;
+ $t = strpos($tab1, '.');
+ if ($t !== false) {
+ $tab = substr($tab1, $t + 1);
+ } else {
+ $tab = $tab1;
+ }
$seqField = $this->seqField;
- $seqname = $this->schema.'.'.$this->seqPrefix.$tab;
- $trigname = $this->schema.'.t_'.$this->seqPrefix.$tab;
+ $seqname = $this->schema . '.' . $this->seqPrefix . $tab;
+ $trigname = $this->schema . '.t_' . $this->seqPrefix . $tab;
} else {
$seqField = $this->seqField;
- $seqname = $this->seqPrefix.$tab1;
- $trigname = 't_'.$seqname;
+ $seqname = $this->seqPrefix . $tab1;
+ $trigname = 't_' . $seqname;
}
- if (isset($tableoptions['DROP']))
- { $sql[] = "DROP GENERATOR $seqname";
- }
- elseif (isset($tableoptions['REPLACE']))
- { $sql[] = "DROP GENERATOR \"$seqname\"";
- $sql[] = "CREATE GENERATOR \"$seqname\"";
- $sql[] = "ALTER TRIGGER \"$trigname\" BEFORE INSERT OR UPDATE AS BEGIN IF ( NEW.$seqField IS NULL OR NEW.$seqField = 0 ) THEN NEW.$seqField = GEN_ID(\"$seqname\", 1); END";
- }
- else
- { $sql[] = "CREATE GENERATOR $seqname";
- $sql[] = "CREATE TRIGGER $trigname FOR $tabname BEFORE INSERT OR UPDATE AS BEGIN IF ( NEW.$seqField IS NULL OR NEW.$seqField = 0 ) THEN NEW.$seqField = GEN_ID($seqname, 1); END";
+ if (isset($taboptions['DROP'])) {
+ $sql[] = "DROP SEQUENCE $seqname";
+ } elseif (isset($taboptions['REPLACE'])) {
+ $sql[] = "DROP SEQUENCE \"$seqname\"";
+ $sql[] = "CREATE SEQUENCE \"$seqname\"";
+ $sql[] = "ALTER TRIGGER \"$trigname\" BEFORE INSERT OR UPDATE AS BEGIN IF ( NEW.$seqField IS NULL OR NEW.$seqField = 0 ) THEN NEW.$seqField = GEN_ID(\"$seqname\", 1); END";
+ } else {
+ $sql[] = "CREATE SEQUENCE $seqname";
+ $sql[] = "CREATE TRIGGER $trigname FOR $tabname BEFORE INSERT OR UPDATE AS BEGIN IF ( NEW.$seqField IS NULL OR NEW.$seqField = 0 ) THEN NEW.$seqField = GEN_ID($seqname, 1); END";
}
$this->seqField = false;
@@ -201,27 +239,39 @@ end;
/**
* Change the definition of one column
*
- * As some DBM's can't do that on there own, you need to supply the complete definition of the new table,
- * to allow, recreating the table and copying the content over to the new table
* @param string $tabname table-name
* @param string $flds column-name and type for the changed column
- * @param string $tableflds='' complete definition of the new table, eg. for postgres, default ''
- * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
+ * @param string $tableflds Unused
+ * @param array|string $tableoptions Unused
+ *
* @return array with SQL strings
*/
- function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
+ public function alterColumnSQL($tabname, $flds, $tableflds = '', $tableoptions = '')
{
- $tabname = $this->TableName ($tabname);
+ $tabname = $this->TableName($tabname);
$sql = array();
- list($lines,$pkey,$idxs) = $this->_GenFields($flds);
+ list($lines, , $idxs) = $this->_GenFields($flds);
// genfields can return FALSE at times
- if ($lines == null) $lines = array();
+
+ if ($lines == null) {
+ $lines = array();
+ }
+
$alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
- foreach($lines as $v) {
+
+ foreach ($lines as $v) {
+ /*
+ * The type must be preceded by the keyword 'TYPE'
+ */
+ $vExplode = explode(' ', $v);
+ $vExplode = array_filter($vExplode);
+ array_splice($vExplode, 1, 0, array('TYPE'));
+ $v = implode(' ', $vExplode);
$sql[] = $alter . $v;
}
+
if (is_array($idxs)) {
- foreach($idxs as $idx => $idxdef) {
+ foreach ($idxs as $idx => $idxdef) {
$sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
$sql = array_merge($sql, $sql_idxs);
}
diff --git a/datadict/datadict-generic.inc.php b/datadict/datadict-generic.inc.php
index c9c8dee..1a60dbc 100644
--- a/datadict/datadict-generic.inc.php
+++ b/datadict/datadict-generic.inc.php
@@ -28,8 +28,19 @@ class ADODB2_generic extends ADODB_DataDict {
var $seqField = false;
+
function ActualType($meta)
{
+
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL':
diff --git a/datadict/datadict-ibase.inc.php b/datadict/datadict-ibase.inc.php
index 5f58880..4310ded 100644
--- a/datadict/datadict-ibase.inc.php
+++ b/datadict/datadict-ibase.inc.php
@@ -30,6 +30,15 @@ class ADODB2_ibase extends ADODB_DataDict {
function ActualType($meta)
{
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL':
diff --git a/datadict/datadict-informix.inc.php b/datadict/datadict-informix.inc.php
index acb5ba7..9e15163 100644
--- a/datadict/datadict-informix.inc.php
+++ b/datadict/datadict-informix.inc.php
@@ -30,6 +30,15 @@ class ADODB2_informix extends ADODB_DataDict {
function ActualType($meta)
{
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
switch($meta) {
case 'C': return 'VARCHAR';// 255
case 'XL':
diff --git a/datadict/datadict-mssql.inc.php b/datadict/datadict-mssql.inc.php
index 1bcb27d..17df9e3 100644
--- a/datadict/datadict-mssql.inc.php
+++ b/datadict/datadict-mssql.inc.php
@@ -68,9 +68,14 @@ class ADODB2_mssql extends ADODB_DataDict {
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
+
+ $t = strtoupper($t);
+
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
$len = -1; // mysql max_length is not accurate
- switch (strtoupper($t)) {
+ switch ($t) {
case 'R':
case 'INT':
case 'INTEGER': return 'I';
@@ -87,6 +92,16 @@ class ADODB2_mssql extends ADODB_DataDict {
function ActualType($meta)
{
+
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
switch(strtoupper($meta)) {
case 'C': return 'VARCHAR';
diff --git a/datadict/datadict-mssqlnative.inc.php b/datadict/datadict-mssqlnative.inc.php
index b53dcd9..59228cb 100644
--- a/datadict/datadict-mssqlnative.inc.php
+++ b/datadict/datadict-mssqlnative.inc.php
@@ -71,7 +71,13 @@ class ADODB2_mssqlnative extends ADODB_DataDict {
$fieldobj = $t;
$t = $fieldobj->type;
}
-
+
+
+ $t = strtoupper($t);
+
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
$_typeConversion = array(
-155 => 'D',
93 => 'D',
@@ -115,7 +121,15 @@ class ADODB2_mssqlnative extends ADODB_DataDict {
function ActualType($meta)
{
$DATE_TYPE = 'DATETIME';
-
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
switch(strtoupper($meta)) {
case 'C': return 'VARCHAR';
diff --git a/datadict/datadict-mysql.inc.php b/datadict/datadict-mysql.inc.php
index a1ee950..9efbba1 100644
--- a/datadict/datadict-mysql.inc.php
+++ b/datadict/datadict-mysql.inc.php
@@ -33,7 +33,7 @@ class ADODB2_mysql extends ADODB_DataDict {
public $blobAllowsNotNull = true;
- function MetaType($t,$len=-1,$fieldobj=false)
+ function metaType($t,$len=-1,$fieldobj=false)
{
if (is_object($t)) {
@@ -44,7 +44,14 @@ class ADODB2_mysql extends ADODB_DataDict {
$is_serial = is_object($fieldobj) && $fieldobj->primary_key && $fieldobj->auto_increment;
$len = -1; // mysql max_length is not accurate
- switch (strtoupper($t)) {
+
+ $t = strtoupper($t);
+
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
+ switch ($t) {
+
case 'STRING':
case 'CHAR':
case 'VARCHAR':
@@ -84,13 +91,27 @@ class ADODB2_mysql extends ADODB_DataDict {
case 'SMALLINT': return $is_serial ? 'R' : 'I2';
case 'MEDIUMINT': return $is_serial ? 'R' : 'I4';
case 'BIGINT': return $is_serial ? 'R' : 'I8';
- default: return ADODB_DEFAULT_METATYPE;
+ default:
+
+ return ADODB_DEFAULT_METATYPE;
}
}
function ActualType($meta)
{
- switch(strtoupper($meta)) {
+
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
+ switch($meta)
+ {
+
case 'C': return 'VARCHAR';
case 'XL':return 'LONGTEXT';
case 'X': return 'TEXT';
@@ -114,7 +135,9 @@ class ADODB2_mysql extends ADODB_DataDict {
case 'F': return 'DOUBLE';
case 'N': return 'NUMERIC';
+
default:
+
return $meta;
}
}
diff --git a/datadict/datadict-oci8.inc.php b/datadict/datadict-oci8.inc.php
index 9a23909..6d2cd24 100644
--- a/datadict/datadict-oci8.inc.php
+++ b/datadict/datadict-oci8.inc.php
@@ -50,7 +50,13 @@ class ADODB2_oci8 extends ADODB_DataDict {
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
- switch (strtoupper($t)) {
+
+ $t = strtoupper($t);
+
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
+ switch ($t) {
case 'VARCHAR':
case 'VARCHAR2':
case 'CHAR':
@@ -92,6 +98,15 @@ class ADODB2_oci8 extends ADODB_DataDict {
function ActualType($meta)
{
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
switch($meta) {
case 'C': return 'VARCHAR';
case 'X': return $this->typeX;
diff --git a/datadict/datadict-postgres.inc.php b/datadict/datadict-postgres.inc.php
index 17627c4..89bcc0a 100644
--- a/datadict/datadict-postgres.inc.php
+++ b/datadict/datadict-postgres.inc.php
@@ -34,7 +34,7 @@ class ADODB2_postgres extends ADODB_DataDict
public $blobAllowsDefaultValue = true;
public $blobAllowsNotNull = true;
-
+
function metaType($t, $len=-1, $fieldobj=false)
{
if (is_object($t)) {
@@ -42,16 +42,23 @@ class ADODB2_postgres extends ADODB_DataDict
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
+
+ $t = strtoupper($t);
+
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
$is_serial = is_object($fieldobj) && !empty($fieldobj->primary_key) && !empty($fieldobj->unique) &&
!empty($fieldobj->has_default) && substr($fieldobj->default_value,0,8) == 'nextval(';
- switch (strtoupper($t)) {
+ switch ($t) {
+
case 'INTERVAL':
case 'CHAR':
case 'CHARACTER':
case 'VARCHAR':
case 'NAME':
- case 'BPCHAR':
+ case 'BPCHAR':
if ($len <= $this->blobSize) return 'C';
case 'TEXT':
@@ -94,13 +101,22 @@ class ADODB2_postgres extends ADODB_DataDict
case 'REAL':
return 'F';
- default:
- return ADODB_DEFAULT_METATYPE;
+ default:
+ return ADODB_DEFAULT_METATYPE;
}
}
- function actualType($meta)
+ function actualType($meta)
{
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
switch ($meta) {
case 'C': return 'VARCHAR';
case 'XL':
@@ -144,7 +160,8 @@ class ADODB2_postgres extends ADODB_DataDict
$sql = array();
$not_null = false;
list($lines,$pkey) = $this->_genFields($flds);
- $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' ';
+ $alter = 'ALTER TABLE ' . $tabname . $this->addCol;
+ $alter .= (float)@$this->serverInfo['version'] < 9.6 ? ' ' : ' IF NOT EXISTS ';
foreach($lines as $v) {
if (($not_null = preg_match('/NOT NULL/i',$v))) {
$v = preg_replace('/NOT NULL/i','',$v);
@@ -152,7 +169,7 @@ class ADODB2_postgres extends ADODB_DataDict
if (preg_match('/^([^ ]+) .*DEFAULT (\'[^\']+\'|\"[^\"]+\"|[^ ]+)/',$v,$matches)) {
list(,$colname,$default) = $matches;
$sql[] = $alter . str_replace('DEFAULT '.$default,'',$v);
- $sql[] = 'UPDATE '.$tabname.' SET '.$colname.'='.$default;
+ $sql[] = 'UPDATE '.$tabname.' SET '.$colname.'='.$default.' WHERE '.$colname.' IS NULL ';
$sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET DEFAULT ' . $default;
} else {
$sql[] = $alter . $v;
@@ -168,18 +185,21 @@ class ADODB2_postgres extends ADODB_DataDict
function dropIndexSQL($idxname, $tabname = NULL)
{
- return array(sprintf($this->dropIndex, $this->tableName($idxname), $this->tableName($tabname)));
+ return array(sprintf($this->dropIndex, $this->tableName($idxname), $this->tableName($tabname)));
}
/**
* Change the definition of one column
*
- * Postgres can't do that on it's own, you need to supply the complete definition of the new table,
- * to allow, recreating the table and copying the content over to the new table
- * @param string $tabname table-name
- * @param string $flds column-name and type for the changed column
- * @param string $tableflds complete definition of the new table, eg. for postgres, default ''
- * @param array/ $tableoptions options for the new table see CreateTableSQL, default ''
+ * Postgres can't do that on its own, you need to supply the complete
+ * definition of the new table, to allow recreating the table and copying
+ * the content over to the new table.
+ *
+ * @param string $tabname table-name
+ * @param string $flds column-name and type for the changed column
+ * @param string $tableflds complete definition of the new table, e.g. for postgres, default ''
+ * @param array $tableoptions options for the new table {@see CreateTableSQL()}, default ''
+ *
* @return array with SQL strings
*/
function alterColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
@@ -197,9 +217,9 @@ class ADODB2_postgres extends ADODB_DataDict
if ($not_null = preg_match('/NOT NULL/i',$v)) {
$v = preg_replace('/NOT NULL/i','',$v);
}
- // this next block doesn't work - there is no way that I can see to
- // explicitly ask a column to be null using $flds
- else if ($set_null = preg_match('/NULL/i',$v)) {
+ // this next block doesn't work - there is no way that I can see to
+ // explicitly ask a column to be null using $flds
+ elseif ($set_null = preg_match('/NULL/i',$v)) {
// if they didn't specify not null, see if they explicitly asked for null
// Lookbehind pattern covers the case 'fieldname NULL datatype DEFAULT NULL'
// only the first NULL should be removed, not the one specifying
@@ -278,7 +298,7 @@ class ADODB2_postgres extends ADODB_DataDict
* @param string $tabname table-name
* @param string $flds column-name and type for the changed column
* @param string $tableflds complete definition of the new table, eg. for postgres, default ''
- * @param array/ $tableoptions options for the new table see CreateTableSQL, default ''
+ * @param array $tableoptions options for the new table {@see CreateTableSQL}, default []
* @return array with SQL strings
*/
function dropColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
@@ -305,7 +325,7 @@ class ADODB2_postgres extends ADODB_DataDict
* @param string $tabname table-name
* @param string $dropflds column-names to drop
* @param string $tableflds complete definition of the new table, eg. for postgres
- * @param array/string $tableoptions options for the new table see CreateTableSQL, default ''
+ * @param array|string $tableoptions options for the new table see CreateTableSQL, default ''
* @return array with SQL strings
*/
function _recreate_copy_table($tabname, $dropflds, $tableflds, $tableoptions='')
@@ -477,11 +497,11 @@ CREATE [ UNIQUE ] INDEX index_name ON table
if (isset($idxoptions['HASH'])) {
$s .= 'USING HASH ';
}
-
+
if (isset($idxoptions[$this->upperName])) {
$s .= $idxoptions[$this->upperName];
}
-
+
if (is_array($flds)) {
$flds = implode(', ', $flds);
}
@@ -514,7 +534,7 @@ CREATE [ UNIQUE ] INDEX index_name ON table
}
return $ftype;
}
-
+
function changeTableSQL($tablename, $flds, $tableoptions = false, $dropOldFlds=false)
{
global $ADODB_FETCH_MODE;
@@ -524,18 +544,18 @@ CREATE [ UNIQUE ] INDEX index_name ON table
if ($this->connection->fetchMode !== false) {
$savem = $this->connection->setFetchMode(false);
}
-
+
// check table exists
$save_handler = $this->connection->raiseErrorFn;
$this->connection->raiseErrorFn = '';
$cols = $this->metaColumns($tablename);
$this->connection->raiseErrorFn = $save_handler;
-
+
if (isset($savem)) {
$this->connection->setFetchMode($savem);
}
$ADODB_FETCH_MODE = $save;
-
+
$sqlResult=array();
if ( empty($cols)) {
$sqlResult=$this->createTableSQL($tablename, $flds, $tableoptions);
@@ -543,7 +563,7 @@ CREATE [ UNIQUE ] INDEX index_name ON table
$sqlResultAdd = $this->addColumnSQL($tablename, $flds);
$sqlResultAlter = $this->alterColumnSQL($tablename, $flds, '', $tableoptions);
$sqlResult = array_merge((array)$sqlResultAdd, (array)$sqlResultAlter);
-
+
if ($dropOldFlds) {
// already exists, alter table instead
list($lines,$pkey,$idxs) = $this->_genFields($flds);
@@ -558,7 +578,7 @@ CREATE [ UNIQUE ] INDEX index_name ON table
}
}
}
-
+
}
return $sqlResult;
}
diff --git a/datadict/datadict-sapdb.inc.php b/datadict/datadict-sapdb.inc.php
index 20c16aa..c469800 100644
--- a/datadict/datadict-sapdb.inc.php
+++ b/datadict/datadict-sapdb.inc.php
@@ -30,6 +30,15 @@ class ADODB2_sapdb extends ADODB_DataDict {
function ActualType($meta)
{
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL':
@@ -65,6 +74,12 @@ class ADODB2_sapdb extends ADODB_DataDict {
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
+
+ $t = strtoupper($t);
+
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
static $maxdb_type2adodb = array(
'VARCHAR' => 'C',
'CHARACTER' => 'C',
diff --git a/datadict/datadict-sqlite.inc.php b/datadict/datadict-sqlite.inc.php
index 942927f..d565f88 100644
--- a/datadict/datadict-sqlite.inc.php
+++ b/datadict/datadict-sqlite.inc.php
@@ -35,6 +35,16 @@ class ADODB2_sqlite extends ADODB_DataDict {
function ActualType($meta)
{
+
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
switch(strtoupper($meta)) {
case 'C': return 'VARCHAR'; // TEXT , TEXT affinity
case 'XL':return 'LONGTEXT'; // TEXT , TEXT affinity
diff --git a/datadict/datadict-sybase.inc.php b/datadict/datadict-sybase.inc.php
index e565f8e..d6573df 100644
--- a/datadict/datadict-sybase.inc.php
+++ b/datadict/datadict-sybase.inc.php
@@ -35,8 +35,15 @@ class ADODB2_sybase extends ADODB_DataDict {
$len = $fieldobj->max_length;
}
+ $t = strtoupper($t);
+
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
$len = -1; // mysql max_length is not accurate
- switch (strtoupper($t)) {
+
+ switch ($t) {
+
case 'INT':
case 'INTEGER': return 'I';
@@ -53,6 +60,15 @@ class ADODB2_sybase extends ADODB_DataDict {
function ActualType($meta)
{
+ $meta = strtoupper($meta);
+
+ /*
+ * Add support for custom meta types. We do this
+ * first, that allows us to override existing types
+ */
+ if (isset($this->connection->customMetaTypes[$meta]))
+ return $this->connection->customMetaTypes[$meta]['actual'];
+
switch(strtoupper($meta)) {
case 'C': return 'VARCHAR';
case 'XL':
diff --git a/debian/changelog b/debian/changelog
index 2f93b13..dc07f0a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-libphp-adodb (5.21.4-2) UNRELEASED; urgency=medium
+libphp-adodb (5.22.6-1) UNRELEASED; urgency=medium
[ Debian Janitor ]
* Remove constraints unnecessary since buster:
@@ -8,7 +8,11 @@ libphp-adodb (5.21.4-2) UNRELEASED; urgency=medium
* d/control: Added Multi-Arch: foreign.
* d/changelog: Updated comment about #1004376.
- -- Jean-Michel Vourgère <nirgal@debian.org> Mon, 14 Mar 2022 11:30:41 +0100
+ [ Debian Janitor ]
+ * New upstream release.
+ * New upstream release.
+
+ -- Jean-Michel Vourgère <nirgal@debian.org> Mon, 10 Jul 2023 00:49:17 -0000
libphp-adodb (5.21.4-1) unstable; urgency=medium
diff --git a/docs/changelog.md b/docs/changelog.md
index 5298b3d..121e102 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -14,8 +14,279 @@ Older changelogs:
--------------------------------------------------------------------------------
-## [5.21.4] - 2022-01-22
-## [5.20.21] - 2022-01-22
+## [5.22.6] - 2023-06-11
+
+### Deprecated
+
+- Date/Time Library
+ [#970](https://github.com/ADOdb/ADOdb/issues/970)
+
+### Fixed
+
+- Creation of dynamic property deprecated warning with PHP 8.2
+ [#954](https://github.com/ADOdb/ADOdb/issues/954)
+ [#975](https://github.com/ADOdb/ADOdb/issues/975)
+- Remove unused oldProvider property in _rs2serialize()
+ [#957](https://github.com/ADOdb/ADOdb/issues/957)
+- Fix ADOConnection::execute() documentation of return type
+ [#964](https://github.com/ADOdb/ADOdb/issues/964)
+- Define _query() method in ADOConnection base class
+ [#966](https://github.com/ADOdb/ADOdb/issues/966)
+- Restore rs2html() $htmlspecialchars param behavior
+ [#968](https://github.com/ADOdb/ADOdb/issues/968)
+- adodb_throw() does not respect @ operator on PHP 8
+ [#981](https://github.com/ADOdb/ADOdb/issues/981)
+- loadbalancer: PHP 8.2 warnings
+ [#951](https://github.com/ADOdb/ADOdb/issues/951)
+- mysql: Fail connection if native driver (mysqlnd) is not available
+ [#967](https://github.com/ADOdb/ADOdb/issues/967)
+- pgsql: Fix PHP 8.1 deprecated warning
+ [#956](https://github.com/ADOdb/ADOdb/issues/956)
+- pgsql: avoid Insert_ID() failing when lastval() is not set
+ [#978](https://github.com/ADOdb/ADOdb/issues/978)
+
+
+## [5.22.5] - 2023-04-03
+
+### Removed
+
+- Obsolete ADOConnection::$databaseName property
+ [#932](https://github.com/ADOdb/ADOdb/issues/932)
+- Dead code related to safe_mode
+ [#934](https://github.com/ADOdb/ADOdb/issues/934)
+- pdo: remove unnecessary methods _init() and _affectedrows()
+ [#935](https://github.com/ADOdb/ADOdb/issues/935)
+
+### Fixed
+
+- ADODB_FETCH_DEFAULT should be treated as ASSOC in getAssoc()
+ [#886](https://github.com/ADOdb/ADOdb/issues/886)
+- Allow dynamic properties for ADOFieldObject class
+ [#906](https://github.com/ADOdb/ADOdb/issues/906)
+- Fix autoExecute() $where parameter type
+ [#915](https://github.com/ADOdb/ADOdb/issues/915)
+- Creation of dynamic property deprecated warning in PHP 8.2
+ [#904](https://github.com/ADOdb/ADOdb/issues/904)
+ [#907](https://github.com/ADOdb/ADOdb/issues/907)
+ [#908](https://github.com/ADOdb/ADOdb/issues/908)
+ [#909](https://github.com/ADOdb/ADOdb/issues/909)
+ [#911](https://github.com/ADOdb/ADOdb/issues/911)
+ [#912](https://github.com/ADOdb/ADOdb/issues/912)
+ [#913](https://github.com/ADOdb/ADOdb/issues/913)
+ [#917](https://github.com/ADOdb/ADOdb/issues/917)
+ [#926](https://github.com/ADOdb/ADOdb/issues/926)
+ [#933](https://github.com/ADOdb/ADOdb/issues/933)
+ [#935](https://github.com/ADOdb/ADOdb/issues/935)
+- Partially-supported callable deprecated warning in PHP 8.2
+ [#928](https://github.com/ADOdb/ADOdb/issues/928)
+- Passing null to non-nullable parameter is deprecated in PHP 8.1
+ [#938](https://github.com/ADOdb/ADOdb/issues/938)
+- Define adodbFetchMode property in base ADORecordSet class
+ [#923](https://github.com/ADOdb/ADOdb/issues/923)
+- mysql: uncaught exception calling execute() with empty SQL on PHP 8
+ [#945](https://github.com/ADOdb/ADOdb/issues/945)
+- oci8: Replace obsolete oci_free_cursor() function alias
+ [#937](https://github.com/ADOdb/ADOdb/issues/937)
+- pdo: Move setTransactionMode() to ADODB_pdo_sqlsrv class
+ [#939](https://github.com/ADOdb/ADOdb/issues/939)
+- pgsql: fix "column already exists" error when adding a new column
+ [#897](https://github.com/ADOdb/ADOdb/issues/897)
+- pgsql: undefined array key in metaIndexes() when column is an expression
+ [#940](https://github.com/ADOdb/ADOdb/issues/940)
+- pgsql: revert non-functional "Noblob optimization"
+ [#112](https://github.com/ADOdb/ADOdb/issues/112)
+- session: full table scan when accessing sessions table on MySQL
+ [#941](https://github.com/ADOdb/ADOdb/issues/941)
+- session: inconsistent DB provider check
+ [#943](https://github.com/ADOdb/ADOdb/issues/943)
+
+
+## [5.22.4] - 2022-10-28
+
+### Fixed
+
+- adodb_strip_order_by() throws deprecated warnings on PHP 8.1
+ [#869](https://github.com/ADOdb/ADOdb/issues/869)
+- adodb_strip_order_by() shouldn't strip clause from subqueries
+ [#870](https://github.com/ADOdb/ADOdb/issues/870)
+- mssql: Affected_Rows() not returning correct value
+ [#895](https://github.com/ADOdb/ADOdb/issues/895)
+- mysqli: Fix mysqli_result could not be converted to int
+ [#867](https://github.com/ADOdb/ADOdb/issues/867)
+- mysqli: regression on errorMsg()/errorCode()
+ [#872](https://github.com/ADOdb/ADOdb/issues/872)
+
+
+## [5.22.3] - 2022-09-06
+
+### Fixed
+
+- alterColumnSql() and changeTableSQL() produce different SQL
+ [#124](https://github.com/ADOdb/ADOdb/issues/124)
+ [#383](https://github.com/ADOdb/ADOdb/issues/383)
+ [#865](https://github.com/ADOdb/ADOdb/issues/865)
+- Fix PHP 8.1 deprecated warning in GetUpdateSQL()
+ [#844](https://github.com/ADOdb/ADOdb/issues/844)
+- Fix PHP 8.1 deprecated warning in tohtml.inc.php
+ [#850](https://github.com/ADOdb/ADOdb/issues/850)
+- Fix str_repeat() error in _adodb_backtrace()
+ [#852](https://github.com/ADOdb/ADOdb/issues/852)
+- firebird/ibase: Fix uncaught TypeError
+ [#858](https://github.com/ADOdb/ADOdb/issues/858)
+- mssql: Fix undefined variable when closing connection
+ [#835](https://github.com/ADOdb/ADOdb/issues/835)
+- mssql: insert_id returns false if value is out of range
+ [#853](https://github.com/ADOdb/ADOdb/issues/853)
+- mysql: Fix regression with portable bind arrays
+ [#838](https://github.com/ADOdb/ADOdb/issues/838)
+- mysql: Fix errorMsg() / errorNo() on MySQL 8
+ [#842](https://github.com/ADOdb/ADOdb/issues/842)
+- oci8po: Replace deprecated functions aliases
+ [#862](https://github.com/ADOdb/ADOdb/issues/862)
+- pdo: Fix uncaught TypeError on PHP 8
+ [#840](https://github.com/ADOdb/ADOdb/issues/840)
+- pgsql: check for dummy query Id before closing recordset
+ [#848](https://github.com/ADOdb/ADOdb/issues/848)
+- active record: fix changing case of class properties in Native mode
+ [#837](https://github.com/ADOdb/ADOdb/issues/837)
+
+
+## [5.22.2] - 2022-05-08
+
+### Fixed
+
+- mssql: Automatic conversion of false to array is deprecated in PHP 8.1
+ [#829](https://github.com/ADOdb/ADOdb/issues/829)
+- mysql: Affected_Rows() not returning correct value
+ [#820](https://github.com/ADOdb/ADOdb/issues/820)
+- mysql: uncaught ValueError exception calling execute() with an empty array
+ [#832](https://github.com/ADOdb/ADOdb/issues/832)
+- pgsql: Affected_Rows() always returns false on PHP 8.1
+ [#833](https://github.com/ADOdb/ADOdb/issues/833)
+
+
+## [5.22.1] - 2022-03-30
+
+### Removed
+
+- Legacy mysql, mysqlpo and mysqlt drivers
+ [#804](https://github.com/ADOdb/ADOdb/issues/804)
+
+### Fixed
+
+- firebird: undefined offset PHP notice in _fetchField()
+ [#808](https://github.com/ADOdb/ADOdb/issues/808)
+- firebird: PHP deprecation warning in _blobDecode()
+ [#811](https://github.com/ADOdb/ADOdb/issues/811)
+- firebird: PHP notice when executing query with empty array
+ [#812](https://github.com/ADOdb/ADOdb/issues/812)
+- firebird: undefined array key with uppercase columns
+ [#813](https://github.com/ADOdb/ADOdb/issues/813)
+- mysql: regression on setConnectionParameter()
+ [#803](https://github.com/ADOdb/ADOdb/issues/803)
+- mysql: regression on bulk binding
+ [#806](https://github.com/ADOdb/ADOdb/issues/806)
+- oci8: fix PHP 8.1 array deprecation warning
+ [#817](https://github.com/ADOdb/ADOdb/issues/817)
+- memcache: weighted servers not connecting
+ [#807](https://github.com/ADOdb/ADOdb/issues/807)
+- memcache: $memCacheCompress option ignored by memcached
+ [#823](https://github.com/ADOdb/ADOdb/issues/823)
+- memcache: use default port in server controller template
+ [#824](https://github.com/ADOdb/ADOdb/issues/824)
+- xml PHP Notice in dbData::create()
+ [#822](https://github.com/ADOdb/ADOdb/issues/822)
+
+
+## [5.22.0] - 2022-02-08
+
+### Added
+
+- Support for custom MetaTypes, e.g. JSON or GEOMETRY
+ [#602](https://github.com/ADOdb/ADOdb/issues/602)
+ [#626](https://github.com/ADOdb/ADOdb/issues/626)
+ [#649](https://github.com/ADOdb/ADOdb/issues/649)
+- Use of weighted server groups with Memcached
+ [#676](https://github.com/ADOdb/ADOdb/issues/676)
+- mssql: implement offsetDate() method
+ [#698](https://github.com/ADOdb/ADOdb/issues/698)
+- oci8: new ADOConnection::releaseStatement() method
+ [#770](https://github.com/ADOdb/ADOdb/issues/770)
+- sqlite3 performance monitor stub
+ [#661](https://github.com/ADOdb/ADOdb/issues/661)
+- sqlite: support blob handling
+ [#702](https://github.com/ADOdb/ADOdb/issues/702)
+
+### Changed
+
+- firebird: complete overhaul to support latest PHP drivers
+ [#710](https://github.com/ADOdb/ADOdb/issues/710)
+- mssql: Refactor _fetchField() method
+ [#725](https://github.com/ADOdb/ADOdb/issues/725)
+- mysql: Support bound variable statements
+ [#655](https://github.com/ADOdb/ADOdb/issues/655)
+- pgsql: missing standard datatypes
+ [#782](https://github.com/ADOdb/ADOdb/issues/782)
+- xml: add field comments
+ [#732](https://github.com/ADOdb/ADOdb/issues/732)
+- loadbalancer: support calling a function upon connection
+ [#784](https://github.com/ADOdb/ADOdb/issues/784)
+- Code cleanup: PHPDoc, code style, whitespace, PHPStan errors, etc.
+ [#774](https://github.com/ADOdb/ADOdb/issues/774)
+
+### Deprecated
+
+- Compatibility with PHP < 7.2
+ [#797](https://github.com/ADOdb/ADOdb/issues/797)
+- Database Replication add-on
+ [#780](https://github.com/ADOdb/ADOdb/issues/780)
+
+### Removed
+
+- Compatibility with PHP 5.x
+ [#797](https://github.com/ADOdb/ADOdb/issues/797)
+- Transpose() function and assorted sub-functions
+ [#586](https://github.com/ADOdb/ADOdb/issues/586)
+- "proxy" server and client scripts
+ [#680](https://github.com/ADOdb/ADOdb/issues/680)
+
+### Fixed
+
+- metaIndexes does not return primary key correctly
+ [#656](https://github.com/ADOdb/ADOdb/issues/656)
+- Uniformize ADOrecordSet::__construct() parameters
+ [#772](https://github.com/ADOdb/ADOdb/issues/772)
+- Prevent PHP warning when throwing exception with P1 or P2 parameter as array
+ [#783](https://github.com/ADOdb/ADOdb/issues/783)
+- $dsnType property not defined before use
+ [#789](https://github.com/ADOdb/ADOdb/issues/789)
+- mysql: Update socket and client flags for ssl
+ [#622](https://github.com/ADOdb/ADOdb/issues/622)
+- mysql: Handle tables that are reserved words
+- [#759](https://github.com/ADOdb/ADOdb/issues/759)
+- pgsql: prevent AddColumnSQL() from updating existing values when default is changed
+ [#635](https://github.com/ADOdb/ADOdb/issues/635)
+- pgsql: Refactored _fixblobs() and replaced it with new _prepFields() method
+ [#767](https://github.com/ADOdb/ADOdb/issues/767)
+- pgsql: Incorrect pg_execute() api calls
+ [#768](https://github.com/ADOdb/ADOdb/issues/768)
+- pgsql: blobDelete() could silently fail with multiple connections
+ [#769](https://github.com/ADOdb/ADOdb/issues/769)
+- pdo: ensure bound statements are correctly formatted
+ [#695](https://github.com/ADOdb/ADOdb/issues/695)
+- perf: fix invalid SQL
+ [#753](https://github.com/ADOdb/ADOdb/issues/753)
+- sqlite: driver returns incorrect time when using $sysTimeStamp
+ [#697](https://github.com/ADOdb/ADOdb/issues/697)
+- sqlite: undeclared connection property
+ [#713](https://github.com/ADOdb/ADOdb/issues/713)
+- xml: Undefined array key error
+ [#775](https://github.com/ADOdb/ADOdb/issues/775)
+- memcache: library does not initialize correctly
+ [#788](https://github.com/ADOdb/ADOdb/issues/788)
+
+
+## [5.21.4] and [5.20.21] - 2022-01-22
### Fixed
@@ -72,6 +343,8 @@ Older changelogs:
[#715](https://github.com/ADOdb/ADOdb/issues/715)
- Incorrect handling of $ADODB_QUOTE_FIELDNAMES = true
[#721](https://github.com/ADOdb/ADOdb/issues/721)
+- array to string conversion in adodb_debug_execute()
+ [#737](https://github.com/ADOdb/ADOdb/issues/737)
- db2: fix columns always returned in lowercase
[#719](https://github.com/ADOdb/ADOdb/issues/719)
- PDO: Bind parameters fail if sent in associative array
@@ -412,9 +685,9 @@ Includes all fixes from 5.20.19.
## [5.20.16] - 2020-01-12
--### Fixed
+### Fixed
- mssql: queries are not correctly closed
+- mssql: queries are not correctly closed
[#590](https://github.com/ADOdb/ADOdb/issues/590)
@@ -1143,7 +1416,13 @@ Released together with [v4.95](changelog_v4.x.md#495---17-may-2007)
- Adodb5 version,more error checking code now will use exceptions if available.
-[Unreleased]: https://github.com/adodb/adodb/compare/v5.21.4...hotfix/5.21
+[5.22.6]: https://github.com/adodb/adodb/compare/v5.22.5...v5.22.6
+[5.22.5]: https://github.com/adodb/adodb/compare/v5.22.4...v5.22.5
+[5.22.4]: https://github.com/adodb/adodb/compare/v5.22.3...v5.22.4
+[5.22.3]: https://github.com/adodb/adodb/compare/v5.22.2...v5.22.3
+[5.22.2]: https://github.com/adodb/adodb/compare/v5.22.1...v5.22.2
+[5.22.1]: https://github.com/adodb/adodb/compare/v5.22.0...v5.22.1
+[5.22.0]: https://github.com/adodb/adodb/compare/v5.21.4...v5.22.0
[5.21.4]: https://github.com/adodb/adodb/compare/v5.21.3...v5.21.4
[5.21.3]: https://github.com/adodb/adodb/compare/v5.21.2...v5.21.3
diff --git a/drivers/adodb-ado.inc.php b/drivers/adodb-ado.inc.php
index 67a032d..df95c69 100644
--- a/drivers/adodb-ado.inc.php
+++ b/drivers/adodb-ado.inc.php
@@ -208,10 +208,6 @@ class ADODB_ado extends ADOConnection {
return empty($arr) ? $false : $arr;
}
-
-
-
- /* returns queryID or false */
function _query($sql,$inputarr=false)
{
@@ -505,6 +501,9 @@ class ADORecordSet_ado extends ADORecordSet {
$len = $fieldobj->max_length;
}
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
if (!is_numeric($t)) return $t;
switch ($t) {
diff --git a/drivers/adodb-ado5.inc.php b/drivers/adodb-ado5.inc.php
index f673d09..04b45ab 100644
--- a/drivers/adodb-ado5.inc.php
+++ b/drivers/adodb-ado5.inc.php
@@ -233,7 +233,6 @@ class ADODB_ado extends ADOConnection {
return $arr;
}
- /* returns queryID or false */
function _query($sql,$inputarr=false)
{
try { // In PHP5, all COM errors are exceptions, so to maintain old behaviour...
@@ -546,7 +545,13 @@ class ADORecordSet_ado extends ADORecordSet {
$len = $fieldobj->max_length;
}
- if (!is_numeric($t)) return $t;
+ $t = strtoupper($t);
+
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
+ if (!is_numeric($t))
+ return $t;
switch ($t) {
case 0:
diff --git a/drivers/adodb-ads.inc.php b/drivers/adodb-ads.inc.php
index b9d4adb..16eec97 100644
--- a/drivers/adodb-ads.inc.php
+++ b/drivers/adodb-ads.inc.php
@@ -97,7 +97,7 @@ class ADODB_ads extends ADOConnection
$this->_connectionID = ads_connect($argDSN, $argUsername, $argPassword, $this->curmode);
}
$this->_errorMsg = $this->getChangedErrorMsg($last_php_error);
- if (isset($this->connectStmt)) {
+ if ($this->connectStmt) {
$this->Execute($this->connectStmt);
}
@@ -127,7 +127,7 @@ class ADODB_ads extends ADOConnection
if ($this->_connectionID && $this->autoRollback) {
@ads_rollback($this->_connectionID);
}
- if (isset($this->connectStmt)) {
+ if ($this->connectStmt) {
$this->Execute($this->connectStmt);
}
@@ -564,7 +564,6 @@ class ADODB_ads extends ADOConnection
return array($sql, $stmt, false);
}
- /* returns queryID or false */
function _query($sql, $inputarr = false)
{
$last_php_error = $this->resetLastError();
diff --git a/drivers/adodb-csv.inc.php b/drivers/adodb-csv.inc.php
index 8a59626..e6694d9 100644
--- a/drivers/adodb-csv.inc.php
+++ b/drivers/adodb-csv.inc.php
@@ -199,7 +199,7 @@ class ADODB_csv extends ADOConnection {
}
} // class
-class ADORecordset_csv extends ADORecordset {
+class ADORecordset_csv extends ADORecordSet {
function _close()
{
diff --git a/drivers/adodb-db2.inc.php b/drivers/adodb-db2.inc.php
index 8f616fa..e214d2d 100644
--- a/drivers/adodb-db2.inc.php
+++ b/drivers/adodb-db2.inc.php
@@ -77,16 +77,6 @@ class ADODB_db2 extends ADOConnection {
*/
public $nameQuote = '"';
- /*
- * Executed after successful connection
- */
- public $connectStmt = '';
-
- /*
- * Holds the current database name
- */
- private $databaseName = '';
-
/*
* Holds information about the stored procedure request
* currently being built
@@ -113,7 +103,6 @@ class ADODB_db2 extends ADOConnection {
private function doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename, $persistent=false)
{
- global $php_errormsg;
if (!function_exists('db2_connect')) {
ADOConnection::outp("DB2 extension not installed.");
@@ -185,7 +174,6 @@ class ADODB_db2 extends ADOConnection {
null,
$db2Options);
- $php_errormsg = '';
$this->_errorMsg = @db2_conn_errormsg();
@@ -209,7 +197,6 @@ class ADODB_db2 extends ADOConnection {
private function unpackParameters($argDSN, $argUsername, $argPassword, $argDatabasename)
{
- global $php_errormsg;
$connectionParameters = array('dsn'=>'',
'uid'=>'',
@@ -260,7 +247,7 @@ class ADODB_db2 extends ADOConnection {
$errorMessage = 'Supply uncatalogued connection parameters ';
$errorMessage.= 'in either the database or DSN arguments, ';
$errorMessage.= 'but not both';
- $php_errormsg = $errorMessage;
+
if ($this->debug)
ADOConnection::outp($errorMessage);
return null;
@@ -285,7 +272,7 @@ class ADODB_db2 extends ADOConnection {
{
$errorMessage = 'For uncatalogued connections, provide ';
$errorMessage.= 'both UID and PWD in the connection string';
- $php_errormsg = $errorMessage;
+
if ($this->debug)
ADOConnection::outp($errorMessage);
return null;
@@ -310,7 +297,7 @@ class ADODB_db2 extends ADOConnection {
}
elseif ($argDatabasename)
{
- $this->databaseName = $argDatabasename;
+ $this->database = $argDatabasename;
$argDSN .= ';database=' . $argDatabasename;
$argDatabasename = '';
$useCataloguedConnection = false;
@@ -320,7 +307,7 @@ class ADODB_db2 extends ADOConnection {
{
$errorMessage = 'Uncatalogued connection parameters ';
$errorMessage.= 'must contain a database= argument';
- $php_errormsg = $errorMessage;
+
if ($this->debug)
ADOConnection::outp($errorMessage);
return null;
@@ -350,9 +337,9 @@ class ADODB_db2 extends ADOConnection {
}
if ($argDatabasename)
- $this->databaseName = $argDatabasename;
- elseif (!$this->databaseName)
- $this->databaseName = $this->getDatabasenameFromDsn($argDSN);
+ $this->database = $argDatabasename;
+ elseif (!$this->database)
+ $this->database = $this->getDatabasenameFromDsn($argDSN);
$connectionParameters = array('dsn'=>$argDSN,
@@ -684,16 +671,17 @@ class ADODB_db2 extends ADOConnection {
}
/**
- * returns assoc array where keys are tables, and values are foreign keys
+ * Returns a list of Foreign Keys associated with a specific table.
*
- * @param string $table
- * @param string $owner [optional][discarded]
- * @param bool $upper [optional][discarded]
- * @param bool $associative[optional][discarded]
+ * @param string $table
+ * @param string $owner discarded
+ * @param bool $upper discarded
+ * @param bool $associative discarded
*
- * @return mixed[] Array of foreign key information
+ * @return string[]|false An array where keys are tables, and values are foreign keys;
+ * false if no foreign keys could be found.
*/
- public function metaForeignKeys($table, $owner = FALSE, $upper = FALSE, $asociative = FALSE )
+ public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false)
{
global $ADODB_FETCH_MODE;
@@ -1005,7 +993,7 @@ class ADODB_db2 extends ADOConnection {
*/
public function metaDatabases(){
- $dbName = $this->getMetaCasedValue($this->databaseName);
+ $dbName = $this->getMetaCasedValue($this->database);
return (array)$dbName;
@@ -1582,13 +1570,6 @@ See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/db2/htm/db2
*/
function _query(&$sql,$inputarr=false)
{
-
- GLOBAL $php_errormsg;
-
- if (isset($php_errormsg))
- $php_errormsg = '';
- $this->_error = '';
-
$db2Options = array();
/*
* Use DB2 Internal case handling for best speed
@@ -1622,7 +1603,12 @@ See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/db2/htm/db2
if ($stmtid == false)
{
- $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+ $this->_errorMsg = @db2_stmt_errormsg();
+ $this->_errorCode = @db2_stmt_error();
+
+ if ($this->debug)
+ ADOConnection::outp($this->_errorMsg);
+
return false;
}
}
@@ -1996,14 +1982,13 @@ class ADORecordSet_db2 extends ADORecordSet {
$ok = @db2_free_result($this->_queryID);
if (!$ok)
{
- $this->_errorMsg = @db2_stmt_errormsg($this->_queryId);
- $this->_errorCode = @db2_stmt_error();
+ $this->connection->_errorMsg = @db2_stmt_errormsg($this->_queryID);
+ $this->connection->_errorCode = @db2_stmt_error();
if ($this->debug)
- ADOConnection::outp($this->_errorMsg);
+ ADOConnection::outp($this->connection->_errorMsg);
return false;
}
-
}
}
diff --git a/drivers/adodb-fbsql.inc.php b/drivers/adodb-fbsql.inc.php
index 0fb895a..64913bc 100644
--- a/drivers/adodb-fbsql.inc.php
+++ b/drivers/adodb-fbsql.inc.php
@@ -134,7 +134,6 @@ class ADODB_fbsql extends ADOConnection {
}
- // returns queryID or false
function _query($sql,$inputarr=false)
{
return fbsql_query("$sql;",$this->_connectionID);
@@ -232,8 +231,15 @@ class ADORecordSet_fbsql extends ADORecordSet{
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
+
+ $t = strtoupper($t);
+
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
$len = -1; // fbsql max_length is not accurate
- switch (strtoupper($t)) {
+
+ switch ($t) {
case 'CHARACTER':
case 'CHARACTER VARYING':
case 'BLOB':
diff --git a/drivers/adodb-firebird.inc.php b/drivers/adodb-firebird.inc.php
index 2fafbe4..db3cca5 100644
--- a/drivers/adodb-firebird.inc.php
+++ b/drivers/adodb-firebird.inc.php
@@ -19,6 +19,10 @@
*
* @copyright 2000-2013 John Lim
* @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
+ *
+ * Driver was cloned from Interbase, so there's quite a lot of duplicated code
+ * @noinspection DuplicatedCode
+ * @noinspection PhpUnused
*/
// security - hide paths
@@ -35,39 +39,113 @@ class ADODB_firebird extends ADOConnection {
var $fmtTimeStamp = "'Y-m-d, H:i:s'";
var $concat_operator='||';
var $_transactionID;
- var $metaTablesSQL = "select lower(rdb\$relation_name) from rdb\$relations where rdb\$relation_name not like 'RDB\$%'";
+
+ public $metaTablesSQL = "SELECT LOWER(rdb\$relation_name) FROM rdb\$relations";
//OPN STUFF start
+
var $metaColumnsSQL = "select lower(a.rdb\$field_name), a.rdb\$null_flag, a.rdb\$default_source, b.rdb\$field_length, b.rdb\$field_scale, b.rdb\$field_sub_type, b.rdb\$field_precision, b.rdb\$field_type from rdb\$relation_fields a, rdb\$fields b where a.rdb\$field_source = b.rdb\$field_name and a.rdb\$relation_name = '%s' order by a.rdb\$field_position asc";
//OPN STUFF end
- var $ibasetrans;
+
+ public $_genSeqSQL = "CREATE SEQUENCE %s START WITH %s";
+
+ public $_dropSeqSQL = "DROP SEQUENCE %s";
+
var $hasGenID = true;
var $_bindInputArray = true;
- var $buffers = 0;
- var $dialect = 3;
var $sysDate = "cast('TODAY' as timestamp)";
var $sysTimeStamp = "CURRENT_TIMESTAMP"; //"cast('NOW' as timestamp)";
var $ansiOuter = true;
var $hasAffectedRows = true;
var $poorAffectedRows = false;
var $blobEncodeType = 'C';
- var $role = false;
+ /*
+ * firebird custom optionally specifies the user role
+ */
+ public $role = false;
+ /*
+ * firebird custom optionally specifies the connection buffers
+ */
+ public $buffers = 0;
+
+ /*
+ * firebird custom optionally specifies database dialect
+ */
+ public $dialect = 3;
+
var $nameQuote = ''; /// string to use to quote identifiers and names
function __construct()
{
- // Ignore IBASE_DEFAULT we want a more practical transaction!
- // if (defined('IBASE_DEFAULT')) $this->ibasetrans = IBASE_DEFAULT;
- // else
- $this->ibasetrans = IBASE_WAIT | IBASE_REC_VERSION | IBASE_COMMITTED;
+ parent::__construct();
+ $this->setTransactionMode('');
}
+ /**
+ * Sets the isolation level of a transaction.
+ *
+ * The default behavior is a more practical IBASE_WAIT | IBASE_REC_VERSION | IBASE_COMMITTED
+ * instead of IBASE_DEFAULT
+ *
+ * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:settransactionmode
+ *
+ * @param string $transaction_mode The transaction mode to set.
+ *
+ * @return void
+ */
+ public function setTransactionMode($transaction_mode)
+ {
+ $this->_transmode = $transaction_mode;
+
+ if (empty($transaction_mode)) {
+ $this->_transmode = IBASE_WAIT | IBASE_REC_VERSION | IBASE_COMMITTED;
+ }
- // returns true or false
- function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$persist=false)
+ }
+
+ /**
+ * Connect to a database.
+ *
+ * @todo add: parameter int $port, parameter string $socket
+ *
+ * @param string|null $argHostname (Optional) The host to connect to.
+ * @param string|null $argUsername (Optional) The username to connect as.
+ * @param string|null $argPassword (Optional) The password to connect with.
+ * @param string|null $argDatabasename (Optional) The name of the database to start in when connected.
+ * @param bool $persist (Optional) Whether or not to use a persistent connection.
+ *
+ * @return bool|null True if connected successfully, false if connection failed, or null if the mysqli extension
+ * isn't currently loaded.
+ */
+ public function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$persist=false)
{
- if (!function_exists('fbird_pconnect')) return null;
- if ($argDatabasename) $argHostname .= ':'.$argDatabasename;
+ if (!function_exists('fbird_pconnect'))
+ return null;
+
+ if ($argDatabasename)
+ $argHostname .= ':'.$argDatabasename;
+
$fn = ($persist) ? 'fbird_pconnect':'fbird_connect';
+
+ /*
+ * Now merge in the standard connection parameters setting
+ */
+ foreach ($this->connectionParameters as $options)
+ {
+ foreach($options as $k=>$v)
+ {
+ switch($k){
+ case 'role':
+ $this->role = $v;
+ break;
+ case 'dialect':
+ $this->dialect = $v;
+ break;
+ case 'buffers':
+ $this->buffers = $v;
+ }
+ }
+ }
+
if ($this->role)
$this->_connectionID = $fn($argHostname,$argUsername,$argPassword,
$this->charSet,$this->buffers,$this->dialect,$this->role);
@@ -75,40 +153,39 @@ class ADODB_firebird extends ADOConnection {
$this->_connectionID = $fn($argHostname,$argUsername,$argPassword,
$this->charSet,$this->buffers,$this->dialect);
- if ($this->dialect != 1) { // http://www.ibphoenix.com/ibp_60_del_id_ds.html
- $this->replaceQuote = "''";
+ if ($this->dialect == 1) { // http://www.ibphoenix.com/ibp_60_del_id_ds.html
+ $this->replaceQuote = "";
}
if ($this->_connectionID === false) {
- $this->_handleerror();
+ $this->_handleError();
return false;
}
- // PHP5 change.
- if (function_exists('fbird_timefmt')) {
- fbird_timefmt($this->fbird_datefmt,fbird_DATE );
- if ($this->dialect == 1) {
- fbird_timefmt($this->fbird_datefmt,fbird_TIMESTAMP );
- } else {
- fbird_timefmt($this->fbird_timestampfmt,fbird_TIMESTAMP );
- }
- fbird_timefmt($this->fbird_timefmt,fbird_TIME );
+ ini_set("ibase.timestampformat", $this->fbird_timestampfmt);
+ ini_set("ibase.dateformat", $this->fbird_datefmt);
+ ini_set("ibase.timeformat", $this->fbird_timefmt);
- } else {
- ini_set("ibase.timestampformat", $this->fbird_timestampfmt);
- ini_set("ibase.dateformat", $this->fbird_datefmt);
- ini_set("ibase.timeformat", $this->fbird_timefmt);
- }
return true;
}
- // returns true or false
+ /**
+ * Connect to a database with a persistent connection.
+ *
+ * @param string|null $argHostname The host to connect to.
+ * @param string|null $argUsername The username to connect as.
+ * @param string|null $argPassword The password to connect with.
+ * @param string|null $argDatabasename The name of the database to start in when connected.
+ *
+ * @return bool|null True if connected successfully, false if connection failed, or null if the mysqli extension
+ * isn't currently loaded.
+ */
function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
{
return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,true);
}
- function MetaPrimaryKeys($table,$owner_notused=false,$internalKey=false)
+ public function metaPrimaryKeys($table,$owner_notused=false,$internalKey=false)
{
if ($internalKey) {
return array('RDB$DB_KEY');
@@ -126,31 +203,58 @@ class ADODB_firebird extends ADOConnection {
return false;
}
- function ServerInfo()
+ /**
+ * Get information about the current Firebird server.
+ *
+ * @return array
+ */
+ public function serverInfo()
{
$arr['dialect'] = $this->dialect;
switch($arr['dialect']) {
- case '':
- case '1': $s = 'Firebird Dialect 1'; break;
- case '2': $s = 'Firebird Dialect 2'; break;
- default:
- case '3': $s = 'Firebird Dialect 3'; break;
+ case '':
+ case '1':
+ $s = 'Firebird Dialect 1';
+ break;
+ case '2':
+ $s = 'Firebird Dialect 2';
+ break;
+ default:
+ case '3':
+ $s = 'Firebird Dialect 3';
+ break;
}
$arr['version'] = ADOConnection::_findvers($s);
$arr['description'] = $s;
return $arr;
}
- function BeginTrans()
+ /**
+ * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
+ *
+ * @return bool true if succeeded or false if database does not support transactions
+ */
+ public function beginTrans()
{
if ($this->transOff) return true;
$this->transCnt += 1;
$this->autoCommit = false;
- $this->_transactionID = fbird_trans( $this->ibasetrans, $this->_connectionID );
+ /*
+ * We manage the transaction mode via fbird_trans
+ */
+ $this->_transactionID = fbird_trans( $this->_transmode, $this->_connectionID );
return $this->_transactionID;
}
- function CommitTrans($ok=true)
+
+ /**
+ * Commits a transaction.
+ *
+ * @param bool $ok false to rollback transaction, true to commit
+ *
+ * @return bool
+ */
+ public function commitTrans($ok=true)
{
if (!$ok) {
return $this->RollbackTrans();
@@ -164,7 +268,6 @@ class ADODB_firebird extends ADOConnection {
$ret = false;
$this->autoCommit = true;
if ($this->_transactionID) {
- //print ' commit ';
$ret = fbird_commit($this->_transactionID);
}
$this->_transactionID = false;
@@ -173,31 +276,26 @@ class ADODB_firebird extends ADOConnection {
function _affectedrows()
{
- return fbird_affected_rows( $this->_transactionID ? $this->_transactionID : $this->_connectionID );
- }
-
- // there are some compat problems with ADODB_COUNTRECS=false and $this->_logsql currently.
- // it appears that ibase extension cannot support multiple concurrent queryid's
- function _Execute($sql,$inputarr=false) {
- global $ADODB_COUNTRECS;
-
- if ($this->_logsql) {
- $savecrecs = $ADODB_COUNTRECS;
- $ADODB_COUNTRECS = true; // force countrecs
- $ret =& ADOConnection::_Execute($sql,$inputarr);
- $ADODB_COUNTRECS = $savecrecs;
- } else {
- $ret = ADOConnection::_Execute($sql,$inputarr);
- }
- return $ret;
+ return fbird_affected_rows($this->_transactionID ?: $this->_connectionID);
}
- function RollbackTrans()
+ /**
+ * Rollback a smart transaction.
+ *
+ * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:rollbacktrans
+ *
+ * @return bool
+ */
+ public function rollbackTrans()
{
- if ($this->transOff) return true;
- if ($this->transCnt) $this->transCnt -= 1;
+ if ($this->transOff)
+ return true;
+ if ($this->transCnt)
+ $this->transCnt -= 1;
+
$ret = false;
$this->autoCommit = true;
+
if ($this->_transactionID) {
$ret = fbird_rollback($this->_transactionID);
}
@@ -206,16 +304,26 @@ class ADODB_firebird extends ADOConnection {
return $ret;
}
- function &MetaIndexes ($table, $primary = FALSE, $owner=false)
+ /**
+ * Get a list of indexes on the specified table.
+ *
+ * @param string $table The name of the table to get indexes for.
+ * @param bool $primary (Optional) Whether or not to include the primary key.
+ * @param bool $owner (Optional) Unused.
+ *
+ * @return array|bool An array of the indexes, or false if the query to get the indexes failed.
+ */
+ public function metaIndexes($table, $primary = false, $owner = false)
{
// save old fetch mode
global $ADODB_FETCH_MODE;
- $false = false;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+
if ($this->fetchMode !== FALSE) {
$savem = $this->SetFetchMode(FALSE);
}
+
$table = strtoupper($table);
$sql = "SELECT * FROM RDB\$INDICES WHERE RDB\$RELATION_NAME = '".$table."'";
if (!$primary) {
@@ -224,19 +332,19 @@ class ADODB_firebird extends ADOConnection {
$sql .= " AND RDB\$INDEX_NAME NOT LIKE 'RDB\$FOREIGN%'";
}
// get index details
- $rs = $this->Execute($sql);
+ $rs = $this->execute($sql);
if (!is_object($rs)) {
// restore fetchmode
if (isset($savem)) {
$this->SetFetchMode($savem);
}
$ADODB_FETCH_MODE = $save;
- return $false;
+ return false;
}
-
$indexes = array();
while ($row = $rs->FetchRow()) {
- $index = $row[0];
+
+ $index = trim($row[0]);
if (!isset($indexes[$index])) {
if (is_null($row[3])) {
$row[3] = 0;
@@ -246,12 +354,13 @@ class ADODB_firebird extends ADOConnection {
'columns' => array()
);
}
- $sql = "SELECT * FROM RDB\$INDEX_SEGMENTS WHERE RDB\$INDEX_NAME = '".$index."' ORDER BY RDB\$FIELD_POSITION ASC";
- $rs1 = $this->Execute($sql);
+ $sql = sprintf("SELECT * FROM RDB\$INDEX_SEGMENTS WHERE RDB\$INDEX_NAME = '%s' ORDER BY RDB\$FIELD_POSITION ASC",$index);
+ $rs1 = $this->execute($sql);
while ($row1 = $rs1->FetchRow()) {
- $indexes[$index]['columns'][$row1[2]] = $row1[1];
+ $indexes[$index]['columns'][$row1[2]] = trim($row1[1]);
}
}
+
// restore fetchmode
if (isset($savem)) {
$this->SetFetchMode($savem);
@@ -261,38 +370,60 @@ class ADODB_firebird extends ADOConnection {
return $indexes;
}
-
- // See http://community.borland.com/article/0,1410,25844,00.html
- function RowLock($tables,$where,$col=false)
+ /**
+ * Lock a table row for a duration of a transaction.
+ *
+ * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:rowlock
+ * @link https://firebirdsql.org/refdocs/langrefupd21-notes-withlock.html
+ *
+ * @param string $table The table(s) to lock rows for.
+ * @param string $where (Optional) The WHERE clause to use to determine which rows to lock.
+ * @param string $col (Optional) The columns to select.
+ *
+ * @return bool True if the locking SQL statement executed successfully, otherwise false.
+ */
+ public function rowLock($table,$where,$col=false)
{
- if ($this->autoCommit) {
- $this->BeginTrans();
- }
- $this->Execute("UPDATE $table SET $col=$col WHERE $where "); // is this correct - jlim?
- return 1;
- }
-
+ if ($this->transCnt==0)
+ $this->beginTrans();
- function CreateSequence($seqname = 'adodbseq', $startID = 1)
- {
- $ok = $this->Execute(("CREATE GENERATOR $seqname" ));
- if (!$ok) return false;
- return $this->Execute("SET GENERATOR $seqname TO ".($startID-1));
+ if ($where) $where = ' where '.$where;
+ $rs = $this->execute("SELECT $col FROM $table $where FOR UPDATE WITH LOCK");
+ return !empty($rs);
}
- function DropSequence($seqname = 'adodbseq')
+ /**
+ * Creates a sequence in the database.
+ *
+ * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:createsequence
+ *
+ * @param string $seqname The sequence name.
+ * @param int $startID The start id.
+ *
+ * @return ADORecordSet|bool A record set if executed successfully, otherwise false.
+ */
+ public function createSequence($seqname='adodbseq', $startID = 1)
{
- $seqname = strtoupper($seqname);
- return $this->Execute("DROP GENERATOR $seqname");
+ $sql = sprintf($this->_genSeqSQL,$seqname,$startID);
+ return $this->execute($sql);
}
- function GenID($seqname='adodbseq',$startID=1)
+ /**
+ * A portable method of creating sequence numbers.
+ *
+ * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:genid
+ *
+ * @param string $seqname (Optional) The name of the sequence to use.
+ * @param int $startID (Optional) The point to start at in the sequence.
+ *
+ * @return int
+ */
+ public function genID($seqname='adodbseq',$startID=1)
{
$getnext = ("SELECT Gen_ID($seqname,1) FROM RDB\$DATABASE");
$rs = @$this->Execute($getnext);
if (!$rs) {
- $this->Execute(("CREATE GENERATOR $seqname" ));
- $this->Execute("SET GENERATOR $seqname TO ".($startID-1).';');
+ $this->Execute("CREATE SEQUENCE $seqname START WITH $startID");
$rs = $this->Execute($getnext);
}
if ($rs && !$rs->EOF) {
@@ -309,39 +440,62 @@ class ADODB_firebird extends ADOConnection {
return $this->genID;
}
- function SelectDB($dbName)
+ function selectDB($dbName)
{
return false;
}
- function _handleerror()
+ function _handleError()
{
- $this->_errorMsg = fbird_errmsg();
+ $this->_errorCode = fbird_errcode();
+ $this->_errorMsg = fbird_errmsg();
}
- function ErrorNo()
+
+ public function errorNo()
{
- if (preg_match('/error code = ([\-0-9]*)/i', $this->_errorMsg,$arr)) return (integer) $arr[1];
- else return 0;
+ return (integer) $this->_errorCode;
}
- function ErrorMsg()
+ function errorMsg()
{
return $this->_errorMsg;
}
- function Prepare($sql)
+ /**
+ * Prepares an SQL statement and returns a handle to use.
+ * This is not used by bound parameters anymore
+ *
+ * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:prepare
+ * @todo update this function to handle prepared statements correctly
+ *
+ * @param string $sql The SQL to prepare.
+ *
+ * @return bool|array The SQL that was provided and the prepared parameters,
+ * or false if the preparation fails
+ */
+ public function prepare($sql)
{
$stmt = fbird_prepare($this->_connectionID,$sql);
- if (!$stmt) return false;
+ if (!$stmt)
+ return false;
return array($sql,$stmt);
}
- // returns query ID if successful, otherwise false
- // there have been reports of problems with nested queries - the code is probably not re-entrant?
- function _query($sql,$iarr=false)
+ /**
+ * Execute a query.
+ *
+ * @param string|array $sql Query to execute.
+ * @param array $inputarr An optional array of parameters.
+ *
+ * @return object|bool Query identifier or true if execution successful, false if failed.
+ */
+ function _query($sql, $inputarr = false)
{
- if ( !$this->isConnected() ) return false;
+ if (!$this->isConnected()) {
+ return false;
+ }
+
if (!$this->autoCommit && $this->_transactionID) {
$conn = $this->_transactionID;
$docommit = false;
@@ -349,36 +503,31 @@ class ADODB_firebird extends ADOConnection {
$conn = $this->_connectionID;
$docommit = true;
}
+
if (is_array($sql)) {
+ // Prepared statement
$fn = 'fbird_execute';
- $sql = $sql[1];
- if (is_array($iarr)) {
- if ( !isset($iarr[0]) )
- $iarr[0] = ''; // PHP5 compat hack
- $fnarr = array_merge( array($sql) , $iarr);
- $ret = call_user_func_array($fn,$fnarr);
- }
- else {
- $ret = $fn($sql);
- }
+ $args = [$sql[1]];
} else {
$fn = 'fbird_query';
- if (is_array($iarr))
- {
- if (sizeof($iarr) == 0)
- $iarr[0] = ''; // PHP5 compat hack
- $fnarr = array_merge( array($conn,$sql) , $iarr);
- $ret = call_user_func_array($fn,$fnarr);
- }
- else {
- $ret = $fn($conn, $sql);
- }
+ $args = [$conn, $sql];
+ }
+ if (is_array($inputarr)) {
+ $args = array_merge($args, $inputarr);
}
+ $ret = call_user_func_array($fn, $args);
+
+ // fbird_query() and fbird_execute() return number of affected rows
+ // ADOConnection::_Execute() expects true for INSERT/UPDATE/DELETE
+ if (is_numeric($ret)) {
+ $ret = true;
+ }
+
if ($docommit && $ret === true) {
fbird_commit($this->_connectionID);
}
- $this->_handleerror();
+ $this->_handleError();
return $ret;
}
@@ -398,122 +547,133 @@ class ADODB_firebird extends ADOConnection {
$fld->max_length = $flen;
$fld->scale = null;
switch($ftype){
- case 7:
- case 8:
- if ($dialect3) {
- 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) {
+ case 7:
+ case 8:
+ if ($dialect3) {
+ 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;
- $fld->max_length = ($ftype == 7 ? 4 : 9);
- } else {
- $fld->type = ($ftype == 7 ? 'smallint' : 'integer');
- }
- }
- break;
- case 16:
- if ($dialect3) {
- 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:
+ break;
+ } // switch
+ } else {
if ($fscale !=0) {
$fld->type = 'decimal';
- $fld->max_length = 15;
- $fld->scale = 5;
- } else {
- $fld->type = 'double';
- }
- break;
- case 35:
- if ($dialect3) {
- $fld->type = 'timestamp';
+ $fld->scale = $fscale;
+ $fld->max_length = ($ftype == 7 ? 4 : 9);
} else {
- $fld->type = 'date';
+ $fld->type = ($ftype == 7 ? 'smallint' : 'integer');
}
- break;
- case 12:
+ }
+ break;
+ case 16:
+ if ($dialect3) {
+ 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 ($dialect3) {
+ $fld->type = 'timestamp';
+ } else {
$fld->type = 'date';
- break;
- case 13:
- $fld->type = 'time';
- break;
- case 37:
- $fld->type = 'varchar';
- break;
- case 40:
- $fld->type = 'cstring';
- break;
- case 261:
- $fld->type = 'blob';
- $fld->max_length = -1;
- break;
+ }
+ break;
+ case 12:
+ $fld->type = 'date';
+ break;
+ case 13:
+ $fld->type = 'time';
+ 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, $normalize=true)
+ /**
+ * Return an array of information about a table's columns.
+ *
+ * @param string $table The name of the table to get the column info for.
+ * @param bool $normalize (Optional) Unused.
+ *
+ * @return ADOFieldObject[]|bool An array of info for each column,
+ * or false if it could not determine the info.
+ */
+ public function metaColumns($table, $normalize = true)
{
- global $ADODB_FETCH_MODE;
+
+ global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
- $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
+ $rs = $this->execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
$ADODB_FETCH_MODE = $save;
- $false = false;
+
if ($rs === false) {
- return $false;
+ return false;
}
$retarr = array();
//OPN STUFF start
- $dialect3 = ($this->dialect==3 ? true : false);
+ $dialect3 = $this->dialect == 3;
//OPN STUFF end
while (!$rs->EOF) { //print_r($rs->fields);
$fld = new ADOFieldObject();
$fld->name = trim($rs->fields[0]);
//OPN STUFF start
- $this->_ConvertFieldType($fld, $rs->fields[7], $rs->fields[3], $rs->fields[4], $rs->fields[5], $rs->fields[6], $dialect3);
+ //print_r($rs->fields);
+ $this->_ConvertFieldType(
+ $fld, $rs->fields[7], $rs->fields[3], $rs->fields[4], $rs->fields[5], $rs->fields[6], $dialect3);
if (isset($rs->fields[1]) && $rs->fields[1]) {
$fld->not_null = true;
}
@@ -521,17 +681,24 @@ class ADODB_firebird extends ADOConnection {
$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;
+ 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;
}
@@ -547,61 +714,115 @@ class ADODB_firebird extends ADOConnection {
$rs->MoveNext();
}
$rs->Close();
- if ( empty($retarr)) return $false;
+ if ( empty($retarr))
+ return false;
else return $retarr;
}
- function BlobEncode( $blob )
+ /**
+ * Retrieves a list of tables based on given criteria
+ *
+ * @param string|bool $ttype (Optional) Table type = 'TABLE', 'VIEW' or false=both (default)
+ * @param string|bool $showSchema (Optional) schema name, false = current schema (default)
+ * @param string|bool $mask (Optional) filters the table by name
+ *
+ * @return array list of tables
+ */
+ public function metaTables($ttype = false, $showSchema = false, $mask = false)
+ {
+ $save = $this->metaTablesSQL;
+ if (!$showSchema) {
+ $this->metaTablesSQL .= " WHERE (rdb\$relation_name NOT LIKE 'RDB\$%' AND rdb\$relation_name NOT LIKE 'MON\$%' AND rdb\$relation_name NOT LIKE 'SEC\$%')";
+ } elseif (is_string($showSchema)) {
+ $this->metaTablesSQL .= $this->qstr($showSchema);
+ }
+
+ if ($mask) {
+ $mask = $this->qstr($mask);
+ $this->metaTablesSQL .= " AND table_name LIKE $mask";
+ }
+ $ret = ADOConnection::metaTables($ttype,$showSchema);
+
+ $this->metaTablesSQL = $save;
+ return $ret;
+ }
+
+ /**
+ * Encodes a blob, then assigns an id ready to be used
+ *
+ * @param string $blob The blob to be encoded
+ *
+ * @return bool success
+ */
+ public function blobEncode( $blob )
{
$blobid = fbird_blob_create( $this->_connectionID);
fbird_blob_add( $blobid, $blob );
return fbird_blob_close( $blobid );
}
- // since we auto-decode all blob's since 2.42,
- // BlobDecode should not do any transforms
- function BlobDecode($blob)
+ /**
+ * Manually decode a blob
+ *
+ * since we auto-decode all blob's since 2.42,
+ * BlobDecode should not do any transforms
+ *
+ * @param string $blob
+ *
+ * @return string the same blob
+ */
+ public function blobDecode($blob)
{
return $blob;
}
- // old blobdecode function
- // still used to auto-decode all blob's
- function _BlobDecode_old( $blob )
+ /**
+ * Auto function called on read of blob to decode
+ *
+ * @param string $blob Value to decode
+ *
+ * @return string Decoded blob
+ */
+ public function _blobDecode($blob)
{
- $blobid = fbird_blob_open($this->_connectionID, $blob );
- $realblob = fbird_blob_get( $blobid,$this->maxblobsize); // 2nd param is max size of blob -- Kevin Boillet <kevinboillet@yahoo.fr>
- while($string = fbird_blob_get($blobid, 8192)){
- $realblob .= $string;
+ if ($blob === null) {
+ return '';
}
- fbird_blob_close( $blobid );
- return( $realblob );
- }
+ $blob_data = fbird_blob_info($this->_connectionID, $blob);
+ $blobId = fbird_blob_open($this->_connectionID, $blob);
- function _BlobDecode( $blob )
- {
- $blob_data = fbird_blob_info($this->_connectionID, $blob );
- $blobid = fbird_blob_open($this->_connectionID, $blob );
-
- if( $blob_data[0] > $this->maxblobsize ) {
- $realblob = fbird_blob_get($blobid, $this->maxblobsize);
-
- while($string = fbird_blob_get($blobid, 8192)) {
- $realblob .= $string;
+ if ($blob_data[0] > $this->maxblobsize) {
+ $realBlob = fbird_blob_get($blobId, $this->maxblobsize);
+ while ($string = fbird_blob_get($blobId, 8192)) {
+ $realBlob .= $string;
}
} else {
- $realblob = fbird_blob_get($blobid, $blob_data[0]);
+ $realBlob = fbird_blob_get($blobId, $blob_data[0]);
}
- fbird_blob_close( $blobid );
- return( $realblob );
+ fbird_blob_close($blobId);
+ return $realBlob;
}
- function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
+ /**
+ * Insert blob data into a database column directly
+ * from file
+ *
+ * @param string $table table to insert
+ * @param string $column column to insert
+ * @param string $path physical file name
+ * @param string $where string to find unique record
+ * @param string $blobtype BLOB or CLOB
+ *
+ * @return bool success
+ */
+ public function updateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
{
$fd = fopen($path,'rb');
- if ($fd === false) return false;
+ if ($fd === false)
+ return false;
+
$blob_id = fbird_blob_create($this->_connectionID);
/* fill with data */
@@ -617,105 +838,106 @@ class ADODB_firebird extends ADOConnection {
return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false;
}
- /*
- Insert a null into the blob field of the table first.
- Then use UpdateBlob to store the blob.
-
- Usage:
-
- $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
- $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
- */
- function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+ /**
+ * Insert blob data into a database column
+ *
+ * @param string $table table to insert
+ * @param string $column column to insert
+ * @param string $val value to insert
+ * @param string $where string to find unique record
+ * @param string $blobtype BLOB or CLOB
+ *
+ * @return bool success
+ */
+ public function updateBlob($table,$column,$val,$where,$blobtype='BLOB')
{
- $blob_id = fbird_blob_create($this->_connectionID);
+ $blob_id = fbird_blob_create($this->_connectionID);
- // fbird_blob_add($blob_id, $val);
+ // fbird_blob_add($blob_id, $val);
- // replacement that solves the problem by which only the first modulus 64K /
- // of $val are stored at the blob field ////////////////////////////////////
- // Thx Abel Berenstein aberenstein#afip.gov.ar
- $len = strlen($val);
- $chunk_size = 32768;
- $tail_size = $len % $chunk_size;
- $n_chunks = ($len - $tail_size) / $chunk_size;
+ // replacement that solves the problem by which only the first modulus 64K /
+ // of $val are stored at the blob field ////////////////////////////////////
+ // Thx Abel Berenstein aberenstein#afip.gov.ar
+ $len = strlen($val);
+ $chunk_size = 32768;
+ $tail_size = $len % $chunk_size;
+ $n_chunks = ($len - $tail_size) / $chunk_size;
- for ($n = 0; $n < $n_chunks; $n++) {
- $start = $n * $chunk_size;
- $data = substr($val, $start, $chunk_size);
- fbird_blob_add($blob_id, $data);
- }
+ for ($n = 0; $n < $n_chunks; $n++) {
+ $start = $n * $chunk_size;
+ $data = substr($val, $start, $chunk_size);
+ fbird_blob_add($blob_id, $data);
+ }
- if ($tail_size) {
- $start = $n_chunks * $chunk_size;
- $data = substr($val, $start, $tail_size);
- fbird_blob_add($blob_id, $data);
- }
- // end replacement /////////////////////////////////////////////////////////
+ if ($tail_size) {
+ $start = $n_chunks * $chunk_size;
+ $data = substr($val, $start, $tail_size);
+ fbird_blob_add($blob_id, $data);
+ }
+ // end replacement /////////////////////////////////////////////////////////
- $blob_id_str = fbird_blob_close($blob_id);
+ $blob_id_str = fbird_blob_close($blob_id);
- return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false;
+ return $this->execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false;
}
- function OldUpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+ /**
+ * Returns a portably-formatted date string from a timestamp database column.
+ *
+ * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:sqldate
+ *
+ * Firebird does not support an AM/PM format, so the A indicator always shows AM
+ *
+ * @param string $fmt The date format to use.
+ * @param string|bool $col (Optional) The table column to date format, or if false, use NOW().
+ *
+ * @return string The SQL DATE_FORMAT() string, or empty if the provided date format was empty.
+ */
+ public function sqlDate($fmt, $col=false)
{
- $blob_id = fbird_blob_create($this->_connectionID);
- fbird_blob_add($blob_id, $val);
- $blob_id_str = fbird_blob_close($blob_id);
- return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false;
- }
+ if (!$col)
+ $col = 'CURRENT_TIMESTAMP';
- // Format date column in sql string given an input format that understands Y M D
- // Only since Interbase 6.0 - uses EXTRACT
- // problem - does not zero-fill the day and month yet
- function SQLDate($fmt, $col=false)
- {
- if (!$col) $col = $this->sysDate;
$s = '';
$len = strlen($fmt);
for ($i=0; $i < $len; $i++) {
if ($s) $s .= '||';
$ch = $fmt[$i];
- switch($ch) {
+ $choice = strtoupper($ch);
+ switch($choice) {
case 'Y':
- case 'y':
- $s .= "extract(year from $col)";
+ $s .= "EXTRACT(YEAR FROM $col)";
break;
case 'M':
- case 'm':
- $s .= "extract(month from $col)";
+ $s .= "RIGHT('0' || TRIM(EXTRACT(MONTH FROM $col)),2)";
break;
case 'W':
- case 'w':
// The more accurate way of doing this is with a stored procedure
// See http://wiki.firebirdsql.org/wiki/index.php?page=DATE+Handling+Functions for details
- $s .= "((extract(yearday from $col) - extract(weekday from $col - 1) + 7) / 7)";
+ $s .= "((EXTRACT(YEARDAY FROM $col) - EXTRACT(WEEKDAY FROM $col - 1) + 7) / 7)";
break;
case 'Q':
- case 'q':
- $s .= "cast(((extract(month from $col)+2) / 3) as integer)";
+ $s .= "CAST(((EXTRACT(MONTH FROM $col)+2) / 3) AS INTEGER)";
break;
case 'D':
- case 'd':
- $s .= "(extract(day from $col))";
+ $s .= "RIGHT('0' || TRIM(EXTRACT(DAY FROM $col)),2)";
break;
case 'H':
- case 'h':
- $s .= "(extract(hour from $col))";
+ $s .= "RIGHT('0' || TRIM(EXTRACT(HOUR FROM $col)),2)";
break;
case 'I':
- case 'i':
- $s .= "(extract(minute from $col))";
+ $s .= "RIGHT('0' || TRIM(EXTRACT(MINUTE FROM $col)),2)";
break;
case 'S':
- case 's':
- $s .= "CAST((extract(second from $col)) AS INTEGER)";
+ //$s .= "CAST((EXTRACT(SECOND FROM $col)) AS INTEGER)";
+ $s .= "RIGHT('0' || TRIM(EXTRACT(SECOND FROM $col)),2)";
+ break;
+ case 'A':
+ $s .= $this->qstr('AM');
break;
-
default:
if ($ch == '\\') {
$i++;
@@ -728,10 +950,44 @@ class ADODB_firebird extends ADOConnection {
return $s;
}
+ /**
+ * Creates a portable date offset field, for use in SQL statements.
+ *
+ * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:offsetdate
+ *
+ * @param float $dayFraction A day in floating point
+ * @param string|bool $date (Optional) The date to offset. If false, uses CURDATE()
+ *
+ * @return string
+ */
+ public function offsetDate($dayFraction, $date=false)
+ {
+ if (!$date)
+ $date = $this->sysTimeStamp;
+
+ $fraction = $dayFraction * 24 * 3600;
+ return sprintf("DATEADD (second, %s, %s) FROM RDB\$DATABASE",$fraction,$date);
+ }
+
+
// Note that Interbase 6.5 uses this ROWS instead - don't you love forking wars!
// SELECT col1, col2 FROM table ROWS 5 -- get 5 rows
// SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2
- function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $secs=0)
+ /**
+ * Executes a provided SQL statement and returns a handle to the result, with the ability to supply a starting
+ * offset and record count.
+ *
+ * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:selectlimit
+ *
+ * @param string $sql The SQL to execute.
+ * @param int $nrows (Optional) The limit for the number of records you want returned. By default, all results.
+ * @param int $offset (Optional) The offset to use when selecting the results. By default, no offset.
+ * @param array|bool $inputarr (Optional) Any parameter values required by the SQL statement, or false if none.
+ * @param int $secs2cache (Optional) If greater than 0, perform a cached execute. By default, normal execution.
+ *
+ * @return ADORecordSet|false The query results, or false if the query failed to execute.
+ */
+ public function selectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $secs2cache=0)
{
$nrows = (integer) $nrows;
$offset = (integer) $offset;
@@ -740,46 +996,88 @@ class ADODB_firebird extends ADOConnection {
$str .=($offset>=0) ? "SKIP $offset " : '';
$sql = preg_replace('/^[ \t]*select/i',$str,$sql);
- if ($secs)
- $rs = $this->CacheExecute($secs,$sql,$inputarr);
+ if ($secs2cache)
+ $rs = $this->cacheExecute($secs2cache,$sql,$inputarr);
else
- $rs = $this->Execute($sql,$inputarr);
+ $rs = $this->execute($sql,$inputarr);
return $rs;
}
}
-/*--------------------------------------------------------------------------------------
- Class Name: Recordset
---------------------------------------------------------------------------------------*/
-
-class ADORecordset_firebird extends ADORecordSet
+/**
+ * Class ADORecordset_firebird
+ */
+class ADORecordset_firebird extends ADORecordSet
{
-
var $databaseType = "firebird";
- var $bind=false;
- var $_cacheType;
+ var $bind = false;
+
+ /**
+ * @var ADOFieldObject[] Holds a cached version of the metadata
+ */
+ private $fieldObjects = false;
+
+ /**
+ * @var bool Flags if we have retrieved the metadata
+ */
+ private $fieldObjectsRetrieved = false;
+
+ /**
+ * @var array Cross-reference the objects by name for easy access
+ */
+ private $fieldObjectsIndex = array();
+
+ /**
+ * @var bool Flag to indicate if the result has a blob
+ */
+ private $fieldObjectsHaveBlob = false;
- function __construct($id,$mode=false)
+ function __construct($id, $mode = false)
{
- global $ADODB_FETCH_MODE;
+ global $ADODB_FETCH_MODE;
- $this->fetchMode = ($mode === false) ? $ADODB_FETCH_MODE : $mode;
- parent::__construct($id);
+ $this->fetchMode = ($mode === false) ? $ADODB_FETCH_MODE : $mode;
+ parent::__construct($id);
}
+
/**
- * Get column information in the Recordset object.
- * fetchField() can be used in order to obtain information about fields in
- * a certain query result. If the field offset isn't specified, the next
- * field that wasn't yet retrieved by fetchField() is retrieved.
- * @return object containing field information.
- */
- function FetchField($fieldOffset = -1)
+ * Returns: an object containing field information.
+ *
+ * Get column information in the Recordset object. fetchField()
+ * can be used in order to obtain information about fields in a
+ * certain query result. If the field offset isn't specified,
+ * the next field that wasn't yet retrieved by fetchField()
+ * is retrieved.
+ *
+ * $param int $fieldOffset (optional default=-1 for all
+ * @return mixed an ADOFieldObject, or array of objects
+ */
+ private function _fetchField($fieldOffset = -1)
{
+ if ($this->fieldObjectsRetrieved) {
+ if ($this->fieldObjects) {
+ // Already got the information
+ if ($fieldOffset == -1) {
+ return $this->fieldObjects;
+ } else {
+ return $this->fieldObjects[$fieldOffset];
+ }
+ } else {
+ // No metadata available
+ return false;
+ }
+ }
+
+ // Populate the field objects cache
+ $this->fieldObjectsRetrieved = true;
+ $this->fieldObjectsHaveBlob = false;
+ $this->_numOfFields = fbird_num_fields($this->_queryID);
+ for ($fieldIndex = 0; $fieldIndex < $this->_numOfFields; $fieldIndex++) {
$fld = new ADOFieldObject;
- $ibf = fbird_field_info($this->_queryID,$fieldOffset);
+ $ibf = fbird_field_info($this->_queryID, $fieldIndex);
$name = empty($ibf['alias']) ? $ibf['name'] : $ibf['alias'];
@@ -799,23 +1097,54 @@ class ADORecordset_firebird extends ADORecordSet
$fld->type = $ibf['type'];
$fld->max_length = $ibf['length'];
- /* This needs to be populated from the metadata */
+ // This needs to be populated from the metadata
$fld->not_null = false;
$fld->has_default = false;
$fld->default_value = 'null';
- return $fld;
+
+ $this->fieldObjects[$fieldIndex] = $fld;
+ $this->fieldObjectsIndex[$fld->name] = $fieldIndex;
+
+ if ($fld->type == 'BLOB') {
+ $this->fieldObjectsHaveBlob = true;
+ }
+ }
+
+ if ($fieldOffset == -1) {
+ return $this->fieldObjects;
+ }
+
+ return $this->fieldObjects[$fieldOffset];
+ }
+
+ /**
+ * Fetchfield copies the oracle method, it loads the field information
+ * into the _fieldobjs array once, to save multiple calls to the
+ * fbird_ function
+ *
+ * @param int $fieldOffset (optional)
+ *
+ * @return adoFieldObject|false
+ */
+ public function fetchField($fieldOffset = -1)
+ {
+ if ($fieldOffset == -1) {
+ return $this->fieldObjects;
+ }
+
+ return $this->fieldObjects[$fieldOffset];
}
function _initrs()
{
$this->_numOfRows = -1;
- $this->_numOfFields = @fbird_num_fields($this->_queryID);
- // cache types for blob decode check
- for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) {
- $f1 = $this->FetchField($i);
- $this->_cacheType[] = $f1->type;
- }
+ /*
+ * Retrieve all of the column information first. We copy
+ * this method from oracle
+ */
+ $this->_fetchField();
+
}
function _seek($row)
@@ -823,98 +1152,171 @@ class ADORecordset_firebird extends ADORecordSet
return false;
}
- function _fetch()
+ public function _fetch()
{
- $f = @fbird_fetch_row($this->_queryID);
+ // Case conversion function for use in Closure defined below
+ $localFnCaseConv = null;
+
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ // Handle either associative or fetch both
+ $localNumeric = false;
+
+ $f = @fbird_fetch_assoc($this->_queryID);
+ if (is_array($f)) {
+ // Optimally do the case_upper or case_lower
+ if (ADODB_ASSOC_CASE == ADODB_ASSOC_CASE_LOWER) {
+ $f = array_change_key_case($f, CASE_LOWER);
+ $localFnCaseConv = 'strtolower';
+ } elseif (ADODB_ASSOC_CASE == ADODB_ASSOC_CASE_UPPER) {
+ $f = array_change_key_case($f, CASE_UPPER);
+ $localFnCaseConv = 'strtoupper';
+ }
+ }
+ } else {
+ // Numeric fetch mode
+ $localNumeric = true;
+ $f = @fbird_fetch_row($this->_queryID);
+ }
+
if ($f === false) {
$this->fields = false;
return false;
}
+
// 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])) {
- $f[$i] = $this->connection->_BlobDecode($f[$i]);
+ // For optimal performance, only process if there is a possibility of something to do
+ if ($this->fieldObjectsHaveBlob || $rtrim) {
+ $localFieldObjects = $this->fieldObjects;
+ $localFieldObjectIndex = $this->fieldObjectsIndex;
+ /** @var ADODB_firebird $localConnection */
+ $localConnection = &$this->connection;
+
+ /**
+ * Closure for an efficient method of iterating over the elements.
+ * @param mixed $value
+ * @param string|int $key
+ * @return void
+ */
+ $rowTransform = function ($value, $key) use (
+ &$f,
+ $rtrim,
+ $localFieldObjects,
+ $localConnection,
+ $localNumeric,
+ $localFnCaseConv,
+ $localFieldObjectIndex
+ ) {
+ if ($localNumeric) {
+ $localKey = $key;
} else {
- $f[$i] = null;
+ // Cross-reference the associative key back to numeric
+ // with appropriate case conversion
+ $index = $localFnCaseConv ? $localFnCaseConv($key) : $key;
+ $localKey = $localFieldObjectIndex[$index];
}
- } else {
- if (!isset($f[$i])) {
- $f[$i] = null;
- } else if ($rtrim && is_string($f[$i])) {
- $f[$i] = rtrim($f[$i]);
+
+ // As we iterate the elements check for blobs and padding
+ if ($localFieldObjects[$localKey]->type == 'BLOB') {
+ $f[$key] = $localConnection->_BlobDecode($value);
+ } else {
+ if ($rtrim && is_string($value)) {
+ $f[$key] = rtrim($value);
+ }
}
- }
+
+ };
+
+ // Walk the array, applying the above closure
+ array_walk($f, $rowTransform);
}
- // OPN stuff end
- $this->fields = $f;
- if ($this->fetchMode == ADODB_FETCH_ASSOC) {
- $this->fields = $this->GetRowAssoc();
- } else if ($this->fetchMode == ADODB_FETCH_BOTH) {
- $this->fields = array_merge($this->fields,$this->GetRowAssoc());
+ if (!$localNumeric && $this->fetchMode & ADODB_FETCH_NUM) {
+ // Creates a fetch both
+ $fNum = array_values($f);
+ $f = array_merge($f, $fNum);
}
+
+ $this->fields = $f;
+
return true;
}
- /* Use associative array to get fields array */
- function Fields($colname)
+ /**
+ * Get the value of a field in the current row by column name.
+ * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
+ *
+ * @param string $colname is the field to access
+ *
+ * @return mixed the value of $colname column
+ */
+ public function fields($colname)
{
- if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ return $this->fields[$colname];
+ }
+
if (!$this->bind) {
- $this->bind = array();
- for ($i=0; $i < $this->_numOfFields; $i++) {
- $o = $this->FetchField($i);
- $this->bind[strtoupper($o->name)] = $i;
- }
+ // fieldsObjectIndex populated by the recordset load
+ $this->bind = array_change_key_case($this->fieldObjectsIndex, CASE_UPPER);
}
return $this->fields[$this->bind[strtoupper($colname)]];
-
}
function _close()
{
- return @fbird_free_result($this->_queryID);
+ return @fbird_free_result($this->_queryID);
}
- function MetaType($t,$len=-1,$fieldobj=false)
+ public function metaType($t, $len = -1, $fieldObj = false)
{
if (is_object($t)) {
- $fieldobj = $t;
- $t = $fieldobj->type;
- $len = $fieldobj->max_length;
+ $fieldObj = $t;
+ $t = $fieldObj->type;
+ $len = $fieldObj->max_length;
}
- switch (strtoupper($t)) {
- case 'CHAR':
- return 'C';
- case 'TEXT':
- case 'VARCHAR':
- case 'VARYING':
- if ($len <= $this->blobSize) return 'C';
- return 'X';
- case 'BLOB':
- return 'B';
+ $t = strtoupper($t);
+
+ if (array_key_exists($t, $this->connection->customActualTypes)) {
+ return $this->connection->customActualTypes[$t];
+ }
- case 'TIMESTAMP':
- case 'DATE': return 'D';
- case 'TIME': return 'T';
- //case 'T': return 'T';
+ switch ($t) {
+ case 'CHAR':
+ return 'C';
- //case 'L': return 'L';
- case 'INT':
- case 'SHORT':
- case 'INTEGER': return 'I';
- default: return ADODB_DEFAULT_METATYPE;
+ case 'TEXT':
+ case 'VARCHAR':
+ case 'VARYING':
+ if ($len <= $this->blobSize) {
+ return 'C';
+ }
+ return 'X';
+ case 'BLOB':
+ return 'B';
+
+ case 'TIMESTAMP':
+ case 'DATE':
+ return 'D';
+ case 'TIME':
+ return 'T';
+ //case 'T': return 'T';
+
+ //case 'L': return 'L';
+ case 'INT':
+ case 'SHORT':
+ case 'INTEGER':
+ return 'I';
+ default:
+ return ADODB_DEFAULT_METATYPE;
}
}
}
+
diff --git a/drivers/adodb-ibase.inc.php b/drivers/adodb-ibase.inc.php
index 69de30d..8159c51 100644
--- a/drivers/adodb-ibase.inc.php
+++ b/drivers/adodb-ibase.inc.php
@@ -256,7 +256,7 @@ class ADODB_ibase extends ADOConnection {
// See http://community.borland.com/article/0,1410,25844,00.html
- function RowLock($tables,$where,$col=false)
+ function rowLock($table, $where, $col = false)
{
if ($this->autoCommit) {
$this->BeginTrans();
@@ -320,7 +320,7 @@ class ADODB_ibase extends ADOConnection {
function ErrorMsg()
{
- return $this->_errorMsg;
+ return $this->_errorMsg;
}
function Prepare($sql)
@@ -332,9 +332,8 @@ class ADODB_ibase extends ADOConnection {
// returns query ID if successful, otherwise false
// there have been reports of problems with nested queries - the code is probably not re-entrant?
- function _query($sql,$iarr=false)
+ function _query($sql, $inputarr = false)
{
-
if (!$this->autoCommit && $this->_transactionID) {
$conn = $this->_transactionID;
$docommit = false;
@@ -345,28 +344,35 @@ class ADODB_ibase extends ADOConnection {
if (is_array($sql)) {
$fn = 'ibase_execute';
$sql = $sql[1];
- if (is_array($iarr)) {
- if ( !isset($iarr[0]) )
- $iarr[0] = ''; // PHP5 compat hack
- $fnarr = array_merge( array($sql) , $iarr);
- $ret = call_user_func_array($fn,$fnarr);
- }
- else {
+ if (is_array($inputarr)) {
+ if (!isset($inputarr[0])) {
+ $inputarr[0] = ''; // PHP5 compat hack
+ }
+ $fnarr = array_merge(array($sql), $inputarr);
+ $ret = call_user_func_array($fn, $fnarr);
+ } else {
$ret = $fn($sql);
}
} else {
$fn = 'ibase_query';
- if (is_array($iarr)) {
- if (sizeof($iarr) == 0)
- $iarr[0] = ''; // PHP5 compat hack
- $fnarr = array_merge( array($conn,$sql) , $iarr);
- $ret = call_user_func_array($fn,$fnarr);
- }
- else {
+ if (is_array($inputarr)) {
+ if (sizeof($inputarr) == 0) {
+ $inputarr[0] = ''; // PHP5 compat hack
+ }
+ $fnarr = array_merge(array($conn, $sql), $inputarr);
+ $ret = call_user_func_array($fn, $fnarr);
+ } else {
$ret = $fn($conn, $sql);
}
}
+
+ // ibase_query() and ibase_execute() return number of affected rows
+ // ADOConnection::_Execute() expects true for INSERT/UPDATE/DELETE
+ if (is_numeric($ret)) {
+ $ret = true;
+ }
+
if ($docommit && $ret === true) {
ibase_commit($this->_connectionID);
}
@@ -514,17 +520,24 @@ class ADODB_ibase extends ADOConnection {
$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;
+ 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;
}
@@ -558,9 +571,6 @@ class ADODB_ibase extends ADOConnection {
return $blob;
}
-
-
-
// old blobdecode function
// still used to auto-decode all blob's
function _BlobDecode_old( $blob )
@@ -625,34 +635,34 @@ class ADODB_ibase extends ADOConnection {
*/
function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
{
- $blob_id = ibase_blob_create($this->_connectionID);
+ $blob_id = ibase_blob_create($this->_connectionID);
- // ibase_blob_add($blob_id, $val);
+ // ibase_blob_add($blob_id, $val);
- // replacement that solves the problem by which only the first modulus 64K /
- // of $val are stored at the blob field ////////////////////////////////////
- // Thx Abel Berenstein aberenstein#afip.gov.ar
- $len = strlen($val);
- $chunk_size = 32768;
- $tail_size = $len % $chunk_size;
- $n_chunks = ($len - $tail_size) / $chunk_size;
+ // replacement that solves the problem by which only the first modulus 64K /
+ // of $val are stored at the blob field ////////////////////////////////////
+ // Thx Abel Berenstein aberenstein#afip.gov.ar
+ $len = strlen($val);
+ $chunk_size = 32768;
+ $tail_size = $len % $chunk_size;
+ $n_chunks = ($len - $tail_size) / $chunk_size;
- for ($n = 0; $n < $n_chunks; $n++) {
- $start = $n * $chunk_size;
- $data = substr($val, $start, $chunk_size);
- ibase_blob_add($blob_id, $data);
- }
+ for ($n = 0; $n < $n_chunks; $n++) {
+ $start = $n * $chunk_size;
+ $data = substr($val, $start, $chunk_size);
+ ibase_blob_add($blob_id, $data);
+ }
- if ($tail_size) {
- $start = $n_chunks * $chunk_size;
- $data = substr($val, $start, $tail_size);
- ibase_blob_add($blob_id, $data);
- }
- // end replacement /////////////////////////////////////////////////////////
+ if ($tail_size) {
+ $start = $n_chunks * $chunk_size;
+ $data = substr($val, $start, $tail_size);
+ ibase_blob_add($blob_id, $data);
+ }
+ // end replacement /////////////////////////////////////////////////////////
- $blob_id_str = ibase_blob_close($blob_id);
+ $blob_id_str = ibase_blob_close($blob_id);
- return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false;
+ return $this->Execute("UPDATE $table SET $column=(?) WHERE $where", array($blob_id_str)) != false;
}
@@ -724,7 +734,7 @@ class ADODB_ibase extends ADOConnection {
Class Name: Recordset
--------------------------------------------------------------------------------------*/
-class ADORecordset_ibase extends ADORecordSet
+class ADORecordSet_ibase extends ADORecordSet
{
var $databaseType = "ibase";
@@ -844,13 +854,12 @@ class ADORecordset_ibase extends ADORecordSet
}
return $this->fields[$this->bind[strtoupper($colname)]];
-
}
function _close()
{
- return @ibase_free_result($this->_queryID);
+ return @ibase_free_result($this->_queryID);
}
function MetaType($t,$len=-1,$fieldobj=false)
@@ -860,28 +869,41 @@ class ADORecordset_ibase extends ADORecordSet
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
- switch (strtoupper($t)) {
- case 'CHAR':
- return 'C';
-
- case 'TEXT':
- case 'VARCHAR':
- case 'VARYING':
- if ($len <= $this->blobSize) return 'C';
- return 'X';
- case 'BLOB':
- return 'B';
-
- case 'TIMESTAMP':
- case 'DATE': return 'D';
- case 'TIME': return 'T';
- //case 'T': return 'T';
-
- //case 'L': return 'L';
- case 'INT':
- case 'SHORT':
- case 'INTEGER': return 'I';
- default: return ADODB_DEFAULT_METATYPE;
+
+ $t = strtoupper($t);
+
+ if (array_key_exists($t, $this->connection->customActualTypes)) {
+ return $this->connection->customActualTypes[$t];
+ }
+
+ switch ($t) {
+ case 'CHAR':
+ return 'C';
+
+ case 'TEXT':
+ case 'VARCHAR':
+ case 'VARYING':
+ if ($len <= $this->blobSize) {
+ return 'C';
+ }
+ return 'X';
+ case 'BLOB':
+ return 'B';
+
+ case 'TIMESTAMP':
+ case 'DATE':
+ return 'D';
+ case 'TIME':
+ return 'T';
+ //case 'T': return 'T';
+
+ //case 'L': return 'L';
+ case 'INT':
+ case 'SHORT':
+ case 'INTEGER':
+ return 'I';
+ default:
+ return ADODB_DEFAULT_METATYPE;
}
}
diff --git a/drivers/adodb-informix72.inc.php b/drivers/adodb-informix72.inc.php
index a9c43e2..6fddde3 100644
--- a/drivers/adodb-informix72.inc.php
+++ b/drivers/adodb-informix72.inc.php
@@ -80,12 +80,9 @@ class ADODB_informix72 extends ADOConnection {
function ServerInfo()
{
- if (isset($this->version)) return $this->version;
-
- $arr['description'] = $this->GetOne("select DBINFO('version','full') from systables where tabid = 1");
- $arr['version'] = $this->GetOne("select DBINFO('version','major') || DBINFO('version','minor') from systables where tabid = 1");
- $this->version = $arr;
- return $arr;
+ $arr['description'] = $this->GetOne("select DBINFO('version','full') from systables where tabid = 1");
+ $arr['version'] = $this->GetOne("select DBINFO('version','major') || DBINFO('version','minor') from systables where tabid = 1");
+ return $arr;
}
@@ -253,12 +250,12 @@ class ADODB_informix72 extends ADOConnection {
return $false;
}
- function xMetaColumns($table)
- {
+ function xMetaColumns($table)
+ {
return ADOConnection::MetaColumns($table,false);
- }
+ }
- function MetaForeignKeys($table, $owner=false, $upper=false) //!Eos
+ public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false)
{
$sql = "
select tr.tabname,updrule,delrule,
@@ -337,7 +334,6 @@ class ADODB_informix72 extends ADOConnection {
else return array($sql,$stmt);
}
*/
- // returns query ID if successful, otherwise false
function _query($sql,$inputarr=false)
{
global $ADODB_COUNTRECS;
diff --git a/drivers/adodb-ldap.inc.php b/drivers/adodb-ldap.inc.php
index 323b358..305f6a7 100644
--- a/drivers/adodb-ldap.inc.php
+++ b/drivers/adodb-ldap.inc.php
@@ -157,7 +157,6 @@ class ADODB_ldap extends ADOConnection {
}
}
- /* returns _queryID or false */
function _query($sql,$inputarr=false)
{
$rs = @ldap_search( $this->_connectionID, $this->database, $sql );
diff --git a/drivers/adodb-mssql.inc.php b/drivers/adodb-mssql.inc.php
index 3de3f8d..c0b714e 100644
--- a/drivers/adodb-mssql.inc.php
+++ b/drivers/adodb-mssql.inc.php
@@ -429,7 +429,7 @@ class ADODB_mssql extends ADOConnection {
return $indexes;
}
- function MetaForeignKeys($table, $owner=false, $upper=false)
+ public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false)
{
global $ADODB_FETCH_MODE;
@@ -541,7 +541,6 @@ order by constraint_name, referenced_table_name, keyno";
function SelectDB($dbName)
{
$this->database = $dbName;
- $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
if ($this->_connectionID) {
return @mssql_select_db($dbName);
}
@@ -726,7 +725,6 @@ order by constraint_name, referenced_table_name, keyno";
return $this->Execute($sql) != false;
}
- // returns query ID if successful, otherwise false
function _query($sql,$inputarr=false)
{
$this->_errorMsg = false;
diff --git a/drivers/adodb-mssqlnative.inc.php b/drivers/adodb-mssqlnative.inc.php
index 36dc543..f7e1bcc 100644
--- a/drivers/adodb-mssqlnative.inc.php
+++ b/drivers/adodb-mssqlnative.inc.php
@@ -151,6 +151,8 @@ class ADODB_mssqlnative extends ADOConnection {
$arrServerInfo = sqlsrv_server_info($this->_connectionID);
$ADODB_FETCH_MODE = $savem;
+
+ $arr = array();
$arr['description'] = $arrServerInfo['SQLServerName'].' connected to '.$arrServerInfo['CurrentDatabase'];
$arr['version'] = $arrServerInfo['SQLServerVersion'];//ADOConnection::_findvers($arr['description']);
return $arr;
@@ -182,8 +184,10 @@ class ADODB_mssqlnative extends ADOConnection {
function _affectedrows()
{
- if ($this->_queryID)
- return sqlsrv_rows_affected($this->_queryID);
+ if ($this->_queryID && is_resource($this->_queryID)) {
+ return sqlsrv_rows_affected($this->_queryID);
+ }
+ return false;
}
function GenID($seq='adodbseq',$start=1) {
@@ -436,7 +440,6 @@ class ADODB_mssqlnative extends ADOConnection {
function SelectDB($dbName)
{
$this->database = $dbName;
- $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
if ($this->_connectionID) {
$rs = $this->Execute('USE '.$dbName);
if($rs) {
@@ -643,13 +646,6 @@ class ADODB_mssqlnative extends ADOConnection {
$rez = sqlsrv_query($this->_connectionID, $sql);
}
- if ($this->debug) {
- ADOConnection::outp("<hr>running query: " . var_export($sql, true)
- . "<hr>input array: " . var_export($inputarr, true)
- . "<hr>result: " . var_export($rez, true)
- );
- }
-
$this->lastInsID = false;
if (!$rez) {
$rez = false;
@@ -659,23 +655,27 @@ class ADODB_mssqlnative extends ADOConnection {
// e.g. if triggers are involved (see #41)
while (sqlsrv_next_result($rez)) {
sqlsrv_fetch($rez);
- $this->lastInsID = sqlsrv_get_field($rez, 0, SQLSRV_PHPTYPE_INT);
+ $this->lastInsID = sqlsrv_get_field($rez, 0);
}
}
return $rez;
}
- // returns true or false
+ /**
+ * Rolls back pending transactions and closes the connection.
+ *
+ * @return bool True, unless the connection id is invalid
+ */
function _close()
{
if ($this->transCnt) {
$this->RollbackTrans();
}
- if($this->_connectionID) {
- $rez = sqlsrv_close($this->_connectionID);
+ if ($this->_connectionID) {
+ return sqlsrv_close($this->_connectionID);
}
$this->_connectionID = false;
- return $rez;
+ return true;
}
@@ -719,7 +719,7 @@ class ADODB_mssqlnative extends ADOConnection {
return $indexes;
}
- function MetaForeignKeys($table, $owner=false, $upper=false)
+ public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false)
{
global $ADODB_FETCH_MODE;
@@ -1009,6 +1009,37 @@ class ADODB_mssqlnative extends ADOConnection {
return $metaProcedures;
}
+ /**
+ * An SQL Statement that adds a specific number of
+ * days or part to local datetime
+ *
+ * @param float $dayFraction
+ * @param string $date
+ *
+ * @return string
+ */
+ public function offsetDate($dayFraction, $date = false)
+ {
+ if (!$date)
+ /*
+ * Use GETDATE() via systTimestamp;
+ */
+ $date = $this->sysTimeStamp;
+
+ /*
+ * seconds, number of seconds, date base
+ */
+ $dateFormat = "DATEADD(s, %s, %s)";
+
+ /*
+ * Adjust the offset back to seconds
+ */
+ $fraction = $dayFraction * 24 * 3600;
+
+ return sprintf($dateFormat,$fraction,$date);
+
+ }
+
}
/*--------------------------------------------------------------------------------------
diff --git a/drivers/adodb-mysql.inc.php b/drivers/adodb-mysql.inc.php
deleted file mode 100644
index f07c081..0000000
--- a/drivers/adodb-mysql.inc.php
+++ /dev/null
@@ -1,932 +0,0 @@
-<?php
-/**
- * MySQL driver
- *
- * @deprecated
- *
- * This driver only supports the original non-transactional MySQL driver,
- * which was deprecated in PHP version 5.5 and removed in PHP version 7.
- * It is deprecated as of ADOdb version 5.20.0, use the mysqli driver
- * instead, which supports both transactional and non-transactional updates.
- *
- * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
- *
- * @package ADOdb
- * @link https://adodb.org Project's web site and documentation
- * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
- *
- * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
- * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
- * any later version. This means you can use it in proprietary products.
- * See the LICENSE.md file distributed with this source code for details.
- * @license BSD-3-Clause
- * @license LGPL-2.1-or-later
- *
- * @copyright 2000-2013 John Lim
- * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
- */
-
-// security - hide paths
-if (!defined('ADODB_DIR')) die();
-
-if (! defined("_ADODB_MYSQL_LAYER")) {
- define("_ADODB_MYSQL_LAYER", 1 );
-
-class ADODB_mysql extends ADOConnection {
- var $databaseType = 'mysql';
- var $dataProvider = 'mysql';
- var $hasInsertID = true;
- var $hasAffectedRows = true;
- var $metaTablesSQL = "SELECT
- TABLE_NAME,
- CASE WHEN TABLE_TYPE = 'VIEW' THEN 'V' ELSE 'T' END
- FROM INFORMATION_SCHEMA.TABLES
- WHERE TABLE_SCHEMA=";
- var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`";
- var $fmtTimeStamp = "'Y-m-d H:i:s'";
- var $hasLimit = true;
- var $hasMoveFirst = true;
- var $hasGenID = true;
- var $isoDates = true; // accepts dates in ISO format
- var $sysDate = 'CURDATE()';
- var $sysTimeStamp = 'NOW()';
- var $hasTransactions = false;
- var $forceNewConnect = false;
- var $poorAffectedRows = true;
- var $clientFlags = 0;
- var $charSet = '';
- var $substr = "substring";
- var $nameQuote = '`'; /// string to use to quote identifiers and names
- var $compat323 = false; // true if compat with mysql 3.23
-
- /**
- * ADODB_mysql constructor.
- */
- public function __construct() {
- if(version_compare(PHP_VERSION, '7.0.0', '>=')) {
- $this->outp_throw(
- 'mysql extension is not supported since PHP 7.0.0, use mysqli instead',
- __METHOD__
- );
- die(1); // Stop execution even if not using Exceptions
- } elseif(version_compare(PHP_VERSION, '5.5.0', '>=')) {
- // If mysql extension is available just print a warning,
- // otherwise die with an error message
- if(function_exists('mysql_connect')) {
- $this->outp('mysql extension is deprecated since PHP 5.5.0, consider using mysqli');
- } else {
- $this->outp_throw(
- 'mysql extension is not available, use mysqli instead',
- __METHOD__
- );
- die(1); // Stop execution even if not using Exceptions
- }
- }
- }
-
- function setCharSet($charset)
- {
- if (!function_exists('mysql_set_charset')) {
- return false;
- }
-
- if ($this->charSet !== $charset) {
- $ok = @mysql_set_charset($charset,$this->_connectionID);
- if ($ok) {
- $this->charSet = $charset;
- return true;
- }
- return false;
- }
- return true;
- }
-
- function serverInfo()
- {
- $arr['description'] = ADOConnection::GetOne("select version()");
- $arr['version'] = ADOConnection::_findvers($arr['description']);
- return $arr;
- }
-
- function ifNull( $field, $ifNull )
- {
- return " IFNULL($field, $ifNull) "; // if MySQL
- }
-
- function metaProcedures($NamePattern = false, $catalog = null, $schemaPattern = null)
- {
- // save old fetch mode
- global $ADODB_FETCH_MODE;
-
- $false = false;
- $save = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-
- if ($this->fetchMode !== FALSE) {
- $savem = $this->SetFetchMode(FALSE);
- }
-
- $procedures = array ();
-
- // get index details
-
- $likepattern = '';
- if ($NamePattern) {
- $likepattern = " LIKE '".$NamePattern."'";
- }
- $rs = $this->Execute('SHOW PROCEDURE STATUS'.$likepattern);
- if (is_object($rs)) {
-
- // parse index data into array
- while ($row = $rs->FetchRow()) {
- $procedures[$row[1]] = array(
- 'type' => 'PROCEDURE',
- 'catalog' => '',
- 'schema' => '',
- 'remarks' => $row[7],
- );
- }
- }
-
- $rs = $this->Execute('SHOW FUNCTION STATUS'.$likepattern);
- if (is_object($rs)) {
- // parse index data into array
- while ($row = $rs->FetchRow()) {
- $procedures[$row[1]] = array(
- 'type' => 'FUNCTION',
- 'catalog' => '',
- 'schema' => '',
- 'remarks' => $row[7]
- );
- }
- }
-
- // restore fetchmode
- if (isset($savem)) {
- $this->SetFetchMode($savem);
- }
- $ADODB_FETCH_MODE = $save;
-
- return $procedures;
- }
-
- /**
- * Retrieves a list of tables based on given criteria
- *
- * @param string $ttype Table type = 'TABLE', 'VIEW' or false=both (default)
- * @param string $showSchema schema name, false = current schema (default)
- * @param string $mask filters the table by name
- *
- * @return array list of tables
- */
- function metaTables($ttype=false,$showSchema=false,$mask=false)
- {
- $save = $this->metaTablesSQL;
- if ($showSchema && is_string($showSchema)) {
- $this->metaTablesSQL .= $this->qstr($showSchema);
- } else {
- $this->metaTablesSQL .= "schema()";
- }
-
- if ($mask) {
- $mask = $this->qstr($mask);
- $this->metaTablesSQL .= " AND table_name LIKE $mask";
- }
- $ret = ADOConnection::MetaTables($ttype,$showSchema);
-
- $this->metaTablesSQL = $save;
- return $ret;
- }
-
-
- function metaIndexes ($table, $primary = FALSE, $owner=false)
- {
- // save old fetch mode
- global $ADODB_FETCH_MODE;
-
- $false = false;
- $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 INDEX 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;
- }
-
-
- /**
- * Appropriately quotes strings with ' characters for insertion into the database.
- *
- * Relies on mysql_real_escape_string()
- * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:qstr
- *
- * @param string $s The string to quote
- * @param bool $magic_quotes This param is not used since 5.21.0.
- * It remains for backwards compatibility.
- *
- * @return string Quoted string
- */
- function qStr($s, $magic_quotes=false)
- {
- if (is_null($s)) {
- return 'NULL';
- }
-
- if (is_resource($this->_connectionID)) {
- return "'" . mysql_real_escape_string($s, $this->_connectionID) . "'";
- }
-
- if ($this->replaceQuote[0] == '\\') {
- $s = str_replace(array('\\', "\0"), array('\\\\', "\\\0"), $s);
- }
- return "'" . str_replace("'", $this->replaceQuote, $s) . "'";
- }
-
- protected function _insertID($table = '', $column = '')
- {
- return ADOConnection::GetOne('SELECT LAST_INSERT_ID()');
- //return mysql_insert_id($this->_connectionID);
- }
-
- function getOne($sql,$inputarr=false)
- {
- global $ADODB_GETONE_EOF;
- if ($this->compat323 == false && strncasecmp($sql,'sele',4) == 0) {
- $rs = $this->SelectLimit($sql,1,-1,$inputarr);
- if ($rs) {
- $rs->Close();
- if ($rs->EOF) return $ADODB_GETONE_EOF;
- return reset($rs->fields);
- }
- } else {
- return ADOConnection::GetOne($sql,$inputarr);
- }
- return false;
- }
-
- function beginTrans()
- {
- if ($this->debug) ADOConnection::outp("Transactions not supported in 'mysql' driver. Use 'mysqlt' or 'mysqli' driver");
- }
-
- function _affectedrows()
- {
- return mysql_affected_rows($this->_connectionID);
- }
-
- // 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 if not exists %s (id int not null)";
- var $_genSeqCountSQL = "select count(*) from %s";
- var $_genSeq2SQL = "insert into %s values (%s)";
- var $_dropSeqSQL = "drop table if exists %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;
-
- $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));
- $cnt = $this->GetOne(sprintf($this->_genSeqCountSQL,$seqname));
- if (!$cnt) $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
- $rs = $this->Execute($getnext);
- }
-
- if ($rs) {
- $this->genID = mysql_insert_id($this->_connectionID);
- $rs->Close();
- } else
- $this->genID = 0;
-
- $this->_logsql = $savelog;
- return $this->genID;
- }
-
- function metaDatabases()
- {
- $qid = mysql_list_dbs($this->_connectionID);
- $arr = array();
- $i = 0;
- $max = mysql_num_rows($qid);
- while ($i < $max) {
- $db = mysql_tablename($qid,$i);
- if ($db != 'mysql') $arr[] = $db;
- $i += 1;
- }
- return $arr;
- }
-
-
- // 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) {
-
- default:
- if ($ch == '\\') {
- $i++;
- $ch = substr($fmt,$i,1);
- }
- /** FALL THROUGH */
- case '-':
- case '/':
- $s .= $ch;
- break;
-
- case 'Y':
- case 'y':
- $s .= '%Y';
- break;
- case 'M':
- $s .= '%b';
- break;
-
- case 'm':
- $s .= '%m';
- break;
- case 'D':
- case 'd':
- $s .= '%d';
- break;
-
- case 'Q':
- case 'q':
- $s .= "'),Quarter($col)";
-
- if ($len > $i+1) $s .= ",DATE_FORMAT($col,'";
- else $s .= ",('";
- $concat = true;
- 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;
-
- case 'w':
- $s .= '%w';
- break;
-
- case 'W':
- $s .= '%U';
- break;
-
- case 'l':
- $s .= '%W';
- 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 '';
- }
-
- function offsetDate($dayFraction,$date=false)
- {
- if (!$date) $date = $this->sysDate;
-
- $fraction = $dayFraction * 24 * 3600;
- return '('. $date . ' + INTERVAL ' . $fraction.' SECOND)';
-
-// return "from_unixtime(unix_timestamp($date)+$fraction)";
- }
-
- // returns true or false
- function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
- {
- if (!empty($this->port))
- $argHostname .= ":".$this->port;
-
- $this->_connectionID =
- mysql_connect($argHostname,
- $argUsername,
- $argPassword,
- $this->forceNewConnect,
- $this->clientFlags
- );
-
-
- if ($this->_connectionID === false)
- return false;
- if ($argDatabasename)
- return $this->SelectDB($argDatabasename);
-
- return true;
- }
-
- // returns true or false
- function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
- {
- if (!empty($this->port)) $argHostname .= ":".$this->port;
-
- $this->_connectionID =
- mysql_pconnect($argHostname,
- $argUsername,
- $argPassword,
- $this->clientFlags);
-
- if ($this->_connectionID === false)
- return false;
- if ($this->autoRollback)
- $this->RollbackTrans();
- if ($argDatabasename)
- return $this->SelectDB($argDatabasename);
- return true;
- }
-
- function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
- {
- $this->forceNewConnect = true;
- return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
- }
-
- function metaColumns($table, $normalize=true)
- {
- $this->_findschema($table,$schema);
- if ($schema) {
- $dbName = $this->database;
- $this->SelectDB($schema);
- }
- global $ADODB_FETCH_MODE;
- $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));
-
- if ($schema) {
- $this->SelectDB($dbName);
- }
-
- if (isset($savem)) $this->SetFetchMode($savem);
- $ADODB_FETCH_MODE = $save;
- if (!is_object($rs)) {
- $false = false;
- return $false;
- }
-
- $retarr = array();
- while (!$rs->EOF){
- $fld = new ADOFieldObject();
- $fld->name = $rs->fields[0];
- $type = $rs->fields[1];
-
- // split type into type(length):
- $fld->scale = null;
- if (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;
- } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) {
- $fld->type = $query_array[1];
- $arr = explode(",",$query_array[2]);
- $fld->enums = $arr;
- $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6
- $fld->max_length = ($zlen > 0) ? $zlen : 1;
- } else {
- $fld->type = $type;
- $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($type,'blob') !== false || strpos($type,'binary') !== false);
- $fld->unsigned = (strpos($type,'unsigned') !== false);
- $fld->zerofill = (strpos($type,'zerofill') !== false);
-
- if (!$fld->binary) {
- $d = $rs->fields[4];
- if ($d != '' && $d != 'NULL') {
- $fld->has_default = true;
- $fld->default_value = $d;
- } else {
- $fld->has_default = false;
- }
- }
-
- if ($save == ADODB_FETCH_NUM) {
- $retarr[] = $fld;
- } else {
- $retarr[strtoupper($fld->name)] = $fld;
- }
- $rs->MoveNext();
- }
-
- $rs->Close();
- return $retarr;
- }
-
- // returns true or false
- function selectDB($dbName)
- {
- $this->database = $dbName;
- $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
- if ($this->_connectionID) {
- return @mysql_select_db($dbName,$this->_connectionID);
- }
- else return false;
- }
-
- // parameters use PostgreSQL convention, not MySQL
- function selectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs=0)
- {
- $nrows = (int) $nrows;
- $offset = (int) $offset;
- $offsetStr =($offset>=0) ? ((integer)$offset)."," : '';
- // jason judge, see PHPLens Issue No: 9220
- if ($nrows < 0) $nrows = '18446744073709551615';
-
- if ($secs)
- $rs = $this->CacheExecute($secs,$sql." LIMIT $offsetStr".((integer)$nrows),$inputarr);
- else
- $rs = $this->Execute($sql." LIMIT $offsetStr".((integer)$nrows),$inputarr);
- return $rs;
- }
-
- // returns queryID or false
- function _query($sql,$inputarr=false)
- {
-
- return mysql_query($sql,$this->_connectionID);
- /*
- global $ADODB_COUNTRECS;
- if($ADODB_COUNTRECS)
- return mysql_query($sql,$this->_connectionID);
- else
- return @mysql_unbuffered_query($sql,$this->_connectionID); // requires PHP >= 4.0.6
- */
- }
-
- /* Returns: the last error message from previous database operation */
- function errorMsg()
- {
-
- if ($this->_logsql) return $this->_errorMsg;
- if (empty($this->_connectionID)) $this->_errorMsg = @mysql_error();
- else $this->_errorMsg = @mysql_error($this->_connectionID);
- return $this->_errorMsg;
- }
-
- /* Returns: the last error number from previous database operation */
- function errorNo()
- {
- if ($this->_logsql) return $this->_errorCode;
- if (empty($this->_connectionID)) return @mysql_errno();
- else return @mysql_errno($this->_connectionID);
- }
-
- // returns true or false
- function _close()
- {
- @mysql_close($this->_connectionID);
-
- $this->charSet = '';
- $this->_connectionID = false;
- }
-
-
- /*
- * Maximum size of C field
- */
- function charMax()
- {
- return 255;
- }
-
- /*
- * Maximum size of X field
- */
- function textMax()
- {
- return 4294967295;
- }
-
- // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx>
- function metaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
- {
- global $ADODB_FETCH_MODE;
- if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true;
-
- if ( !empty($owner) ) {
- $table = "$owner.$table";
- }
- $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table));
- if ($associative) {
- $create_sql = isset($a_create_table["Create Table"]) ? $a_create_table["Create Table"] : $a_create_table["Create View"];
- } else {
- $create_sql = $a_create_table[1];
- }
-
- $matches = array();
-
- if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false;
- $foreign_keys = array();
- $num_keys = count($matches[0]);
- for ( $i = 0; $i < $num_keys; $i ++ ) {
- $my_field = explode('`, `', $matches[1][$i]);
- $ref_table = $matches[2][$i];
- $ref_field = explode('`, `', $matches[3][$i]);
-
- if ( $upper ) {
- $ref_table = strtoupper($ref_table);
- }
-
- // see https://sourceforge.net/p/adodb/bugs/100/
- if (!isset($foreign_keys[$ref_table])) {
- $foreign_keys[$ref_table] = array();
- }
- $num_fields = count($my_field);
- for ( $j = 0; $j < $num_fields; $j ++ ) {
- if ( $associative ) {
- $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j];
- } else {
- $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}";
- }
- }
- }
-
- return $foreign_keys;
- }
-
-
-}
-
-/*--------------------------------------------------------------------------------------
- Class Name: Recordset
---------------------------------------------------------------------------------------*/
-
-
-class ADORecordSet_mysql extends ADORecordSet{
-
- var $databaseType = "mysql";
- var $canSeek = true;
-
- function __construct($queryID,$mode=false)
- {
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- switch ($mode)
- {
- case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
- case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
- case ADODB_FETCH_DEFAULT:
- case ADODB_FETCH_BOTH:
- default:
- $this->fetchMode = MYSQL_BOTH; break;
- }
- $this->adodbFetchMode = $mode;
- parent::__construct($queryID);
- }
-
- function _initrs()
- {
- //GLOBAL $ADODB_COUNTRECS;
- // $this->_numOfRows = ($ADODB_COUNTRECS) ? @mysql_num_rows($this->_queryID):-1;
- $this->_numOfRows = @mysql_num_rows($this->_queryID);
- $this->_numOfFields = @mysql_num_fields($this->_queryID);
- }
-
- function fetchField($fieldOffset = -1)
- {
- if ($fieldOffset != -1) {
- $o = @mysql_fetch_field($this->_queryID, $fieldOffset);
- $f = @mysql_field_flags($this->_queryID,$fieldOffset);
- if ($o) $o->max_length = @mysql_field_len($this->_queryID,$fieldOffset); // suggested by: Jim Nicholson (jnich#att.com)
- //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
- if ($o) $o->binary = (strpos($f,'binary')!== false);
- }
- else { /* The $fieldOffset argument is not provided thus its -1 */
- $o = @mysql_fetch_field($this->_queryID);
- //if ($o) $o->max_length = @mysql_field_len($this->_queryID); // suggested by: Jim Nicholson (jnich#att.com)
- $o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
- }
-
- return $o;
- }
-
- function getRowAssoc($upper = ADODB_ASSOC_CASE)
- {
- if ($this->fetchMode == MYSQL_ASSOC && $upper == ADODB_ASSOC_CASE_LOWER) {
- $row = $this->fields;
- }
- else {
- $row = ADORecordSet::GetRowAssoc($upper);
- }
- return $row;
- }
-
- /* Use associative array to get fields array */
- function fields($colname)
- {
- // added @ by "Michael William Miller" <mille562@pilot.msu.edu>
- if ($this->fetchMode != MYSQL_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;
- return @mysql_data_seek($this->_queryID,$row);
- }
-
- function moveNext()
- {
- if (@$this->fields = mysql_fetch_array($this->_queryID,$this->fetchMode)) {
- $this->_updatefields();
- $this->_currentRow += 1;
- return true;
- }
- if (!$this->EOF) {
- $this->_currentRow += 1;
- $this->EOF = true;
- }
- return false;
- }
-
- function _fetch()
- {
- $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode);
- $this->_updatefields();
- return is_array($this->fields);
- }
-
- function _close() {
- @mysql_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':
- case 'BINARY':
- 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';
-
- default: return ADODB_DEFAULT_METATYPE;
- }
- }
-
-}
-
-/**
- * Class ADORecordSet_ext_mysql
- */
-class ADORecordSet_ext_mysql extends ADORecordSet_mysql {
-
- function moveNext()
- {
- return @adodb_movenext($this);
- }
-}
-
-}
diff --git a/drivers/adodb-mysqli.inc.php b/drivers/adodb-mysqli.inc.php
index 160f5fa..5271db1 100644
--- a/drivers/adodb-mysqli.inc.php
+++ b/drivers/adodb-mysqli.inc.php
@@ -75,12 +75,17 @@ class ADODB_mysqli extends ADOConnection {
var $ssl_capath = null;
var $ssl_cipher = null;
+ /** @var mysqli Identifier for the native database connection */
+ var $_connectionID = false;
+
/**
* Tells the insert_id method how to obtain the last value, depending on whether
* we are using a stored procedure or not
*/
private $usePreparedStatement = false;
private $useLastInsertStatement = false;
+ private $usingBoundVariables = false;
+ private $statementAffectedRows = -1;
/**
* @var bool True if the last executed statement is a SELECT {@see _query()}
@@ -123,13 +128,12 @@ class ADODB_mysqli extends ADOConnection {
/**
* Adds a parameter to the connection string.
*
- * Parameter must be one of the the constants listed in mysqli_options().
+ * Parameter must be one of the constants listed in mysqli_options().
* @see https://www.php.net/manual/en/mysqli.options.php
*
- * @param int $parameter The parameter to set
- * @param string $value The value of the parameter
+ * @param int $parameter The parameter to set
+ * @param string $value The value of the parameter
*
- * @example, for mssqlnative driver ('CharacterSet','UTF-8')
* @return bool
*/
public function setConnectionParameter($parameter, $value) {
@@ -137,8 +141,7 @@ class ADODB_mysqli extends ADOConnection {
$this->outp_throw("Invalid connection parameter '$parameter'", __METHOD__);
return false;
}
- $this->connectionParameters[$parameter] = $value;
- return true;
+ return parent::setConnectionParameter($parameter, $value);
}
/**
@@ -164,6 +167,14 @@ class ADODB_mysqli extends ADOConnection {
if(!extension_loaded("mysqli")) {
return null;
}
+ // Check for a function that only exists in mysqlnd
+ if (!function_exists('mysqli_stmt_get_result')) {
+ // @TODO This will be treated as if the mysqli extension were not available
+ // This could be misleading, so we output an additional error message.
+ // We should probably throw a specific exception instead.
+ $this->outp("MySQL Native Driver (msqlnd) required");
+ return null;
+ }
$this->_connectionID = @mysqli_init();
if (is_null($this->_connectionID)) {
@@ -184,13 +195,15 @@ class ADODB_mysqli extends ADOConnection {
}
// Now merge in the standard connection parameters setting
- foreach ($this->connectionParameters as $parameter => $value) {
- // Make sure parameter is numeric before calling mysqli_options()
- // that to avoid Warning (or TypeError exception on PHP 8).
- if (!is_numeric($parameter)
- || !mysqli_options($this->_connectionID, $parameter, $value)
- ) {
- $this->outp_throw("Invalid connection parameter '$parameter'", __METHOD__);
+ foreach ($this->connectionParameters as $options) {
+ foreach ($options as $parameter => $value) {
+ // Make sure parameter is numeric before calling mysqli_options()
+ // to avoid Warning (or TypeError exception on PHP 8).
+ if (!is_numeric($parameter)
+ || !mysqli_options($this->_connectionID, $parameter, $value)
+ ) {
+ $this->outp_throw("Invalid connection parameter '$parameter'", __METHOD__);
+ }
}
}
@@ -202,9 +215,12 @@ class ADODB_mysqli extends ADOConnection {
// SSL Connections for MySQLI
if ($this->ssl_key || $this->ssl_cert || $this->ssl_ca || $this->ssl_capath || $this->ssl_cipher) {
mysqli_ssl_set($this->_connectionID, $this->ssl_key, $this->ssl_cert, $this->ssl_ca, $this->ssl_capath, $this->ssl_cipher);
+ $this->socket = MYSQLI_CLIENT_SSL;
+ $this->clientFlags = MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT;
}
#if (!empty($this->port)) $argHostname .= ":".$this->port;
+ /** @noinspection PhpCastIsUnnecessaryInspection */
$ok = @mysqli_real_connect($this->_connectionID,
$argHostname,
$argUsername,
@@ -252,15 +268,15 @@ class ADODB_mysqli extends ADOConnection {
* @param string|null $argHostname The host to connect to.
* @param string|null $argUsername The username to connect as.
* @param string|null $argPassword The password to connect with.
- * @param string|null $argDatabasename The name of the database to start in when connected.
+ * @param string|null $argDatabaseName The name of the database to start in when connected.
*
* @return bool|null True if connected successfully, false if connection failed, or null if the mysqli extension
* isn't currently loaded.
*/
- function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
{
$this->forceNewConnect = true;
- return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
+ return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
}
/**
@@ -376,17 +392,17 @@ class ADODB_mysqli extends ADOConnection {
*
* @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:rowlock
*
- * @param string $tables The table(s) to lock rows for.
+ * @param string $table The table(s) to lock rows for.
* @param string $where (Optional) The WHERE clause to use to determine which rows to lock.
* @param string $col (Optional) The columns to select.
*
* @return bool True if the locking SQL statement executed successfully, otherwise false.
*/
- function RowLock($tables, $where = '', $col = '1 as adodbignore')
+ function RowLock($table, $where = '', $col = '1 as adodbignore')
{
if ($this->transCnt==0) $this->beginTrans();
if ($where) $where = ' where '.$where;
- $rs = $this->execute("select $col from $tables $where for update");
+ $rs = $this->execute("select $col from $table $where for update");
return !empty($rs);
}
@@ -457,10 +473,17 @@ class ADODB_mysqli extends ADOConnection {
// the rowcount, but ADOdb does not do that.
return false;
}
-
- $result = @mysqli_affected_rows($this->_connectionID);
- if ($result == -1) {
- if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : " . $this->errorMsg());
+ else if ($this->statementAffectedRows >= 0)
+ {
+ $result = $this->statementAffectedRows;
+ $this->statementAffectedRows = -1;
+ }
+ else
+ {
+ $result = @mysqli_affected_rows($this->_connectionID);
+ if ($result == -1) {
+ if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : " . $this->errorMsg());
+ }
}
return $result;
}
@@ -566,7 +589,6 @@ class ADODB_mysqli extends ADOConnection {
// save old fetch mode
global $ADODB_FETCH_MODE;
- $false = false;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($this->fetchMode !== FALSE) {
@@ -574,7 +596,7 @@ class ADODB_mysqli extends ADOConnection {
}
// get index details
- $rs = $this->execute(sprintf('SHOW INDEXES FROM %s',$table));
+ $rs = $this->Execute(sprintf('SHOW INDEXES FROM `%s`',$table));
// restore fetchmode
if (isset($savem)) {
@@ -583,7 +605,7 @@ class ADODB_mysqli extends ADOConnection {
$ADODB_FETCH_MODE = $save;
if (!is_object($rs)) {
- return $false;
+ return false;
}
$indexes = array ();
@@ -621,7 +643,7 @@ class ADODB_mysqli extends ADOConnection {
* @param string $fmt The date format to use.
* @param string|bool $col (Optional) The table column to date format, or if false, use NOW().
*
- * @return bool|string The SQL DATE_FORMAT() string, or false if the provided date format was empty.
+ * @return string The SQL DATE_FORMAT() string, or false if the provided date format was empty.
*/
function SQLDate($fmt, $col = false)
{
@@ -740,13 +762,13 @@ class ADODB_mysqli extends ADOConnection {
/**
* Returns information about stored procedures and stored functions.
*
- * @param string|bool $NamePattern (Optional) Only look for procedures/functions with a name matching this pattern.
+ * @param string|bool $procedureNamePattern (Optional) Only look for procedures/functions with a name matching this pattern.
* @param null $catalog (Optional) Unused.
* @param null $schemaPattern (Optional) Unused.
*
* @return array
*/
- function MetaProcedures($NamePattern = false, $catalog = null, $schemaPattern = null)
+ function MetaProcedures($procedureNamePattern = false, $catalog = null, $schemaPattern = null)
{
// save old fetch mode
global $ADODB_FETCH_MODE;
@@ -763,8 +785,8 @@ class ADODB_mysqli extends ADOConnection {
// get index details
$likepattern = '';
- if ($NamePattern) {
- $likepattern = " LIKE '".$NamePattern."'";
+ if ($procedureNamePattern) {
+ $likepattern = " LIKE '".$procedureNamePattern."'";
}
$rs = $this->execute('SHOW PROCEDURE STATUS'.$likepattern);
if (is_object($rs)) {
@@ -840,9 +862,8 @@ class ADODB_mysqli extends ADOConnection {
*
* @return array|bool An array of foreign keys, or false no foreign keys could be found.
*/
- function MetaForeignKeys($table, $owner = false, $upper = false, $associative = false)
+ public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false)
{
-
global $ADODB_FETCH_MODE;
if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC
@@ -856,7 +877,7 @@ class ADODB_mysqli extends ADOConnection {
$table = "$owner.$table";
}
- $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table));
+ $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE `%s`', $table));
$this->setFetchMode($savem);
@@ -919,7 +940,7 @@ class ADODB_mysqli extends ADOConnection {
$SQL = "SELECT column_name, column_type
FROM information_schema.columns
- WHERE table_schema='{$this->databaseName}'
+ WHERE table_schema='{$this->database}'
AND table_name='$table'";
$schemaArray = $this->getAssoc($SQL);
@@ -935,7 +956,6 @@ class ADODB_mysqli extends ADOConnection {
while (!$rs->EOF) {
$fld = new ADOFieldObject();
$fld->name = $rs->fields[0];
- $type = $rs->fields[1];
/*
* Type from information_schema returns
@@ -1005,7 +1025,6 @@ class ADODB_mysqli extends ADOConnection {
{
// $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID);
$this->database = $dbName;
- $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
if ($this->_connectionID) {
$result = @mysqli_select_db($this->_connectionID, $dbName);
@@ -1027,7 +1046,7 @@ class ADODB_mysqli extends ADOConnection {
* @param int $nrows (Optional) The limit for the number of records you want returned. By default, all results.
* @param int $offset (Optional) The offset to use when selecting the results. By default, no offset.
* @param array|bool $inputarr (Optional) Any parameter values required by the SQL statement, or false if none.
- * @param int $secs (Optional) If greater than 0, perform a cached execute. By default, normal execution.
+ * @param int $secs2cache (Optional) If greater than 0, perform a cached execute. By default, normal execution.
*
* @return ADORecordSet|false The query results, or false if the query failed to execute.
*/
@@ -1035,15 +1054,15 @@ class ADODB_mysqli extends ADOConnection {
$nrows = -1,
$offset = -1,
$inputarr = false,
- $secs = 0)
+ $secs2cache = 0)
{
$nrows = (int) $nrows;
$offset = (int) $offset;
$offsetStr = ($offset >= 0) ? "$offset," : '';
if ($nrows < 0) $nrows = '18446744073709551615';
- if ($secs)
- $rs = $this->cacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr );
+ if ($secs2cache)
+ $rs = $this->cacheExecute($secs2cache, $sql . " LIMIT $offsetStr$nrows" , $inputarr );
else
$rs = $this->execute($sql . " LIMIT $offsetStr$nrows" , $inputarr );
@@ -1052,6 +1071,7 @@ class ADODB_mysqli extends ADOConnection {
/**
* Prepares an SQL statement and returns a handle to use.
+ * This is not used by bound parameters anymore
*
* @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:prepare
* @todo update this function to handle prepared statements correctly
@@ -1079,15 +1099,102 @@ class ADODB_mysqli extends ADOConnection {
return array($sql,$stmt);
}
+ public function execute($sql, $inputarr = false)
+ {
+ if ($this->fnExecute) {
+ $fn = $this->fnExecute;
+ $ret = $fn($this, $sql, $inputarr);
+ if (isset($ret)) {
+ return $ret;
+ }
+ }
+
+ if ($inputarr === false || $inputarr === []) {
+ return $this->_execute($sql);
+ }
+
+ if (!is_array($inputarr)) {
+ $inputarr = array($inputarr);
+ }
+ else {
+ //remove alphanumeric placeholders
+ $inputarr = array_values($inputarr);
+ }
+
+ if (!is_array($sql)) {
+ // Check if we are bulkbinding. If so, $inputarr is a 2d array,
+ // and we make a gross assumption that all rows have the same number
+ // of columns of the same type, and use the elements of the first row
+ // to determine the MySQL bind param types.
+ if (is_array($inputarr[0])) {
+ if (!$this->bulkBind) {
+ $this->outp_throw(
+ "2D Array of values sent to execute and 'ADOdb_mysqli::bulkBind' not set",
+ 'Execute'
+ );
+ return false;
+ }
+
+ $bulkTypeArray = [];
+ foreach ($inputarr as $v) {
+ if (is_string($this->bulkBind)) {
+ $typeArray = array_merge((array)$this->bulkBind, $v);
+ } else {
+ $typeArray = $this->getBindParamWithType($v);
+ }
+ $bulkTypeArray[] = $typeArray;
+ }
+ $this->bulkBind = false;
+ $ret = $this->_execute($sql, $bulkTypeArray);
+ } else {
+ $typeArray = $this->getBindParamWithType($inputarr);
+ $ret = $this->_execute($sql, $typeArray);
+ }
+ } else {
+ $ret = $this->_execute($sql, $inputarr);
+ }
+ return $ret;
+ }
+
/**
- * Return the query id.
+ * Inserts the bind param type string at the front of the parameter array.
*
- * @param string|array $sql
- * @param array $inputarr
+ * @see https://www.php.net/manual/en/mysqli-stmt.bind-param.php
*
- * @return bool|mysqli_result
+ * @param array $inputArr
+ * @return array
*/
- function _query($sql, $inputarr)
+ private function getBindParamWithType($inputArr): array
+ {
+ $typeString = '';
+ foreach ($inputArr as $v) {
+ if (is_integer($v) || is_bool($v)) {
+ $typeString .= 'i';
+ } elseif (is_float($v)) {
+ $typeString .= 'd';
+ } elseif (is_object($v)) {
+ // Assume a blob
+ $typeString .= 'b';
+ } else {
+ $typeString .= 's';
+ }
+ }
+
+ // Place the field type list at the front of the parameter array.
+ // This is the mysql specific format
+ array_unshift($inputArr, $typeString);
+ return $inputArr;
+ }
+
+ /**
+ * Execute a query.
+ *
+ * @param string|array $sql Query to execute.
+ * @param array $inputarr An optional array of parameters.
+ *
+ * @return mysqli_result|bool
+ */
+ function _query($sql, $inputarr = false)
{
global $ADODB_COUNTRECS;
// Move to the next recordset, or return false if there is none. In a stored proc
@@ -1097,6 +1204,14 @@ class ADODB_mysqli extends ADOConnection {
// Commented out for reasons of performance. You should retrieve every recordset yourself.
// if (!mysqli_next_result($this->connection->_connectionID)) return false;
+ // When SQL is empty, mysqli_query() throws exception on PHP 8 (#945)
+ if (!$sql) {
+ if ($this->debug) {
+ ADOConnection::outp("Empty query");
+ }
+ return false;
+ }
+
if (is_array($sql)) {
// Prepare() not supported because mysqli_stmt_execute does not return a recordset, but
@@ -1104,7 +1219,7 @@ class ADODB_mysqli extends ADOConnection {
$stmt = $sql[1];
$a = '';
- foreach($inputarr as $k => $v) {
+ foreach($inputarr as $v) {
if (is_string($v)) $a .= 's';
else if (is_integer($v)) $a .= 'i';
else $a .= 'd';
@@ -1118,8 +1233,109 @@ class ADODB_mysqli extends ADOConnection {
$fnarr = array_merge( array($stmt,$a) , $inputarr);
call_user_func_array('mysqli_stmt_bind_param',$fnarr);
- $ret = mysqli_stmt_execute($stmt);
- return $ret;
+ return mysqli_stmt_execute($stmt);
+ }
+ else if (is_string($sql) && is_array($inputarr))
+ {
+
+ /*
+ * This is support for true prepared queries
+ * with bound parameters
+ *
+ * set prepared statement flags
+ */
+ $this->usePreparedStatement = true;
+ $this->usingBoundVariables = true;
+
+ $bulkBindArray = array();
+ if (is_array($inputarr[0]))
+ {
+ $bulkBindArray = $inputarr;
+ $inputArrayCount = count($inputarr[0]) - 1;
+ }
+ else
+ {
+ $bulkBindArray[] = $inputarr;
+ $inputArrayCount = count($inputarr) - 1;
+ }
+
+
+ /*
+ * Prepare the statement with the placeholders,
+ * prepare will fail if the statement is invalid
+ * so we trap and error if necessary. Note that we
+ * are calling MySQL prepare here, not ADOdb
+ */
+ $stmt = $this->_connectionID->prepare($sql);
+ if ($stmt === false)
+ {
+ $this->outp_throw(
+ "SQL Statement failed on preparation: " . htmlspecialchars($sql) . "'",
+ 'Execute'
+ );
+ return false;
+ }
+ /*
+ * Make sure the number of parameters provided in the input
+ * array matches what the query expects. We must discount
+ * the first parameter which contains the data types in
+ * our inbound parameters
+ */
+ $nparams = $stmt->param_count;
+
+ if ($nparams != $inputArrayCount)
+ {
+
+ $this->outp_throw(
+ "Input array has " . $inputArrayCount .
+ " params, does not match query: '" . htmlspecialchars($sql) . "'",
+ 'Execute'
+ );
+ return false;
+ }
+
+ foreach ($bulkBindArray as $inputarr)
+ {
+ /*
+ * Must pass references into call_user_func_array
+ */
+ $paramsByReference = array();
+ foreach($inputarr as $key => $value) {
+ /** @noinspection PhpArrayAccessCanBeReplacedWithForeachValueInspection */
+ $paramsByReference[$key] = &$inputarr[$key];
+ }
+
+ /*
+ * Bind the params
+ */
+ call_user_func_array(array($stmt, 'bind_param'), $paramsByReference);
+
+ /*
+ * Execute
+ */
+
+ $ret = mysqli_stmt_execute($stmt);
+
+ // Store error code and message
+ $this->_errorCode = $stmt->errno;
+ $this->_errorMsg = $stmt->error;
+
+ /*
+ * Did we throw an error?
+ */
+ if ($ret == false)
+ return false;
+ }
+
+ // Tells affected_rows to be compliant
+ $this->isSelectStatement = $stmt->affected_rows == -1;
+ if (!$this->isSelectStatement) {
+ $this->statementAffectedRows = $stmt->affected_rows;
+ return true;
+ }
+
+ // Turn the statement into a result set and return it
+ return $stmt->get_result();
}
else
{
@@ -1129,6 +1345,10 @@ class ADODB_mysqli extends ADOConnection {
*/
$this->usePreparedStatement = false;
$this->useLastInsertStatement = false;
+
+ // Reset error code and message
+ $this->_errorCode = 0;
+ $this->_errorMsg = '';
}
/*
@@ -1144,7 +1364,7 @@ class ADODB_mysqli extends ADOConnection {
$rs = mysqli_multi_query($this->_connectionID, $sql.';');
if ($rs) {
$rs = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->_connectionID ) : @mysqli_use_result( $this->_connectionID );
- return $rs ? $rs : true; // mysqli_more_results( $this->_connectionID )
+ return $rs ?: true; // mysqli_more_results( $this->_connectionID )
}
} else {
$rs = mysqli_query($this->_connectionID, $sql, $ADODB_COUNTRECS ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT);
@@ -1170,10 +1390,13 @@ class ADODB_mysqli extends ADOConnection {
*/
function ErrorMsg()
{
- if (empty($this->_connectionID))
- $this->_errorMsg = @mysqli_connect_error();
- else
- $this->_errorMsg = @mysqli_error($this->_connectionID);
+ if (!$this->_errorMsg) {
+ if (empty($this->_connectionID)) {
+ $this->_errorMsg = mysqli_connect_error();
+ } else {
+ $this->_errorMsg = $this->_connectionID->error ?? $this->_connectionID->connect_error;
+ }
+ }
return $this->_errorMsg;
}
@@ -1184,10 +1407,14 @@ class ADODB_mysqli extends ADOConnection {
*/
function ErrorNo()
{
- if (empty($this->_connectionID))
- return @mysqli_connect_errno();
- else
- return @mysqli_errno($this->_connectionID);
+ if (!$this->_errorCode) {
+ if (empty($this->_connectionID)) {
+ $this->_errorCode = mysqli_connect_errno();
+ } else {
+ $this->_errorCode = $this->_connectionID->errno ?? $this->_connectionID->connect_errno;
+ }
+ }
+ return $this->_errorCode;
}
/**
@@ -1237,6 +1464,9 @@ class ADODB_mysqli extends ADOConnection {
return $this->charSet ?: false;
}
+ /**
+ * @deprecated 5.21.0 Use {@see setConnectionParameter()} instead
+ */
function setCharSet($charset)
{
if (!$this->_connectionID || !method_exists($this->_connectionID,'set_charset')) {
@@ -1262,6 +1492,12 @@ class ADORecordSet_mysqli extends ADORecordSet{
var $databaseType = "mysqli";
var $canSeek = true;
+ /** @var ADODB_mysqli The parent connection */
+ var $connection = false;
+
+ /** @var mysqli_result result link identifier */
+ var $_queryID;
+
function __construct($queryID, $mode = false)
{
if ($mode === false) {
@@ -1368,8 +1604,7 @@ class ADORecordSet_mysqli extends ADORecordSet{
if ($this->fetchMode == MYSQLI_ASSOC && $upper == ADODB_ASSOC_CASE_LOWER) {
return $this->fields;
}
- $row = ADORecordSet::getRowAssoc($upper);
- return $row;
+ return ADORecordSet::getRowAssoc($upper);
}
/**
@@ -1524,6 +1759,7 @@ class ADORecordSet_mysqli extends ADORecordSet{
12 = MYSQLI_TYPE_DATETIME
13 = MYSQLI_TYPE_YEAR
14 = MYSQLI_TYPE_NEWDATE
+245 = MYSQLI_TYPE_JSON
247 = MYSQLI_TYPE_ENUM
248 = MYSQLI_TYPE_SET
249 = MYSQLI_TYPE_TINY_BLOB
@@ -1544,7 +1780,7 @@ class ADORecordSet_mysqli extends ADORecordSet{
*
* @return string The MetaType
*/
- function MetaType($t, $len = -1, $fieldobj = false)
+ function metaType($t, $len = -1, $fieldobj = false)
{
if (is_object($t)) {
$fieldobj = $t;
@@ -1552,8 +1788,16 @@ class ADORecordSet_mysqli extends ADORecordSet{
$len = $fieldobj->max_length;
}
+ $t = strtoupper($t);
+ /*
+ * Add support for custom actual types. We do this
+ * first, that allows us to override existing types
+ */
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
$len = -1; // mysql max_length is not accurate
- switch (strtoupper($t)) {
+ switch ($t) {
case 'STRING':
case 'CHAR':
case 'VARCHAR':
@@ -1631,6 +1875,8 @@ class ADORecordSet_mysqli extends ADORecordSet{
case 'DEC':
case 'FIXED':
default:
+
+
//if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>";
return 'N';
}
@@ -1661,8 +1907,14 @@ class ADORecordSet_array_mysqli extends ADORecordSet_array
$len = $fieldobj->max_length;
}
+ $t = strtoupper($t);
+
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
$len = -1; // mysql max_length is not accurate
- switch (strtoupper($t)) {
+
+ switch ($t) {
case 'STRING':
case 'CHAR':
case 'VARCHAR':
diff --git a/drivers/adodb-mysqlpo.inc.php b/drivers/adodb-mysqlpo.inc.php
deleted file mode 100644
index 8aa7779..0000000
--- a/drivers/adodb-mysqlpo.inc.php
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-/**
- * Portable MySQL driver
- *
- * @deprecated
- *
- * Extends the deprecated mysql driver, and was originally designed to be a
- * portable driver in the same manner as oci8po and mssqlpo. Its functionality
- * is exactly duplicated in the mysqlt driver, which is itself deprecated.
- * This driver will be removed in ADOdb version 6.0.0.
- *
- * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
- *
- * @package ADOdb
- * @link https://adodb.org Project's web site and documentation
- * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
- *
- * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
- * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
- * any later version. This means you can use it in proprietary products.
- * See the LICENSE.md file distributed with this source code for details.
- * @license BSD-3-Clause
- * @license LGPL-2.1-or-later
- *
- * @copyright 2000-2013 John Lim
- * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
- */
-
-// security - hide paths
-if (!defined('ADODB_DIR')) die();
-
-include_once(ADODB_DIR."/drivers/adodb-mysql.inc.php");
-
-
-class ADODB_mysqlt extends ADODB_mysql {
- var $databaseType = 'mysqlt';
- var $ansiOuter = true; // for Version 3.23.17 or later
- var $hasTransactions = true;
- var $autoRollback = true; // apparently mysql does not autorollback properly
-
- 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;
- }
-
- function RowLock($tables,$where='',$col='1 as adodbignore')
- {
- if ($this->transCnt==0) $this->BeginTrans();
- if ($where) $where = ' where '.$where;
- $rs = $this->Execute("select $col from $tables $where for update");
- return !empty($rs);
- }
-
-}
-
-class ADORecordSet_mysqlt extends ADORecordSet_mysql{
- var $databaseType = "mysqlt";
-
- function __construct($queryID,$mode=false)
- {
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
-
- switch ($mode)
- {
- case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
- case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
-
- case ADODB_FETCH_DEFAULT:
- case ADODB_FETCH_BOTH:
- default: $this->fetchMode = MYSQL_BOTH; break;
- }
-
- $this->adodbFetchMode = $mode;
- parent::__construct($queryID);
- }
-
- function MoveNext()
- {
- if (@$this->fields = mysql_fetch_array($this->_queryID,$this->fetchMode)) {
- $this->_currentRow += 1;
- return true;
- }
- if (!$this->EOF) {
- $this->_currentRow += 1;
- $this->EOF = true;
- }
- return false;
- }
-}
-
-class ADORecordSet_ext_mysqlt extends ADORecordSet_mysqlt {
-
- function MoveNext()
- {
- return adodb_movenext($this);
- }
-}
diff --git a/drivers/adodb-mysqlt.inc.php b/drivers/adodb-mysqlt.inc.php
deleted file mode 100644
index cccd93f..0000000
--- a/drivers/adodb-mysqlt.inc.php
+++ /dev/null
@@ -1,141 +0,0 @@
-<?php
-/**
- * MySQL driver in transactional mode
- *
- * @deprecated
- *
- * This driver only supports the original MySQL driver in transactional mode. It
- * is deprecated in PHP version 5.5 and removed in PHP version 7. It is deprecated
- * as of ADOdb version 5.20.0. Use the mysqli driver instead, which supports both
- * transactional and non-transactional updates
- *
- * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
- *
- * @package ADOdb
- * @link https://adodb.org Project's web site and documentation
- * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
- *
- * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
- * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
- * any later version. This means you can use it in proprietary products.
- * See the LICENSE.md file distributed with this source code for details.
- * @license BSD-3-Clause
- * @license LGPL-2.1-or-later
- *
- * @copyright 2000-2013 John Lim
- * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
- */
-
-// security - hide paths
-if (!defined('ADODB_DIR')) die();
-
-include_once(ADODB_DIR."/drivers/adodb-mysql.inc.php");
-
-
-class ADODB_mysqlt extends ADODB_mysql {
- var $databaseType = 'mysqlt';
- var $ansiOuter = true; // for Version 3.23.17 or later
- var $hasTransactions = true;
- var $autoRollback = true; // apparently mysql does not autorollback properly
-
- /* set transaction mode
-
- SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL
-{ READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
-
- */
- function SetTransactionMode( $transaction_mode )
- {
- $this->_transmode = $transaction_mode;
- if (empty($transaction_mode)) {
- $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ');
- return;
- }
- if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
- $this->Execute("SET SESSION TRANSACTION ".$transaction_mode);
- }
-
- 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;
- $ok = $this->Execute('COMMIT');
- $this->Execute('SET AUTOCOMMIT=1');
- return $ok ? true : false;
- }
-
- function RollbackTrans()
- {
- if ($this->transOff) return true;
- if ($this->transCnt) $this->transCnt -= 1;
- $ok = $this->Execute('ROLLBACK');
- $this->Execute('SET AUTOCOMMIT=1');
- return $ok ? true : false;
- }
-
- function RowLock($tables,$where='',$col='1 as adodbignore')
- {
- if ($this->transCnt==0) $this->BeginTrans();
- if ($where) $where = ' where '.$where;
- $rs = $this->Execute("select $col from $tables $where for update");
- return !empty($rs);
- }
-
-}
-
-class ADORecordSet_mysqlt extends ADORecordSet_mysql{
- var $databaseType = "mysqlt";
-
- function __construct($queryID,$mode=false)
- {
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
-
- switch ($mode)
- {
- case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
- case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
-
- case ADODB_FETCH_DEFAULT:
- case ADODB_FETCH_BOTH:
- default: $this->fetchMode = MYSQL_BOTH; break;
- }
-
- $this->adodbFetchMode = $mode;
- parent::__construct($queryID);
- }
-
- function MoveNext()
- {
- if (@$this->fields = mysql_fetch_array($this->_queryID,$this->fetchMode)) {
- $this->_currentRow += 1;
- return true;
- }
- if (!$this->EOF) {
- $this->_currentRow += 1;
- $this->EOF = true;
- }
- return false;
- }
-}
-
-class ADORecordSet_ext_mysqlt extends ADORecordSet_mysqlt {
-
- function MoveNext()
- {
- return adodb_movenext($this);
- }
-}
diff --git a/drivers/adodb-oci8.inc.php b/drivers/adodb-oci8.inc.php
index e541b6b..f361d68 100644
--- a/drivers/adodb-oci8.inc.php
+++ b/drivers/adodb-oci8.inc.php
@@ -321,10 +321,6 @@ END;
protected function _insertID($table = '', $column = '')
{
-
- if (!$this->seqField)
- return false;
-
if ($this->schema)
{
$t = strpos($table,'.');
@@ -791,6 +787,11 @@ END;
$nrows += $offset;
}
$sql = "select * from (".$sql.") where rownum <= :adodb_offset";
+
+ // If non-bound statement, $inputarr is false
+ if (!$inputarr) {
+ $inputarr = array();
+ }
$inputarr['adodb_offset'] = $nrows;
$nrows = -1;
}
@@ -970,13 +971,6 @@ END;
return $rez;
}
- /**
- * Execute SQL
- *
- * @param sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
- * @param [inputarr] holds the input data to bind to. Null elements will be set to null.
- * @return RecordSet or false
- */
function Execute($sql,$inputarr=false)
{
if ($this->fnExecute) {
@@ -1094,6 +1088,22 @@ END;
return array($sql,$stmt,0,$BINDNUM);
}
+ function releaseStatement(&$stmt)
+ {
+ if (is_array($stmt)
+ && isset($stmt[1])
+ && is_resource($stmt[1])
+ && oci_free_statement($stmt[1])
+ ) {
+ // Clearing the resource to avoid it being of type Unknown
+ $stmt[1] = null;
+ return true;
+ }
+
+ // Not a valid prepared statement
+ return false;
+ }
+
/*
Call an oracle stored procedure and returns a cursor variable as a recordset.
Concept by Robert Tuttle robert@ud.com
@@ -1127,10 +1137,11 @@ END;
} else
$hasref = false;
+ /** @var ADORecordset_oci8 $rs */
$rs = $this->Execute($stmt);
if ($rs) {
if ($rs->databaseType == 'array') {
- oci_free_cursor($stmt[4]);
+ oci_free_statement($stmt[4]);
}
elseif ($hasref) {
$rs->_refcursor = $stmt[4];
@@ -1241,12 +1252,12 @@ END;
* $db->Parameter($stmt,$group,'group');
* $db->Execute($stmt);
*
- * @param $stmt Statement returned by Prepare() or PrepareSP().
+ * @param $stmt Statement returned by {@see Prepare()} or {@see PrepareSP()}.
* @param $var PHP variable to bind to
* @param $name Name of stored procedure variable name to bind to.
- * @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
- * @param [$maxLen] Holds an maximum length of the variable.
- * @param [$type] The data type of $var. Legal values depend on driver.
+ * @param bool $isOutput Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
+ * @param int $maxLen Holds an maximum length of the variable.
+ * @param mixed $type The data type of $var. Legal values depend on driver.
*
* @link http://php.net/oci_bind_by_name
*/
@@ -1261,7 +1272,8 @@ END;
}
/**
- * returns query ID if successful, otherwise false
+ * Execute a query.
+ *
* this version supports:
*
* 1. $db->execute('select * from table');
@@ -1274,6 +1286,11 @@ END;
* 4. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
* $db->bind($stmt,1); $db->bind($stmt,2); $db->bind($stmt,3);
* $db->execute($stmt);
+ *
+ * @param string|array $sql Query to execute.
+ * @param array $inputarr An optional array of parameters.
+ *
+ * @return mixed|bool Query identifier or true if execution successful, false if failed.
*/
function _query($sql,$inputarr=false)
{
@@ -1484,16 +1501,17 @@ SELECT /*+ RULE */ distinct b.column_name
}
/**
- * returns assoc array where keys are tables, and values are foreign keys
+ * Returns a list of Foreign Keys associated with a specific table.
*
- * @param str $table
- * @param str $owner [optional][default=NULL]
- * @param bool $upper [optional][discarded]
- * @return mixed[] Array of foreign key information
+ * @param string $table
+ * @param string $owner
+ * @param bool $upper discarded
+ * @param bool $associative discarded
*
- * @link http://gis.mit.edu/classes/11.521/sqlnotes/referential_integrity.html
+ * @return string[]|false An array where keys are tables, and values are foreign keys;
+ * false if no foreign keys could be found.
*/
- function MetaForeignKeys($table, $owner=false, $upper=false)
+ public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false)
{
global $ADODB_FETCH_MODE;
@@ -1579,6 +1597,9 @@ class ADORecordset_oci8 extends ADORecordSet {
var $bind=false;
var $_fieldobjs;
+ /** @var resource Cursor reference */
+ var $_refcursor;
+
function __construct($queryID,$mode=false)
{
if ($mode === false) {
@@ -1810,7 +1831,12 @@ class ADORecordset_oci8 extends ADORecordSet {
$len = $fieldobj->max_length;
}
- switch (strtoupper($t)) {
+ $t = strtoupper($t);
+
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
+ switch ($t) {
case 'VARCHAR':
case 'VARCHAR2':
case 'CHAR':
diff --git a/drivers/adodb-oci8po.inc.php b/drivers/adodb-oci8po.inc.php
index 50630ca..71c203b 100644
--- a/drivers/adodb-oci8po.inc.php
+++ b/drivers/adodb-oci8po.inc.php
@@ -70,7 +70,16 @@ class ADODB_oci8po extends ADODB_oci8 {
return ADOConnection::SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
}
- // emulate handling of parameters ? ?, replacing with :bind0 :bind1
+ /**
+ * Execute a query.
+ *
+ * Emulate handling of parameters ? ?, replacing with :bind0 :bind1
+ *
+ * @param string|array $sql Query to execute.
+ * @param array $inputarr An optional array of parameters.
+ *
+ * @return mixed|bool Query identifier or true if execution successful, false if failed.
+ */
function _query($sql,$inputarr=false)
{
if (is_array($inputarr)) {
@@ -85,21 +94,21 @@ class ADODB_oci8po extends ADODB_oci8 {
}
return ADODB_oci8::_query($sql,$inputarr);
}
-
+
/**
* Replaces compatibility bind markers with oracle ones and returns a
* valid sql statement
*
* This replaces a regexp based section of code that has been subject
* to numerous tweaks, as more extreme test cases have appeared. This
- * is now done this like this to help maintainability and avoid the
+ * is now done this like this to help maintainability and avoid the
* need to rely on regexp experienced maintainers
*
* @param string $sql The sql statement
* @param string[] $inputarr The bind array
*
* @return string The modified statement
- */
+ */
private function extractBinds($sql,$inputarr)
{
$inString = false;
@@ -107,14 +116,13 @@ class ADODB_oci8po extends ADODB_oci8 {
$sqlLength = strlen($sql) - 1;
$newSql = '';
$bindCount = 0;
-
+
/*
* inputarr is the passed in bind list, which is associative, but
* we only want the keys here
*/
$inputKeys = array_keys($inputarr);
-
-
+
for ($i=0;$i<=$sqlLength;$i++)
{
/*
@@ -137,7 +145,7 @@ class ADODB_oci8po extends ADODB_oci8 {
* We found the end of the string
*/
$inString = false;
-
+
if ($escaped == 2)
$escaped = 0;
@@ -151,7 +159,7 @@ class ADODB_oci8po extends ADODB_oci8 {
* Add the current character the pile
*/
$newSql .= $c;
-
+
if ($escaped == 1)
/*
* We have just found an escape character, make sure we ignore the
@@ -159,9 +167,9 @@ class ADODB_oci8po extends ADODB_oci8 {
*/
$escaped = 2;
}
-
+
return $newSql;
-
+
}
}
@@ -192,14 +200,14 @@ class ADORecordset_oci8po extends ADORecordset_oci8 {
{
$fld = new ADOFieldObject;
$fieldOffset += 1;
- $fld->name = OCIcolumnname($this->_queryID, $fieldOffset);
+ $fld->name = oci_field_name($this->_queryID, $fieldOffset);
if (ADODB_ASSOC_CASE == ADODB_ASSOC_CASE_LOWER) {
$fld->name = strtolower($fld->name);
}
- $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);
- $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);
+ $fld->type = oci_field_type($this->_queryID, $fieldOffset);
+ $fld->max_length = oci_field_size($this->_queryID, $fieldOffset);
if ($fld->type == 'NUMBER') {
- $sc = OCIColumnScale($this->_queryID, $fieldOffset);
+ $sc = oci_field_scale($this->_queryID, $fieldOffset);
if ($sc == 0) {
$fld->type = 'INT';
}
@@ -231,7 +239,6 @@ class ADORecordset_oci8po extends ADORecordset_oci8 {
return false;
}
- /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */
function GetArrayLimit($nrows,$offset=-1)
{
if ($offset <= 0) {
@@ -239,7 +246,7 @@ class ADORecordset_oci8po extends ADORecordset_oci8 {
return $arr;
}
for ($i=1; $i < $offset; $i++)
- if (!@OCIFetch($this->_queryID)) {
+ if (!@oci_fetch($this->_queryID)) {
$arr = array();
return $arr;
}
diff --git a/drivers/adodb-odbc.inc.php b/drivers/adodb-odbc.inc.php
index a9705e2..56db8b0 100644
--- a/drivers/adodb-odbc.inc.php
+++ b/drivers/adodb-odbc.inc.php
@@ -26,7 +26,7 @@ if (!defined('ADODB_DIR')) die();
/*
* These constants are used to set define MetaColumns() method's behavior.
- * - METACOLUMNS_RETURNS_ACTUAL makes the driver return the actual type,
+ * - METACOLUMNS_RETURNS_ACTUAL makes the driver return the actual type,
* like all other drivers do (default)
* - METACOLUMNS_RETURNS_META is provided for legacy compatibility (makes
* driver behave as it did prior to v5.21)
@@ -35,7 +35,7 @@ if (!defined('ADODB_DIR')) die();
*/
DEFINE('METACOLUMNS_RETURNS_ACTUAL', 0);
DEFINE('METACOLUMNS_RETURNS_META', 1);
-
+
/*--------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------*/
@@ -57,7 +57,7 @@ class ADODB_odbc extends ADOConnection {
var $_autocommit = true;
var $_lastAffectedRows = 0;
var $uCaseTables = true; // for meta* functions, uppercase table names
-
+
/*
* Tells the metaColumns feature whether to return actual or meta type
*/
@@ -81,7 +81,9 @@ class ADODB_odbc extends ADOConnection {
if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword);
else $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword,$this->curmode);
$this->_errorMsg = $this->getChangedErrorMsg($last_php_error);
- if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
+ if ($this->connectStmt) {
+ $this->Execute($this->connectStmt);
+ }
return $this->_connectionID != false;
}
@@ -102,7 +104,9 @@ class ADODB_odbc extends ADOConnection {
$this->_errorMsg = $this->getChangedErrorMsg($last_php_error);
if ($this->_connectionID && $this->autoRollback) @odbc_rollback($this->_connectionID);
- if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
+ if ($this->connectStmt) {
+ $this->Execute($this->connectStmt);
+ }
return $this->_connectionID != false;
}
@@ -469,7 +473,7 @@ See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/od
$fld = new ADOFieldObject();
$fld->name = $rs->fields[3];
if ($this->metaColumnsReturnType == METACOLUMNS_RETURNS_META)
- /*
+ /*
* This is the broken, original value
*/
$fld->type = $this->ODBCTypes($rs->fields[4]);
@@ -514,7 +518,6 @@ See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/od
return array($sql,$stmt,false);
}
- /* returns queryID or false */
function _query($sql,$inputarr=false)
{
$last_php_error = $this->resetLastError();
diff --git a/drivers/adodb-odbc_mssql.inc.php b/drivers/adodb-odbc_mssql.inc.php
index 37185aa..1f8b98d 100644
--- a/drivers/adodb-odbc_mssql.inc.php
+++ b/drivers/adodb-odbc_mssql.inc.php
@@ -49,8 +49,12 @@ class ADODB_odbc_mssql extends ADODB_odbc {
var $ansiOuter = true; // for mssql7 or later
var $identitySQL = 'select SCOPE_IDENTITY()'; // 'select SCOPE_IDENTITY'; # for mssql 2000
var $hasInsertID = true;
- var $connectStmt = 'SET CONCAT_NULL_YIELDS_NULL OFF'; # When SET CONCAT_NULL_YIELDS_NULL is ON,
- # concatenating a null value with a string yields a NULL result
+ /**
+ * When SET CONCAT_NULL_YIELDS_NULL is ON, concatenating a null value with
+ * a string yields a NULL result.
+ * @var string SQL statement executed after successful connection.
+ */
+ public $connectStmt = 'SET CONCAT_NULL_YIELDS_NULL OFF'; #
// crashes php...
function ServerInfo()
@@ -81,8 +85,7 @@ class ADODB_odbc_mssql extends ADODB_odbc {
return $this->GetOne($this->identitySQL);
}
-
- function MetaForeignKeys($table, $owner=false, $upper=false)
+ public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false)
{
global $ADODB_FETCH_MODE;
diff --git a/drivers/adodb-odbc_mssql2012.inc.php b/drivers/adodb-odbc_mssql2012.inc.php
index 79fa325..86f7f8c 100644
--- a/drivers/adodb-odbc_mssql2012.inc.php
+++ b/drivers/adodb-odbc_mssql2012.inc.php
@@ -26,10 +26,11 @@ include_once(ADODB_DIR."/drivers/adodb-odbc_mssql.inc.php");
class ADODB_odbc_mssql2012 extends ADODB_odbc_mssql
{
- /*
- * Makes behavior similar to prior versions of SQL Server
- */
- var $connectStmt = 'SET CONCAT_NULL_YIELDS_NULL ON';
+ /**
+ * Makes behavior similar to prior versions of SQL Server.
+ * @var string SQL statement executed after successful connection.
+ */
+ public $connectStmt = 'SET CONCAT_NULL_YIELDS_NULL ON';
}
class ADORecordSet_odbc_mssql2012 extends ADORecordSet_odbc_mssql
diff --git a/drivers/adodb-odbtp.inc.php b/drivers/adodb-odbtp.inc.php
index bd167a1..e3f8148 100644
--- a/drivers/adodb-odbtp.inc.php
+++ b/drivers/adodb-odbtp.inc.php
@@ -46,6 +46,15 @@ class ADODB_odbtp extends ADOConnection{
var $_canPrepareSP = false;
var $_dontPoolDBC = true;
+ /** @var string DBMS name. */
+ var $odbc_name;
+
+ /** @var bool */
+ var $_canSelectDb = false;
+
+ /** @var mixed */
+ var $_lastAffectedRows;
+
function ServerInfo()
{
return array('description' => @odbtp_get_attr( ODB_ATTR_DBMSNAME, $this->_connectionID),
@@ -304,7 +313,6 @@ class ADODB_odbtp extends ADOConnection{
return false;
}
$this->database = $dbName;
- $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
return true;
}
@@ -393,7 +401,7 @@ class ADODB_odbtp extends ADOConnection{
return $arr2;
}
- function MetaForeignKeys($table, $owner='', $upper=false)
+ public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false)
{
global $ADODB_FETCH_MODE;
diff --git a/drivers/adodb-oracle.inc.php b/drivers/adodb-oracle.inc.php
index 1a2735b..dc0462f 100644
--- a/drivers/adodb-oracle.inc.php
+++ b/drivers/adodb-oracle.inc.php
@@ -181,7 +181,6 @@ class ADODB_oracle extends ADOConnection {
}
- // returns query ID if successful, otherwise false
function _query($sql,$inputarr=false)
{
// <G. Giunta 2003/03/03/> Reset error messages before executing
diff --git a/drivers/adodb-pdo.inc.php b/drivers/adodb-pdo.inc.php
index cf8e4e2..d3ce12d 100644
--- a/drivers/adodb-pdo.inc.php
+++ b/drivers/adodb-pdo.inc.php
@@ -82,10 +82,17 @@ class ADODB_pdo extends ADOConnection {
var $_errormsg = false;
var $_errorno = false;
- var $dsnType = '';
- var $stmt = false;
+ var $_stmt = false;
+
+ /** @var ADODB_pdo_base */
var $_driver;
+ /** @var PDO */
+ var $_connectionID;
+
+ /** @var PDOStatement */
+ var $_queryID;
+
/*
* Describe parameters passed directly to the PDO driver
*
@@ -231,11 +238,31 @@ class ADODB_pdo extends ADOConnection {
function Concat()
{
$args = func_get_args();
- if(method_exists($this->_driver, 'Concat')) {
+ if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'Concat')) {
return call_user_func_array(array($this->_driver, 'Concat'), $args);
}
- return call_user_func_array('parent::Concat', $args);
+ return call_user_func_array(parent::class . '::Concat', $args);
+ }
+
+ /**
+ * Triggers a driver-specific request for a bind parameter
+ *
+ * @param string $name
+ * @param string $type
+ *
+ * @return string
+ */
+ public function param($name,$type='C') {
+
+ $args = func_get_args();
+ if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'param')) {
+ // Return the driver specific entry, that mimics the native driver
+ return call_user_func_array(array($this->_driver, 'param'), $args);
+ }
+
+ // No driver specific method defined, use mysql format '?'
+ return call_user_func_array(parent::class . '::param', $args);
}
// returns true or false
@@ -294,18 +321,19 @@ class ADODB_pdo extends ADOConnection {
}
/**
- * Returns a list of Foreign Keys for a specified table.
+ * Returns a list of Foreign Keys associated with a specific table.
*
* @param string $table
- * @param bool $owner (optional) not used in this driver
+ * @param string $owner (optional) not used in this driver
* @param bool $upper
* @param bool $associative
*
- * @return string[] where keys are tables, and values are foreign keys
+ * @return string[]|false An array where keys are tables, and values are foreign keys;
+ * false if no foreign keys could be found.
*/
- public function metaForeignKeys($table, $owner=false, $upper=false,$associative=false) {
+ public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false) {
if (method_exists($this->_driver,'metaForeignKeys'))
- return $this->_driver->metaForeignKeys($table,$owner,$upper,$associative);
+ return $this->_driver->metaForeignKeys($table, $owner, $upper, $associative);
}
/**
@@ -421,14 +449,14 @@ class ADODB_pdo extends ADOConnection {
*/
function SetAutoCommit($auto_commit)
{
- if(method_exists($this->_driver, 'SetAutoCommit')) {
+ if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'SetAutoCommit')) {
$this->_driver->SetAutoCommit($auto_commit);
}
}
function SetTransactionMode($transaction_mode)
{
- if(method_exists($this->_driver, 'SetTransactionMode')) {
+ if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'SetTransactionMode')) {
return $this->_driver->SetTransactionMode($transaction_mode);
}
@@ -437,7 +465,7 @@ class ADODB_pdo extends ADOConnection {
function beginTrans()
{
- if(method_exists($this->_driver, 'beginTrans')) {
+ if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'beginTrans')) {
return $this->_driver->beginTrans();
}
@@ -457,7 +485,7 @@ class ADODB_pdo extends ADOConnection {
function commitTrans($ok=true)
{
- if(method_exists($this->_driver, 'commitTrans')) {
+ if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'commitTrans')) {
return $this->_driver->commitTrans($ok);
}
@@ -482,7 +510,7 @@ class ADODB_pdo extends ADOConnection {
function RollbackTrans()
{
- if(method_exists($this->_driver, 'RollbackTrans')) {
+ if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'RollbackTrans')) {
return $this->_driver->RollbackTrans();
}
@@ -524,7 +552,7 @@ class ADODB_pdo extends ADOConnection {
public function createSequence($seqname='adodbseq',$startID=1)
{
- if(method_exists($this->_driver, 'createSequence')) {
+ if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'createSequence')) {
return $this->_driver->createSequence($seqname, $startID);
}
@@ -533,7 +561,7 @@ class ADODB_pdo extends ADOConnection {
function DropSequence($seqname='adodbseq')
{
- if(method_exists($this->_driver, 'DropSequence')) {
+ if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'DropSequence')) {
return $this->_driver->DropSequence($seqname);
}
@@ -542,7 +570,7 @@ class ADODB_pdo extends ADOConnection {
function GenID($seqname='adodbseq',$startID=1)
{
- if(method_exists($this->_driver, 'GenID')) {
+ if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'GenID')) {
return $this->_driver->GenID($seqname, $startID);
}
@@ -550,7 +578,6 @@ class ADODB_pdo extends ADOConnection {
}
- /* returns queryID or false */
function _query($sql,$inputarr=false)
{
$ok = false;
@@ -565,6 +592,7 @@ class ADODB_pdo extends ADOConnection {
$this->_driver->debug = $this->debug;
}
if ($inputarr) {
+
/*
* inputarr must be numeric
*/
@@ -640,6 +668,9 @@ class ADODB_pdo extends ADOConnection {
}
+/**
+ * Base class for Database-specific PDO drivers.
+ */
class ADODB_pdo_base extends ADODB_pdo {
var $sysDate = "'?'";
@@ -758,6 +789,9 @@ class ADORecordSet_pdo extends ADORecordSet {
var $databaseType = "pdo";
var $dataProvider = "pdo";
+ /** @var PDOStatement */
+ var $_queryID;
+
function __construct($id,$mode=false)
{
if ($mode === false) {
@@ -898,4 +932,7 @@ class ADORecordSet_pdo extends ADORecordSet {
}
-class ADORecordSet_array_pdo extends ADORecordSet_array {}
+class ADORecordSet_array_pdo extends ADORecordSet_array {
+ /** @var PDOStatement */
+ var $_queryID;
+}
diff --git a/drivers/adodb-pdo_firebird.inc.php b/drivers/adodb-pdo_firebird.inc.php
index 0ee5e02..f8847c3 100644
--- a/drivers/adodb-pdo_firebird.inc.php
+++ b/drivers/adodb-pdo_firebird.inc.php
@@ -32,14 +32,6 @@ class ADODB_pdo_firebird extends ADODB_pdo
var $arrayClass = 'ADORecordSet_array_pdo_firebird';
- function _init($parentDriver)
- {
- $this->pdoDriver = $parentDriver;
- //$parentDriver->_bindInputArray = true;
- //$parentDriver->hasTransactions = false; // // should be set to false because of PDO SQLite driver not supporting changing autocommit mode
- //$parentDriver->hasInsertID = true;
- }
-
/**
* Gets the version iformation from the server
*
@@ -243,12 +235,6 @@ class ADODB_pdo_firebird extends ADODB_pdo
return $this->Execute("DROP SEQUENCE $seqname");
}
-
- public function _affectedrows()
- {
- return fbird_affected_rows($this->_transactionID ? $this->_transactionID : $this->_connectionID);
- }
-
public function genId($seqname = 'adodbseq', $startID = 1)
{
$getnext = ("SELECT Gen_ID($seqname,1) FROM RDB\$DATABASE");
diff --git a/drivers/adodb-pdo_mysql.inc.php b/drivers/adodb-pdo_mysql.inc.php
index c881245..a00c859 100644
--- a/drivers/adodb-pdo_mysql.inc.php
+++ b/drivers/adodb-pdo_mysql.inc.php
@@ -57,7 +57,7 @@ class ADODB_pdo_mysql extends ADODB_pdo {
return $date . ' + INTERVAL ' . $fraction . ' SECOND';
// return "from_unixtime(unix_timestamp($date)+$fraction)";
}
-
+
/**
* Get a list of indexes on the specified table.
*
@@ -266,7 +266,6 @@ class ADODB_pdo_mysql extends ADODB_pdo {
function SelectDB($dbName)
{
$this->database = $dbName;
- $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
$try = $this->Execute('use ' . $dbName);
return ($try !== false);
}
@@ -275,7 +274,7 @@ class ADODB_pdo_mysql extends ADODB_pdo {
function SelectLimit($sql, $nrows=-1, $offset=-1, $inputarr=false, $secs=0)
{
$nrows = (int) $nrows;
- $offset = (int) $offset;
+ $offset = (int) $offset;
$offsetStr =($offset>=0) ? "$offset," : '';
// jason judge, see PHPLens Issue No: 9220
if ($nrows < 0) {
diff --git a/drivers/adodb-pdo_oci.inc.php b/drivers/adodb-pdo_oci.inc.php
index 9a05ee6..20b47de 100644
--- a/drivers/adodb-pdo_oci.inc.php
+++ b/drivers/adodb-pdo_oci.inc.php
@@ -75,15 +75,15 @@ class ADODB_pdo_oci extends ADODB_pdo_base {
$retarr = array();
while (!$rs->EOF) { //print_r($rs->fields);
$fld = new ADOFieldObject();
- $fld->name = $rs->fields[0];
- $fld->type = $rs->fields[1];
- $fld->max_length = $rs->fields[2];
+ $fld->name = $rs->fields[0];
+ $fld->type = $rs->fields[1];
+ $fld->max_length = $rs->fields[2];
$fld->scale = $rs->fields[3];
if ($rs->fields[1] == 'NUMBER' && $rs->fields[3] == 0) {
$fld->type ='INT';
- $fld->max_length = $rs->fields[4];
- }
- $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0);
+ $fld->max_length = $rs->fields[4];
+ }
+ $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0);
$fld->binary = (strpos($fld->type,'BLOB') !== false);
$fld->default_value = $rs->fields[6];
@@ -98,12 +98,25 @@ class ADODB_pdo_oci extends ADODB_pdo_base {
return $retarr;
}
- /**
- * @param bool $auto_commit
- * @return void
- */
- function SetAutoCommit($auto_commit)
- {
- $this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT, $auto_commit);
- }
+ /**
+ * @param bool $auto_commit
+ * @return void
+ */
+ function SetAutoCommit($auto_commit)
+ {
+ $this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT, $auto_commit);
+ }
+
+ /**
+ * Returns a driver-specific format for a bind parameter
+ *
+ * @param string $name
+ * @param string $type (ignored in driver)
+ *
+ * @return string
+ */
+ public function param($name,$type='C')
+ {
+ return sprintf(':%s', $name);
+ }
}
diff --git a/drivers/adodb-pdo_pgsql.inc.php b/drivers/adodb-pdo_pgsql.inc.php
index 0212d4f..6c06ac1 100644
--- a/drivers/adodb-pdo_pgsql.inc.php
+++ b/drivers/adodb-pdo_pgsql.inc.php
@@ -21,11 +21,11 @@
class ADODB_pdo_pgsql extends ADODB_pdo {
var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1";
- var $metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%'
- and tablename not in ('sql_features', 'sql_implementation_info', 'sql_languages',
- 'sql_packages', 'sql_sizing', 'sql_sizing_profiles')
- union
- select viewname,'V' from pg_views where viewname not like 'pg\_%'";
+ var $metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%'
+ and tablename not in ('sql_features', 'sql_implementation_info', 'sql_languages',
+ 'sql_packages', 'sql_sizing', 'sql_sizing_profiles')
+ union
+ select viewname,'V' from pg_views where viewname not like 'pg\_%'";
//"select tablename from pg_tables where tablename not like 'pg_%' order by 1";
var $isoDates = true; // accepts dates in ISO format
var $sysDate = "CURRENT_DATE";
@@ -34,15 +34,15 @@ class ADODB_pdo_pgsql extends ADODB_pdo {
var $metaColumnsSQL = "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
WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) and a.attname not like '....%%'
-AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
+ AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
// used when schema defined
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 in ('r','v') 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";
+ FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n
+ WHERE relkind in ('r','v') 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
@@ -97,23 +97,27 @@ WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s'))
{
$info = $this->ServerInfo();
if ($info['version'] >= 7.3) {
- $this->metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%'
- and schemaname not in ( 'pg_catalog','information_schema')
- union
- select viewname,'V' from pg_views where viewname not like 'pg\_%' and schemaname not in ( 'pg_catalog','information_schema') ";
+ $this->metaTablesSQL = "
+select tablename,'T' from pg_tables
+where tablename not like 'pg\_%' and schemaname not in ( 'pg_catalog','information_schema')
+union
+select viewname,'V' from pg_views
+where viewname not like 'pg\_%' and schemaname not in ( 'pg_catalog','information_schema')";
}
if ($mask) {
$save = $this->metaTablesSQL;
$mask = $this->qstr(strtolower($mask));
if ($info['version']>=7.3)
$this->metaTablesSQL = "
-select tablename,'T' from pg_tables where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema')
- union
-select viewname,'V' from pg_views where viewname like $mask and schemaname not in ( 'pg_catalog','information_schema') ";
+select tablename,'T' from pg_tables
+where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema')
+union
+select viewname,'V' from pg_views
+where viewname like $mask and schemaname not in ( 'pg_catalog','information_schema')";
else
$this->metaTablesSQL = "
select tablename,'T' from pg_tables where tablename like $mask
- union
+union
select viewname,'V' from pg_views where viewname like $mask";
}
$ret = ADOConnection::MetaTables($ttype,$showSchema);
@@ -297,4 +301,23 @@ select viewname,'V' from pg_views where viewname like $mask";
if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
$this->_connectionID->query("SET TRANSACTION ".$transaction_mode);
}
+
+ /**
+ * Returns a driver-specific format for a bind parameter
+ *
+ * Unlike the native driver, we use :name parameters
+ * instead of offsets
+ *
+ * @param string $name
+ * @param string $type (ignored in driver)
+ *
+ * @return string
+ */
+ public function param($name,$type='C') {
+ if (!$name) {
+ return '';
+ }
+
+ return sprintf(':%s', $name);
+ }
}
diff --git a/drivers/adodb-pdo_sqlite.inc.php b/drivers/adodb-pdo_sqlite.inc.php
index b62ca35..dab1de9 100644
--- a/drivers/adodb-pdo_sqlite.inc.php
+++ b/drivers/adodb-pdo_sqlite.inc.php
@@ -34,7 +34,7 @@ class ADODB_pdo_sqlite extends ADODB_pdo {
var $_genSeq2SQL = 'INSERT INTO %s VALUES(%s)';
var $_dropSeqSQL = 'DROP TABLE %s';
var $concat_operator = '||';
- var $pdoDriver = false;
+ var $pdoDriver = false;
var $random='abs(random())';
function _init($parentDriver)
@@ -156,40 +156,48 @@ class ADODB_pdo_sqlite extends ADODB_pdo {
// mark newnham
function MetaColumns($tab,$normalize=true)
{
- global $ADODB_FETCH_MODE;
-
- $parent = $this->pdoDriver;
- $false = false;
- $save = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
- if ($parent->fetchMode !== false) $savem = $parent->SetFetchMode(false);
- $rs = $parent->Execute("PRAGMA table_info('$tab')");
- if (isset($savem)) $parent->SetFetchMode($savem);
- if (!$rs) {
- $ADODB_FETCH_MODE = $save;
- return $false;
- }
- $arr = array();
- while ($r = $rs->FetchRow()) {
- $type = explode('(',$r['type']);
- $size = '';
- if (sizeof($type)==2)
- $size = trim($type[1],')');
- $fn = strtoupper($r['name']);
- $fld = new ADOFieldObject;
- $fld->name = $r['name'];
- $fld->type = $type[0];
- $fld->max_length = $size;
- $fld->not_null = $r['notnull'];
- $fld->primary_key = $r['pk'];
- $fld->default_value = $r['dflt_value'];
- $fld->scale = 0;
- if ($save == ADODB_FETCH_NUM) $arr[] = $fld;
- else $arr[strtoupper($fld->name)] = $fld;
- }
- $rs->Close();
- $ADODB_FETCH_MODE = $save;
- return $arr;
+ global $ADODB_FETCH_MODE;
+
+ $parent = $this->pdoDriver;
+ $false = false;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ if ($parent->fetchMode !== false) {
+ $savem = $parent->SetFetchMode(false);
+ }
+ $rs = $parent->Execute("PRAGMA table_info('$tab')");
+ if (isset($savem)) {
+ $parent->SetFetchMode($savem);
+ }
+ if (!$rs) {
+ $ADODB_FETCH_MODE = $save;
+ return $false;
+ }
+ $arr = array();
+ while ($r = $rs->FetchRow()) {
+ $type = explode('(', $r['type']);
+ $size = '';
+ if (sizeof($type) == 2) {
+ $size = trim($type[1], ')');
+ }
+ $fn = strtoupper($r['name']);
+ $fld = new ADOFieldObject;
+ $fld->name = $r['name'];
+ $fld->type = $type[0];
+ $fld->max_length = $size;
+ $fld->not_null = $r['notnull'];
+ $fld->primary_key = $r['pk'];
+ $fld->default_value = $r['dflt_value'];
+ $fld->scale = 0;
+ if ($save == ADODB_FETCH_NUM) {
+ $arr[] = $fld;
+ } else {
+ $arr[strtoupper($fld->name)] = $fld;
+ }
+ }
+ $rs->Close();
+ $ADODB_FETCH_MODE = $save;
+ return $arr;
}
function MetaTables($ttype=false,$showSchema=false,$mask=false)
@@ -208,5 +216,18 @@ class ADODB_pdo_sqlite extends ADODB_pdo {
$this->metaTablesSQL = $save;
}
return $ret;
- }
+ }
+
+ /**
+ * Returns a driver-specific format for a bind parameter
+ *
+ * @param string $name
+ * @param string $type (ignored in driver)
+ *
+ * @return string
+ */
+ public function param($name,$type='C')
+ {
+ return sprintf(':%s', $name);
+ }
}
diff --git a/drivers/adodb-pdo_sqlsrv.inc.php b/drivers/adodb-pdo_sqlsrv.inc.php
index ed73f3a..de5fbba 100644
--- a/drivers/adodb-pdo_sqlsrv.inc.php
+++ b/drivers/adodb-pdo_sqlsrv.inc.php
@@ -36,10 +36,15 @@ class ADODB_pdo_sqlsrv extends ADODB_pdo
$parentDriver->fmtDate = "'Y-m-d'";
}
- function BeginTrans()
+ function setTransactionMode( $transaction_mode )
{
- $returnval = parent::BeginTrans();
- return $returnval;
+ $this->_transmode = $transaction_mode;
+ if (empty($transaction_mode)) {
+ $this->_connectionID->query('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
+ return;
+ }
+ if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+ $this->_connectionID->query("SET TRANSACTION ".$transaction_mode);
}
function MetaColumns($table, $normalize = true)
@@ -54,8 +59,7 @@ class ADODB_pdo_sqlsrv extends ADODB_pdo
function SelectLimit($sql, $nrows = -1, $offset = -1, $inputarr = false, $secs2cache = 0)
{
- $ret = ADOConnection::SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
- return $ret;
+ return ADOConnection::SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
}
function ServerInfo()
@@ -167,15 +171,5 @@ class ADORecordSet_array_pdo_sqlsrv extends ADORecordSet_array_pdo
return $o;
}
-
- function SetTransactionMode( $transaction_mode )
- {
- $this->_transmode = $transaction_mode;
- if (empty($transaction_mode)) {
- $this->_connectionID->query('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
- return;
- }
- if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
- $this->_connectionID->query("SET TRANSACTION ".$transaction_mode);
- }
+
}
diff --git a/drivers/adodb-postgres64.inc.php b/drivers/adodb-postgres64.inc.php
index 3f351f9..9bf9e71 100644
--- a/drivers/adodb-postgres64.inc.php
+++ b/drivers/adodb-postgres64.inc.php
@@ -26,6 +26,7 @@ class ADODB_postgres64 extends ADOConnection{
var $databaseType = 'postgres64';
var $dataProvider = 'postgres';
var $hasInsertID = true;
+ /** @var PgSql\Connection|resource|false */
var $_resultid = false;
var $concat_operator='||';
var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1";
@@ -83,6 +84,9 @@ class ADODB_postgres64 extends ADOConnection{
/** @var int $_pnum Number of the last assigned query parameter {@see param()} */
var $_pnum = 0;
+ var $version;
+ var $_nestedSQL = false;
+
// The last (fmtTimeStamp is not entirely correct:
// PostgreSQL also has support for time zones,
// and writes these time in this format: "2001-03-01 18:59:26+02".
@@ -154,7 +158,7 @@ class ADODB_postgres64 extends ADOConnection{
*/
protected function _insertID($table = '', $column = '')
{
- if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;
+ if ($this->_resultid === false) return false;
$oid = pg_last_oid($this->_resultid);
// to really return the id, we need the table and column-name, else we can only return the oid != id
return empty($table) || empty($column) ? $oid : $this->GetOne("SELECT $column FROM $table WHERE oid=".(int)$oid);
@@ -162,13 +166,13 @@ class ADODB_postgres64 extends ADOConnection{
function _affectedrows()
{
- if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;
+ if ($this->_resultid === false) return false;
return pg_affected_rows($this->_resultid);
}
/**
- * @return true/false
+ * @return bool
*/
function BeginTrans()
{
@@ -254,7 +258,9 @@ class ADODB_postgres64 extends ADOConnection{
if ($this->_connectionID) {
return "'" . pg_escape_string($this->_connectionID, $s) . "'";
} else {
- return "'" . pg_escape_string($s) . "'";
+ // Fall back to emulated escaping when there is no database connection.
+ // Avoids errors when using setSessionVariables() in the load balancer.
+ return parent::qStr( $s );
}
}
@@ -378,7 +384,7 @@ class ADODB_postgres64 extends ADOConnection{
function BlobDelete( $blob )
{
pg_query($this->_connectionID, 'begin');
- $result = @pg_lo_unlink($blob);
+ $result = @pg_lo_unlink($this->_connectionID, $blob);
pg_query($this->_connectionID, 'commit');
return( $result );
}
@@ -655,14 +661,16 @@ class ADODB_postgres64 extends ADOConnection{
return $false;
}
+ // Get column names indexed by attnum so we can lookup the index key
$col_names = $this->MetaColumnNames($table,true,true);
- // 3rd param is use attnum,
- // see https://sourceforge.net/p/adodb/bugs/45/
$indexes = array();
while ($row = $rs->FetchRow()) {
$columns = array();
foreach (explode(' ', $row[2]) as $col) {
- $columns[] = $col_names[$col];
+ // When index attribute (pg_index.indkey) is an expression, $col == 0
+ // @see https://www.postgresql.org/docs/current/catalog-pg-index.html
+ // so there is no matching column name - set it to null (see #940).
+ $columns[] = $col_names[$col] ?? null;
}
$indexes[$row[0]] = array(
@@ -751,8 +759,7 @@ class ADODB_postgres64 extends ADOConnection{
# PHP does not handle 'hex' properly ('x74657374' is returned as 't657374')
# https://bugs.php.net/bug.php?id=59831 states this is in fact not a bug,
# so we manually set bytea_output
- if (!empty($this->connection->noBlobs)
- && version_compare($info['version'], '9.0', '>=')
+ if (version_compare($info['version'], '9.0', '>=')
&& version_compare($info['client'], '9.2', '<')
) {
$this->Execute('set bytea_output=escape');
@@ -777,7 +784,6 @@ class ADODB_postgres64 extends ADOConnection{
}
- // returns queryID or false
function _query($sql,$inputarr=false)
{
$this->_pnum = 0;
@@ -808,8 +814,7 @@ class ADODB_postgres64 extends ADOConnection{
if ($execp) $exsql = "EXECUTE $plan ($execp)";
else $exsql = "EXECUTE $plan";
-
- $rez = @pg_execute($this->_connectionID,$exsql);
+ $rez = @pg_query($this->_connectionID, $exsql);
if (!$rez) {
# Perhaps plan does not exist? Prepare/compile plan.
$params = '';
@@ -833,18 +838,18 @@ class ADODB_postgres64 extends ADOConnection{
}
$s = "PREPARE $plan ($params) AS ".substr($sql,0,strlen($sql)-2);
//adodb_pr($s);
- $rez = pg_execute($this->_connectionID,$s);
+ $rez = pg_query($this->_connectionID, $s);
//echo $this->ErrorMsg();
}
if ($rez)
- $rez = pg_execute($this->_connectionID,$exsql);
+ $rez = pg_query($this->_connectionID, $exsql);
} else {
//adodb_backtrace();
- $rez = pg_query($this->_connectionID,$sql);
+ $rez = pg_query($this->_connectionID, $sql);
}
// check if no data returned, then no need to create real recordset
if ($rez && pg_num_fields($rez) <= 0) {
- if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') {
+ if ($this->_resultid !== false) {
pg_free_result($this->_resultid);
}
$this->_resultid = $rez;
@@ -1020,8 +1025,20 @@ class ADORecordSet_postgres64 extends ADORecordSet{
return pg_unescape_bytea($blob);
}
- function _fixblobs()
+ /**
+ * Fetches and prepares the RecordSet's fields.
+ *
+ * Fixes the blobs if there are any.
+ */
+ protected function _prepFields()
{
+ $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+
+ // Check prerequisites and bail early if we do not have what we need.
+ if (!isset($this->_blobArr) || $this->fields === false) {
+ return;
+ }
+
if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) {
foreach($this->_blobArr as $k => $v) {
$this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]);
@@ -1040,9 +1057,8 @@ class ADORecordSet_postgres64 extends ADORecordSet{
if (!$this->EOF) {
$this->_currentRow++;
if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
- $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
- if (is_array($this->fields) && $this->fields) {
- if (isset($this->_blobArr)) $this->_fixblobs();
+ $this->_prepfields();
+ if ($this->fields !== false) {
return true;
}
}
@@ -1054,22 +1070,17 @@ class ADORecordSet_postgres64 extends ADORecordSet{
function _fetch()
{
-
- if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)
+ if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0) {
return false;
+ }
- $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
-
- if ($this->fields && isset($this->_blobArr)) $this->_fixblobs();
-
- return (is_array($this->fields));
+ $this->_prepfields();
+ return $this->fields !== false;
}
function _close()
{
- if (!is_resource($this->_queryID)
- || get_resource_type($this->_queryID) != 'pgsql result'
- ) {
+ if ($this->_queryID === false || $this->_queryID == self::DUMMY_QUERY_ID) {
return true;
}
return pg_free_result($this->_queryID);
@@ -1082,7 +1093,13 @@ class ADORecordSet_postgres64 extends ADORecordSet{
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
- switch (strtoupper($t)) {
+
+ $t = strtoupper($t);
+
+ if (array_key_exists($t,$this->connection->customActualTypes))
+ return $this->connection->customActualTypes[$t];
+
+ switch ($t) {
case 'MONEY': // stupid, postgres expects money to be a string
case 'INTERVAL':
case 'CHAR':
@@ -1094,6 +1111,7 @@ class ADORecordSet_postgres64 extends ADORecordSet{
case 'CIDR':
case 'INET':
case 'MACADDR':
+ case 'UUID':
if ($len <= $this->blobSize) return 'C';
case 'TEXT':
@@ -1134,6 +1152,12 @@ class ADORecordSet_postgres64 extends ADORecordSet{
case 'SERIAL':
return 'R';
+ case 'NUMERIC':
+ case 'DECIMAL':
+ case 'FLOAT4':
+ case 'FLOAT8':
+ return 'N';
+
default:
return ADODB_DEFAULT_METATYPE;
}
diff --git a/drivers/adodb-postgres7.inc.php b/drivers/adodb-postgres7.inc.php
index 59174f6..b5e63ac 100644
--- a/drivers/adodb-postgres7.inc.php
+++ b/drivers/adodb-postgres7.inc.php
@@ -154,10 +154,7 @@ class ADODB_postgres7 extends ADODB_postgres64 {
}
}
- /**
- * @returns assoc array where keys are tables, and values are foreign keys
- */
- function MetaForeignKeys($table, $owner=false, $upper=false)
+ public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false)
{
# Regex isolates the 2 terms between parenthesis using subexpressions
$regex = '^.*\((.*)\).*\((.*)\).*$';
@@ -193,50 +190,18 @@ class ADODB_postgres7 extends ADODB_postgres64 {
$a = array();
while (!$rs->EOF) {
+ $lookup_table = $rs->fields('lookup_table');
+ $fields = $rs->fields('dep_field') . '=' . $rs->fields('lookup_field');
if ($upper) {
- $a[strtoupper($rs->Fields('lookup_table'))][] = strtoupper(str_replace('"','',$rs->Fields('dep_field').'='.$rs->Fields('lookup_field')));
- } else {
- $a[$rs->Fields('lookup_table')][] = str_replace('"','',$rs->Fields('dep_field').'='.$rs->Fields('lookup_field'));
+ $lookup_table = strtoupper($lookup_table);
+ $fields = strtoupper($fields);
}
+ $a[$lookup_table][] = str_replace('"','', $fields);
+
$rs->MoveNext();
}
return $a;
-
- }
-
- // from Edward Jaramilla, improved version - works on pg 7.4
- function _old_MetaForeignKeys($table, $owner=false, $upper=false)
- {
- $sql = 'SELECT t.tgargs as args
- FROM
- pg_trigger t,pg_class c,pg_proc p
- WHERE
- t.tgenabled AND
- t.tgrelid = c.oid AND
- t.tgfoid = p.oid AND
- p.proname = \'RI_FKey_check_ins\' AND
- c.relname = \''.strtolower($table).'\'
- ORDER BY
- t.tgrelid';
-
- $rs = $this->Execute($sql);
-
- if (!$rs || $rs->EOF) return false;
-
- $arr = $rs->GetArray();
- $a = array();
- foreach($arr as $v) {
- $data = explode(chr(0), $v['args']);
- $size = count($data)-1; //-1 because the last node is empty
- for($i = 4; $i < $size; $i++) {
- if ($upper)
- $a[strtoupper($data[2])][] = strtoupper($data[$i].'='.$data[++$i]);
- else
- $a[$data[2]][] = $data[$i].'='.$data[++$i];
- }
- }
- return $a;
}
function _query($sql,$inputarr=false)
@@ -266,7 +231,7 @@ class ADODB_postgres7 extends ADODB_postgres64 {
}
// check if no data returned, then no need to create real recordset
if ($rez && pg_num_fields($rez) <= 0) {
- if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') {
+ if ($this->_resultid !== false) {
pg_free_result($this->_resultid);
}
$this->_resultid = $rez;
@@ -334,10 +299,8 @@ class ADORecordSet_postgres7 extends ADORecordSet_postgres64{
if (!$this->EOF) {
$this->_currentRow++;
if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
- $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
-
- if (is_array($this->fields)) {
- if ($this->fields && isset($this->_blobArr)) $this->_fixblobs();
+ $this->_prepfields();
+ if ($this->fields !== false) {
return true;
}
}
@@ -360,14 +323,13 @@ class ADORecordSet_assoc_postgres7 extends ADORecordSet_postgres64{
return false;
}
- $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
-
- if ($this->fields) {
- if (isset($this->_blobArr)) $this->_fixblobs();
+ $this->_prepfields();
+ if ($this->fields !== false) {
$this->_updatefields();
+ return true;
}
- return (is_array($this->fields));
+ return false;
}
function MoveNext()
@@ -375,19 +337,13 @@ class ADORecordSet_assoc_postgres7 extends ADORecordSet_postgres64{
if (!$this->EOF) {
$this->_currentRow++;
if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
- $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
-
- if (is_array($this->fields)) {
- if ($this->fields) {
- if (isset($this->_blobArr)) $this->_fixblobs();
-
- $this->_updatefields();
- }
+ $this->_prepfields();
+ if ($this->fields !== false) {
+ $this->_updatefields();
return true;
}
}
-
$this->fields = false;
$this->EOF = true;
}
diff --git a/drivers/adodb-postgres8.inc.php b/drivers/adodb-postgres8.inc.php
index 37c2aae..58df47c 100644
--- a/drivers/adodb-postgres8.inc.php
+++ b/drivers/adodb-postgres8.inc.php
@@ -45,11 +45,23 @@ class ADODB_postgres8 extends ADODB_postgres7
* @return int last inserted ID for given table/column, or the most recently
* returned one if $table or $column are empty
*/
- protected function _insertID($table = '', $column = '')
+ protected function _insertID( $table = '', $column = '' )
{
- return empty($table) || empty($column)
- ? $this->GetOne("SELECT lastval()")
- : $this->GetOne("SELECT currval(pg_get_serial_sequence('$table', '$column'))");
+ global $ADODB_GETONE_EOF;
+
+ $sql = empty($table) || empty($column)
+ ? 'SELECT lastval()'
+ : "SELECT currval(pg_get_serial_sequence('$table', '$column'))";
+
+ // Squelch "ERROR: lastval is not yet defined in this session" (see #978)
+ $result = @$this->GetOne($sql);
+ if ($result === false || $result == $ADODB_GETONE_EOF) {
+ if ($this->debug) {
+ ADOConnection::outp(__FUNCTION__ . "() failed : " . $this->errorMsg());
+ }
+ return false;
+ }
+ return $result;
}
}
diff --git a/drivers/adodb-sqlanywhere.inc.php b/drivers/adodb-sqlanywhere.inc.php
index 88897af..8d909fd 100644
--- a/drivers/adodb-sqlanywhere.inc.php
+++ b/drivers/adodb-sqlanywhere.inc.php
@@ -116,7 +116,7 @@ if (!defined('ADODB_SYBASE_SQLANYWHERE')){
$conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
$conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
*/
- function UpdateBlob($table,$column,&$val,$where,$blobtype='BLOB')
+ function updateBlob($table, $column, $val, $where, $blobtype = 'BLOB')
{
$blobVarName = 'hold_blob';
$this->create_blobvar($blobVarName);
diff --git a/drivers/adodb-sqlite.inc.php b/drivers/adodb-sqlite.inc.php
index 0711f1d..d41829c 100644
--- a/drivers/adodb-sqlite.inc.php
+++ b/drivers/adodb-sqlite.inc.php
@@ -211,7 +211,6 @@ class ADODB_sqlite extends ADOConnection {
return true;
}
- // returns query ID if successful, otherwise false
function _query($sql,$inputarr=false)
{
$rez = sqlite_query($sql,$this->_connectionID);
diff --git a/drivers/adodb-sqlite3.inc.php b/drivers/adodb-sqlite3.inc.php
index 548727d..7623a3c 100644
--- a/drivers/adodb-sqlite3.inc.php
+++ b/drivers/adodb-sqlite3.inc.php
@@ -24,6 +24,9 @@
// security - hide paths
if (!defined('ADODB_DIR')) die();
+/**
+ * Class ADODB_sqlite3
+ */
class ADODB_sqlite3 extends ADOConnection {
var $databaseType = "sqlite3";
var $dataProvider = "sqlite";
@@ -34,10 +37,13 @@ class ADODB_sqlite3 extends ADOConnection {
var $hasInsertID = true; /// supports autoincrement ID?
var $hasAffectedRows = true; /// supports affected rows for update/delete?
var $metaTablesSQL = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
- var $sysDate = "adodb_date('Y-m-d')";
- var $sysTimeStamp = "adodb_date('Y-m-d H:i:s')";
+ var $sysDate = "DATE('now','localtime')";
+ var $sysTimeStamp = "DATETIME('now','localtime')";
var $fmtTimeStamp = "'Y-m-d H:i:s'";
+ /** @var SQLite3 */
+ var $_connectionID;
+
function ServerInfo()
{
$version = SQLite3::version();
@@ -51,7 +57,7 @@ class ADODB_sqlite3 extends ADOConnection {
if ($this->transOff) {
return true;
}
- $ret = $this->Execute("BEGIN TRANSACTION");
+ $this->Execute("BEGIN TRANSACTION");
$this->transCnt += 1;
return true;
}
@@ -95,6 +101,9 @@ class ADODB_sqlite3 extends ADOConnection {
$t = strtoupper($t);
+ if (array_key_exists($t,$this->customActualTypes))
+ return $this->customActualTypes[$t];
+
/*
* We are using the Sqlite affinity method here
* @link https://www.sqlite.org/datatype3.html
@@ -197,7 +206,7 @@ class ADODB_sqlite3 extends ADOConnection {
return $arr;
}
- function metaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
+ public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false)
{
global $ADODB_FETCH_MODE;
if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC
@@ -214,7 +223,7 @@ class ADODB_sqlite3 extends ADOConnection {
)
WHERE type != 'meta'
AND sql NOTNULL
- AND LOWER(name) ='" . strtolower($table) . "'";
+ AND LOWER(name) ='" . strtolower($table) . "'";
$tableSql = $this->getOne($sql);
@@ -304,8 +313,7 @@ class ADODB_sqlite3 extends ADOConnection {
$this->_connectionID->createFunction('adodb_date2', 'adodb_date2', 2);
}
-
- // returns true or false
+ /** @noinspection PhpUnusedParameterInspection */
function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
{
if (empty($argHostname) && $argDatabasename) {
@@ -317,14 +325,12 @@ class ADODB_sqlite3 extends ADOConnection {
return true;
}
- // returns true or false
function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
{
// There's no permanent connect in SQLite3
return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
}
- // returns query ID if successful, otherwise false
function _query($sql,$inputarr=false)
{
$rez = $this->_connectionID->query($sql);
@@ -394,7 +400,7 @@ class ADODB_sqlite3 extends ADOConnection {
return false;
}
- function CreateSequence($seqname='adodbseq',$start=1)
+ function createSequence($seqname='adodbseq', $startID=1)
{
if (empty($this->_genSeqSQL)) {
return false;
@@ -403,8 +409,8 @@ class ADODB_sqlite3 extends ADOConnection {
if (!$ok) {
return false;
}
- $start -= 1;
- return $this->Execute("insert into $seqname values($start)");
+ $startID -= 1;
+ return $this->Execute("insert into $seqname values($startID)");
}
var $_dropSeqSQL = 'drop table %s';
@@ -559,14 +565,13 @@ class ADODB_sqlite3 extends ADOConnection {
*
* This uses the more efficient strftime native function to process
*
- * @param str $fld The name of the field to process
+ * @param string $fld The name of the field to process
*
- * @return str The SQL Statement
+ * @return string The SQL Statement
*/
function month($fld)
{
- $x = "strftime('%m',$fld)";
- return $x;
+ return "strftime('%m',$fld)";
}
/**
@@ -574,13 +579,12 @@ class ADODB_sqlite3 extends ADOConnection {
*
* This uses the more efficient strftime native function to process
*
- * @param str $fld The name of the field to process
+ * @param string $fld The name of the field to process
*
- * @return str The SQL Statement
+ * @return string The SQL Statement
*/
function day($fld) {
- $x = "strftime('%d',$fld)";
- return $x;
+ return "strftime('%d',$fld)";
}
/**
@@ -588,14 +592,116 @@ class ADODB_sqlite3 extends ADOConnection {
*
* This uses the more efficient strftime native function to process
*
- * @param str $fld The name of the field to process
+ * @param string $fld The name of the field to process
*
- * @return str The SQL Statement
+ * @return string The SQL Statement
*/
function year($fld)
{
- $x = "strftime('%Y',$fld)";
- return $x;
+ return "strftime('%Y',$fld)";
+ }
+
+ /**
+ * SQLite update for blob
+ *
+ * SQLite must be a fully prepared statement (all variables must be bound),
+ * so $where can either be an array (array params) or a string that we will
+ * do our best to unpack and turn into a prepared statement.
+ *
+ * @param string $table
+ * @param string $column
+ * @param string $val Blob value to set
+ * @param mixed $where An array of parameters (key => value pairs),
+ * or a string (where clause).
+ * @param string $blobtype ignored
+ *
+ * @return bool success
+ */
+ function updateBlob($table, $column, $val, $where, $blobtype = 'BLOB')
+ {
+ if (is_array($where)) {
+ // We were passed a set of key=>value pairs
+ $params = $where;
+ } else {
+ // Given a where clause string, we have to disassemble the
+ // statements into keys and values
+ $params = array();
+ $temp = preg_split('/(where|and)/i', $where);
+ $where = array_filter($temp);
+
+ foreach ($where as $wValue) {
+ $wTemp = preg_split('/[= \']+/', $wValue);
+ $wTemp = array_filter($wTemp);
+ $wTemp = array_values($wTemp);
+ $params[$wTemp[0]] = $wTemp[1];
+ }
+ }
+
+ $paramWhere = array();
+ foreach ($params as $bindKey => $bindValue) {
+ $paramWhere[] = $bindKey . '=?';
+ }
+
+ $sql = "UPDATE $table SET $column=? WHERE "
+ . implode(' AND ', $paramWhere);
+
+ // Prepare the statement
+ $stmt = $this->_connectionID->prepare($sql);
+
+ // Set the first bind value equal to value we want to update
+ if (!$stmt->bindValue(1, $val, SQLITE3_BLOB)) {
+ return false;
+ }
+
+ // Build as many keys as available
+ $bindIndex = 2;
+ foreach ($params as $bindValue) {
+ if (is_integer($bindValue) || is_bool($bindValue) || is_float($bindValue)) {
+ $type = SQLITE3_NUM;
+ } elseif (is_object($bindValue)) {
+ // Assume a blob, this should never appear in
+ // the binding for a where statement anyway
+ $type = SQLITE3_BLOB;
+ } else {
+ $type = SQLITE3_TEXT;
+ }
+
+ if (!$stmt->bindValue($bindIndex, $bindValue, $type)) {
+ return false;
+ }
+
+ $bindIndex++;
+ }
+
+ // Now execute the update. NB this is SQLite execute, not ADOdb
+ $ok = $stmt->execute();
+ return is_object($ok);
+ }
+
+ /**
+ * SQLite update for blob from a file
+ *
+ * @param string $table
+ * @param string $column
+ * @param string $path Filename containing blob data
+ * @param mixed $where {@see updateBlob()}
+ * @param string $blobtype ignored
+ *
+ * @return bool success
+ */
+ function updateBlobFile($table, $column, $path, $where, $blobtype = 'BLOB')
+ {
+ if (!file_exists($path)) {
+ return false;
+ }
+
+ // Read file information
+ $fileContents = file_get_contents($path);
+ if ($fileContents === false)
+ // Distinguish between an empty file and failure
+ return false;
+
+ return $this->updateBlob($table, $column, $fileContents, $where, $blobtype);
}
}
@@ -609,9 +715,12 @@ class ADORecordset_sqlite3 extends ADORecordSet {
var $databaseType = "sqlite3";
var $bind = false;
+ /** @var SQLite3Result */
+ var $_queryID;
+
+ /** @noinspection PhpMissingParentConstructorInspection */
function __construct($queryID,$mode=false)
{
-
if ($mode === false) {
global $ADODB_FETCH_MODE;
$mode = $ADODB_FETCH_MODE;
diff --git a/drivers/adodb-sybase.inc.php b/drivers/adodb-sybase.inc.php
index b8db074..79fb82e 100644
--- a/drivers/adodb-sybase.inc.php
+++ b/drivers/adodb-sybase.inc.php
@@ -95,7 +95,9 @@ class ADODB_sybase extends ADOConnection {
// http://www.isug.com/Sybase_FAQ/ASE/section6.1.html#6.1.4
function RowLock($tables,$where,$col='top 1 null as ignore')
{
- if (!$this->_hastrans) $this->BeginTrans();
+ if (!$this->hasTransactions) {
+ $this->BeginTrans();
+ }
$tables = str_replace(',',' HOLDLOCK,',$tables);
return $this->GetOne("select $col from $tables HOLDLOCK where $where");
@@ -104,7 +106,6 @@ class ADODB_sybase extends ADOConnection {
function SelectDB($dbName)
{
$this->database = $dbName;
- $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
if ($this->_connectionID) {
return @sybase_select_db($dbName);
}
@@ -169,7 +170,6 @@ class ADODB_sybase extends ADOConnection {
return true;
}
- // returns query ID if successful, otherwise false
function _query($sql,$inputarr=false)
{
global $ADODB_COUNTRECS;
diff --git a/drivers/adodb-text.inc.php b/drivers/adodb-text.inc.php
index 77ad06a..36a1a0d 100644
--- a/drivers/adodb-text.inc.php
+++ b/drivers/adodb-text.inc.php
@@ -129,14 +129,21 @@ class ADODB_text extends ADOConnection {
return true;
}
-
-
- // returns queryID or false
- // We presume that the select statement is on the same table (what else?),
- // with the only difference being the order by.
- //You can filter by using $eval and each clause is stored in $arr .eg. $arr[1] == 'name'
- // also supports SELECT [DISTINCT] COL FROM ... -- only 1 col supported
- function _query($sql,$input_arr,$eval=false)
+ /**
+ * Execute a query.
+ *
+ * We presume that the select statement is on the same table (what else?),
+ * with the only difference being the order by.
+ * You can filter by using $eval and each clause is stored in $arr e.g. $arr[1] == 'name'
+ * also supports SELECT [DISTINCT] COL FROM ... -- only 1 col supported
+ *
+ * @param string|array $sql Query to execute.
+ * @param array $inputarr An optional array of parameters.
+ * @param string $eval Optional eval string
+ *
+ * @return mixed|bool Query identifier or true if execution successful, false if failed.
+ */
+ function _query($sql, $inputarr=false, $eval=false)
{
if ($this->_origarray === false) return false;
diff --git a/perf/perf-mysql.inc.php b/perf/perf-mysql.inc.php
index dae4422..ed92c80 100644
--- a/perf/perf-mysql.inc.php
+++ b/perf/perf-mysql.inc.php
@@ -125,7 +125,7 @@ class perf_mysql extends adodb_perf{
/**
* Returns a list of table statuses.
- *
+ *
* @param string $orderby Unused (compatibility with parent method)
* @return string A formatted set of recordsets
*/
@@ -299,7 +299,7 @@ class perf_mysql extends adodb_perf{
var $optimizeTableHigh = 'OPTIMIZE TABLE %s';
/**
- * @see adodb_perf#optimizeTable
+ * @see adodb_perf::optimizeTable()
*/
function optimizeTable( $table, $mode = ADODB_OPT_LOW)
{
diff --git a/perf/perf-oci8.inc.php b/perf/perf-oci8.inc.php
index c11b261..345d892 100644
--- a/perf/perf-oci8.inc.php
+++ b/perf/perf-oci8.inc.php
@@ -23,7 +23,7 @@
if (!defined('ADODB_DIR')) die();
-class perf_oci8 extends ADODB_perf{
+class perf_oci8 extends adodb_perf{
var $noShowIxora = 15; // if the sql for suspicious sql is taking too long, then disable ixora
diff --git a/perf/perf-postgres.inc.php b/perf/perf-postgres.inc.php
index 315c17f..16b767d 100644
--- a/perf/perf-postgres.inc.php
+++ b/perf/perf-postgres.inc.php
@@ -102,7 +102,7 @@ class perf_postgres extends adodb_perf{
var $optimizeTableHigh = 'VACUUM ANALYZE %s';
/**
- * @see adodb_perf#optimizeTable
+ * @see adodb_perf::optimizeTable()
*/
function optimizeTable($table, $mode = ADODB_OPT_LOW)
@@ -131,7 +131,7 @@ class perf_postgres extends adodb_perf{
if ($partial) {
$sqlq = $this->conn->qstr($sql.'%');
- $arr = $this->conn->GetArray("select distinct distinct sql1 from adodb_logsql where sql1 like $sqlq");
+ $arr = $this->conn->getArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq");
if ($arr) {
foreach($arr as $row) {
$sql = reset($row);
diff --git a/perf/perf-sqlite3.inc.php b/perf/perf-sqlite3.inc.php
new file mode 100644
index 0000000..19198d5
--- /dev/null
+++ b/perf/perf-sqlite3.inc.php
@@ -0,0 +1,40 @@
+<?php
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class perf_sqlite3 extends adodb_perf{
+
+ var $tablesSQL = "SELECT * FROM sqlite_master WHERE type='table'";
+
+ var $createTableSQL = "CREATE TABLE adodb_logsql (
+ created datetime NOT NULL,
+ sql0 varchar(250) NOT NULL,
+ sql1 text NOT NULL,
+ params text NOT NULL,
+ tracer text NOT NULL,
+ timer decimal(16,6) NOT NULL
+ )";
+
+ var $settings = array();
+
+ function __construct(&$conn)
+ {
+ $this->conn = $conn;
+ }
+
+ function tables($orderby='1')
+ {
+ if (!$this->tablesSQL){
+ return false;
+ }
+
+ $rs = $this->conn->execute($this->tablesSQL);
+ if (!$rs) {
+ return false;
+ }
+
+ $html = rs2html($rs, false, false, false, false);
+ return $html;
+ }
+}
diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml
new file mode 100644
index 0000000..bbddd3d
--- /dev/null
+++ b/phpdoc.dist.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<phpdocumentor
+ configVersion="3"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="https://www.phpdoc.org"
+ xsi:noNamespaceSchemaLocation="https://docs.phpdoc.org/latest/phpdoc.xsd"
+>
+ <paths>
+ <output>docs/api</output>
+ <cache>docs/cache</cache>
+ </paths>
+ <version number="latest">
+ <api>
+ <source dsn=".">
+ </source>
+ <ignore>
+ <path>scripts</path>
+ <path>tests</path>
+ <path>vendor/**/*</path>
+ <path>xsl</path>
+ </ignore>
+ </api>
+ </version>
+</phpdocumentor>
diff --git a/server.php b/server.php
deleted file mode 100644
index 76e757f..0000000
--- a/server.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-/**
- * ADOdb Proxy Server.
- *
- * @deprecated 5.21.0
- *
- * Security warning - use with extreme caution !
- * Depending on how it is setup, this feature can potentially expose the
- * database to attacks, particularly if used with a privileged user account.
- *
- * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
- *
- * @package ADOdb
- * @link https://adodb.org Project's web site and documentation
- * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
- *
- * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
- * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
- * any later version. This means you can use it in proprietary products.
- * See the LICENSE.md file distributed with this source code for details.
- * @license BSD-3-Clause
- * @license LGPL-2.1-or-later
- *
- * @copyright 2000-2013 John Lim
- * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
- */
-
-/* Documentation on usage is at https://adodb.org/dokuwiki/doku.php?id=v5:proxy:proxy_index
- *
- * Legal query string parameters:
- *
- * sql = holds sql string
- * nrows = number of rows to return
- * offset = skip offset rows of data
- * fetch = $ADODB_FETCH_MODE
- *
- * example:
- *
- * http://localhost/php/server.php?sql=select+*+from+table&nrows=10&offset=2
- */
-
-
-/*
- * Define the IP address you want to accept requests from
- * as a security measure. If blank we accept anyone promisciously!
- */
-$ACCEPTIP = '127.0.0.1';
-
-/*
- * Connection parameters
- */
-$driver = 'mysqli';
-$host = 'localhost'; // DSN for odbc
-$uid = 'root';
-$pwd = 'garbase-it-is';
-$database = 'test';
-
-/*============================ DO NOT MODIFY BELOW HERE =================================*/
-// $sep must match csv2rs() in adodb.inc.php
-$sep = ' :::: ';
-
-include('./adodb.inc.php');
-include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
-
-function err($s)
-{
- die('**** '.$s.' ');
-}
-
-///////////////////////////////////////// DEFINITIONS
-
-
-$remote = $_SERVER["REMOTE_ADDR"];
-
-
-if (!empty($ACCEPTIP))
- if ($remote != '127.0.0.1' && $remote != $ACCEPTIP)
- err("Unauthorised client: '$remote'");
-
-
-if (empty($_REQUEST['sql'])) err('No SQL');
-
-
-$conn = ADONewConnection($driver);
-
-if (!$conn->connect($host,$uid,$pwd,$database)) err($conn->errorNo(). $sep . $conn->errorMsg());
-$sql = $_REQUEST['sql'];
-
-if (isset($_REQUEST['fetch']))
- $ADODB_FETCH_MODE = $_REQUEST['fetch'];
-
-if (isset($_REQUEST['nrows'])) {
- $nrows = $_REQUEST['nrows'];
- $offset = isset($_REQUEST['offset']) ? $_REQUEST['offset'] : -1;
- $rs = $conn->selectLimit($sql,$nrows,$offset);
-} else
- $rs = $conn->execute($sql);
-if ($rs){
- //$rs->timeToLive = 1;
- echo _rs2serialize($rs,$conn,$sql);
- $rs->close();
-} else
- err($conn->errorNo(). $sep .$conn->errorMsg());
diff --git a/session/adodb-session2.php b/session/adodb-session2.php
index bf64b41..1979396 100644
--- a/session/adodb-session2.php
+++ b/session/adodb-session2.php
@@ -28,15 +28,14 @@ if (defined('ADODB_SESSION')) return 1;
define('ADODB_SESSION', dirname(__FILE__));
define('ADODB_SESSION2', ADODB_SESSION);
-/*
- Unserialize session data manually. See PHPLens Issue No: 9821
-
- From Kerr Schere, to unserialize session data stored via ADOdb.
- 1. Pull the session data from the db and loop through it.
- 2. Inside the loop, you will need to urldecode the data column.
- 3. After urldecode, run the serialized string through this function:
-
-*/
+/**
+ * Unserialize session data manually. See PHPLens Issue No: 9821
+ *
+ * From Kerr Schere, to unserialize session data stored via ADOdb.
+ * 1. Pull the session data from the db and loop through it.
+ * 2. Inside the loop, you will need to urldecode the data column.
+ * 3. After urldecode, run the serialized string through this function:
+ */
function adodb_unserialize( $serialized_string )
{
$variables = array( );
@@ -47,10 +46,13 @@ function adodb_unserialize( $serialized_string )
return( $variables );
}
-/*
- Thanks Joe Li. See PHPLens Issue No: 11487&x=1
- Since adodb 4.61.
-*/
+/**
+ * Regenerate session id
+ *
+ * Thanks Joe Li. See PHPLens Issue No: 11487&x=1
+ *
+ * @since 4.61
+ */
function adodb_session_regenerate_id()
{
$conn = ADODB_Session::_conn();
@@ -79,45 +81,52 @@ function adodb_session_regenerate_id()
return true;
}
-/*
- Generate database table for session data
- @see PHPLens Issue No: 12280
- @return 0 if failure, 1 if errors, 2 if successful.
- @author Markus Staab http://www.public-4u.de
-*/
+/**
+ * Generate database table for session data.
+ * @see PHPLens Issue No: 12280
+ *
+ * @return int 0 if failure, 1 if errors, 2 if successful.
+ *
+ * @author Markus Staab http://www.public-4u.de
+ */
function adodb_session_create_table($schemaFile=null,$conn = null)
{
- // set default values
- if ($schemaFile===null) $schemaFile = ADODB_SESSION . '/session_schema2.xml';
- if ($conn===null) $conn = ADODB_Session::_conn();
+ // set default values
+ if ($schemaFile===null) $schemaFile = ADODB_SESSION . '/session_schema2.xml';
+ if ($conn===null) $conn = ADODB_Session::_conn();
if (!$conn) return 0;
- $schema = new adoSchema($conn);
- $schema->ParseSchema($schemaFile);
- return $schema->ExecuteSchema();
+ $schema = new adoSchema($conn);
+ $schema->ParseSchema($schemaFile);
+ return $schema->ExecuteSchema();
}
-/*!
- \static
-*/
+/**
+ * ADOdb Session v2 class.
+ */
class ADODB_Session {
+
+ /**
+ * Session Connection's Database provider.
+ *
+ * Populated when opening the database connection.
+ * @see ADODB_Session::open()}.
+ *
+ * @var string
+ */
+ protected static $provider;
+
/////////////////////
// getter/setter methods
/////////////////////
- /*
-
- function Lock($lock=null)
- {
- static $_lock = false;
-
- if (!is_null($lock)) $_lock = $lock;
- return $lock;
- }
- */
- /*!
- */
+ /**
+ * Get/Set Database driver.
+ *
+ * @param string $driver
+ * @return string
+ */
static function driver($driver = null)
{
static $_driver = 'mysqli';
@@ -136,8 +145,12 @@ class ADODB_Session {
return $_driver;
}
- /*!
- */
+ /**
+ * Get/Set Database hostname.
+ *
+ * @param string $host
+ * @return string
+ */
static function host($host = null) {
static $_host = 'localhost';
static $set = false;
@@ -155,8 +168,12 @@ class ADODB_Session {
return $_host;
}
- /*!
- */
+ /**
+ * Get/Set Database connection user.
+ *
+ * @param string $user
+ * @return string
+ */
static function user($user = null)
{
static $_user = 'root';
@@ -175,8 +192,12 @@ class ADODB_Session {
return $_user;
}
- /*!
- */
+ /**
+ * Get/Set Database connection password.
+ *
+ * @param null $password
+ * @return string
+ */
static function password($password = null)
{
static $_password = '';
@@ -195,8 +216,12 @@ class ADODB_Session {
return $_password;
}
- /*!
- */
+ /**
+ * Get/Set Database name.
+ *
+ * @param null $database
+ * @return string
+ */
static function database($database = null)
{
static $_database = '';
@@ -214,8 +239,12 @@ class ADODB_Session {
return $_database;
}
- /*!
- */
+ /**
+ * Get/Set Connection's persistence mode.
+ *
+ * @param $persist
+ * @return string|true
+ */
static function persist($persist = null)
{
static $_persist = true;
@@ -227,8 +256,12 @@ class ADODB_Session {
return $_persist;
}
- /*!
- */
+ /**
+ * Get/Set Connection's lifetime.
+ *
+ * @param int $lifetime
+ * @return int
+ */
static function lifetime($lifetime = null)
{
static $_lifetime;
@@ -255,8 +288,12 @@ class ADODB_Session {
return $_lifetime;
}
- /*!
- */
+ /**
+ * Get/Set Connection's debug mode.
+ *
+ * @param bool $debug
+ * @return bool
+ */
static function debug($debug = null)
{
static $_debug = false;
@@ -264,11 +301,6 @@ class ADODB_Session {
if (!is_null($debug)) {
$_debug = (bool) $debug;
-
- $conn = ADODB_Session::_conn();
- if ($conn) {
- #$conn->debug = $_debug;
- }
$set = true;
} elseif (!$set) {
// backwards compatibility
@@ -280,8 +312,12 @@ class ADODB_Session {
return $_debug;
}
- /*!
- */
+ /**
+ * Get/Set garbage collection function.
+ *
+ * @param callable $expire_notify Function name
+ * @return callable|false
+ */
static function expireNotify($expire_notify = null)
{
static $_expire_notify;
@@ -300,8 +336,12 @@ class ADODB_Session {
return $_expire_notify;
}
- /*!
- */
+ /**
+ * Get/Set Sessions table name.
+ *
+ * @param string $table Session table name (defaults to 'sessions2')
+ * @return string
+ */
static function table($table = null)
{
static $_table = 'sessions2';
@@ -320,8 +360,15 @@ class ADODB_Session {
return $_table;
}
- /*!
- */
+ /**
+ * Get/Set table optimization mode.
+ *
+ * If true, with MySQL and PostgreSQL databases, the Sessions table will
+ * be optimized when garbage collection is performed.
+ *
+ * @param bool $optimize
+ * @return bool
+ */
static function optimize($optimize = null)
{
static $_optimize = false;
@@ -340,16 +387,21 @@ class ADODB_Session {
return $_optimize;
}
- /*!
- */
+ /**
+ * No longer used, kept for backwards-compatibility only.
+ *
+ * @param int $sync_seconds
+ * @return int
+ *
+ * @deprecated
+ */
static function syncSeconds($sync_seconds = null) {
- //echo ("<p>WARNING: ADODB_SESSION::syncSeconds is longer used, please remove this function for your code</p>");
-
return 0;
}
- /*!
- */
+ /**
+ * Get/Set if CLOBs are available to store session data.
+ */
static function clob($clob = null) {
static $_clob = false;
static $set = false;
@@ -367,15 +419,24 @@ class ADODB_Session {
return $_clob;
}
- /*!
- */
+ /**
+ * No longer used, kept for backwards-compatibility only.
+ *
+ * @param string $data_field_name
+ * @return string
+ *
+ * @deprecated
+ */
static function dataFieldName($data_field_name = null) {
- //echo ("<p>WARNING: ADODB_SESSION::dataFieldName() is longer used, please remove this function for your code</p>");
return '';
}
- /*!
- */
+ /**
+ * Get/Set session data filter.
+ *
+ * @param array $filter
+ * @return array
+ */
static function filter($filter = null) {
static $_filter = array();
@@ -389,8 +450,12 @@ class ADODB_Session {
return $_filter;
}
- /*!
- */
+ /**
+ * Get/Set the encryption key if encrypted sessions are in use.
+ *
+ * @param string $encryption_key
+ * @return string
+ */
static function encryptionKey($encryption_key = null) {
static $_encryption_key = 'CRYPTED ADODB SESSIONS ROCK!';
@@ -405,14 +470,19 @@ class ADODB_Session {
// private methods
/////////////////////
- /*!
- */
+ /**
+ * Returns the Session's Database Connection.
+ *
+ * @return ADOConnection|false
+ */
static function _conn($conn=null) {
return isset($GLOBALS['ADODB_SESS_CONN']) ? $GLOBALS['ADODB_SESS_CONN'] : false;
}
- /*!
- */
+ /**
+ * @param $crc
+ * @return false|mixed
+ */
static function _crc($crc = null) {
static $_crc = false;
@@ -423,8 +493,9 @@ class ADODB_Session {
return $_crc;
}
- /*!
- */
+ /**
+ * Initialize session handler.
+ */
static function _init() {
session_set_save_handler(
array('ADODB_Session', 'open'),
@@ -437,16 +508,19 @@ class ADODB_Session {
}
- /*!
- */
+ /**
+ * Create the encryption key for crypted sessions.
+ *
+ * Crypt the used key, ADODB_Session::encryptionKey() as key and
+ * session_id() as salt.
+ */
static 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());
}
- /*!
- */
+ /**
+ * Dump recordset.
+ */
static function _dumprs(&$rs) {
$conn = ADODB_Session::_conn();
$debug = ADODB_Session::debug();
@@ -476,10 +550,39 @@ class ADODB_Session {
$rs->MoveFirst();
}
+ /**
+ * Check if Session Connection's DB type is MySQL.
+ *
+ * @return bool
+ */
+ static protected function isConnectionMysql() {
+ return self::$provider == 'mysql';
+ }
+
+ /**
+ * Check if Session Connection's DB type is PostgreSQL.
+ *
+ * @return bool
+ */
+ static protected function isConnectionPostgres() {
+ return self::$provider == 'postgres';
+ }
+
/////////////////////
// public methods
/////////////////////
+ /**
+ * Establishes a connection to the database for session management.
+ *
+ * @param string $host
+ * @param string $driver
+ * @param string $user
+ * @param string $password
+ * @param string $database
+ * @param array $options
+ * @return void
+ */
static function config($driver, $host, $user, $password, $database=false,$options=false)
{
ADODB_Session::driver($driver);
@@ -495,11 +598,17 @@ class ADODB_Session {
if (isset($options['debug'])) ADODB_Session::debug($options['debug']);
}
- /*!
- Create the connection to the database.
-
- If $conn already exists, reuse that connection
- */
+ /**
+ * Create the connection to the database.
+ *
+ * If $conn already exists, reuse that connection.
+ *
+ * @param string $save_path
+ * @param string $session_name
+ * @param bool $persist
+ *
+ * @return bool
+ */
static function open($save_path, $session_name, $persist = null)
{
$conn = ADODB_Session::_conn();
@@ -521,10 +630,6 @@ class ADODB_Session {
$persist = ADODB_Session::persist();
}
-# these can all be defaulted to in php.ini
-# assert('$database');
-# assert('$driver');
-# assert('$host');
if (strpos($driver, 'pdo_') === 0){
$conn = ADONewConnection('pdo');
$driver = str_replace('pdo_', '', $driver);
@@ -562,8 +667,15 @@ class ADODB_Session {
}
}
+ if ($ok) {
+ $GLOBALS['ADODB_SESS_CONN'] = $conn;
- if ($ok) $GLOBALS['ADODB_SESS_CONN'] = $conn;
+ // Initialize Session data provider
+ self::$provider = $conn->dataProvider;
+ if (self::$provider == 'pdo') {
+ self::$provider = $conn->dsnType == 'pgsql' ? 'postgres' : $conn->dsnType;
+ }
+ }
else
ADOConnection::outp('<p>Session: connection failed</p>', false);
@@ -571,9 +683,9 @@ class ADODB_Session {
return $ok;
}
- /*!
- Close the connection
- */
+ /**
+ * Close the connection
+ */
static function close()
{
/*
@@ -583,9 +695,12 @@ class ADODB_Session {
return true;
}
- /*
- Slurp in the session variables and return the serialized string
- */
+ /**
+ * Slurp in the session variables and return the serialized string.
+ *
+ * @param string $key
+ * @return string
+ */
static function read($key)
{
$conn = ADODB_Session::_conn();
@@ -596,9 +711,7 @@ class ADODB_Session {
return '';
}
- //assert('$table');
-
- $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+ $binary = ADODB_Session::isConnectionMysql() ? '/*! BINARY */' : '';
global $ADODB_SESSION_SELECT_FIELDS;
if (!isset($ADODB_SESSION_SELECT_FIELDS)) $ADODB_SESSION_SELECT_FIELDS = 'sessdata';
@@ -635,16 +748,22 @@ class ADODB_Session {
return '';
}
- /*!
- Write the serialized data to a database.
-
- If the data has not been modified since the last read(), we do not write.
- */
+ /**
+ * Write the serialized data to a database.
+ *
+ * If the data has not been modified since the last read(), we do not write.
+ *
+ * @param string $key
+ * @param string $oval
+ *
+ * @return bool
+ */
static function write($key, $oval)
{
- global $ADODB_SESSION_READONLY;
-
- if (!empty($ADODB_SESSION_READONLY)) return;
+ global $ADODB_SESSION_READONLY;
+ if (!empty($ADODB_SESSION_READONLY)) {
+ return false;
+ }
$clob = ADODB_Session::clob();
$conn = ADODB_Session::_conn();
@@ -662,11 +781,9 @@ class ADODB_Session {
if ($debug) $conn->debug = 1;
$sysTimeStamp = $conn->sysTimeStamp;
- //assert('$table');
-
$expiry = $conn->OffsetDate($lifetime/(24*3600),$sysTimeStamp);
- $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+ $binary = ADODB_Session::isConnectionMysql() ? '/*! BINARY */' : '';
// crc32 optimization since adodb 2.1
// now we only update expiry date, thx to sebastian thom in adodb 2.32
@@ -684,8 +801,9 @@ class ADODB_Session {
}
}
-
- $sql = "UPDATE $table SET expiry = $expiry ,expireref=".$conn->Param('0').", modified = $sysTimeStamp WHERE $binary sesskey = ".$conn->Param('1')." AND expiry >= $sysTimeStamp";
+ $sql = "UPDATE $table SET expiry = $expiry, expireref=" . $conn->Param('0')
+ . ", modified = $sysTimeStamp WHERE sesskey = $binary " . $conn->Param('1')
+ . " AND expiry >= $sysTimeStamp";
$rs = $conn->Execute($sql,array($expirevar,$key));
return true;
}
@@ -705,7 +823,8 @@ class ADODB_Session {
}
}
- if (!$clob) { // no lobs, simply use replace()
+ if (!$clob) {
+ // no lobs, simply use replace()
$rs = $conn->Execute("SELECT COUNT(*) AS cnt FROM $table WHERE $binary sesskey = ".$conn->Param(0),array($key));
if ($rs) $rs->Close();
@@ -717,7 +836,6 @@ class ADODB_Session {
VALUES ($expiry,".$conn->Param('0').", ". $conn->Param('1').", ".$conn->Param('2').", $sysTimeStamp, $sysTimeStamp)";
}
-
$rs = $conn->Execute($sql,array($val,$expireref,$key));
} else {
@@ -737,14 +855,12 @@ class ADODB_Session {
VALUES ($expiry,$lob_value, ". $conn->Param('0').", ".$conn->Param('1').", $sysTimeStamp, $sysTimeStamp)";
}
- $rs = $conn->Execute($sql,array($expireref,$key));
+ $conn->Execute($sql,array($expireref,$key));
$qkey = $conn->qstr($key);
- $rs2 = $conn->UpdateBlob($table, 'sessdata', $val, " sesskey=$qkey", strtoupper($clob));
+ $conn->UpdateBlob($table, 'sessdata', $val, " sesskey=$qkey", strtoupper($clob));
if ($debug) echo "<hr>",htmlspecialchars($oval), "<hr>";
$rs = @$conn->CompleteTrans();
-
-
}
if (!$rs) {
@@ -768,8 +884,12 @@ class ADODB_Session {
return $rs ? true : false;
}
- /*!
- */
+ /**
+ * Destroy session.
+ *
+ * @param string $key
+ * @return bool
+ */
static function destroy($key) {
$conn = ADODB_Session::_conn();
$table = ADODB_Session::table();
@@ -780,16 +900,15 @@ class ADODB_Session {
}
$debug = ADODB_Session::debug();
if ($debug) $conn->debug = 1;
- //assert('$table');
$qkey = $conn->quote($key);
- $binary = $conn->dataProvider === 'mysql' || $conn->dataProvider === 'pdo' ? '/*! BINARY */' : '';
+ $binary = ADODB_Session::isConnectionMysql() ? '/*! 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";
+ $sql = "SELECT expireref, sesskey FROM $table WHERE sesskey = $binary $qkey";
$rs = $conn->Execute($sql);
ADODB_Session::_dumprs($rs);
$conn->SetFetchMode($savem);
@@ -799,24 +918,26 @@ class ADODB_Session {
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";
+ $sql = "DELETE FROM $table WHERE sesskey = $binary $qkey";
$rs = $conn->Execute($sql);
if ($rs) {
$rs->Close();
}
- return $rs ? true : false;
+ return (bool)$rs;
}
- /*!
- */
+ /**
+ * Perform garbage collection.
+ *
+ * @param int $maxlifetime
+ * @return bool
+ */
static function gc($maxlifetime)
{
$conn = ADODB_Session::_conn();
@@ -829,8 +950,6 @@ class ADODB_Session {
return false;
}
-
- $debug = ADODB_Session::debug();
if ($debug) {
$conn->debug = 1;
$COMMITNUM = 2;
@@ -838,10 +957,8 @@ class ADODB_Session {
$COMMITNUM = 20;
}
- //assert('$table');
-
$time = $conn->OffsetDate(-$maxlifetime/24/3600,$conn->sysTimeStamp);
- $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+ $binary = ADODB_Session::isConnectionMysql() ? '/*! BINARY */' : '';
if ($expire_notify) {
reset($expire_notify);
@@ -858,13 +975,12 @@ class ADODB_Session {
if ($rs) {
$tr = $conn->hasTransactions;
if ($tr) $conn->BeginTrans();
- $keys = array();
$ccnt = 0;
while (!$rs->EOF) {
$ref = $rs->fields[0];
$key = $rs->fields[1];
if ($fn) $fn($ref, $key);
- $del = $conn->Execute("DELETE FROM $table WHERE sesskey=".$conn->Param('0'),array($key));
+ $conn->Execute("DELETE FROM $table WHERE sesskey = $binary " . $conn->Param('0'), array($key));
$rs->MoveNext();
$ccnt += 1;
if ($tr && $ccnt % $COMMITNUM == 0) {
@@ -881,12 +997,9 @@ class ADODB_Session {
// suggested by Cameron, "GaM3R" <gamr@outworld.cx>
if ($optimize) {
- $driver = ADODB_Session::driver();
-
- if (preg_match('/mysql/i', $driver)) {
+ if (ADODB_Session::isConnectionMysql()) {
$sql = "OPTIMIZE TABLE $table";
- }
- if (preg_match('/postgres/i', $driver)) {
+ } elseif (ADODB_Session::isConnectionPostgres()) {
$sql = "VACUUM $table";
}
if (!empty($sql)) {
@@ -903,12 +1016,16 @@ ADODB_Session::_init();
if (empty($ADODB_SESSION_READONLY))
register_shutdown_function('session_write_close');
-// for backwards compatibility only
+/**
+ * @deprecated for backwards compatibility only
+ */
function adodb_sess_open($save_path, $session_name, $persist = true) {
return ADODB_Session::open($save_path, $session_name, $persist);
}
-// for backwards compatibility only
+/**
+ * @deprecated for backwards compatibility only
+ */
function adodb_sess_gc($t)
{
return ADODB_Session::gc($t);
diff --git a/session/session_schema2.xml b/session/session_schema2.xml
index 89cb4f2..a8a1b22 100644
--- a/session/session_schema2.xml
+++ b/session/session_schema2.xml
@@ -1,37 +1,33 @@
<?xml version="1.0"?>
<schema version="0.3">
<table name="sessions2">
- <descr>table for ADOdb session-management</descr>
-
+ <descr>Table for ADOdb session management</descr>
<field name="SESSKEY" type="C" size="64">
- <descr>session key</descr>
+ <descr>Session key to identify a user's browser session.</descr>
<KEY/>
<NOTNULL/>
</field>
-
-
-
<field name="EXPIRY" type="T">
- <descr></descr>
+ <descr>Slightly redundant as it can be dynamically calculated by NOW() and MODIFIED field,
+ but it enables forcing a fixed timeout for specific sessions.
+ </descr>
<NOTNULL/>
</field>
-
- <field name="CREATED" type="T">
- <descr></descr>
+ <field name="CREATED" type="T">
+ <descr>New session creation Timestamp.</descr>
<NOTNULL/>
</field>
-
- <field name="MODIFIED" type="T">
- <descr></descr>
+ <field name="MODIFIED" type="T">
+ <descr>Timestamp which is usually updated when the user interacts with a site, to extend the expire time.</descr>
<NOTNULL/>
</field>
-
<field name="EXPIREREF" type="C" size="250">
- <descr></descr>
+ <descr>Usually a User Id or unique username of your application.
+ The name EXPIREREF is a bit weird, it may be better to call it USERREF?
+ </descr>
</field>
-
<field name="SESSDATA" type="XL">
- <descr></descr>
+ <descr>PHP's serialized session data or encrypted serialized session data.</descr>
<NOTNULL/>
</field>
</table>
diff --git a/tohtml.inc.php b/tohtml.inc.php
index e92c8b4..6e9a628 100644
--- a/tohtml.inc.php
+++ b/tohtml.inc.php
@@ -113,7 +113,8 @@ GLOBAL $gSQLMaxRows,$gSQLBlockRows,$ADODB_ROUND;
else
$v = round($v,$ADODB_ROUND);
case 'I':
- $vv = stripslashes((trim($v)));
+ $vv = $v ? stripslashes(trim($v)) : '';
+ $vv = $vv ?: ' ';
if (strlen($vv) == 0) $vv .= ' ';
$s .= " <TD align=right>".$vv ."</TD>\n";
@@ -139,11 +140,17 @@ GLOBAL $gSQLMaxRows,$gSQLBlockRows,$ADODB_ROUND;
*/
default:
- if ($htmlspecialchars) $v = htmlspecialchars(trim($v));
- $v = trim($v);
- if (strlen($v) == 0) $v = ' ';
- $s .= " <TD>". str_replace("\n",'<br>',stripslashes($v)) ."</TD>\n";
-
+ if ($v) {
+ $v = trim($v);
+ if ($htmlspecialchars) {
+ $v = htmlspecialchars($v);
+ }
+ } elseif ($v === null) {
+ $v = '(NULL)';
+ } else {
+ $v = ' ';
+ }
+ $s .= " <TD>" . str_replace("\n", '<br>', $v) . "</TD>\n";
}
} // for
$s .= "</TR>\n\n";
Debdiff
[The following lists of changes regard files as different if they have different names, permissions or owners.]
Files in second set of .debs but not in first
-rw-r--r-- root/root /usr/share/php/adodb/perf/perf-sqlite3.inc.php
Files in first set of .debs but not in second
-rw-r--r-- root/root /usr/share/php/adodb/drivers/adodb-mysql.inc.php -rw-r--r-- root/root /usr/share/php/adodb/drivers/adodb-mysqlpo.inc.php -rw-r--r-- root/root /usr/share/php/adodb/drivers/adodb-mysqlt.inc.php -rw-r--r-- root/root /usr/share/php/adodb/server.php
No differences were encountered in the control files