summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/adodb-ado.inc.php18
-rw-r--r--drivers/adodb-ado5.inc.php18
-rw-r--r--drivers/adodb-ads.inc.php23
-rw-r--r--drivers/adodb-db2.inc.php3396
-rw-r--r--drivers/adodb-fbsql.inc.php26
-rw-r--r--drivers/adodb-firebird.inc.php18
-rw-r--r--drivers/adodb-ibase.inc.php7
-rw-r--r--drivers/adodb-informix72.inc.php11
-rw-r--r--drivers/adodb-ldap.inc.php494
-rw-r--r--drivers/adodb-mssql.inc.php12
-rw-r--r--drivers/adodb-mssqlnative.inc.php131
-rw-r--r--drivers/adodb-mysqli.inc.php274
-rw-r--r--drivers/adodb-netezza.inc.php2
-rw-r--r--drivers/adodb-oci8.inc.php165
-rw-r--r--drivers/adodb-oci8po.inc.php13
-rw-r--r--drivers/adodb-odbc.inc.php11
-rw-r--r--drivers/adodb-odbc_oracle.inc.php29
-rw-r--r--drivers/adodb-odbtp.inc.php13
-rw-r--r--drivers/adodb-oracle.inc.php19
-rw-r--r--drivers/adodb-pdo.inc.php119
-rw-r--r--drivers/adodb-pdo_dblib.inc.php20
-rw-r--r--drivers/adodb-pdo_firebird.inc.php20
-rw-r--r--drivers/adodb-pdo_mssql.inc.php7
-rw-r--r--drivers/adodb-pdo_mysql.inc.php31
-rw-r--r--drivers/adodb-pdo_oci.inc.php37
-rw-r--r--drivers/adodb-pdo_pgsql.inc.php17
-rw-r--r--drivers/adodb-pdo_sqlite.inc.php11
-rw-r--r--drivers/adodb-pdo_sqlsrv.inc.php12
-rw-r--r--drivers/adodb-postgres64.inc.php325
-rw-r--r--drivers/adodb-sqlite.inc.php33
-rw-r--r--drivers/adodb-sqlite3.inc.php409
-rw-r--r--drivers/adodb-sybase.inc.php16
32 files changed, 3179 insertions, 2558 deletions
diff --git a/drivers/adodb-ado.inc.php b/drivers/adodb-ado.inc.php
index b0979ff5..aa8a6197 100644
--- a/drivers/adodb-ado.inc.php
+++ b/drivers/adodb-ado.inc.php
@@ -122,7 +122,7 @@ class ADODB_ado extends ADOConnection {
adSchemaConstraintColumnUsage = 6,
adSchemaConstraintTableUsage = 7,
adSchemaKeyColumnUsage = 8,
- adSchemaReferentialContraints = 9,
+ adSchemaReferentialConstraints = 9,
adSchemaTableConstraints = 10,
adSchemaColumnsDomainUsage = 11,
adSchemaIndexes = 12,
@@ -345,16 +345,6 @@ class ADORecordSet_ado extends ADORecordSet {
var $canSeek = true;
var $hideErrors = true;
- function __construct($id,$mode=false)
- {
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- $this->fetchMode = $mode;
- parent::__construct($id);
- }
-
// returns the field object
function FetchField($fieldOffset = -1) {
@@ -584,7 +574,7 @@ class ADORecordSet_ado extends ADORecordSet {
$val=(float) variant_cast($f->value,VT_R8)*3600*24-2209161600;
else
$val = $f->value;
- $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
+ $this->fields[] = date('Y-m-d H:i:s',$val);
}
break;
case 133:// A date value (yyyymmdd)
@@ -599,8 +589,8 @@ class ADORecordSet_ado extends ADORecordSet {
if (!is_numeric($f->value)) $val = variant_date_to_timestamp($f->value);
else $val = $f->value;
- if (($val % 86400) == 0) $this->fields[] = adodb_date('Y-m-d',$val);
- else $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
+ if (($val % 86400) == 0) $this->fields[] = date('Y-m-d',$val);
+ else $this->fields[] = date('Y-m-d H:i:s',$val);
}
break;
case 1: // null
diff --git a/drivers/adodb-ado5.inc.php b/drivers/adodb-ado5.inc.php
index e4fa0cfe..76b85335 100644
--- a/drivers/adodb-ado5.inc.php
+++ b/drivers/adodb-ado5.inc.php
@@ -147,7 +147,7 @@ class ADODB_ado extends ADOConnection {
adSchemaConstraintColumnUsage = 6,
adSchemaConstraintTableUsage = 7,
adSchemaKeyColumnUsage = 8,
- adSchemaReferentialContraints = 9,
+ adSchemaReferentialConstraints = 9,
adSchemaTableConstraints = 10,
adSchemaColumnsDomainUsage = 11,
adSchemaIndexes = 12,
@@ -382,16 +382,6 @@ class ADORecordSet_ado extends ADORecordSet {
var $canSeek = true;
var $hideErrors = true;
- function __construct($id,$mode=false)
- {
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- $this->fetchMode = $mode;
- parent::__construct($id);
- }
-
// returns the field object
function FetchField($fieldOffset = -1) {
@@ -631,7 +621,7 @@ class ADORecordSet_ado extends ADORecordSet {
$val= (float) variant_cast($f->value,VT_R8)*3600*24-2209161600;
else
$val = $f->value;
- $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
+ $this->fields[] = date('Y-m-d H:i:s',$val);
}
break;
case 133:// A date value (yyyymmdd)
@@ -646,8 +636,8 @@ class ADORecordSet_ado extends ADORecordSet {
if (!is_numeric($f->value)) $val = variant_date_to_timestamp($f->value);
else $val = $f->value;
- if (($val % 86400) == 0) $this->fields[] = adodb_date('Y-m-d',$val);
- else $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
+ if (($val % 86400) == 0) $this->fields[] = date('Y-m-d',$val);
+ else $this->fields[] = date('Y-m-d H:i:s',$val);
}
break;
case 1: // null
diff --git a/drivers/adodb-ads.inc.php b/drivers/adodb-ads.inc.php
index 436a2d62..5362123f 100644
--- a/drivers/adodb-ads.inc.php
+++ b/drivers/adodb-ads.inc.php
@@ -287,7 +287,7 @@ class ADODB_ads extends ADOConnection
// Returns tables,Views or both on successful execution. Returns
// tables by default on successful execution.
- function &MetaTables($ttype = false, $showSchema = false, $mask = false)
+ function MetaTables($ttype = false, $showSchema = false, $mask = false)
{
$recordSet1 = $this->Execute("select * from system.tables");
if (!$recordSet1) {
@@ -325,7 +325,7 @@ class ADODB_ads extends ADOConnection
}
- function &MetaPrimaryKeys($table, $owner = false)
+ function MetaPrimaryKeys($table, $owner = false)
{
$recordSet = $this->Execute("select table_primary_key from system.tables where name='$table'");
if (!$recordSet) {
@@ -533,7 +533,7 @@ class ADODB_ads extends ADOConnection
}
// Returns an array of columns names for a given table
- function &MetaColumnNames($table, $numIndexes = false, $useattnum = false)
+ function MetaColumnNames($table, $numIndexes = false, $useattnum = false)
{
$recordSet = $this->Execute("select name from system.columns where parent='$table'");
if (!$recordSet) {
@@ -684,20 +684,13 @@ class ADORecordSet_ads extends ADORecordSet
var $dataProvider = "ads";
var $useFetchArray;
- function __construct($id, $mode = false)
+ function __construct($queryID, $mode = false)
{
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- $this->fetchMode = $mode;
-
- $this->_queryID = $id;
+ parent::__construct($queryID, $mode);
// the following is required for mysql odbc driver in 4.3.1 -- why?
$this->EOF = false;
$this->_currentRow = -1;
- //parent::__construct($id);
}
@@ -760,7 +753,7 @@ class ADORecordSet_ads extends ADORecordSet
function &GetArrayLimit($nrows, $offset = -1)
{
if ($offset <= 0) {
- $rs =& $this->GetArray($nrows);
+ $rs = $this->GetArray($nrows);
return $rs;
}
$savem = $this->fetchMode;
@@ -769,7 +762,7 @@ class ADORecordSet_ads extends ADORecordSet
$this->fetchMode = $savem;
if ($this->fetchMode & ADODB_FETCH_ASSOC) {
- $this->fields =& $this->GetRowAssoc();
+ $this->fields = $this->GetRowAssoc();
}
$results = array();
@@ -802,7 +795,7 @@ class ADORecordSet_ads extends ADORecordSet
$rez = @ads_fetch_into($this->_queryID, $this->fields);
if ($rez) {
if ($this->fetchMode & ADODB_FETCH_ASSOC) {
- $this->fields =& $this->GetRowAssoc();
+ $this->fields = $this->GetRowAssoc();
}
return true;
}
diff --git a/drivers/adodb-db2.inc.php b/drivers/adodb-db2.inc.php
index 77466db1..c5f9992a 100644
--- a/drivers/adodb-db2.inc.php
+++ b/drivers/adodb-db2.inc.php
@@ -11,7 +11,7 @@
* about all the changes, see the update information on the ADOdb website
* for version 5.21.0.
*
- * @link http://pecl.php.net/package/ibm_db2 PECL Extension For DB2
+ * @link https://pecl.php.net/package/ibm_db2 PECL Extension For DB2
*
* This file is part of ADOdb, a Database Abstraction Layer library for PHP.
*
@@ -38,993 +38,1168 @@ define("_ADODB_DB2_LAYER", 2 );
class ADODB_db2 extends ADOConnection {
- var $databaseType = "db2";
- var $fmtDate = "'Y-m-d'";
- var $concat_operator = '||';
+ var $databaseType = "db2";
+ var $fmtDate = "'Y-m-d'";
+ var $concat_operator = '||';
- var $sysTime = 'CURRENT TIME';
- var $sysDate = 'CURRENT DATE';
- var $sysTimeStamp = 'CURRENT TIMESTAMP';
+ var $sysTime = 'CURRENT TIME';
+ var $sysDate = 'CURRENT DATE';
+ var $sysTimeStamp = 'CURRENT TIMESTAMP';
- var $fmtTimeStamp = "'Y-m-d H:i:s'";
- var $replaceQuote = "''"; // string to use to replace quotes
- var $dataProvider = "db2";
- var $hasAffectedRows = true;
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $dataProvider = "db2";
+ var $hasAffectedRows = true;
- var $binmode = DB2_BINARY;
+ var $binmode = DB2_BINARY;
- /*
- * setting this to true will make array elements in FETCH_ASSOC
- * mode case-sensitive breaking backward-compat
- */
- var $useFetchArray = false;
- var $_bindInputArray = true;
- var $_genIDSQL = "VALUES NEXTVAL FOR %s";
- var $_genSeqSQL = "
- CREATE SEQUENCE %s START WITH %s
- NO MAXVALUE NO CYCLE INCREMENT BY 1 NO CACHE
- ";
- var $_dropSeqSQL = "DROP SEQUENCE %s";
- var $_autocommit = true;
- var $_lastAffectedRows = 0;
- var $hasInsertID = true;
- var $hasGenID = true;
+ /*
+ * setting this to true will make array elements in FETCH_ASSOC
+ * mode case-sensitive breaking backward-compat
+ */
+ var $useFetchArray = false;
+ var $_bindInputArray = true;
+ var $_genIDSQL = "VALUES NEXTVAL FOR %s";
- /*
- * Character used to wrap column and table names for escaping special
- * characters in column and table names as well as forcing upper and
- * lower case
- */
- public $nameQuote = '"';
+ /**
+ * SQL to create a new sequence
+ *
+ * @var string
+ */
+ var $_genSeqSQL = "
+ CREATE SEQUENCE %s START WITH %s
+ NO MAXVALUE NO CYCLE INCREMENT BY 1 NO CACHE
+ ";
- /*
- * Holds information about the stored procedure request
- * currently being built
- */
- private $storedProcedureParameters = false;
+ /**
+ * SQL to drop a sequence
+ *
+ * @var string
+ */
+ var $_dropSeqSQL = "DROP SEQUENCE %s";
+ var $_autocommit = true;
+ var $_lastAffectedRows = 0;
+ var $hasInsertID = true;
+ var $hasGenID = true;
+ /*
+ * Character used to wrap column and table names for escaping special
+ * characters in column and table names as well as forcing upper and
+ * lower case
+ */
+ public $nameQuote = '"';
- function __construct() {}
+ /*
+ * Holds information about the stored procedure request
+ * currently being built
+ */
+ private $storedProcedureParameters = false;
- protected function _insertID($table = '', $column = '')
- {
- return ADOConnection::GetOne('VALUES IDENTITY_VAL_LOCAL()');
- }
- public function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
- {
- return $this->doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename);
- }
+ /**
+ * Supports older DB2 versions without record counts
+ *
+ * @var boolean
+ */
+ public bool $useLegacyRecordCounting = false;
- public function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
- {
- return $this->doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename,true);
- }
+ /**
+ * Supports older DB2 versions without 'OFFSET' support
+ *
+ * @var boolean
+ */
+ public bool $useLegacyRowOffsets = false;
- private function doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename, $persistent=false)
- {
+ function __construct() {}
- if (!function_exists('db2_connect')) {
- ADOConnection::outp("DB2 extension not installed.");
- return null;
- }
+ protected function _insertID($table = '', $column = '')
+ {
+ return ADOConnection::GetOne('VALUES IDENTITY_VAL_LOCAL()');
+ }
- $connectionParameters = $this->unpackParameters(
- $argDSN,
- $argUsername,
- $argPassword,
- $argDatabasename
- );
+ public function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
+ {
+ return $this->doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename);
+ }
- if ($connectionParameters == null)
- {
- /*
- * Error thrown
- */
- return null;
- }
+ public function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
+ {
+ return $this->doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename,true);
+ }
- $argDSN = $connectionParameters['dsn'];
- $argUsername = $connectionParameters['uid'];
- $argPassword = $connectionParameters['pwd'];
- $argDatabasename = $connectionParameters['database'];
- $useCataloguedConnection = $connectionParameters['catalogue'];
+ private function doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename, $persistent=false)
+ {
- if ($this->debug){
- if (strcmp($argDSN,'*LOCAL') == 0)
- {
- $connectMessage = '*LOCAL connection';
- }
- else if ($useCataloguedConnection)
- {
- $connectMessage = "Catalogued connection using parameters: ";
- $connectMessage .= "DB=$argDatabasename / ";
- $connectMessage .= "UID=$argUsername / ";
- $connectMessage .= "PWD=$argPassword";
- }
- else
- {
- $connectMessage = "Uncatalogued connection using DSN: $argDSN";
- }
- ADOConnection::outp($connectMessage);
- }
+ if (!function_exists('db2_connect')) {
+ ADOConnection::outp("DB2 extension not installed.");
+ return null;
+ }
- /*
- * This needs to be set before the connect().
- */
- ini_set('ibm_db2.binmode', $this->binmode);
+ $connectionParameters = $this->unpackParameters(
+ $argDSN,
+ $argUsername,
+ $argPassword,
+ $argDatabasename
+ );
- if ($persistent)
- $db2Function = 'db2_pconnect';
- else
- $db2Function = 'db2_connect';
+ if ($connectionParameters == null)
+ {
+ /*
+ * Error thrown
+ */
+ return null;
+ }
- /*
- * We need to flatten out the connectionParameters
- */
+ $argDSN = $connectionParameters['dsn'];
+ $argUsername = $connectionParameters['uid'];
+ $argPassword = $connectionParameters['pwd'];
+ $argDatabasename = $connectionParameters['database'];
+ $useCataloguedConnection = $connectionParameters['catalogue'];
- $db2Options = array();
- if ($this->connectionParameters)
- {
- foreach($this->connectionParameters as $p)
- foreach($p as $k=>$v)
- $db2Options[$k] = $v;
- }
+ if ($this->debug){
+ if (strcmp($argDSN,'*LOCAL') == 0)
+ {
+ $connectMessage = '*LOCAL connection';
+ }
+ else if ($useCataloguedConnection)
+ {
+ $connectMessage = "Catalogued connection using parameters: ";
+ $connectMessage .= "DB=$argDatabasename / ";
+ $connectMessage .= "UID=$argUsername / ";
+ $connectMessage .= "PWD=$argPassword";
+ }
+ else
+ {
+ $connectMessage = "Uncatalogued connection using DSN: $argDSN";
+ }
+ ADOConnection::outp($connectMessage);
+ }
- if ($useCataloguedConnection)
- {
- $this->_connectionID = $db2Function($argDatabasename,
- $argUsername,
- $argPassword,
- $db2Options);
- }
- else
+ /*
+ * This needs to be set before the connect().
+ */
+ ini_set('ibm_db2.binmode', $this->binmode);
- $this->_connectionID = $db2Function($argDSN,
- '',
- '',
- $db2Options);
+ if ($persistent)
+ $db2Function = 'db2_pconnect';
+ else
+ $db2Function = 'db2_connect';
+ /*
+ * We need to flatten out the connectionParameters
+ */
- $this->_errorMsg = @db2_conn_errormsg();
+ $db2Options = array();
+ if ($this->connectionParameters)
+ {
+ foreach($this->connectionParameters as $p)
+ foreach($p as $k=>$v)
+ $db2Options[$k] = $v;
+ }
- if ($this->_connectionID && $this->connectStmt)
- $this->execute($this->connectStmt);
+ if ($useCataloguedConnection)
+ {
+ $this->_connectionID = $db2Function($argDatabasename,
+ $argUsername,
+ $argPassword,
+ $db2Options);
+ }
+ else
- if ($this->_connectionID && $argDatabasename)
- $this->execute("SET SCHEMA=$argDatabasename");
+ $this->_connectionID = $db2Function($argDSN,
+ '',
+ '',
+ $db2Options);
- return $this->_connectionID != false;
- }
+ $this->_errorMsg = @db2_conn_errormsg();
- /**
- * Validates and preprocesses the passed parameters for consistency
- *
- * @param string $argDSN Either DSN or database
- * @param string $argUsername User name or null
- * @param string $argPassword Password or null
- * @param string $argDatabasename Either DSN or database
- *
- * @return mixed array if correct, null if not
- */
- private function unpackParameters($argDSN, $argUsername, $argPassword, $argDatabasename)
- {
+ if ($this->_connectionID && $this->connectStmt)
+ $this->execute($this->connectStmt);
+ if ($this->_connectionID && $argDatabasename)
+ $this->execute("SET SCHEMA=$argDatabasename");
- $connectionParameters = array(
- 'dsn'=>'',
- 'uid'=>'',
- 'pwd'=>'',
- 'database'=>'',
- 'catalogue'=>true
- );
+ return $this->_connectionID != false;
- /*
- * Shortcut for *LOCAL
- */
- if (strcmp($argDSN,'*LOCAL') == 0)
- {
- $connectionParameters['dsn'] = $argDSN;
- $connectionParameters['database'] = $argDatabasename;
- $connectionParameters['catalogue'] = false;
+ }
- return $connectionParameters;
- }
+ /**
+ * Validates and preprocesses the passed parameters for consistency
+ *
+ * @param string $argDSN Either DSN or database
+ * @param string $argUsername User name or null
+ * @param string $argPassword Password or null
+ * @param string $argDatabasename Either DSN or database
+ *
+ * @return mixed array if correct, null if not
+ */
+ private function unpackParameters($argDSN, $argUsername, $argPassword, $argDatabasename)
+ {
- /*
- * Uou can either connect to a catalogued connection
- * with a database name e.g. 'SAMPLE'
- * or an uncatalogued connection with a DSN like connection
- * DATABASE=database;HOSTNAME=hostname;PORT=port;PROTOCOL=TCPIP;UID=username;PWD=password;
- */
- if (!$argDSN && !$argDatabasename)
- {
- $errorMessage = 'Supply either catalogued or uncatalogued connection parameters';
- $this->_errorMsg = $errorMessage;
- if ($this->debug)
- ADOConnection::outp($errorMessage);
- return null;
- }
+ $connectionParameters = array(
+ 'dsn'=>'',
+ 'uid'=>'',
+ 'pwd'=>'',
+ 'database'=>'',
+ 'catalogue'=>true
+ );
- $useCataloguedConnection = true;
- $schemaName = '';
+ /*
+ * Shortcut for *LOCAL
+ */
+ if (strcmp($argDSN,'*LOCAL') == 0)
+ {
+ $connectionParameters['dsn'] = $argDSN;
+ $connectionParameters['database'] = $argDatabasename;
+ $connectionParameters['catalogue'] = false;
- if ($argDSN && $argDatabasename)
- {
- /*
- * If a catalogued connection if provided,
- * as well as user and password
- * that will take priority
- */
- if ($argUsername && $argPassword && !$this->isDsn($argDatabasename))
- {
- if ($this->debug){
- $errorMessage = 'Warning: Because you provided user,';
- $errorMessage.= 'password and database, DSN connection ';
- $errorMessage.= 'parameters were discarded';
- ADOConnection::outp($errorMessage);
+ return $connectionParameters;
+ }
- }
- $argDSN = '';
- }
- else if ($this->isDsn($argDSN) && $this->isDsn($argDatabasename))
- {
- $errorMessage = 'Supply uncatalogued connection parameters ';
- $errorMessage.= 'in either the database or DSN arguments, ';
- $errorMessage.= 'but not both';
+ /*
+ * Uou can either connect to a catalogued connection
+ * with a database name e.g. 'SAMPLE'
+ * or an uncatalogued connection with a DSN like connection
+ * DATABASE=database;HOSTNAME=hostname;PORT=port;PROTOCOL=TCPIP;UID=username;PWD=password;
+ */
- if ($this->debug)
- ADOConnection::outp($errorMessage);
- return null;
- }
- }
+ if (!$argDSN && !$argDatabasename)
+ {
+ $errorMessage = 'Supply either catalogued or uncatalogued connection parameters';
+ $this->_errorMsg = $errorMessage;
+ if ($this->debug)
+ ADOConnection::outp($errorMessage);
+ return null;
+ }
- if (!$this->isDsn($argDSN) && $this->isDsn($argDatabasename))
- {
- /*
- * Switch them around for next test
- */
- $temp = $argDSN;
- $argDsn = $argDatabasename;
- $argDatabasenME = $temp;
- }
+ $useCataloguedConnection = true;
+ $schemaName = '';
- if ($this->isDsn($argDSN))
- {
+ if ($argDSN && $argDatabasename)
+ {
+ /*
+ * If a catalogued connection if provided,
+ * as well as user and password
+ * that will take priority
+ */
+ if ($argUsername && $argPassword && !$this->isDsn($argDatabasename))
+ {
+ if ($this->debug){
+ $errorMessage = 'Warning: Because you provided user,';
+ $errorMessage.= 'password and database, DSN connection ';
+ $errorMessage.= 'parameters were discarded';
+ ADOConnection::outp($errorMessage);
- if (!preg_match('/uid=/i',$argDSN)
- || !preg_match('/pwd=/i',$argDSN))
- {
- $errorMessage = 'For uncatalogued connections, provide ';
- $errorMessage.= 'both UID and PWD in the connection string';
+ }
+ $argDSN = '';
+ }
+ else if ($this->isDsn($argDSN) && $this->isDsn($argDatabasename))
+ {
+ $errorMessage = 'Supply uncatalogued connection parameters ';
+ $errorMessage.= 'in either the database or DSN arguments, ';
+ $errorMessage.= 'but not both';
- if ($this->debug)
- ADOConnection::outp($errorMessage);
- return null;
- }
+ if ($this->debug)
+ ADOConnection::outp($errorMessage);
+ return null;
+ }
+ }
- if (preg_match('/database=/i',$argDSN))
- {
- if ($argDatabasename)
- {
- $argDatabasename = '';
- if ($this->debug)
- {
- $errorMessage = 'Warning: Because you provided ';
- $errorMessage.= 'database information in the DSN ';
- $errorMessage.= 'parameters, the supplied database ';
- $errorMessage.= 'name was discarded';
- ADOConnection::outp($errorMessage);
- }
- }
- $useCataloguedConnection = false;
+ if (!$this->isDsn($argDSN) && $this->isDsn($argDatabasename))
+ {
+ /*
+ * Switch them around for next test
+ */
+ $temp = $argDSN;
+ $argDsn = $argDatabasename;
+ $argDatabasenME = $temp;
+ }
- }
- elseif ($argDatabasename)
- {
- $this->database = $argDatabasename;
- $argDSN .= ';database=' . $argDatabasename;
- $argDatabasename = '';
- $useCataloguedConnection = false;
+ if ($this->isDsn($argDSN))
+ {
- }
- else
- {
- $errorMessage = 'Uncatalogued connection parameters ';
- $errorMessage.= 'must contain a database= argument';
+ if (!preg_match('/uid=/i',$argDSN)
+ || !preg_match('/pwd=/i',$argDSN))
+ {
+ $errorMessage = 'For uncatalogued connections, provide ';
+ $errorMessage.= 'both UID and PWD in the connection string';
- if ($this->debug)
- ADOConnection::outp($errorMessage);
- return null;
- }
- }
+ if ($this->debug)
+ ADOConnection::outp($errorMessage);
+ return null;
+ }
- if ($argDSN && !$argDatabasename && $useCataloguedConnection)
- {
- $argDatabasename = $argDSN;
- $argDSN = '';
- }
+ if (preg_match('/database=/i',$argDSN))
+ {
+ if ($argDatabasename)
+ {
+ $argDatabasename = '';
+ if ($this->debug)
+ {
+ $errorMessage = 'Warning: Because you provided ';
+ $errorMessage.= 'database information in the DSN ';
+ $errorMessage.= 'parameters, the supplied database ';
+ $errorMessage.= 'name was discarded';
+ ADOConnection::outp($errorMessage);
+ }
+ }
+ $useCataloguedConnection = false;
+ }
+ elseif ($argDatabasename)
+ {
+ $this->database = $argDatabasename;
+ $argDSN .= ';database=' . $argDatabasename;
+ $argDatabasename = '';
+ $useCataloguedConnection = false;
- if ($useCataloguedConnection
- && (!$argDatabasename
- || !$argUsername
- || !$argPassword))
- {
+ }
+ else
+ {
+ $errorMessage = 'Uncatalogued connection parameters ';
+ $errorMessage.= 'must contain a database= argument';
- $errorMessage = 'For catalogued connections, provide ';
- $errorMessage.= 'database, username and password';
- $this->_errorMsg = $errorMessage;
- if ($this->debug)
- ADOConnection::outp($errorMessage);
- return null;
+ if ($this->debug)
+ ADOConnection::outp($errorMessage);
+ return null;
+ }
+ }
- }
+ if ($argDSN && !$argDatabasename && $useCataloguedConnection)
+ {
+ $argDatabasename = $argDSN;
+ $argDSN = '';
+ }
- if ($argDatabasename)
- $this->database = $argDatabasename;
- elseif (!$this->database)
- $this->database = $this->getDatabasenameFromDsn($argDSN);
+ if ($useCataloguedConnection
+ && (!$argDatabasename
+ || !$argUsername
+ || !$argPassword))
+ {
- $connectionParameters = array('dsn'=>$argDSN,
- 'uid'=>$argUsername,
- 'pwd'=>$argPassword,
- 'database'=>$argDatabasename,
- 'catalogue'=>$useCataloguedConnection
- );
+ $errorMessage = 'For catalogued connections, provide ';
+ $errorMessage.= 'database, username and password';
+ $this->_errorMsg = $errorMessage;
+ if ($this->debug)
+ ADOConnection::outp($errorMessage);
+ return null;
- return $connectionParameters;
+ }
- }
+ if ($argDatabasename)
+ $this->database = $argDatabasename;
+ elseif (!$this->database)
+ $this->database = $this->getDatabasenameFromDsn($argDSN);
- /**
- * Does the provided string look like a DSN
- *
- * @param string $dsnString
- *
- * @return bool
- */
- private function isDsn($dsnString){
- $dsnArray = preg_split('/[;=]+/',$dsnString);
- if (count($dsnArray) > 2)
- return true;
- return false;
- }
+ $connectionParameters = array('dsn'=>$argDSN,
+ 'uid'=>$argUsername,
+ 'pwd'=>$argPassword,
+ 'database'=>$argDatabasename,
+ 'catalogue'=>$useCataloguedConnection
+ );
- /**
- * Gets the database name from the DSN
- *
- * @param string $dsnString
- *
- * @return string
- */
- private function getDatabasenameFromDsn($dsnString){
+ return $connectionParameters;
- $dsnArray = preg_split('/[;=]+/',$dsnString);
- $dbIndex = array_search('database',$dsnArray);
+ }
- return $dsnArray[$dbIndex + 1];
- }
+ /**
+ * Does the provided string look like a DSN
+ *
+ * @param string $dsnString
+ *
+ * @return bool
+ */
+ private function isDsn($dsnString){
+ $dsnArray = preg_split('/[;=]+/',$dsnString);
+ if (count($dsnArray) > 2)
+ return true;
+ return false;
+ }
- /**
- * format and return date string in database timestamp format
- *
- * @param mixed $ts either a string or a unixtime
- * @param bool $isField discarded
- *
- * @return string
- */
- function dbTimeStamp($ts,$isField=false)
- {
- if (empty($ts) && $ts !== 0) return 'null';
- if (is_string($ts)) $ts = ADORecordSet::unixTimeStamp($ts);
- return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'YYYY-MM-DD HH24:MI:SS')";
- }
+ /**
+ * Gets the database name from the DSN
+ *
+ * @param string $dsnString
+ *
+ * @return string
+ */
+ private function getDatabasenameFromDsn($dsnString){
- /**
- * Format date column in sql string given an input format that understands Y M D
- *
- * @param string $fmt
- * @param bool $col
- *
- * @return string
- */
- function sqlDate($fmt, $col=false)
- {
- if (!$col) $col = $this->sysDate;
+ $dsnArray = preg_split('/[;=]+/',$dsnString);
+ $dbIndex = array_search('database',$dsnArray);
- /* use TO_CHAR() if $fmt is TO_CHAR() allowed fmt */
- if ($fmt== 'Y-m-d H:i:s')
- return 'TO_CHAR('.$col.", 'YYYY-MM-DD HH24:MI:SS')";
+ return $dsnArray[$dbIndex + 1];
+ }
- $s = '';
- $len = strlen($fmt);
- for ($i=0; $i < $len; $i++) {
- if ($s) $s .= $this->concat_operator;
- $ch = $fmt[$i];
- switch($ch) {
- case 'Y':
- case 'y':
- if ($len==1) return "year($col)";
- $s .= "char(year($col))";
- break;
- case 'M':
- if ($len==1) return "monthname($col)";
- $s .= "substr(monthname($col),1,3)";
- break;
- case 'm':
- if ($len==1) return "month($col)";
- $s .= "right(digits(month($col)),2)";
- break;
- case 'D':
- case 'd':
- if ($len==1) return "day($col)";
- $s .= "right(digits(day($col)),2)";
- break;
- case 'H':
- case 'h':
- if ($len==1) return "hour($col)";
- if ($col != $this->sysDate) $s .= "right(digits(hour($col)),2)";
- else $s .= "''";
- break;
- case 'i':
- case 'I':
- if ($len==1) return "minute($col)";
- if ($col != $this->sysDate)
- $s .= "right(digits(minute($col)),2)";
- else $s .= "''";
- break;
- case 'S':
- case 's':
- if ($len==1) return "second($col)";
- if ($col != $this->sysDate)
- $s .= "right(digits(second($col)),2)";
- else $s .= "''";
- break;
- default:
- if ($ch == '\\') {
- $i++;
- $ch = substr($fmt,$i,1);
- }
- $s .= $this->qstr($ch);
- }
- }
- return $s;
- }
+ /**
+ * format and return date string in database timestamp format
+ *
+ * @param mixed $ts either a string or a unixtime
+ * @param bool $isField discarded
+ *
+ * @return string
+ */
+ function dbTimeStamp($ts,$isField=false)
+ {
+ if (empty($ts) && $ts !== 0) return 'null';
+ if (is_string($ts)) $ts = ADORecordSet::unixTimeStamp($ts);
+ return 'TO_DATE('.date($this->fmtTimeStamp,$ts).",'YYYY-MM-DD HH24:MI:SS')";
+ }
+ /**
+ * Format date column in sql string given an input format that understands Y M D
+ *
+ * @param string $fmt The format string e.g. 'm/d/Y'
+ * @param string $col optionally either a column name,an ISO date string or a
+ * ate geerating DB2 function like CURRENT DATE
+ *
+ * @return string
+ */
+ public function sqlDate($fmt, $col=false)
+ {
+ $usesSysDate = false;
+ $trailer = '';
+ $dCol = '';
+ $tCol = '';
+ if (!$col) {
+ /*
+ * If no column is provided, we use the system date or time
+ */
- function serverInfo()
- {
- $sql = "SELECT service_level, fixpack_num
- FROM TABLE(sysproc.env_get_inst_info())
- AS INSTANCEINFO";
- $row = $this->GetRow($sql);
+ $dCol = $this->sysDate;
+ $tCol = $this->sysTime;
+ /*
+ * Anything not from a column needs this
+ */
+ $trailer = 'FROM SYSIBM.SYSDUMMY1';
- if ($row) {
- $info['version'] = $row[0].':'.$row[1];
- $info['fixpack'] = $row[1];
- $info['description'] = '';
- } else {
- return ADOConnection::serverInfo();
- }
+ } else if (preg_match('/(\d{4})-(\d{2})-(\d{2})/',$col)) {
+ /*
+ * If the column is an ISO date string, we use it as is
+ */
+ $trailer = 'FROM SYSIBM.SYSDUMMY1';
+ if (substr($col,0,1) != "'") {
+ $col = $this->qstr($col);
+ }
+ }
- return $info;
- }
+ /* use TO_CHAR() if $fmt is TO_CHAR() allowed fmt */
+ if ($fmt== 'Y-m-d H:i:s')
+ return 'TO_CHAR('.$col.", 'YYYY-MM-DD HH24:MI:SS')";
- function createSequence($seqname='adodbseq',$start=1)
- {
- if (empty($this->_genSeqSQL))
- return false;
+ $s = '';
- $ok = $this->execute(sprintf($this->_genSeqSQL,$seqname,$start));
- if (!$ok)
- return false;
- return true;
- }
+ $len = strlen($fmt);
+ for ($i=0; $i < $len; $i++) {
+ if ($s) {
+ $s .= $this->concat_operator;
+ }
- function dropSequence($seqname='adodbseq')
- {
- if (empty($this->_dropSeqSQL)) return false;
- return $this->execute(sprintf($this->_dropSeqSQL,$seqname));
- }
+ $ch = $fmt[$i];
- function selectLimit($sql,$nrows=-1,$offset=-1,$inputArr=false,$secs2cache=0)
- {
- $nrows = (int) $nrows;
+ switch($ch) {
+ case 'Y':
+ case 'y':
- if ($offset <= 0)
- {
- if ($nrows >= 0)
- $sql .= " FETCH FIRST $nrows ROWS ONLY ";
+ if ($len==1) {
+ return "YEAR($col$dCol) $trailer";
+ }
- $rs = $this->execute($sql,$inputArr);
+ /*
+ * the CHAR creates a CHAR(20) so trim it
+ */
+ $s .= "RTRIM(CHAR(YEAR($col$dCol)))";
- }
- else
- {
- if ($offset > 0 && $nrows < 0);
+ break;
- else
- {
- $nrows += $offset;
- $sql .= " FETCH FIRST $nrows ROWS ONLY ";
- }
+ case 'M':
- /*
- * DB2 has no native support for mid table offset
- */
- $rs = ADOConnection::selectLimit($sql,$nrows,$offset,$inputArr);
+ /*
+ * Returns "January" we want "Jan"
+ */
+ $cmd = "SUBSTR(MONTHNAME($col$dCol),1,3)";
- }
+ if ($len==1) {
+ return "$cmd $trailer";
+ }
+ $s .= $cmd;
- return $rs;
- }
+ break;
+ case 'm':
- function errorMsg()
- {
- if ($this->_errorMsg !== false)
- return $this->_errorMsg;
+ $cmd = "RIGHT(DIGITS(MONTH($col$dCol)),2)";
+ if ($len==1) {
+ return "$cmd $trailer";
+ }
- if (empty($this->_connectionID))
- return @db2_conn_errormsg();
+ $s .= $cmd;
+ break;
- return @db2_conn_errormsg($this->_connectionID);
- }
+ case 'D':
+ case 'd':
- function errorNo()
- {
+ $cmd = "RIGHT(DIGITS(DAY($col$dCol)),2)";
- if ($this->_errorCode !== false)
- return $this->_errorCode;
+ if ($len==1) {
+ return "$cmd $trailer";
+ }
+ $s .= $cmd;
+ break;
- if (empty($this->_connectionID))
- $e = @db2_conn_error();
+ case 'H':
+ case 'h':
- else
- $e = @db2_conn_error($this->_connectionID);
+ $cmd = "RIGHT(DIGITS(HOUR($col$tCol)),2)";
+ if ($len==1) {
+ return "$cmd $trailer";
+ }
- return $e;
- }
+ $s .= $cmd;
+ break;
+ case 'i':
+ case 'I':
- function beginTrans()
- {
- if (!$this->hasTransactions)
- return false;
- if ($this->transOff)
- return true;
+ $cmd = "RIGHT(DIGITS(MINUTE($col$tCol)),2)";
+ if ($len==1) {
+ return "$cmd $trailer";
+ }
- $this->transCnt += 1;
+ $s .= $cmd;
- $this->_autocommit = false;
+ break;
- return db2_autocommit($this->_connectionID,false);
- }
+ case 'S':
+ case 's':
+ $cmd = "RIGHT(DIGITS(SECOND($col$tCol)),2)";
+ if ($len==1) {
+ return "$cmd $trailer";
+ }
- function CommitTrans($ok=true)
- {
- if ($this->transOff)
- return true;
+ $s .= $cmd;
+ break;
- if (!$ok)
- return $this->RollbackTrans();
+ default:
- if ($this->transCnt)
- $this->transCnt -= 1;
+ if ($ch == '\\') {
+ $i++;
+ $ch = substr($fmt, $i, 1);
+ }
- $this->_autocommit = true;
- $ret = @db2_commit($this->_connectionID);
- @db2_autocommit($this->_connectionID,true);
- return $ret;
- }
+ $s .= $this->qstr($ch);
+ }
+ }
- function RollbackTrans()
- {
- if ($this->transOff) return true;
- if ($this->transCnt) $this->transCnt -= 1;
- $this->_autocommit = true;
- $ret = @db2_rollback($this->_connectionID);
- @db2_autocommit($this->_connectionID,true);
- return $ret;
- }
+ $s .= " $trailer";
- /**
- * Return a list of Primary Keys for a specified table
- *
- * We don't use db2_statistics as the function does not seem to play
- * well with mixed case table names
- *
- * @param string $table
- * @param bool $primary (optional) only return primary keys
- * @param bool $owner (optional) not used in this driver
- *
- * @return string[] Array of indexes
- */
- public function metaPrimaryKeys($table,$owner=false)
- {
+ return $s;
+ }
- $primaryKeys = array();
+ /**
+ * Return information about the database server
+ *
+ * @return array
+ */
+ public function serverInfo()
+ {
+ global $ADODB_FETCH_MODE;
+ $savem = $ADODB_FETCH_MODE;
- global $ADODB_FETCH_MODE;
+ $this->setFetchMode(ADODB_FETCH_NUM);
- $schema = '';
- $this->_findschema($table,$schema);
+ $sql = "SELECT service_level, fixpack_num
+ FROM TABLE(sysproc.env_get_inst_info())
+ AS INSTANCEINFO";
+ $row = $this->GetRow($sql);
- $table = $this->getTableCasedValue($table);
+ $this->setFetchMode($savem);
- $savem = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
- $this->setFetchMode(ADODB_FETCH_NUM);
+ if ($row) {
+ $info['version'] = $row[0].':'.$row[1];
+ $info['fixpack'] = $row[1];
+ $info['description'] = '';
+ } else {
+ return ADOConnection::serverInfo();
+ }
+ return $info;
+ }
- $sql = "SELECT *
- FROM syscat.indexes
- WHERE tabname='$table'";
+ /**
+ * Select a limited number of rows.
+ *
+ * @param string $sql The SQL to execute
+ * @param int $nrows Number of rows to get
+ * @param int $offset Row to start calculations from (1-based)
+ * @param array|bool $inputArr Array of bind variables
+ * @param int $secs2cache Private parameter only used by jlim
+ *
+ * @return ADORecordSet The recordset ($rs->databaseType == 'array')
+ */
+ function selectLimit($sql, $nrows=-1, $offset=-1, $inputArr=false, $secs2cache=0)
+ {
+ $nrows = (int) $nrows;
- $rows = $this->getAll($sql);
+ if ($this->useLegacyRowOffsets) {
+ /*
+ * Disables support for OFFSET
+ */
+ if ($offset <= 0) {
+ if ($nrows >= 0)
+ $sql .= " FETCH FIRST $nrows ROWS ONLY ";
- $this->setFetchMode($savem);
- $ADODB_FETCH_MODE = $savem;
+ $rs = $this->execute($sql, $inputArr);
- if (empty($rows))
- return false;
+ } else {
- foreach ($rows as $r)
- {
- if ($r[7] != 'P')
- continue;
+ if ($offset > 0 && $nrows < 0) {
- $cols = explode('+',$r[6]);
- foreach ($cols as $colIndex=>$col)
- {
- if ($colIndex == 0)
- continue;
- $columnName = $this->getMetaCasedValue($col);
- $primaryKeys[] = $columnName;
- }
- break;
- }
- return $primaryKeys;
- }
+ } else {
+ $nrows += $offset;
+ $sql .= " FETCH FIRST $nrows ROWS ONLY ";
+ }
- /**
- * Returns a list of Foreign Keys associated with a specific table.
- *
- * @param string $table
- * @param string $owner discarded
- * @param bool $upper discarded
- * @param bool $associative discarded
- *
- * @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 = '', $upper = false, $associative = false)
- {
+ /*
+ * Disabled DB2 support for mid table offset
+ */
+ $rs = ADOConnection::selectLimit($sql, $nrows, $offset, $inputArr);
- global $ADODB_FETCH_MODE;
+ }
+ } else {
- $schema = '';
- $this->_findschema($table,$schema);
+ $rowString = '';
+ $offsetString = '';
- $savem = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($nrows > 0) {
+ $rowString = sprintf('FETCH FIRST %d ROWS ONLY', $nrows);
+ }
- $this->setFetchMode(ADODB_FETCH_NUM);
+ if ($offset > 0) {
+ $offsetString = sprintf('OFFSET %d ROWS', $offset);
+ }
- $sql = "SELECT SUBSTR(tabname,1,20) table_name,
- SUBSTR(constname,1,20) fk_name,
- SUBSTR(REFTABNAME,1,12) parent_table,
- SUBSTR(refkeyname,1,20) pk_orig_table,
- fk_colnames
- FROM syscat.references
- WHERE tabname = '$table'";
+ $sql = sprintf('%s %s %s', $sql, $offsetString, $rowString);
+ if ($secs2cache) {
+ $rs = $this->cacheExecute($secs2cache, $sql, $inputArr);
+ } else {
+ $rs = $this->execute($sql, $inputArr);
+ }
+ }
- $results = $this->getAll($sql);
+ return $rs;
+ }
- $ADODB_FETCH_MODE = $savem;
- $this->setFetchMode($savem);
- if (empty($results))
- return false;
+ function errorMsg()
+ {
+ if ($this->_errorMsg !== false)
+ return $this->_errorMsg;
- $foreignKeys = array();
+ if (empty($this->_connectionID))
+ return @db2_conn_errormsg();
- foreach ($results as $r)
- {
- $parentTable = trim($this->getMetaCasedValue($r[2]));
- $keyName = trim($this->getMetaCasedValue($r[1]));
- $foreignKeys[$parentTable] = $keyName;
- }
+ return @db2_conn_errormsg($this->_connectionID);
+ }
- return $foreignKeys;
- }
+ function errorNo()
+ {
- /**
- * Returns a list of tables
- *
- * @param string $ttype (optional)
- * @param string $schema (optional)
- * @param string $mask (optional)
- *
- * @return array
- */
- public function metaTables($ttype=false,$schema=false,$mask=false)
- {
+ if ($this->_errorCode !== false)
+ return $this->_errorCode;
- global $ADODB_FETCH_MODE;
- $savem = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if (empty($this->_connectionID))
+ $e = @db2_conn_error();
- /*
- * Values for TABLE_TYPE
- * ---------------------------
- * ALIAS, HIERARCHY TABLE, INOPERATIVE VIEW, NICKNAME,
- * MATERIALIZED QUERY TABLE, SYSTEM TABLE, TABLE,
- * TYPED TABLE, TYPED VIEW, and VIEW
- *
- * If $ttype passed as '', match 'TABLE' and 'VIEW'
- * If $ttype passed as 'T' it is assumed to be 'TABLE'
- * if $ttype passed as 'V' it is assumed to be 'VIEW'
- */
- $ttype = strtoupper($ttype);
- if ($ttype) {
- /*
- * @todo We could do valid type checking or array type
- */
- if ($ttype == 'V')
- $ttype = 'VIEW';
- if ($ttype == 'T')
- $ttype = 'TABLE';
- }
+ else
+ $e = @db2_conn_error($this->_connectionID);
- if (!$schema)
- $schema = '%';
+ return $e;
+ }
- if (!$mask)
- $mask = '%';
- $qid = @db2_tables($this->_connectionID,NULL,$schema,$mask,$ttype);
- $rs = new ADORecordSet_db2($qid);
+ function beginTrans()
+ {
+ if (!$this->hasTransactions)
+ return false;
+ if ($this->transOff)
+ return true;
- $ADODB_FETCH_MODE = $savem;
+ $this->transCnt += 1;
- if (!$rs)
- return false;
+ $this->_autocommit = false;
- $arr = $rs->getArray();
+ return db2_autocommit($this->_connectionID,false);
+ }
- $rs->Close();
+ function CommitTrans($ok=true)
+ {
+ if ($this->transOff)
+ return true;
- $tableList = array();
+ if (!$ok)
+ return $this->RollbackTrans();
- /*
- * Array items
- * ---------------------------------
- * 0 TABLE_CAT The catalog that contains the table.
- * The value is NULL if this table does not have catalogs.
- * 1 TABLE_SCHEM Name of the schema that contains the table.
- * 2 TABLE_NAME Name of the table.
- * 3 TABLE_TYPE Table type identifier for the table.
- * 4 REMARKS Description of the table.
- */
+ if ($this->transCnt)
+ $this->transCnt -= 1;
- for ($i=0; $i < sizeof($arr); $i++)
- {
+ $this->_autocommit = true;
+ $ret = @db2_commit($this->_connectionID);
+ @db2_autocommit($this->_connectionID,true);
+ return $ret;
+ }
- $tableRow = $arr[$i];
- $tableName = $tableRow[2];
- $tableType = $tableRow[3];
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->_autocommit = true;
+ $ret = @db2_rollback($this->_connectionID);
+ @db2_autocommit($this->_connectionID,true);
+ return $ret;
+ }
- if (!$tableName)
- continue;
+ /**
+ * Return a list of Primary Keys for a specified table
+ *
+ * We don't use db2_statistics as the function does not seem to play
+ * well with mixed case table names
+ *
+ * @param string $table
+ * @param bool $primary (optional) only return primary keys
+ * @param bool $owner (optional) not used in this driver
+ *
+ * @return string[] Array of indexes
+ */
+ public function metaPrimaryKeys($table,$owner=false)
+ {
- if ($ttype == '' && (strcmp($tableType,'TABLE') <> 0 && strcmp($tableType,'VIEW') <> 0))
- continue;
+ $primaryKeys = array();
- /*
- * Set metacasing if required
- */
- $tableName = $this->getMetaCasedValue($tableName);
+ global $ADODB_FETCH_MODE;
- /*
- * If we requested a schema, we prepend the schema
- name to the table name
- */
- if (strcmp($schema,'%') <> 0)
- $tableName = $schema . '.' . $tableName;
+ $schema = '';
+ $this->_findschema($table,$schema);
- $tableList[] = $tableName;
+ $table = $this->metaTables('T','',$table);
+ if ($table == false)
+ return false;
- }
- return $tableList;
- }
+ $table = $table[0];
- /**
- * Return a list of indexes for a specified table
- *
- * We don't use db2_statistics as the function does not seem to play
- * well with mixed case table names
- *
- * @param string $table
- * @param bool $primary (optional) only return primary keys
- * @param bool $owner (optional) not used in this driver
- *
- * @return string[] Array of indexes
- */
- public function metaIndexes($table, $primary = false, $owner = false) {
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $this->setFetchMode(ADODB_FETCH_NUM);
- global $ADODB_FETCH_MODE;
- /* Array(
- * [name_of_index] => Array(
- * [unique] => true or false
- * [columns] => Array(
- * [0] => firstcol
- * [1] => nextcol
- * [2] => etc........
- * )
- * )
- * )
- */
- $indices = array();
- $primaryKeyName = '';
+ $sql = "SELECT *
+ FROM SYSCAT.INDEXES
+ WHERE TABNAME='$table'";
- $table = $this->getTableCasedValue($table);
+ $rows = $this->getAll($sql);
+ $this->setFetchMode($savem);
+ $ADODB_FETCH_MODE = $savem;
- $savem = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
- $this->setFetchMode(ADODB_FETCH_NUM);
+ if (empty($rows))
+ return false;
- $sql = "SELECT *
- FROM syscat.indexes
- WHERE tabname='$table'";
+ foreach ($rows as $r)
+ {
+ if ($r[7] != 'P')
+ continue;
- $rows = $this->getAll($sql);
+ $cols = explode('+',$r[6]);
+ foreach ($cols as $colIndex=>$col)
+ {
+ if ($colIndex == 0)
+ continue;
+ $columnName = $this->getMetaCasedValue($col);
+ $primaryKeys[] = $columnName;
+ }
+ break;
+ }
+ return $primaryKeys;
+ }
- $this->setFetchMode($savem);
- $ADODB_FETCH_MODE = $savem;
+ /**
+ * Returns a list of Foreign Keys associated with a specific table.
+ *
+ * @param string $table
+ * @param string $owner discarded
+ * @param bool $upper discarded
+ * @param bool $associative discarded
+ *
+ * @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 = '', $upper = false, $associative = false)
+ {
- if (empty($rows))
- return false;
+ global $ADODB_FETCH_MODE;
- foreach ($rows as $r)
- {
+ $schema = '';
+ $this->_findschema($table,$schema);
- $primaryIndex = $r[7] == 'P'?1:0;
- if (!$primary)
- /*
- * Primary key not requested, ignore that one
- */
- if ($r[7] == 'P')
- continue;
+ $metaTables = $this->metaTables('T','',$table);
- $indexName = $this->getMetaCasedValue($r[1]);
- if (!isset($indices[$indexName]))
- {
- $unique = ($r[7] == 'U')?1:0;
- $indices[$indexName] = array('unique'=>$unique,
- 'primary'=>$primaryIndex,
- 'columns'=>array()
- );
- }
- $cols = explode('+',$r[6]);
- foreach ($cols as $colIndex=>$col)
- {
- if ($colIndex == 0)
- continue;
- $columnName = $this->getMetaCasedValue($col);
- $indices[$indexName]['columns'][] = $columnName;
- }
+ if ($metaTables == false) {
+ return false;
+ }
- }
+ $table = $metaTables[0];
- return $indices;
+ $baseFetchMode = $ADODB_FETCH_MODE;
- }
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
- /**
- * List procedures or functions in an array.
- *
- * We interrogate syscat.routines instead of calling the PHP
- * function procedures because ADOdb requires the type of procedure
- * this is not available in the php function
- *
- * @param string $procedureNamePattern (optional)
- * @param string $catalog (optional)
- * @param string $schemaPattern (optional)
+ $this->setFetchMode(ADODB_FETCH_ASSOC);
+ $sql = "SELECT *
+ FROM syscat.references
+ WHERE tabname = '$table'";
- * @return array of procedures on current database.
- *
- */
- public function metaProcedures($procedureNamePattern = null, $catalog = null, $schemaPattern = null) {
+ $results = $this->getAll($sql);
+ $this->setFetchMode($baseFetchMode);
- global $ADODB_FETCH_MODE;
+ if (empty($results))
+ return false;
- $metaProcedures = array();
- $procedureSQL = '';
- $catalogSQL = '';
- $schemaSQL = '';
+ $foreignKeys = array();
- $savem = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ foreach ($results as $r)
+ {
- if ($procedureNamePattern)
- $procedureSQL = "AND ROUTINENAME LIKE " . strtoupper($this->qstr($procedureNamePattern));
+ /*
- if ($catalog)
- $catalogSQL = "AND OWNER=" . strtoupper($this->qstr($catalog));
+ [CONSTNAME] => SQL250829011849680
+ [TABSCHEMA] => DB2INST1
+ [TABNAME] => TESTTABLE_2
+ [OWNER] => DB2INST1
+ [OWNERTYPE] => U
+ [REFKEYNAME] => SQL250829011847480
+ [REFTABSCHEMA] => DB2INST1
+ [REFTABNAME] => TESTTABLE_1
+ [COLCOUNT] => 1
+ [DELETERULE] => C
+ [UPDATERULE] => A
+ [CREATE_TIME] => 2025-08-29 01:18:49.717630
+ [FK_COLNAMES] => TT_ID
+ [PK_COLNAMES] => ID
+ [DEFINER] => DB2INST1
+ )
+ */
+ $referenceTable = trim($r['REFTABNAME']);
- if ($schemaPattern)
- $schemaSQL = "AND ROUTINESCHEMA LIKE {$this->qstr($schemaPattern)}";
+ if (!array_key_exists($referenceTable,$foreignKeys)) {
+ $foreignKeys[$referenceTable] = array();
+ }
+ $pkColnames = array_filter(preg_split('/ +/', $r['PK_COLNAMES']));
+ $fkColnames = array_filter(preg_split('/ +/', $r['FK_COLNAMES']));
+ foreach ($pkColnames as $i=>$pkColname) {
- $fields = "
- ROUTINENAME,
- CASE ROUTINETYPE
- WHEN 'P' THEN 'PROCEDURE'
- WHEN 'F' THEN 'FUNCTION'
- ELSE 'METHOD'
- END AS ROUTINETYPE_NAME,
- ROUTINESCHEMA,
- REMARKS";
+ $pkColname = trim($pkColname);
+ $fkColname = trim($fkColnames[$i]);
+ if ($baseFetchMode == ADODB_FETCH_ASSOC) {
+ $foreignKeys[$referenceTable][$pkColname] = $fkColname;
+ } else {
+ $foreignKeys[$referenceTable][] = sprintf('%s=%s',$pkColname,$fkColname);
+ }
- $SQL = "SELECT $fields
- FROM syscat.routines
- WHERE OWNER IS NOT NULL
- $procedureSQL
- $catalogSQL
- $schemaSQL
- ORDER BY ROUTINENAME
- ";
+ }
- $result = $this->execute($SQL);
+ }
+ return $foreignKeys;
+ }
- $ADODB_FETCH_MODE = $savem;
+ /**
+ * Returns a list of tables
+ *
+ * @param string $ttype (optional)
+ * @param string $schema (optional)
+ * @param string $mask (optional)
+ *
+ * @return array
+ */
+ public function metaTables($ttype=false,$schema=false,$mask=false)
+ {
- if (!$result)
- return false;
+ global $ADODB_FETCH_MODE;
- while ($r = $result->fetchRow()){
- $procedureName = $this->getMetaCasedValue($r[0]);
- $schemaName = $this->getMetaCasedValue($r[2]);
- $metaProcedures[$procedureName] = array('type'=> $r[1],
- 'catalog' => '',
- 'schema' => $schemaName,
- 'remarks' => $r[3]
- );
- }
+ $savem = $ADODB_FETCH_MODE;
+ $this->SetFetchMode(ADODB_FETCH_ASSOC);
- return $metaProcedures;
+ /*
+ * Values for TABLE_TYPE
+ * ---------------------------
+ * ALIAS, HIERARCHY TABLE, INOPERATIVE VIEW, NICKNAME,
+ * MATERIALIZED QUERY TABLE, SYSTEM TABLE, TABLE,
+ * TYPED TABLE, TYPED VIEW, and VIEW
+ *
+ * If $ttype passed as '', match 'TABLE' and 'VIEW'
+ * If $ttype passed as 'T' it is assumed to be 'TABLE'
+ * if $ttype passed as 'V' it is assumed to be 'VIEW'
+ */
- }
+ $sqlFilters = array();
+ $sqlFilter = '';
+ $returnedColumn = 'TRIM(TABNAME)';
- /**
- * Lists databases. Because instances are independent, we only know about
- * the current database name
- *
- * @return string[]
- */
- public function metaDatabases(){
+ if ($ttype) {
- $dbName = $this->getMetaCasedValue($this->database);
+ /*
+ * We only support 'T' for TABLE and 'V' for VIEW
+ * All types are returned if $ttype is passed as ''
+ */
+ $ttype = strtoupper(substr($ttype,0,1));
- return (array)$dbName;
+ if ($ttype == 'V') {
+ $sqlFilters[] = "TYPE='V'";
+ } else if ($ttype == 'T') {
+ $sqlFilters[] = "TYPE='T'";
+ }
+ }
- }
+ if ($schema && $schema != '%') {
+
+ $schema = strtoupper($schema);
+ $returnedColumn = $this->concat('TRIM(TABSCHEMA)',"'.'",'TRIM(TABNAME)');
+
+ if (strpos($schema,'%') !== false) {
+ $sqlFilters[] = "UPPER(TABSCHEMA) LIKE '$schema'";
+ } else {
+ $sqlFilters[] = "UPPER(TABSCHEMA)='" . strtoupper($schema) . "'";
+ }
+ }
+
+ if ($mask) {
+ /*
+ * Mask is SQL LIKE format. We match on upper case
+ * unless the match is quoted in which case we match
+ * exactly
+ */
+
+ if (in_array(substr($mask,0,1),array('"','[')))
+ {
+ if (strpos($mask,'%') !== false)
+ {
+ $sqlFilters[] = "TABNAME LIKE '$mask'";
+ } else {
+ $sqlFilters[] = "TABNAME='$mask'";
+ }
+ } else {
+ $mask = strtoupper($mask);
+ if (strpos($mask,'%') !== false) {
+ $sqlFilters[] = "UPPER(TABNAME) LIKE '$mask'";
+ } else {
+ $sqlFilters[] = "UPPER(TABNAME)='$mask'";
+ }
+ }
+ }
+
+ if (count($sqlFilters) > 0) {
+ $sqlFilter = 'WHERE ' . implode(' AND ',$sqlFilters);
+ }
+
+ $sql = "SELECT $returnedColumn FROM SYSCAT.TABLES $sqlFilter ORDER BY TABSCHEMA, TABNAME";
+
+
+ $metaTables = $this->getCol($sql);
+
+ $this->SetFetchMode($savem);
+
+ if (count($metaTables) == 0)
+ return false;
+
+ return $metaTables;
+ }
+
+ /**
+ * Return a list of indexes for a specified table
+ *
+ * We don't use db2_statistics as the function does not seem to play
+ * well with mixed case table names
+ *
+ * @param string $table
+ * @param bool $primary (optional) only return primary keys
+ * @param bool $owner (optional) not used in this driver
+ *
+ * @return string[] Array of indexes
+ */
+ public function metaIndexes($table, $primary = false, $owner = false) {
+
+ global $ADODB_FETCH_MODE;
+
+ /* Array(
+ * [name_of_index] => Array(
+ * [unique] => true or false
+ * [columns] => Array(
+ * [0] => firstcol
+ * [1] => nextcol
+ * [2] => etc........
+ * )
+ * )
+ * )
+ */
+ $indices = array();
+ $primaryKeyName = '';
+
+ $table = $this->getTableCasedValue($table);
+
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $this->setFetchMode(ADODB_FETCH_NUM);
+
+ $sql = "SELECT *
+ FROM syscat.indexes
+ WHERE tabname='$table'";
+
+ $rows = $this->getAll($sql);
+
+ $this->setFetchMode($savem);
+ $ADODB_FETCH_MODE = $savem;
+
+ if (empty($rows))
+ return false;
+
+ foreach ($rows as $r)
+ {
+
+ $primaryIndex = $r[7] == 'P'?1:0;
+ if (!$primary)
+ /*
+ * Primary key not requested, ignore that one
+ */
+ if ($r[7] == 'P')
+ continue;
+
+ $indexName = $this->getMetaCasedValue($r[1]);
+ if (!isset($indices[$indexName]))
+ {
+ $unique = ($r[7] == 'U')?1:0;
+ $indices[$indexName] = array('unique'=>$unique,
+ 'primary'=>$primaryIndex,
+ 'columns'=>array()
+ );
+ }
+ $cols = explode('+',$r[6]);
+ foreach ($cols as $colIndex=>$col)
+ {
+ if ($colIndex == 0)
+ continue;
+ $columnName = $this->getMetaCasedValue($col);
+ $indices[$indexName]['columns'][] = $columnName;
+ }
+
+ }
+
+ return $indices;
+
+ }
+
+ /**
+ * List procedures or functions in an array.
+ *
+ * We interrogate syscat.routines instead of calling the PHP
+ * function procedures because ADOdb requires the type of procedure
+ * this is not available in the php function
+ *
+ * @param string $procedureNamePattern (optional)
+ * @param string $catalog (optional)
+ * @param string $schemaPattern (optional)
+
+ * @return array of procedures on current database.
+ *
+ */
+ public function metaProcedures($procedureNamePattern = null, $catalog = null, $schemaPattern = null) {
+
+
+ global $ADODB_FETCH_MODE;
+
+ $metaProcedures = array();
+ $procedureSQL = '';
+ $catalogSQL = '';
+ $schemaSQL = '';
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+
+ if ($procedureNamePattern)
+ $procedureSQL = "AND ROUTINENAME LIKE " . strtoupper($this->qstr($procedureNamePattern));
+
+ if ($catalog)
+ $catalogSQL = "AND OWNER=" . strtoupper($this->qstr($catalog));
+
+ if ($schemaPattern)
+ $schemaSQL = "AND ROUTINESCHEMA LIKE {$this->qstr($schemaPattern)}";
+
+
+ $fields = "
+ ROUTINENAME,
+ CASE ROUTINETYPE
+ WHEN 'P' THEN 'PROCEDURE'
+ WHEN 'F' THEN 'FUNCTION'
+ ELSE 'METHOD'
+ END AS ROUTINETYPE_NAME,
+ ROUTINESCHEMA,
+ REMARKS";
+
+ $SQL = "SELECT $fields
+ FROM syscat.routines
+ WHERE OWNER IS NOT NULL
+ $procedureSQL
+ $catalogSQL
+ $schemaSQL
+ ORDER BY ROUTINENAME
+ ";
+
+ $result = $this->execute($SQL);
+
+ $ADODB_FETCH_MODE = $savem;
+
+ if (!$result)
+ return false;
+
+ while ($r = $result->fetchRow()){
+ $procedureName = $this->getMetaCasedValue($r[0]);
+ $schemaName = $this->getMetaCasedValue($r[2]);
+ $metaProcedures[$procedureName] = array('type'=> $r[1],
+ 'catalog' => '',
+ 'schema' => $schemaName,
+ 'remarks' => $r[3]
+ );
+ }
+
+ return $metaProcedures;
+
+ }
+
+ /**
+ * Lists databases. Because instances are independent, we only know about
+ * the current database name
+ *
+ * @return string[]
+ */
+ public function metaDatabases(){
+
+ $dbName = $this->getMetaCasedValue($this->database);
+
+ return (array)$dbName;
+
+ }
@@ -1057,965 +1232,998 @@ See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/db2/htm/db2
#define SQL_UNICODE_VARCHAR (-96)
#define SQL_UNICODE_LONGVARCHAR (-97)
*/
- function DB2Types($t)
- {
- switch ((int)$t) {
- case 1:
- case 12:
- case 0:
- case -95:
- case -96:
- return 'C';
- case -97:
- case -1: //text
- return 'X';
- case -4: //image
- return 'B';
+ function DB2Types($t)
+ {
+ switch ((int)$t) {
+ case 1:
+ case 12:
+ case 0:
+ case -95:
+ case -96:
+ return 'C';
+ case -97:
+ case -1: //text
+ return 'X';
+ case -4: //image
+ return 'B';
+
+ case 9:
+ case 91:
+ return 'D';
+
+ case 10:
+ case 11:
+ case 92:
+ case 93:
+ return 'T';
- case 9:
- case 91:
- return 'D';
+ case 4:
+ case 5:
+ case -6:
+ return 'I';
- case 10:
- case 11:
- case 92:
- case 93:
- return 'T';
+ case -11: // uniqidentifier
+ return 'R';
+ case -7: //bit
+ return 'L';
- case 4:
- case 5:
- case -6:
- return 'I';
+ default:
+ return 'N';
+ }
+ }
- case -11: // uniqidentifier
- return 'R';
- case -7: //bit
- return 'L';
+ public function metaColumns($table, $ignored=true)
+ {
+ global $ADODB_FETCH_MODE;
- default:
- return 'N';
- }
- }
+ $schema = '%';
+ $this->_findschema($table,$schema);
- public function metaColumns($table, $normalize=true)
- {
- global $ADODB_FETCH_MODE;
+ $findMatchingTable = $this->metaTables('T','',$table);
- $savem = $ADODB_FETCH_MODE;
+ if ($findMatchingTable === false)
+ return false;
- $schema = '%';
- $this->_findschema($table,$schema);
- $table = $this->getTableCasedValue($table);
- $colname = "%";
- $qid = db2_columns($this->_connectionID, null, $schema, $table, $colname);
- if (empty($qid))
- {
- if ($this->debug)
- {
- $errorMessage = @db2_conn_errormsg($this->_connectionID);
- ADOConnection::outp($errorMessage);
- }
- return false;
- }
+ $table = $findMatchingTable[0];
- $rs = new ADORecordSet_db2($qid);
+ $savem = $ADODB_FETCH_MODE;
+ $this->setFetchMode(ADODB_FETCH_NUM);
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
- if (!$rs)
- return false;
+ /*
+ * The returned table name has the correct casing
+ */
- $rs->_fetch();
+ //$table = $this->getTableCasedValue($table);
+ $colname = "%";
+ $qid = db2_columns($this->_connectionID, null, $schema, $table, $colname);
+ if (empty($qid))
+ {
+ if ($this->debug)
+ {
+ $errorMessage = @db2_conn_errormsg($this->_connectionID);
+ ADOConnection::outp($errorMessage);
+ }
+ return false;
+ }
- $retarr = array();
+ $rs = new ADORecordSet_db2($qid);
- /*
- $rs->fields indices
- 0 TABLE_QUALIFIER
- 1 TABLE_SCHEM
- 2 TABLE_NAME
- 3 COLUMN_NAME
- 4 DATA_TYPE
- 5 TYPE_NAME
- 6 PRECISION
- 7 LENGTH
- 8 SCALE
- 9 RADIX
- 10 NULLABLE
- 11 REMARKS
- 12 Column Default
- 13 SQL Data Type
- 14 SQL DateTime SubType
- 15 Max length in Octets
- 16 Ordinal Position
- 17 Is NULLABLE
- */
- while (!$rs->EOF)
- {
- if ($rs->fields[2] == $table)
- {
+ if (!$rs)
+ return false;
- $fld = new ADOFieldObject();
- $fld->name = $rs->fields[3];
- $fld->type = $this->DB2Types($rs->fields[4]);
+ $rs->_fetch();
- // ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp
- // access uses precision to store length for char/varchar
+ $retarr = array();
- if ($fld->type == 'C' or $fld->type == 'X') {
- if ($rs->fields[4] <= -95) // UNICODE
- $fld->max_length = $rs->fields[7]/2;
- else
- $fld->max_length = $rs->fields[7];
- } else
- $fld->max_length = $rs->fields[7];
+ /*
+ $rs->fields indices
+ 0 TABLE_QUALIFIER
+ 1 TABLE_SCHEM
+ 2 TABLE_NAME
+ 3 COLUMN_NAME
+ 4 DATA_TYPE
+ 5 TYPE_NAME
+ 6 PRECISION
+ 7 LENGTH
+ 8 SCALE
+ 9 RADIX
+ 10 NULLABLE
+ 11 REMARKS
+ 12 Column Default
+ 13 SQL Data Type
+ 14 SQL DateTime SubType
+ 15 Max length in Octets
+ 16 Ordinal Position
+ 17 Is NULLABLE
+ */
+ while (!$rs->EOF)
+ {
- $fld->not_null = !empty($rs->fields[10]);
- $fld->scale = $rs->fields[8];
- $fld->primary_key = false;
+ if ($rs->fields[2] == $table)
+ {
- //$columnName = $this->getMetaCasedValue($fld->name);
- $columnName = strtoupper($fld->name);
- $retarr[$columnName] = $fld;
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[3];
+ $fld->type = $this->DB2Types($rs->fields[4]);
- }
- else if (sizeof($retarr)>0)
- break;
+ // ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp
+ // access uses precision to store length for char/varchar
- $rs->MoveNext();
+ if ($fld->type == 'C' or $fld->type == 'X') {
+ if ($rs->fields[4] <= -95) // UNICODE
+ $fld->max_length = $rs->fields[7]/2;
+ else
+ $fld->max_length = $rs->fields[7];
+ } else
+ $fld->max_length = $rs->fields[7];
- }
+ $fld->not_null = !empty($rs->fields[10]);
+ $fld->scale = $rs->fields[8];
+ $fld->primary_key = 0;
- $rs->Close();
- if (empty($retarr))
- $retarr = false;
+ //$columnName = $this->getMetaCasedValue($fld->name);
+ $columnName = strtoupper($fld->name);
+ $retarr[$columnName] = $fld;
- /*
- * Now we find out if the column is part of a primary key
- */
+ }
+ else if (sizeof($retarr)>0)
+ break;
- $qid = @db2_primary_keys($this->_connectionID, "", $schema, $table);
- if (empty($qid))
- return false;
+ $rs->MoveNext();
- $rs = new ADORecordSet_db2($qid);
+ }
- if (!$rs)
- {
- $ADODB_FETCH_MODE = $savem;
- return $retarr;
- }
- $rs->_fetch();
+ $this->setFetchMode($savem);
- /*
- $rs->fields indices
- 0 TABLE_CAT
- 1 TABLE_SCHEM
- 2 TABLE_NAME
- 3 COLUMN_NAME
- 4 KEY_SEQ
- 5 PK_NAME
- */
- while (!$rs->EOF) {
- if (strtoupper(trim($rs->fields[2])) == $table
- && (!$schema || strtoupper($rs->fields[1]) == $schema))
- {
- $retarr[strtoupper($rs->fields[3])]->primary_key = true;
- }
- else if (sizeof($retarr)>0)
- break;
+ $rs->Close();
+ if (empty($retarr))
+ $retarr = false;
- $rs->MoveNext();
- }
- $rs->Close();
- $ADODB_FETCH_MODE = $savem;
+ $this->setFetchMode(ADODB_FETCH_NUM );
- if (empty($retarr))
- return false;
+ /*
+ * Now we find out if the column is part of a primary key
+ */
+ $primaryKeys = $this->metaPrimaryKeys($table);
+ if (!$primaryKeys) {
+ return $retarr;
+ }
- /*
- * If the fetch mode is numeric, return as numeric array
- */
- if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM)
- $retarr = array_values($retarr);
- return $retarr;
- }
+ foreach ($primaryKeys as $pk)
+ {
+ $pk = strtoupper($pk);
+ if (isset($retarr[$pk])) {
+ $retarr[$pk]->primary_key = true;
+ }
+ }
- /**
- * In this version if prepareSp, we just check to make sure
- * that the name of the stored procedure is correct
- * If true, we returns an array
- * else false
- *
- * @param string $procedureName
- * @param mixed $parameters (not used in db2 connections)
- * @return mixed[]
- */
- function prepareSp($procedureName,$parameters=false) {
+ return $retarr;
- global $ADODB_FETCH_MODE;
- $this->storedProcedureParameters = array('name'=>'',
- 'resource'=>false,
- 'in'=>array(),
- 'out'=>array(),
- 'index'=>array(),
- 'parameters'=>array(),
- 'keyvalue' => array());
- //$procedureName = strtoupper($procedureName);
- //$procedureName = $this->getTableCasedValue($procedureName);
+ $qid = @db2_primary_keys($this->_connectionID, "", $schema, $table);
+ if (empty($qid))
+ return false;
- $savem = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $rs = new ADORecordSet_db2($qid);
- $qid = db2_procedures($this->_connectionID, NULL , '%' , $procedureName );
+ if (!$rs)
+ {
+ $ADODB_FETCH_MODE = $savem;
+ return $retarr;
+ }
+ $rs->_fetch();
- $ADODB_FETCH_MODE = $savem;
+ /*
+ $rs->fields indices
+ 0 TABLE_CAT
+ 1 TABLE_SCHEM
+ 2 TABLE_NAME
+ 3 COLUMN_NAME
+ 4 KEY_SEQ
+ 5 PK_NAME
+ */
+ while (!$rs->EOF) {
- if (!$qid)
- {
- if ($this->debug)
- ADOConnection::outp(sprintf('No Procedure of name %s available',$procedureName));
- return false;
- }
+ if (strtoupper(trim($rs->fields[2])) == $table
+ && (!$schema || strtoupper($rs->fields[1]) == $schema))
+ {
+ $retarr[strtoupper($rs->fields[3])]->primary_key = true;
+ }
+ else if (sizeof($retarr)>0)
+ break;
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ $ADODB_FETCH_MODE = $savem;
- $this->storedProcedureParameters['name'] = $procedureName;
- /*
- * Now we know we have a valid procedure name, lets see if it requires
- * parameters
- */
- $savem = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if (empty($retarr))
+ return false;
- $qid = db2_procedure_columns($this->_connectionID, NULL , '%' , $procedureName , NULL );
+ /*
+ * If the fetch mode is numeric, return as numeric array
+ */
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM)
+ $retarr = array_values($retarr);
- $ADODB_FETCH_MODE = $savem;
+ return $retarr;
+ }
- if (!$qid)
- {
- if ($this->debug)
- ADOConnection::outp(sprintf('No columns of name %s available',$procedureName));
- return false;
- }
- $rs = new ADORecordSet_db2($qid);
- if (!$rs)
- return false;
+ /**
+ * In this version if prepareSp, we just check to make sure
+ * that the name of the stored procedure is correct
+ * If true, we returns an array
+ * else false
+ *
+ * @param string $procedureName
+ * @param mixed $parameters (not used in db2 connections)
+ * @return mixed[]
+ */
+ function prepareSp($procedureName,$parameters=false) {
- $preparedStatement = 'CALL %s(%s)';
- $parameterMarkers = array();
- while (!$rs->EOF)
- {
- $parameterName = $rs->fields[3];
- if ($parameterName == '')
- {
- $rs->moveNext();
- continue;
- }
- $parameterType = $rs->fields[4];
- $ordinalPosition = $rs->fields[17];
- switch($parameterType)
- {
- case DB2_PARAM_IN:
- case DB2_PARAM_INOUT:
- $this->storedProcedureParameters['in'][$parameterName] = '';
- break;
- case DB2_PARAM_INOUT:
- case DB2_PARAM_OUT:
- $this->storedProcedureParameters['out'][$parameterName] = '';
- break;
- }
- $this->storedProcedureParameters['index'][$parameterName] = $ordinalPosition;
- $this->storedProcedureParameters['parameters'][$ordinalPosition] = $rs->fields;
- $rs->moveNext();
+ global $ADODB_FETCH_MODE;
- }
- $parameterCount = count($this->storedProcedureParameters['index']);
- $parameterMarkers = array_fill(0,$parameterCount,'?');
+ $this->storedProcedureParameters = array('name'=>'',
+ 'resource'=>false,
+ 'in'=>array(),
+ 'out'=>array(),
+ 'index'=>array(),
+ 'parameters'=>array(),
+ 'keyvalue' => array());
- /*
- * We now know how many parameters to bind to the stored procedure
- */
- $parameterList = implode(',',$parameterMarkers);
+ //$procedureName = strtoupper($procedureName);
+ //$procedureName = $this->getTableCasedValue($procedureName);
- $sql = sprintf($preparedStatement,$procedureName,$parameterList);
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
- $spResource = @db2_prepare($this->_connectionID,$sql);
+ $qid = db2_procedures($this->_connectionID, NULL , '%' , $procedureName );
- if (!$spResource)
- {
- $errorMessage = @db2_conn_errormsg($this->_connectionID);
- $this->_errorMsg = $errorMessage;
+ $ADODB_FETCH_MODE = $savem;
- if ($this->debug)
- ADOConnection::outp($errorMessage);
+ if (!$qid)
+ {
+ if ($this->debug)
+ ADOConnection::outp(sprintf('No Procedure of name %s available',$procedureName));
+ return false;
+ }
- return false;
- }
- $this->storedProcedureParameters['resource'] = $spResource;
- if ($this->debug)
- {
+ $this->storedProcedureParameters['name'] = $procedureName;
+ /*
+ * Now we know we have a valid procedure name, lets see if it requires
+ * parameters
+ */
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
- ADOConnection::outp('The following parameters will be used in the SP call');
- ADOConnection::outp(print_r($this->storedProcedureParameters));
- }
- /*
- * We now have a stored parameter resource
- * to bind to. The spResource and sql that is returned are
- * not usable, its for dummy compatibility. Everything
- * will be handled by the storedProcedureParameters
- * array
- */
- return array($sql,$spResource);
+ $qid = db2_procedure_columns($this->_connectionID, NULL , '%' , $procedureName , NULL );
- }
+ $ADODB_FETCH_MODE = $savem;
- private function storedProcedureParameter(&$stmt,
- &$var,
- $name,
- $isOutput=false,
- $maxLen=4000,
- $type=false)
- {
+ if (!$qid)
+ {
+ if ($this->debug)
+ ADOConnection::outp(sprintf('No columns of name %s available',$procedureName));
+ return false;
+ }
+ $rs = new ADORecordSet_db2($qid);
+ if (!$rs)
+ return false;
+ $preparedStatement = 'CALL %s(%s)';
+ $parameterMarkers = array();
+ while (!$rs->EOF)
+ {
+ $parameterName = $rs->fields[3];
+ if ($parameterName == '')
+ {
+ $rs->moveNext();
+ continue;
+ }
+ $parameterType = $rs->fields[4];
+ $ordinalPosition = $rs->fields[17];
+ switch($parameterType)
+ {
+ case DB2_PARAM_IN:
+ case DB2_PARAM_INOUT:
+ $this->storedProcedureParameters['in'][$parameterName] = '';
+ break;
+ case DB2_PARAM_INOUT:
+ case DB2_PARAM_OUT:
+ $this->storedProcedureParameters['out'][$parameterName] = '';
+ break;
+ }
+ $this->storedProcedureParameters['index'][$parameterName] = $ordinalPosition;
+ $this->storedProcedureParameters['parameters'][$ordinalPosition] = $rs->fields;
+ $rs->moveNext();
- $name = strtoupper($name);
+ }
+ $parameterCount = count($this->storedProcedureParameters['index']);
+ $parameterMarkers = array_fill(0,$parameterCount,'?');
- /*
- * Must exist in the list of parameter names for the type
- */
- if ($isOutput
- && !isset( $this->storedProcedureParameters['out'][$name]))
- {
- $errorMessage = sprintf('%s is not a valid OUT parameter name',$name);
+ /*
+ * We now know how many parameters to bind to the stored procedure
+ */
+ $parameterList = implode(',',$parameterMarkers);
- $this->_errorMsg = $errorMessage;
- if ($this->debug)
- ADOConnection::outp($errorMessage);
- return false;
- }
+ $sql = sprintf($preparedStatement,$procedureName,$parameterList);
- if (!$isOutput
- && !isset( $this->storedProcedureParameters['in'][$name]))
- {
- $errorMessage = sprintf('%s is not a valid IN parameter name',$name);
+ $spResource = @db2_prepare($this->_connectionID,$sql);
- $this->_errorMsg = $errorMessage;
- if ($this->debug)
- ADOConnection::outp($errorMessage);
- return false;
- }
+ if (!$spResource)
+ {
+ $errorMessage = @db2_conn_errormsg($this->_connectionID);
+ $this->_errorMsg = $errorMessage;
- /*
- * We will use these values to bind to when we execute
- * the query
- */
- $this->storedProcedureParameters['keyvalue'][$name] = &$var;
+ if ($this->debug)
+ ADOConnection::outp($errorMessage);
- return true;
+ return false;
+ }
- }
+ $this->storedProcedureParameters['resource'] = $spResource;
- /**
- * Executes a prepared stored procedure.
- *
- * The function uses the previously accumulated information and
- * resources in the $storedProcedureParameters array
- *
- * @return mixed The statement id if successful, or false
- */
- private function executeStoredProcedure()
- {
+ if ($this->debug)
+ {
- /*
- * Get the previously built resource
- */
- $stmtid = $this->storedProcedureParameters['resource'];
+ ADOConnection::outp('The following parameters will be used in the SP call');
+ ADOConnection::outp(print_r($this->storedProcedureParameters));
+ }
+ /*
+ * We now have a stored parameter resource
+ * to bind to. The spResource and sql that is returned are
+ * not usable, its for dummy compatibility. Everything
+ * will be handled by the storedProcedureParameters
+ * array
+ */
+ return array($sql,$spResource);
- /*
- * Bind our variables to the DB2 procedure
- */
- foreach ($this->storedProcedureParameters['keyvalue'] as $spName=>$spValue){
+ }
- /*
- * Get the ordinal position, required for binding
- */
- $ordinalPosition = $this->storedProcedureParameters['index'][$spName];
+ private function storedProcedureParameter(&$stmt,
+ &$var,
+ $name,
+ $isOutput=false,
+ $maxLen=4000,
+ $type=false)
+ {
- /*
- * Get the db2 column dictionary for the parameter
- */
- $columnDictionary = $this->storedProcedureParameters['parameters'][$ordinalPosition];
- $parameterType = $columnDictionary[4];
- $dataType = $columnDictionary[5];
- $precision = $columnDictionary[10];
- $scale = $columnDictionary[9];
- $ok = @db2_bind_param ($this->storedProcedureParameters['resource'],
- $ordinalPosition ,
- $spName,
- $parameterType,
- $dataType,
- $precision,
- $scale
- );
+ $name = strtoupper($name);
- if (!$ok)
- {
- $this->_errorMsg = @db2_stmt_errormsg();
- $this->_errorCode = @db2_stmt_error();
+ /*
+ * Must exist in the list of parameter names for the type
+ */
+ if ($isOutput
+ && !isset( $this->storedProcedureParameters['out'][$name]))
+ {
+ $errorMessage = sprintf('%s is not a valid OUT parameter name',$name);
- if ($this->debug)
- ADOConnection::outp($this->_errorMsg);
- return false;
- }
+ $this->_errorMsg = $errorMessage;
+ if ($this->debug)
+ ADOConnection::outp($errorMessage);
+ return false;
+ }
- if ($this->debug)
- ADOConnection::outp("Correctly Bound parameter $spName to procedure");
+ if (!$isOutput
+ && !isset( $this->storedProcedureParameters['in'][$name]))
+ {
+ $errorMessage = sprintf('%s is not a valid IN parameter name',$name);
- /*
- * Build a variable in the current environment that matches
- * the parameter name
- */
- ${$spName} = $spValue;
+ $this->_errorMsg = $errorMessage;
+ if ($this->debug)
+ ADOConnection::outp($errorMessage);
+ return false;
+ }
- }
+ /*
+ * We will use these values to bind to when we execute
+ * the query
+ */
+ $this->storedProcedureParameters['keyvalue'][$name] = &$var;
- /*
- * All bound, execute
- */
+ return true;
- if (!@db2_execute($stmtid))
- {
- $this->_errorMsg = @db2_stmt_errormsg();
- $this->_errorCode = @db2_stmt_error();
+ }
- if ($this->debug)
- ADOConnection::outp($this->_errorMsg);
- return false;
- }
+ /**
+ * Executes a prepared stored procedure.
+ *
+ * The function uses the previously accumulated information and
+ * resources in the $storedProcedureParameters array
+ *
+ * @return mixed The statement id if successful, or false
+ */
+ private function executeStoredProcedure()
+ {
- /*
- * We now take the changed parameters back into the
- * stored procedures array where we can query them later
- * Remember that $spValue was passed in by reference, so we
- * can access the value in the variable that was originally
- * passed to inParameter or outParameter
- */
- foreach ($this->storedProcedureParameters['keyvalue'] as $spName=>$spValue)
- {
- /*
- * We make it available to the environment
- */
- $spValue = ${$spName};
- $this->storedProcedureParameters['keyvalue'][$spName] = $spValue;
- }
+ /*
+ * Get the previously built resource
+ */
+ $stmtid = $this->storedProcedureParameters['resource'];
- return $stmtid;
- }
+ /*
+ * Bind our variables to the DB2 procedure
+ */
+ foreach ($this->storedProcedureParameters['keyvalue'] as $spName=>$spValue){
- /**
- *
- * Accepts an input or output parameter to bind to either a stored
- * or prepared statements. For DB2, this should not be called as an
- * API. always wrap with inParameter and outParameter
- *
- * @param mixed[] $stmt Statement returned by Prepare() or PrepareSP().
- * @param mixed $var PHP variable to bind to. Can set to null (for isNull support).
- * @param string $name Name of stored procedure variable name to bind to.
- * @param int $isOutput optional) Indicates direction of parameter
- * 0/false=IN 1=OUT 2= IN/OUT
- * This is ignored for Stored Procedures
- * @param int $maxLen (optional)Holds an maximum length of the variable.
- * This is ignored for Stored Procedures
- * @param int $type (optional) The data type of $var.
- * This is ignored for Stored Procedures
- *
- * @return bool Success of the operation
- */
- public function parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=4000, $type=false)
- {
+ /*
+ * Get the ordinal position, required for binding
+ */
+ $ordinalPosition = $this->storedProcedureParameters['index'][$spName];
- /*
- * If the $stmt is the name of a stored procedure we are
- * setting up, we will process it one way, otherwise
- * we assume we are setting up a prepared statement
- */
- if (is_array($stmt))
- {
- if ($this->debug)
- ADOConnection::outp("Adding parameter to stored procedure");
- if ($stmt[1] == $this->storedProcedureParameters['resource'])
- return $this->storedProcedureParameter($stmt[1],
- $var,
- $name,
- $isOutput,
- $maxLen,
- $type);
+ /*
+ * Get the db2 column dictionary for the parameter
+ */
+ $columnDictionary = $this->storedProcedureParameters['parameters'][$ordinalPosition];
+ $parameterType = $columnDictionary[4];
+ $dataType = $columnDictionary[5];
+ $precision = $columnDictionary[10];
+ $scale = $columnDictionary[9];
- }
+ $ok = @db2_bind_param ($this->storedProcedureParameters['resource'],
+ $ordinalPosition ,
+ $spName,
+ $parameterType,
+ $dataType,
+ $precision,
+ $scale
+ );
- /*
- * We are going to add a parameter to a prepared statement
- */
- if ($this->debug)
- ADOConnection::outp("Adding parameter to prepared statement");
- }
+ if (!$ok)
+ {
+ $this->_errorMsg = @db2_stmt_errormsg();
+ $this->_errorCode = @db2_stmt_error();
+ if ($this->debug)
+ ADOConnection::outp($this->_errorMsg);
+ return false;
+ }
- /**
- * Prepares a prepared SQL statement, not used for stored procedures
- *
- * @param string $sql
- *
- * @return mixed
- */
- function prepare($sql)
- {
+ if ($this->debug)
+ ADOConnection::outp("Correctly Bound parameter $spName to procedure");
- if (! $this->_bindInputArray) return $sql; // no binding
+ /*
+ * Build a variable in the current environment that matches
+ * the parameter name
+ */
+ ${$spName} = $spValue;
- $stmt = @db2_prepare($this->_connectionID,$sql);
- if (!$stmt) {
- // we don't know whether db2 driver is parsing prepared stmts, so just return sql
- return $sql;
- }
- return array($sql,$stmt,false);
- }
+ }
- /**
- * Executes a query
- *
- * @param mixed $sql
- * @param mixed $inputarr An optional array of parameters
- *
- * @return mixed either the queryID or false
- */
- function _query($sql, $inputarr = false)
- {
- $db2Options = array();
- /*
- * Use DB2 Internal case handling for best speed
- */
- switch(ADODB_ASSOC_CASE)
- {
- case ADODB_ASSOC_CASE_UPPER:
- $db2Options = array('db2_attr_case'=>DB2_CASE_UPPER);
- $setOption = @db2_set_option($this->_connectionID,$db2Options,1);
- break;
+ /*
+ * All bound, execute
+ */
- case ADODB_ASSOC_CASE_LOWER:
- $db2Options = array('db2_attr_case'=>DB2_CASE_LOWER);
- $setOption = @db2_set_option($this->_connectionID,$db2Options,1);
- break;
+ if (!@db2_execute($stmtid))
+ {
+ $this->_errorMsg = @db2_stmt_errormsg();
+ $this->_errorCode = @db2_stmt_error();
- default:
- $db2Options = array('db2_attr_case'=>DB2_CASE_NATURAL);
- $setOption = @db2_set_option($this->_connectionID,$db2Options,1);
- }
+ if ($this->debug)
+ ADOConnection::outp($this->_errorMsg);
+ return false;
+ }
- if ($inputarr)
- {
- if (is_array($sql))
- {
- $stmtid = $sql[1];
- }
- else
- {
- $stmtid = @db2_prepare($this->_connectionID,$sql);
+ /*
+ * We now take the changed parameters back into the
+ * stored procedures array where we can query them later
+ * Remember that $spValue was passed in by reference, so we
+ * can access the value in the variable that was originally
+ * passed to inParameter or outParameter
+ */
+ foreach ($this->storedProcedureParameters['keyvalue'] as $spName=>$spValue)
+ {
+ /*
+ * We make it available to the environment
+ */
+ $spValue = ${$spName};
+ $this->storedProcedureParameters['keyvalue'][$spName] = $spValue;
+ }
- if ($stmtid == false)
- {
- $this->_errorMsg = @db2_stmt_errormsg();
- $this->_errorCode = @db2_stmt_error();
+ return $stmtid;
+ }
- if ($this->debug)
- ADOConnection::outp($this->_errorMsg);
+ /**
+ *
+ * Accepts an input or output parameter to bind to either a stored
+ * or prepared statements. For DB2, this should not be called as an
+ * API. always wrap with inParameter and outParameter
+ *
+ * @param mixed[] $stmt Statement returned by Prepare() or PrepareSP().
+ * @param mixed $var PHP variable to bind to. Can set to null (for isNull support).
+ * @param string $name Name of stored procedure variable name to bind to.
+ * @param int $isOutput optional) Indicates direction of parameter
+ * 0/false=IN 1=OUT 2= IN/OUT
+ * This is ignored for Stored Procedures
+ * @param int $maxLen (optional)Holds an maximum length of the variable.
+ * This is ignored for Stored Procedures
+ * @param int $type (optional) The data type of $var.
+ * This is ignored for Stored Procedures
+ *
+ * @return bool Success of the operation
+ */
+ public function parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=4000, $type=false)
+ {
- return false;
- }
- }
+ /*
+ * If the $stmt is the name of a stored procedure we are
+ * setting up, we will process it one way, otherwise
+ * we assume we are setting up a prepared statement
+ */
+ if (is_array($stmt))
+ {
+ if ($this->debug)
+ ADOConnection::outp("Adding parameter to stored procedure");
+ if ($stmt[1] == $this->storedProcedureParameters['resource'])
+ return $this->storedProcedureParameter($stmt[1],
+ $var,
+ $name,
+ $isOutput,
+ $maxLen,
+ $type);
- if (! @db2_execute($stmtid,$inputarr))
- {
- $this->_errorMsg = @db2_stmt_errormsg();
- $this->_errorCode = @db2_stmt_error();
- if ($this->debug)
- ADOConnection::outp($this->_errorMsg);
- return false;
- }
+ }
- }
- else if (is_array($sql))
- {
+ /*
+ * We are going to add a parameter to a prepared statement
+ */
+ if ($this->debug)
+ ADOConnection::outp("Adding parameter to prepared statement");
+ }
- /*
- * Either a prepared statement or a stored procedure
- */
- if (is_array($this->storedProcedureParameters)
- && is_resource($this->storedProcedureParameters['resource']
- ))
- /*
- * This is all handled in the separate method for
- * readability
- */
- return $this->executeStoredProcedure();
+ /**
+ * Prepares a prepared SQL statement, not used for stored procedures
+ *
+ * @param string $sql
+ *
+ * @return mixed
+ */
+ function prepare($sql)
+ {
- /*
- * First, we prepare the statement
- */
- $stmtid = @db2_prepare($this->_connectionID,$sql[0]);
- if (!$stmtid){
- $this->_errorMsg = @db2_stmt_errormsg();
- $this->_errorCode = @db2_stmt_error();
- if ($this->debug)
- ADOConnection::outp("Prepare failed: " . $this->_errorMsg);
+ if (! $this->_bindInputArray) return $sql; // no binding
- return false;
- }
- /*
- * We next bind some input parameters
- */
- $ordinal = 1;
- foreach ($sql[1] as $psVar=>$psVal){
- ${$psVar} = $psVal;
- $ok = @db2_bind_param($stmtid, $ordinal, $psVar, DB2_PARAM_IN);
- if (!$ok)
- {
- $this->_errorMsg = @db2_stmt_errormsg();
- $this->_errorCode = @db2_stmt_error();
- if ($this->debug)
- ADOConnection::outp("Bind failed: " . $this->_errorMsg);
- return false;
- }
- }
+ $stmt = @db2_prepare($this->_connectionID,$sql);
+ if (!$stmt) {
+ // we don't know whether db2 driver is parsing prepared stmts, so just return sql
+ return $sql;
+ }
+ return array($sql,$stmt,false);
+ }
- if (!@db2_execute($stmtid))
- {
- $this->_errorMsg = @db2_stmt_errormsg();
- $this->_errorCode = @db2_stmt_error();
- if ($this->debug)
- ADOConnection::outp($this->_errorMsg);
- return false;
- }
+ /**
+ * Executes a query
+ *
+ * @param mixed $sql
+ * @param mixed $inputarr An optional array of parameters
+ *
+ * @return mixed either the queryID or false
+ */
+ function _query($sql, $inputarr = false)
+ {
+ $db2Options = array();
+ /*
+ * Use DB2 Internal case handling for best speed
+ */
+ switch(ADODB_ASSOC_CASE)
+ {
+ case ADODB_ASSOC_CASE_UPPER:
+ $db2Options = array('db2_attr_case'=>DB2_CASE_UPPER);
+ $setOption = @db2_set_option($this->_connectionID,$db2Options,1);
+ break;
- return $stmtid;
- }
- else
- {
+ case ADODB_ASSOC_CASE_LOWER:
+ $db2Options = array('db2_attr_case'=>DB2_CASE_LOWER);
+ $setOption = @db2_set_option($this->_connectionID,$db2Options,1);
+ break;
- $stmtid = @db2_exec($this->_connectionID,$sql);
- }
- $this->_lastAffectedRows = 0;
- if ($stmtid)
- {
- if (@db2_num_fields($stmtid) == 0)
- {
- $this->_lastAffectedRows = db2_num_rows($stmtid);
- $stmtid = true;
- }
- else
- {
- $this->_lastAffectedRows = 0;
- }
+ default:
+ $db2Options = array('db2_attr_case'=>DB2_CASE_NATURAL);
+ $setOption = @db2_set_option($this->_connectionID,$db2Options,1);
+ }
- $this->_errorMsg = '';
- $this->_errorCode = 0;
+ if (!$this->useLegacyRecordCounting) {
+ $db2Options = array('rowcount'=>DB2_ROWCOUNT_PREFETCH_ON);
+ $setOption = @db2_set_option($this->_connectionID,$db2Options,1);
+ }
- }
- else
- {
+ if ($inputarr)
+ {
+ if (is_array($sql))
+ {
+ $stmtid = $sql[1];
+ }
+ else
+ {
+ $stmtid = @db2_prepare($this->_connectionID,$sql);
- $this->_errorMsg = @db2_stmt_errormsg();
- $this->_errorCode = @db2_stmt_error();
+ if ($stmtid == false)
+ {
+ $this->_errorMsg = @db2_stmt_errormsg();
+ $this->_errorCode = @db2_stmt_error();
- }
- return $stmtid;
- }
+ if ($this->debug)
+ ADOConnection::outp($this->_errorMsg);
- /*
- Insert a null into the blob field of the table first.
- Then use UpdateBlob to store the blob.
+ return false;
+ }
+ }
- Usage:
+ if (! @db2_execute($stmtid,$inputarr))
+ {
+ $this->_errorMsg = @db2_stmt_errormsg();
+ $this->_errorCode = @db2_stmt_error();
+ if ($this->debug)
+ ADOConnection::outp($this->_errorMsg);
+ return false;
+ }
- $conn->execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
- $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
- */
- function updateBlob($table,$column,$val,$where,$blobtype='BLOB')
- {
- return $this->execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
- }
+ }
+ else if (is_array($sql))
+ {
- // returns true or false
- function _close()
- {
- $ret = @db2_close($this->_connectionID);
- $this->_connectionID = false;
- return $ret;
- }
+ /*
+ * Either a prepared statement or a stored procedure
+ */
- function _affectedrows()
- {
- return $this->_lastAffectedRows;
- }
+ if (is_array($this->storedProcedureParameters)
+ && is_resource($this->storedProcedureParameters['resource']
+ ))
+ /*
+ * This is all handled in the separate method for
+ * readability
+ */
+ return $this->executeStoredProcedure();
- /**
- * Gets a meta cased parameter
- *
- * Receives an input variable to be processed per the metaCasing
- * rule, and returns the same value, processed
- *
- * @param string $value
- *
- * @return string
- */
- final public function getMetaCasedValue($value)
- {
- global $ADODB_ASSOC_CASE;
+ /*
+ * First, we prepare the statement
+ */
+ $stmtid = @db2_prepare($this->_connectionID,$sql[0]);
+ if (!$stmtid){
+ $this->_errorMsg = @db2_stmt_errormsg();
+ $this->_errorCode = @db2_stmt_error();
+ if ($this->debug)
+ ADOConnection::outp("Prepare failed: " . $this->_errorMsg);
- switch($ADODB_ASSOC_CASE)
- {
- case ADODB_ASSOC_CASE_LOWER:
- $value = strtolower($value);
- break;
- case ADODB_ASSOC_CASE_UPPER:
- $value = strtoupper($value);
- break;
- }
- return $value;
- }
+ return false;
+ }
+ /*
+ * We next bind some input parameters
+ */
+ $ordinal = 1;
+ foreach ($sql[1] as $psVar=>$psVal){
+ ${$psVar} = $psVal;
+ $ok = @db2_bind_param($stmtid, $ordinal, $psVar, DB2_PARAM_IN);
+ if (!$ok)
+ {
+ $this->_errorMsg = @db2_stmt_errormsg();
+ $this->_errorCode = @db2_stmt_error();
+ if ($this->debug)
+ ADOConnection::outp("Bind failed: " . $this->_errorMsg);
+ return false;
+ }
+ }
+ if (!@db2_execute($stmtid))
+ {
+ $this->_errorMsg = @db2_stmt_errormsg();
+ $this->_errorCode = @db2_stmt_error();
+ if ($this->debug)
+ ADOConnection::outp($this->_errorMsg);
+ return false;
+ }
- const TABLECASE_LOWER = 0;
- const TABLECASE_UPPER = 1;
- const TABLECASE_DEFAULT = 2;
+ return $stmtid;
+ }
+ else
+ {
- /**
- * Controls the casing of the table provided to the meta functions
- */
- private $tableCase = 2;
+ $stmtid = @db2_exec($this->_connectionID,$sql);
+ }
+ $this->_lastAffectedRows = 0;
+ if ($stmtid)
+ {
+ if (@db2_num_fields($stmtid) == 0)
+ {
+ $this->_lastAffectedRows = db2_num_rows($stmtid);
+ $stmtid = true;
+ }
+ else
+ {
+ $this->_lastAffectedRows = 0;
+ }
- /**
- * Sets the table case parameter
- *
- * @param int $caseOption
- * @return null
- */
- final public function setTableCasing($caseOption)
- {
- $this->tableCase = $caseOption;
- }
+ $this->_errorMsg = '';
+ $this->_errorCode = 0;
- /**
- * Gets the table casing parameter
- *
- * @return int $caseOption
- */
- final public function getTableCasing()
- {
- return $this->tableCase;
- }
+ }
+ else
+ {
- /**
- * Gets a table cased parameter
- *
- * Receives an input variable to be processed per the tableCasing
- * rule, and returns the same value, processed
- *
- * @param string $value
- *
- * @return string
- */
- final public function getTableCasedValue($value)
- {
- switch($this->tableCase)
- {
- case self::TABLECASE_LOWER:
- $value = strtolower($value);
- break;
- case self::TABLECASE_UPPER:
- $value = strtoupper($value);
- break;
- }
- return $value;
- }
+ $this->_errorMsg = @db2_stmt_errormsg();
+ $this->_errorCode = @db2_stmt_error();
+
+ }
+ return $stmtid;
+ }
+
+ /*
+ Insert a null into the blob field of the table first.
+ Then use UpdateBlob to store the blob.
+
+ Usage:
+
+ $conn->execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+ $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
+ */
+ function updateBlob($table,$column,$val,$where,$blobtype='BLOB')
+ {
+ return $this->execute("UPDATE $table SET $column=? WHERE $where",$val) != false;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ $ret = @db2_close($this->_connectionID);
+ $this->_connectionID = false;
+ return $ret;
+ }
+
+ function _affectedrows()
+ {
+ return $this->_lastAffectedRows;
+ }
+
+ /**
+ * Gets a meta cased parameter
+ *
+ * Receives an input variable to be processed per the metaCasing
+ * rule, and returns the same value, processed
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ final public function getMetaCasedValue($value)
+ {
+ global $ADODB_ASSOC_CASE;
+
+ switch($ADODB_ASSOC_CASE)
+ {
+ case ADODB_ASSOC_CASE_LOWER:
+ $value = strtolower($value);
+ break;
+ case ADODB_ASSOC_CASE_UPPER:
+ $value = strtoupper($value);
+ break;
+ }
+ return $value;
+ }
+
+
+ const TABLECASE_LOWER = 0;
+ const TABLECASE_UPPER = 1;
+ const TABLECASE_DEFAULT = 2;
+
+ /**
+ * Controls the casing of the table provided to the meta functions
+ */
+ private $tableCase = 2;
+
+ /**
+ * Sets the table case parameter
+ *
+ * @param int $caseOption
+ * @return null
+ */
+ final public function setTableCasing($caseOption)
+ {
+ $this->tableCase = $caseOption;
+ }
+
+ /**
+ * Gets the table casing parameter
+ *
+ * @return int $caseOption
+ */
+ final public function getTableCasing()
+ {
+ return $this->tableCase;
+ }
+
+ /**
+ * Gets a table cased parameter
+ *
+ * Receives an input variable to be processed per the tableCasing
+ * rule, and returns the same value, processed
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ final public function getTableCasedValue($value)
+ {
+ switch($this->tableCase)
+ {
+ case self::TABLECASE_LOWER:
+ $value = strtolower($value);
+ break;
+ case self::TABLECASE_UPPER:
+ $value = strtoupper($value);
+ break;
+ }
+ return $value;
+ }
}
/*--------------------------------------------------------------------------------------
- Class Name: Recordset
+ Class Name: Recordset
--------------------------------------------------------------------------------------*/
class ADORecordSet_db2 extends ADORecordSet {
- var $bind = false;
- var $databaseType = "db2";
- var $dataProvider = "db2";
- var $useFetchArray;
-
- function __construct($id,$mode=false)
- {
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- $this->fetchMode = $mode;
-
- $this->_queryID = $id;
- }
-
+ var $bind = false;
+ var $databaseType = "db2";
+ var $dataProvider = "db2";
+ var $useFetchArray;
- // returns the field object
- function fetchField($offset = 0)
- {
- $o = new ADOFieldObject();
- $o->name = @db2_field_name($this->_queryID,$offset);
- $o->type = @db2_field_type($this->_queryID,$offset);
- $o->max_length = @db2_field_width($this->_queryID,$offset);
- /*
- if (ADODB_ASSOC_CASE == 0)
- $o->name = strtolower($o->name);
- else if (ADODB_ASSOC_CASE == 1)
- $o->name = strtoupper($o->name);
- */
- return $o;
- }
+ // returns the field object
+ function fetchField($offset = 0)
+ {
+ $o = new ADOFieldObject();
+ $o->name = @db2_field_name($this->_queryID,$offset);
+ $o->type = @db2_field_type($this->_queryID,$offset);
+ $o->max_length = @db2_field_width($this->_queryID,$offset);
- /* Use associative array to get fields array */
- function fields($colname)
- {
+ /*
+ if (ADODB_ASSOC_CASE == 0)
+ $o->name = strtolower($o->name);
+ else if (ADODB_ASSOC_CASE == 1)
+ $o->name = strtoupper($o->name);
+ */
+ return $o;
+ }
- if ($this->fetchMode & ADODB_FETCH_ASSOC) {
- return $this->fields[$colname];
- }
+ /* Use associative array to get fields array */
+ function 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;
- }
- }
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ return $this->fields[$colname];
+ }
- return $this->fields[$this->bind[strtoupper($colname)]];
- }
+ if (!$this->bind) {
+ $this->bind = array();
+ for ($i=0; $i < $this->_numOfFields; $i++) {
+ $o = $this->FetchField($i);
+ $this->bind[strtoupper($o->name)] = $i;
+ }
+ }
+ return $this->fields[$this->bind[strtoupper($colname)]];
+ }
- function _initrs()
- {
- global $ADODB_COUNTRECS;
- $this->_numOfRows = ($ADODB_COUNTRECS) ? @db2_num_rows($this->_queryID) : -1;
- $this->_numOfFields = @db2_num_fields($this->_queryID);
+ function _initrs()
+ {
+ global $ADODB_COUNTRECS;
+ /*
+ * If legacy rowcount is activated, this will return -1;
+ */
+ $this->_numOfRows = ($ADODB_COUNTRECS) ? @db2_num_rows($this->_queryID) : -1;
- // some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0
+ $this->_numOfFields = @db2_num_fields($this->_queryID);
- if ($this->_numOfRows == 0)
- $this->_numOfRows = -1;
- }
+ if ($this->_numOfRows == 0)
+ $this->_numOfRows = -1;
+ }
- function _seek($row)
- {
- return false;
- }
+ function _seek($row)
+ {
+ return false;
+ }
- function getArrayLimit($nrows,$offset=0)
- {
- if ($offset <= 0) {
- $rs = $this->GetArray($nrows);
- return $rs;
- }
+ function getArrayLimit($nrows,$offset=0)
+ {
+ if ($offset <= 0) {
+ $rs = $this->GetArray($nrows);
+ return $rs;
+ }
- $this->Move($offset);
+ $this->Move($offset);
- $results = array();
- $cnt = 0;
- while (!$this->EOF && $nrows != $cnt) {
- $results[$cnt++] = $this->fields;
- $this->MoveNext();
- }
+ $results = array();
+ $cnt = 0;
+ while (!$this->EOF && $nrows != $cnt) {
+ $results[$cnt++] = $this->fields;
+ $this->MoveNext();
+ }
- return $results;
- }
+ return $results;
+ }
- function moveNext()
- {
- if ($this->EOF || $this->_numOfRows == 0)
- return false;
+ function moveNext()
+ {
+ if ($this->EOF || $this->_numOfRows == 0)
+ return false;
- $this->_currentRow++;
+ $this->_currentRow++;
- $this->processCoreFetch();
- return $this->processMoveRecord();
+ $this->processCoreFetch();
+ return $this->processMoveRecord();
- }
+ }
- private function processCoreFetch()
- {
- switch ($this->fetchMode){
- case ADODB_FETCH_ASSOC:
+ private function processCoreFetch()
+ {
+ switch ($this->fetchMode){
+ case ADODB_FETCH_ASSOC:
- /*
- * Associative array
- */
- $this->fields = @db2_fetch_assoc($this->_queryID);
- break;
+ /*
+ * Associative array
+ */
+ $this->fields = @db2_fetch_assoc($this->_queryID);
+ break;
- case ADODB_FETCH_BOTH:
- /*
- * Fetch both numeric and Associative array
- */
- $this->fields = @db2_fetch_both($this->_queryID);
- break;
- default:
- /*
- * Numeric array
- */
- $this->fields = @db2_fetch_array($this->_queryID);
- break;
- }
- }
+ case ADODB_FETCH_BOTH:
+ /*
+ * Fetch both numeric and Associative array
+ */
+ $this->fields = @db2_fetch_both($this->_queryID);
+ break;
+ default:
+ /*
+ * Numeric array
+ */
+ $this->fields = @db2_fetch_array($this->_queryID);
+ break;
+ }
+ }
- private function processMoveRecord()
- {
- if (!$this->fields){
- $this->EOF = true;
- return false;
- }
+ private function processMoveRecord()
+ {
+ if (!$this->fields){
+ $this->EOF = true;
+ return false;
+ }
- return true;
- }
+ return true;
+ }
- function _fetch()
- {
- $this->processCoreFetch();
- if ($this->fields)
- return true;
+ function _fetch()
+ {
+ $this->processCoreFetch();
+ if ($this->fields)
+ return true;
- $this->fields = false;
- return false;
- }
+ $this->fields = false;
+ return false;
+ }
- function _close()
- {
- $ok = @db2_free_result($this->_queryID);
- if (!$ok)
- {
- $this->connection->_errorMsg = @db2_stmt_errormsg($this->_queryID);
- $this->connection->_errorCode = @db2_stmt_error();
+ function _close()
+ {
+ $ok = @db2_free_result($this->_queryID);
+ if (!$ok)
+ {
+ $this->connection->_errorMsg = @db2_stmt_errormsg($this->_queryID);
+ $this->connection->_errorCode = @db2_stmt_error();
- if ($this->debug)
- ADOConnection::outp($this->connection->_errorMsg);
- return false;
- }
- }
+ if ($this->debug)
+ ADOConnection::outp($this->connection->_errorMsg);
+ return false;
+ }
+ }
}
diff --git a/drivers/adodb-fbsql.inc.php b/drivers/adodb-fbsql.inc.php
index 64913bc2..cfbadf99 100644
--- a/drivers/adodb-fbsql.inc.php
+++ b/drivers/adodb-fbsql.inc.php
@@ -169,20 +169,22 @@ class ADORecordSet_fbsql extends ADORecordSet{
var $databaseType = "fbsql";
var $canSeek = true;
- function __construct($queryID,$mode=false)
+ function __construct($queryID, $mode=false)
{
- if (!$mode) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- switch ($mode) {
- case ADODB_FETCH_NUM: $this->fetchMode = FBSQL_NUM; break;
- case ADODB_FETCH_ASSOC: $this->fetchMode = FBSQL_ASSOC; break;
- case ADODB_FETCH_BOTH:
- default:
- $this->fetchMode = FBSQL_BOTH; break;
+ parent::__construct($queryID, $mode);
+
+ switch ($this->adodbFetchMode) {
+ case ADODB_FETCH_NUM:
+ $this->fetchMode = FBSQL_NUM;
+ break;
+ case ADODB_FETCH_ASSOC:
+ $this->fetchMode = FBSQL_ASSOC;
+ break;
+ case ADODB_FETCH_BOTH:
+ default:
+ $this->fetchMode = FBSQL_BOTH;
+ break;
}
- parent::__construct($queryID);
}
function _initrs()
diff --git a/drivers/adodb-firebird.inc.php b/drivers/adodb-firebird.inc.php
index 52d751d8..6d495973 100644
--- a/drivers/adodb-firebird.inc.php
+++ b/drivers/adodb-firebird.inc.php
@@ -1020,28 +1020,10 @@ class ADORecordset_firebird extends ADORecordSet
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)
- {
- global $ADODB_FETCH_MODE;
-
- $this->fetchMode = ($mode === false) ? $ADODB_FETCH_MODE : $mode;
- parent::__construct($id);
- }
-
/**
* Returns: an object containing field information.
diff --git a/drivers/adodb-ibase.inc.php b/drivers/adodb-ibase.inc.php
index 7a37976b..1eaf07fe 100644
--- a/drivers/adodb-ibase.inc.php
+++ b/drivers/adodb-ibase.inc.php
@@ -741,13 +741,6 @@ class ADORecordSet_ibase extends ADORecordSet
var $bind=false;
var $_cacheType;
- function __construct($id,$mode=false)
- {
- global $ADODB_FETCH_MODE;
-
- $this->fetchMode = ($mode === false) ? $ADODB_FETCH_MODE : $mode;
- parent::__construct($id);
- }
/* Returns: an object containing field information.
Get column information in the Recordset object. fetchField() can be used in order to obtain information about
diff --git a/drivers/adodb-informix72.inc.php b/drivers/adodb-informix72.inc.php
index 6fddde3d..d4083d5e 100644
--- a/drivers/adodb-informix72.inc.php
+++ b/drivers/adodb-informix72.inc.php
@@ -399,17 +399,6 @@ class ADORecordset_informix72 extends ADORecordSet {
var $canSeek = true;
var $_fieldprops = false;
- function __construct($id,$mode=false)
- {
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- $this->fetchMode = $mode;
- parent::__construct($id);
- }
-
-
/* Returns: an object containing field information.
Get column information in the Recordset object. fetchField() can be used in order to obtain information about
diff --git a/drivers/adodb-ldap.inc.php b/drivers/adodb-ldap.inc.php
index 55d4334a..032abbe5 100644
--- a/drivers/adodb-ldap.inc.php
+++ b/drivers/adodb-ldap.inc.php
@@ -31,70 +31,101 @@ if (!defined('LDAP_ASSOC')) {
define('LDAP_BOTH',ADODB_FETCH_BOTH);
}
-class ADODB_ldap extends ADOConnection {
- var $databaseType = 'ldap';
- var $dataProvider = 'ldap';
+class ADODB_ldap extends ADOConnection
+{
+ public $databaseType = 'ldap';
+ public $dataProvider = 'ldap';
- # Connection information
- var $username = false;
- var $password = false;
+ /**
+ * @var string[] Caches the version info
+ */
+ protected $version;
- # Used during searches
- var $filter;
- var $dn;
- var $version;
- var $port = 389;
+ /**
+ * @var string Bind error message, eg. "Binding: invalid credentials"
+ */
+ protected $_bind_errmsg = "Binding: %s";
- # Options configuration information
- var $LDAP_CONNECT_OPTIONS;
-
- # error on binding, eg. "Binding: invalid credentials"
- var $_bind_errmsg = "Binding: %s";
+ protected $connectionParameters = array(
+ LDAP_OPT_PROTOCOL_VERSION => 3,
+ LDAP_OPT_REFERRALS => 0
+ );
- // returns true or false
- function _connect( $host, $username, $password, $ldapbase)
+ /**
+ * Connect to an LDAP Server
+ *
+ * @param string|null $ldapServer The LDAP Server to connect to.
+ * @param string|null $username The username to connect as.
+ * @param string|null $password The password to connect with.
+ * @param string|null $ldapbase The Base DN
+ *
+ * @return bool|null True if connected successfully, false if connection failed, or null if the ldap extension
+ * isn't currently loaded.
+ */
+ public function _connect($ldapServer, $username, $password, $ldapbase)
{
global $LDAP_CONNECT_OPTIONS;
- if ( !function_exists( 'ldap_connect' ) ) return null;
+ if (!function_exists('ldap_connect')) {
+ return null;
+ }
- if (strpos($host,'ldap://') === 0 || strpos($host,'ldaps://') === 0) {
- $this->_connectionID = @ldap_connect($host);
- } else {
- $conn_info = array( $host,$this->port);
+ if (strpos($ldapServer, 'ldap://') !== 0 && strpos($ldapServer, 'ldaps://') !== 0) {
+ /*
+ * If ldap SSL not explicitly specified, fall back to insecure
+ */
+ $ldapServer = sprintf('ldap://%s', $ldapServer);
+ }
- if ( strstr( $host, ':' ) ) {
- $conn_info = explode( ':', $host );
- }
+ $this->_connectionID = @ldap_connect($ldapServer);
- $this->_connectionID = @ldap_connect( $conn_info[0], $conn_info[1] );
- }
if (!$this->_connectionID) {
- $e = 'Could not connect to ' . $conn_info[0];
+ $e = 'Could not connect to ' . $ldapServer;
$this->_errorMsg = $e;
- if ($this->debug) ADOConnection::outp($e);
+ if ($this->debug) {
+ ADOConnection::outp($e);
+ }
+
return false;
}
- if(!empty($LDAP_CONNECT_OPTIONS)) {
- $this->_inject_bind_options( $LDAP_CONNECT_OPTIONS );
+
+ if(!empty($LDAP_CONNECT_OPTIONS) && is_array($LDAP_CONNECT_OPTIONS)) {
+ // Convert options to connectionParameters()
+ trigger_error('$LDAP_CONNECT_OPTIONS is deprecated, use setConnectionParameter() instead', E_USER_DEPRECATED);
+ $this->_inject_bind_options($LDAP_CONNECT_OPTIONS);
+ }
+
+ // Iterate over any connection parameters
+ foreach ($this->connectionParameters as $parameter => $value) {
+ if (!ldap_set_option($this->_connectionID, $parameter, $value)) {
+ if ($this->debug) {
+ $message = sprintf('Warning - Setting connection parameter %s to value %s failed', $parameter,
+ $value);
+ ADOConnection::outp($message);
+ $this->_errorMsg = $message;
+ }
+ }
}
if ($username) {
- $bind = @ldap_bind( $this->_connectionID, $username, $password );
+ $bind = @ldap_bind($this->_connectionID, $username, $password);
} else {
- $username = 'anonymous';
- $bind = @ldap_bind( $this->_connectionID );
+ $bind = @ldap_bind($this->_connectionID);
}
if (!$bind) {
- $e = sprintf($this->_bind_errmsg,ldap_error($this->_connectionID));
+ $e = sprintf($this->_bind_errmsg, ldap_error($this->_connectionID));
$this->_errorMsg = $e;
- if ($this->debug) ADOConnection::outp($e);
+ if ($this->debug) {
+ ADOConnection::outp($e);
+ }
return false;
}
+
$this->_errorMsg = '';
$this->database = $ldapbase;
+
return $this->_connectionID;
}
@@ -150,48 +181,95 @@ class ADODB_ldap extends ADOConnection {
);
*/
- function _inject_bind_options( $options ) {
- foreach( $options as $option ) {
- ldap_set_option( $this->_connectionID, $option["OPTION_NAME"], $option["OPTION_VALUE"] )
- or die( "Unable to set server option: " . $option["OPTION_NAME"] );
+ /**
+ * Converts old style global options into connection parameters
+ *
+ * @param array $options
+ * @return void
+ * @deprecated 5.23.0
+ */
+ private function _inject_bind_options($options)
+ {
+ foreach ($options as $option) {
+ $this->connectionParameters[$option["OPTION_NAME"]] = $option["OPTION_VALUE"];
+ //ldap_set_option( $this->_connectionID, $option["OPTION_NAME"], $option["OPTION_VALUE"] );
+ // or die( "Unable to set server option: " . $option["OPTION_NAME"] );
}
}
- function _query($sql,$inputarr=false)
+
+ /**
+ * Execute a query against the AD Database.
+ *
+ * @param string|array $ldapQuery Query to execute.
+ * @param array $inputarr [Ignored] An optional array of parameters.
+ *
+ * @return resource|false
+ * @noinspection PhpParameterNameChangedDuringInheritanceInspection
+ */
+ function _query($ldapQuery, $inputarr = false)
{
- $rs = @ldap_search( $this->_connectionID, $this->database, $sql );
- $this->_errorMsg = ($rs) ? '' : 'Search error on '.$sql.': '.ldap_error($this->_connectionID);
+ $rs = ldap_search($this->_connectionID, $this->database, $ldapQuery);
+
+ $this->_errorMsg = ($rs) ? '' : 'Search error on ' . $ldapQuery . ': ' . ldap_error($this->_connectionID);
+
return $rs;
}
- function ErrorMsg()
- {
- return $this->_errorMsg;
- }
- function ErrorNo()
+ /**
+ * Returns the last error number from previous AD operation.
+ *
+ * @return int The last error number.
+ */
+ function errorNo()
{
return @ldap_errno($this->_connectionID);
}
- /* closes the LDAP connection */
+ /**
+ * closes the LDAP connection
+ *
+ * @return void
+ */
function _close()
{
- @ldap_close( $this->_connectionID );
+ if (is_resource($this->_connectionID)) {
+ @ldap_close($this->_connectionID);
+ }
+
$this->_connectionID = false;
}
- function SelectDB($db) {
- $this->database = $db;
+ /**
+ * Switches the baseDN to a new value. Just like _connect(),
+ * its impossible to determine if the parameter is correct
+ * until you issue a query
+ *
+ * @return bool true
+ * @noinspection PhpParameterNameChangedDuringInheritanceInspection
+ */
+ public function selectDB($baseDN)
+ {
+ $this->database = $baseDN;
return true;
- } // SelectDB
+ }
- function ServerInfo()
+ /**
+ * Get server version info.
+ *
+ * @return string[]|false Array with multiple string elements that define the connection
+ */
+ public function serverInfo()
{
- if( !empty( $this->version ) ) {
+ if (!empty($this->version)) {
return $this->version;
}
+ if (!is_resource($this->_connectionID)) {
+ return false;
+ }
+
$version = array();
/*
Determines how aliases are handled during search.
@@ -204,16 +282,20 @@ class ADODB_ldap extends ADOConnection {
aliases are dereferenced when locating the base object but not during the search.
Default: LDAP_DEREF_NEVER
*/
- ldap_get_option( $this->_connectionID, LDAP_OPT_DEREF, $version['LDAP_OPT_DEREF'] ) ;
- switch ( $version['LDAP_OPT_DEREF'] ) {
+ ldap_get_option($this->_connectionID, LDAP_OPT_DEREF, $version['LDAP_OPT_DEREF']);
+ switch ($version['LDAP_OPT_DEREF']) {
case 0:
$version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_NEVER';
+ break;
case 1:
$version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_SEARCHING';
+ break;
case 2:
$version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_FINDING';
+ break;
case 3:
$version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_ALWAYS';
+ break;
}
/*
@@ -221,8 +303,8 @@ class ADODB_ldap extends ADOConnection {
LDAP_NO_LIMIT (0) means no limit.
Default: LDAP_NO_LIMIT
*/
- ldap_get_option( $this->_connectionID, LDAP_OPT_SIZELIMIT, $version['LDAP_OPT_SIZELIMIT'] );
- if ( $version['LDAP_OPT_SIZELIMIT'] == 0 ) {
+ ldap_get_option($this->_connectionID, LDAP_OPT_SIZELIMIT, $version['LDAP_OPT_SIZELIMIT']);
+ if ($version['LDAP_OPT_SIZELIMIT'] == 0) {
$version['LDAP_OPT_SIZELIMIT'] = 'LDAP_NO_LIMIT';
}
@@ -231,8 +313,8 @@ class ADODB_ldap extends ADOConnection {
LDAP_NO_LIMIT (0) means no limit.
Default: LDAP_NO_LIMIT
*/
- ldap_get_option( $this->_connectionID, LDAP_OPT_TIMELIMIT, $version['LDAP_OPT_TIMELIMIT'] );
- if ( $version['LDAP_OPT_TIMELIMIT'] == 0 ) {
+ ldap_get_option($this->_connectionID, LDAP_OPT_TIMELIMIT, $version['LDAP_OPT_TIMELIMIT']);
+ if ($version['LDAP_OPT_TIMELIMIT'] == 0) {
$version['LDAP_OPT_TIMELIMIT'] = 'LDAP_NO_LIMIT';
}
@@ -242,8 +324,8 @@ class ADODB_ldap extends ADOConnection {
LDAP_OPT_OFF
Default: ON
*/
- ldap_get_option( $this->_connectionID, LDAP_OPT_REFERRALS, $version['LDAP_OPT_REFERRALS'] );
- if ( $version['LDAP_OPT_REFERRALS'] == 0 ) {
+ ldap_get_option($this->_connectionID, LDAP_OPT_REFERRALS, $version['LDAP_OPT_REFERRALS']);
+ if ($version['LDAP_OPT_REFERRALS'] == 0) {
$version['LDAP_OPT_REFERRALS'] = 'LDAP_OPT_OFF';
} else {
$version['LDAP_OPT_REFERRALS'] = 'LDAP_OPT_ON';
@@ -255,8 +337,8 @@ class ADODB_ldap extends ADOConnection {
LDAP_OPT_OFF
Default: OFF
*/
- ldap_get_option( $this->_connectionID, LDAP_OPT_RESTART, $version['LDAP_OPT_RESTART'] );
- if ( $version['LDAP_OPT_RESTART'] == 0 ) {
+ ldap_get_option($this->_connectionID, LDAP_OPT_RESTART, $version['LDAP_OPT_RESTART']);
+ if ($version['LDAP_OPT_RESTART'] == 0) {
$version['LDAP_OPT_RESTART'] = 'LDAP_OPT_OFF';
} else {
$version['LDAP_OPT_RESTART'] = 'LDAP_OPT_ON';
@@ -268,18 +350,18 @@ class ADODB_ldap extends ADOConnection {
LDAP_VERSION3 (3)
Default: LDAP_VERSION2 (2)
*/
- ldap_get_option( $this->_connectionID, LDAP_OPT_PROTOCOL_VERSION, $version['LDAP_OPT_PROTOCOL_VERSION'] );
- if ( $version['LDAP_OPT_PROTOCOL_VERSION'] == 2 ) {
+ ldap_get_option($this->_connectionID, LDAP_OPT_PROTOCOL_VERSION, $version['LDAP_OPT_PROTOCOL_VERSION']);
+ if ($version['LDAP_OPT_PROTOCOL_VERSION'] == 2) {
$version['LDAP_OPT_PROTOCOL_VERSION'] = 'LDAP_VERSION2';
} else {
$version['LDAP_OPT_PROTOCOL_VERSION'] = 'LDAP_VERSION3';
}
/* The host name (or list of hosts) for the primary LDAP server. */
- ldap_get_option( $this->_connectionID, LDAP_OPT_HOST_NAME, $version['LDAP_OPT_HOST_NAME'] );
- ldap_get_option( $this->_connectionID, LDAP_OPT_ERROR_NUMBER, $version['LDAP_OPT_ERROR_NUMBER'] );
- ldap_get_option( $this->_connectionID, LDAP_OPT_ERROR_STRING, $version['LDAP_OPT_ERROR_STRING'] );
- ldap_get_option( $this->_connectionID, LDAP_OPT_MATCHED_DN, $version['LDAP_OPT_MATCHED_DN'] );
+ ldap_get_option($this->_connectionID, LDAP_OPT_HOST_NAME, $version['LDAP_OPT_HOST_NAME']);
+ ldap_get_option($this->_connectionID, LDAP_OPT_ERROR_NUMBER, $version['LDAP_OPT_ERROR_NUMBER']);
+ ldap_get_option($this->_connectionID, LDAP_OPT_ERROR_STRING, $version['LDAP_OPT_ERROR_STRING']);
+ ldap_get_option($this->_connectionID, LDAP_OPT_MATCHED_DN, $version['LDAP_OPT_MATCHED_DN']);
return $this->version = $version;
}
@@ -289,140 +371,206 @@ class ADODB_ldap extends ADOConnection {
Class Name: Recordset
--------------------------------------------------------------------------------------*/
-class ADORecordSet_ldap extends ADORecordSet{
+class ADORecordSet_ldap extends ADORecordSet
+{
+
+ public $databaseType = "ldap";
+ public $canSeek = false;
+
+ protected $_entryID; /* keeps track of the entry resource identifier */
- var $databaseType = "ldap";
- var $canSeek = false;
- var $_entryID; /* keeps track of the entry resource identifier */
+ protected $seekData = array();
- function __construct($queryID,$mode=false)
+ /**
+ * Constructor
+ *
+ * @param resource $queryID
+ * @param boolean $mode
+ */
+ public function __construct($queryID, $mode = false)
{
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- switch ($mode)
- {
- case ADODB_FETCH_NUM:
- $this->fetchMode = LDAP_NUM;
- break;
- case ADODB_FETCH_ASSOC:
- $this->fetchMode = LDAP_ASSOC;
- break;
- case ADODB_FETCH_DEFAULT:
- case ADODB_FETCH_BOTH:
- default:
- $this->fetchMode = LDAP_BOTH;
- break;
- }
+ parent::__construct($queryID, $mode);
- parent::__construct($queryID);
+ switch ($this->adodbFetchMode) {
+ case ADODB_FETCH_NUM:
+ $this->fetchMode = LDAP_NUM;
+ break;
+ case ADODB_FETCH_ASSOC:
+ $this->fetchMode = LDAP_ASSOC;
+ break;
+ case ADODB_FETCH_DEFAULT:
+ case ADODB_FETCH_BOTH:
+ default:
+ $this->fetchMode = LDAP_BOTH;
+ break;
+ }
}
- function _initrs()
+ /**
+ * Recordset initialization stub
+ *
+ * @return void
+ */
+ protected function _initrs()
{
- /*
- This could be teaked to respect the $COUNTRECS directive from ADODB
- It's currently being used in the _fetch() function and the
- GetAssoc() function
- */
- $this->_numOfRows = ldap_count_entries( $this->connection->_connectionID, $this->_queryID );
+ // This could be tweaked to respect the $COUNTRECS directive from ADODB
+ // It's currently being used in the _fetch() function and the GetAssoc() function
+ $this->_numOfRows = ldap_count_entries($this->connection->_connectionID, $this->_queryID);
}
- /*
- Return whole recordset as a multi-dimensional associative array
- */
- function GetAssoc($force_array = false, $first2cols = false, $fetchMode = -1)
+
+ /**
+ * Returns raw, database specific information about a field.
+ *
+ * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:recordset:fetchfield
+ *
+ * @param int $fieldOffset (Optional) The field number to get information for.
+ *
+ * @return ADOFieldObject|bool
+ */
+ public function fetchField($fieldOffset = -1)
{
- $records = $this->_numOfRows;
- $results = array();
- for ( $i=0; $i < $records; $i++ ) {
- foreach ( $this->fields as $k=>$v ) {
- if ( is_array( $v ) ) {
- if ( $v['count'] == 1 ) {
- $results[$i][$k] = $v[0];
- } else {
- array_shift( $v );
- $results[$i][$k] = $v;
- }
- }
- }
+
+ if (!array_key_exists($fieldOffset, $this->seekData)) {
+ return false;
}
- return $results;
+ $o = new ADOFieldObject;
+ $o->name = $this->seekData[$fieldOffset];
+ $o->max_length = 1024;
+ $o->type = 'C';
+
+ return $o;
}
- function GetRowAssoc($upper = ADODB_ASSOC_CASE)
+ /**
+ * Attempt to fetch a result row using the current fetch mode and return whether or not this was successful.
+ *
+ * @return bool True if row was fetched successfully, otherwise false.
+ */
+ public function _fetch()
{
- $results = array();
- foreach ( $this->fields as $k=>$v ) {
- if ( is_array( $v ) ) {
- if ( $v['count'] == 1 ) {
- $results[$k] = $v[0];
- } else {
- array_shift( $v );
- $results[$k] = $v;
- }
- }
+ if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0) {
+ $this->EOF = true;
+ return false;
}
+ $this->EOF = false;
- return $results;
- }
-
- function GetRowNums()
- {
- $results = array();
- foreach ( $this->fields as $k=>$v ) {
- static $i = 0;
- if (is_array( $v )) {
- if ( $v['count'] == 1 ) {
- $results[$i] = $v[0];
- } else {
- array_shift( $v );
- $results[$i] = $v;
- }
- $i++;
- }
+ if ($this->_currentRow == 0) {
+ $this->_entryID = ldap_first_entry($this->connection->_connectionID, $this->_queryID);
+ } else {
+ $this->_entryID = ldap_next_entry($this->connection->_connectionID, $this->_entryID);
}
- return $results;
- }
- function _fetch()
- {
- if ( $this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0 ) {
+ $r = ldap_get_attributes($this->connection->_connectionID, $this->_entryID);
+
+ if (!$r) {
+ $this->EOF = true;
return false;
}
- if ( $this->_currentRow == 0 ) {
- $this->_entryID = ldap_first_entry( $this->connection->_connectionID, $this->_queryID );
- } else {
- $this->_entryID = ldap_next_entry( $this->connection->_connectionID, $this->_entryID );
+ $rowentries = $r['count'];
+ unset($r['count']);
+
+ $objectClass = false;
+
+ if ($r[0] == 'objectClass') {
+ /*
+ * Always an array, move to the end of the row we want to use getAssoc
+ */
+ $objectClass = $r['objectClass'];
+ unset($r[0]);
+ unset($r['objectClass']);
+ unset($objectClass['count']);
}
- $this->fields = ldap_get_attributes( $this->connection->_connectionID, $this->_entryID );
- $this->_numOfFields = $this->fields['count'];
+ $rowData = array();
+ $rowIndex = 0;
+ for ($rowentry = 0; $rowentry < $rowentries; $rowentry++) {
+ if (!array_key_exists($rowentry, $r)) /*
+ * We moved objectClass
+ */ {
+ continue;
+ }
- switch ( $this->fetchMode ) {
+ $eName = $r[$rowentry];
+ $eData = $r[$eName];
+ $dataEntries = $eData['count'];
- case LDAP_ASSOC:
- $this->fields = $this->GetRowAssoc();
- break;
+ unset($eData['count']);
- case LDAP_NUM:
- $this->fields = array_merge($this->GetRowNums(),$this->GetRowAssoc());
- break;
+ if ($dataEntries == 1) {
+ $element = $eData[0];
+ } else {
+ $element = $eData;
+ }
- case LDAP_BOTH:
- default:
- $this->fields = $this->GetRowNums();
+ switch ($this->fetchMode) {
+ case LDAP_ASSOC:
+ $rowData[$eName] = $element;
+ break;
+ case LDAP_NUM:
+ $rowData[$rowIndex] = $element;
+ break;
+ case LDAP_BOTH:
+ default:
+ $rowData[$eName] = $element;
+ $rowData[$rowIndex] = $element;
+ break;
+ }
+
+ $this->seekData[$rowIndex] = $eName;
+
+ $rowIndex++;
+ }
+
+ if ($objectClass) {
+ // Append the element onto the end of the row
+ switch ($this->fetchMode) {
+ case LDAP_ASSOC:
+ $rowData['objectClass'] = $objectClass;
+ break;
+ case LDAP_NUM:
+ $rowData[$rowIndex] = $objectClass;
+ break;
+ case LDAP_BOTH:
+ default:
+ $rowData['objectClass'] = $objectClass;
+ $rowData[$rowIndex] = $objectClass;
+ break;
+ }
+ }
+
+ switch (ADODB_ASSOC_CASE) {
+ case ADODB_ASSOC_CASE_UPPER:
+ $rowData = array_change_key_case($rowData, CASE_UPPER);
+ array_map('strtoupper', $this->seekData);
+ break;
+ case ADODB_ASSOC_CASE_LOWER:
+ $rowData = array_change_key_case($rowData, CASE_LOWER);
+ array_map('strtolower', $this->seekData);
break;
}
- return is_array( $this->fields );
+ $this->bind = array_flip($this->seekData);
+
+ $this->fields = $rowData;
+ $this->_numOfFields = count($rowData);
+
+ return is_array($this->fields);
}
- function _close() {
- @ldap_free_result( $this->_queryID );
+ /**
+ * Frees the memory from a query recordset
+ *
+ * @return void
+ */
+ public function _close()
+ {
+ if (is_resource($this->_queryID)) {
+ @ldap_free_result($this->_queryID);
+ }
+
$this->_queryID = false;
}
diff --git a/drivers/adodb-mssql.inc.php b/drivers/adodb-mssql.inc.php
index c0b714ed..c0a2eabd 100644
--- a/drivers/adodb-mssql.inc.php
+++ b/drivers/adodb-mssql.inc.php
@@ -857,18 +857,12 @@ class ADORecordset_mssql extends ADORecordSet {
var $hasFetchAssoc; // see PHPLens Issue No: 6083
// _mths works only in non-localised system
- function __construct($id,$mode=false)
+ function __construct($queryID, $mode=false)
{
+ parent::__construct($queryID, $mode);
+
// freedts check...
$this->hasFetchAssoc = function_exists('mssql_fetch_assoc');
-
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
-
- }
- $this->fetchMode = $mode;
- return parent::__construct($id);
}
diff --git a/drivers/adodb-mssqlnative.inc.php b/drivers/adodb-mssqlnative.inc.php
index f7e1bcc1..528a7018 100644
--- a/drivers/adodb-mssqlnative.inc.php
+++ b/drivers/adodb-mssqlnative.inc.php
@@ -95,7 +95,9 @@ class ADODB_mssqlnative extends ADOConnection {
var $identitySQL = 'select SCOPE_IDENTITY()'; // 'select SCOPE_IDENTITY'; # for mssql 2000
var $uniqueOrderBy = true;
var $_bindInputArray = true;
- var $_dropSeqSQL = "drop table %s";
+
+ /** @var string SQL statement to drop a Sequence. */
+ var $_dropSeqSQL = "DROP SEQUENCE %s";
var $connectionInfo = array('ReturnDatesAsStrings'=>true);
var $cachedSchemaFlush = false;
@@ -136,26 +138,12 @@ class ADODB_mssqlnative extends ADOConnection {
$this->mssql_version = $version;
}
- function ServerInfo() {
- global $ADODB_FETCH_MODE;
- static $arr = false;
- if (is_array($arr))
- return $arr;
- if ($this->fetchMode === false) {
- $savem = $ADODB_FETCH_MODE;
- $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
- } elseif ($this->fetchMode >=0 && $this->fetchMode <=2) {
- $savem = $this->fetchMode;
- } else
- $savem = $this->SetFetchMode(ADODB_FETCH_NUM);
-
- $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;
+ function serverInfo() {
+ $info = sqlsrv_server_info($this->_connectionID);
+ return array(
+ 'description' => $info['SQLServerName'] . ' connected to ' . $info['CurrentDatabase'],
+ 'version' => $info['SQLServerVersion'],
+ );
}
function IfNull( $field, $ifNull )
@@ -217,7 +205,15 @@ class ADODB_mssqlnative extends ADOConnection {
/**
* For Server 2005,2008, duplicate a sequence with an identity table
- */
+ *
+ *
+ * @param string $seq The name of the sequence
+ * @param int $start the start number of the sequence
+ *
+ * @return bool|object
+ *
+ * @deprecated
+ */
function CreateSequence2008($seq='adodbseq',$start=1)
{
if($this->debug) ADOConnection::outp("<hr>CreateSequence($seq,$start)");
@@ -231,25 +227,42 @@ class ADODB_mssqlnative extends ADOConnection {
return false;
}
sqlsrv_commit($this->_connectionID);
- return true;
+ return $ok;
}
/**
* Proper Sequences Only available to Server 2012 and up
+ *
+ * @param string $seq The name of the sequence
+ * @param int $start the start number of the sequence
+ *
+ * @return bool|object
*/
- function CreateSequence2012($seq='adodbseq',$start=1){
+ function CreateSequence2012($seq='adodbseq',$start=1) {
+
if (!$this->sequences){
$sql = "SELECT name FROM sys.sequences";
$this->sequences = $this->GetCol($sql);
}
- $ok = $this->Execute("CREATE SEQUENCE $seq START WITH $start INCREMENT BY 1");
- if (!$ok)
- die("CANNOT CREATE SEQUENCE" . print_r(sqlsrv_errors(),true));
+
+ $sql = "CREATE SEQUENCE $seq START WITH $start INCREMENT BY 1";
+ $ok = $this->execute($sql);
+
+ if (!$ok) {
+ $creationErrors = print_r(sqlsrv_errors(), true);
+ ADOConnection::outp("Error creating sequence:" . $creationErrors);
+ return false;
+ }
+
$this->sequences[] = $seq;
+
+ return new ADORecordSet_empty;
}
/**
* For Server 2005,2008, duplicate a sequence with an identity table
+ *
+ * @deprecated
*/
function GenID2008($seq='adodbseq',$start=1)
{
@@ -275,6 +288,11 @@ class ADODB_mssqlnative extends ADOConnection {
* Cannot do this the normal adodb way by trapping an error if the
* sequence does not exist because sql server will auto create a
* sequence with the starting number of -9223372036854775808
+ *
+ * @param string $seq The sequence name
+ * @param int $start The start number for the sequence
+ *
+ * @return int
*/
function GenID2012($seq='adodbseq',$start=1)
{
@@ -286,17 +304,47 @@ class ADODB_mssqlnative extends ADOConnection {
* we need access to at least 1. If we really care about
* performance, we could maybe flag a 'nocheck' class variable
*/
- if (!$this->sequences){
+ if (!$this->sequences) {
$sql = "SELECT name FROM sys.sequences";
$this->sequences = $this->GetCol($sql);
}
if (!is_array($this->sequences)
- || is_array($this->sequences) && !in_array($seq,$this->sequences)){
+ || is_array($this->sequences) && !in_array($seq, $this->sequences)){
$this->CreateSequence2012($seq, $start);
}
$num = $this->GetOne("SELECT NEXT VALUE FOR $seq");
- return $num;
+ return (int)$num;
+ }
+
+ /**
+ * Drops a sequence
+ * Overrides the default because SQL Server returns
+ * a resource for the drop which confuses execute()
+ *
+ * @param string $seqname
+ *
+ * @return bool|ADORecordset_empty
+ */
+ public function dropSequence($seqname='adodbseq') {
+
+ if (!$seqname) {
+ return false;
+ }
+
+ $success = $this->_query(sprintf($this->_dropSeqSQL,$seqname));
+
+ if ($success) {
+ /*
+ * Remove from the sequence list
+ */
+ $index = array_search($seqname,$this->sequences);
+ if ($index !== false) {
+ unset($this->sequences[$index]);
+ }
+ return new ADORecordSet_empty;
+ }
+ return false;
}
// Format date column in sql string given an input format that understands Y M D
@@ -1053,15 +1101,6 @@ class ADORecordset_mssqlnative extends ADORecordSet {
var $fieldOffset = 0;
// _mths works only in non-localised system
- /**
- * @var bool True if we have retrieved the fields metadata
- */
- private $fieldObjectsRetrieved = false;
-
- /*
- * Cross-reference the objects by name for easy access
- */
- private $fieldObjectsIndex = array();
/*
* Cross references the dateTime objects for faster decoding
@@ -1107,20 +1146,6 @@ class ADORecordset_mssqlnative extends ADORecordSet {
);
-
-
- function __construct($id,$mode=false)
- {
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
-
- }
- $this->fetchMode = $mode;
- parent::__construct($id);
- }
-
-
function _initrs()
{
$this->_numOfRows = -1;//not supported
diff --git a/drivers/adodb-mysqli.inc.php b/drivers/adodb-mysqli.inc.php
index a6678274..dd992434 100644
--- a/drivers/adodb-mysqli.inc.php
+++ b/drivers/adodb-mysqli.inc.php
@@ -22,6 +22,9 @@
*
* @copyright 2000-2013 John Lim
* @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
+ *
+ * @noinspection PhpComposerExtensionStubsInspection, SqlNoDataSourceInspection
+ * @noinspection PhpMissingFieldTypeInspection, PhpMissingParamTypeInspection, PhpMissingReturnTypeInspection
*/
// security - hide paths
@@ -44,7 +47,8 @@ class ADODB_mysqli extends ADOConnection {
var $dataProvider = 'mysql';
var $hasInsertID = true;
var $hasAffectedRows = true;
- var $metaTablesSQL = "SELECT
+ var $metaTablesSQL = /** @lang text */
+ "SELECT
TABLE_NAME,
CASE WHEN TABLE_TYPE = 'VIEW' THEN 'V' ELSE 'T' END
FROM INFORMATION_SCHEMA.TABLES
@@ -55,8 +59,8 @@ class ADODB_mysqli extends ADOConnection {
var $hasMoveFirst = true;
var $hasGenID = true;
var $isoDates = true; // accepts dates in ISO format
- var $sysDate = 'CURDATE()';
- var $sysTimeStamp = 'NOW()';
+ var $sysDate = '(CURDATE())';
+ var $sysTimeStamp = '(NOW())';
var $hasTransactions = true;
var $forceNewConnect = false;
var $poorAffectedRows = true;
@@ -66,7 +70,6 @@ class ADODB_mysqli extends ADOConnection {
var $socket = ''; //Default to empty string to fix HHVM bug
var $_bindInputArray = false;
var $nameQuote = '`'; /// string to use to quote identifiers and names
- var $optionFlags = array(array(MYSQLI_READ_DEFAULT_GROUP,0));
var $arrayClass = 'ADORecordSet_array_mysqli';
var $multiQuery = false;
var $ssl_key = null;
@@ -100,9 +103,13 @@ class ADODB_mysqli extends ADOConnection {
/**
* Tells the insert_id method how to obtain the last value, depending on whether
* we are using a stored procedure or not
+ * @var bool
+ * @noinspection PhpPropertyOnlyWrittenInspection
*/
private $usePreparedStatement = false;
private $useLastInsertStatement = false;
+
+ /** @noinspection PhpPropertyOnlyWrittenInspection */
private $usingBoundVariables = false;
private $statementAffectedRows = -1;
@@ -218,21 +225,21 @@ class ADODB_mysqli extends ADOConnection {
/**
* 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 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.
+ *@todo add: parameter int $port, parameter string $socket
+ *
*/
function _connect($argHostname = null,
$argUsername = null,
$argPassword = null,
- $argDatabasename = null,
+ $argDatabaseName = null,
$persist = false)
{
if(!extension_loaded("mysqli")) {
@@ -255,15 +262,6 @@ class ADODB_mysqli extends ADOConnection {
}
return false;
}
- /*
- I suggest a simple fix which would enable adodb and mysqli driver to
- read connection options from the standard mysql configuration file
- /etc/my.cnf - "Bastien Duclaux" <bduclaux#yahoo.com>
- */
- $this->optionFlags = array();
- foreach($this->optionFlags as $arr) {
- mysqli_options($this->_connectionID,$arr[0],$arr[1]);
- }
// Now merge in the standard connection parameters setting
foreach ($this->connectionParameters as $options) {
@@ -295,20 +293,18 @@ class ADODB_mysqli extends ADOConnection {
}
}
- #if (!empty($this->port)) $argHostname .= ":".$this->port;
- /** @noinspection PhpCastIsUnnecessaryInspection */
$ok = @mysqli_real_connect($this->_connectionID,
$argHostname,
$argUsername,
$argPassword,
- $argDatabasename,
+ $argDatabaseName,
# PHP7 compat: port must be int. Use default port if cast yields zero
(int)$this->port != 0 ? (int)$this->port : 3306,
$this->socket,
$this->clientFlags);
if ($ok) {
- if ($argDatabasename) return $this->selectDB($argDatabasename);
+ if ($argDatabaseName) return $this->selectDB($argDatabaseName);
return true;
} else {
if ($this->debug) {
@@ -325,14 +321,14 @@ 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 _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
{
- return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true);
+ return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
}
/**
@@ -565,7 +561,7 @@ class ADODB_mysqli extends ADOConnection {
}
// Reference on Last_Insert_ID on the recommended way to simulate sequences
- var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
+ var $_genIDSQL = /** @lang text */ "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)";
@@ -688,7 +684,7 @@ class ADODB_mysqli extends ADOConnection {
// parse index data into array
while ($row = $rs->fetchRow()) {
- if ($primary == FALSE AND $row[2] == 'PRIMARY') {
+ if (!$primary AND $row[2] == 'PRIMARY') {
continue;
}
@@ -831,8 +827,6 @@ class ADODB_mysqli extends ADOConnection {
$fraction = $dayFraction * 24 * 3600;
return $date . ' + INTERVAL ' . $fraction.' SECOND';
-
-// return "from_unixtime(unix_timestamp($date)+$fraction)";
}
/**
@@ -953,15 +947,27 @@ class ADODB_mysqli extends ADOConnection {
$table = "$owner.$table";
}
- $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE `%s`', $table));
+ $a_create_table = array_change_key_case(
+ $this->getRow(
+ sprintf('SHOW CREATE TABLE `%s`', $table)),
+ CASE_UPPER
+ );
$this->setFetchMode($savem);
- $create_sql = isset($a_create_table["Create Table"]) ? $a_create_table["Create Table"] : $a_create_table["Create View"];
+ $create_sql = $a_create_table["CREATE TABLE"] ?? $a_create_table["CREATE VIEW"];
$matches = array();
- if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false;
+ 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 ++ ) {
@@ -982,7 +988,7 @@ class ADODB_mysqli extends ADOConnection {
if ( $associative ) {
$foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j];
} else {
- $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}";
+ $foreign_keys[$ref_table][] = $my_field[$j] . '=' . $ref_field[$j];
}
}
}
@@ -1000,9 +1006,8 @@ class ADODB_mysqli extends ADOConnection {
*/
function MetaColumns($table, $normalize = true)
{
- $false = false;
if (!$this->metaColumnsSQL)
- return $false;
+ return false;
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
@@ -1016,7 +1021,7 @@ class ADODB_mysqli extends ADOConnection {
$SQL = "SELECT column_name, column_type
FROM information_schema.columns
- WHERE table_schema='{$this->database}'
+ WHERE table_schema='$this->database'
AND table_name='$table'";
$schemaArray = $this->getAssoc($SQL);
@@ -1028,7 +1033,7 @@ class ADODB_mysqli extends ADOConnection {
if (isset($savem)) $this->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
if (!is_object($rs))
- return $false;
+ return false;
$retarr = array();
while (!$rs->EOF) {
@@ -1101,7 +1106,6 @@ class ADODB_mysqli extends ADOConnection {
*/
function SelectDB($dbName)
{
-// $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID);
$this->database = $dbName;
if ($this->_connectionID) {
@@ -1160,21 +1164,11 @@ class ADODB_mysqli extends ADOConnection {
*/
function Prepare($sql)
{
- /*
- * Flag the insert_id method to use the correct retrieval method
- */
+ // Flag the insert_id method to use the correct retrieval method
$this->usePreparedStatement = true;
- /*
- * Prepared statements are not yet handled correctly
- */
+ // Prepared statements are not yet handled correctly
return $sql;
- $stmt = $this->_connectionID->prepare($sql);
- if (!$stmt) {
- echo $this->errorMsg();
- return $sql;
- }
- return array($sql,$stmt);
}
public function execute($sql, $inputarr = false)
@@ -1281,12 +1275,6 @@ class ADODB_mysqli extends ADOConnection {
function _query($sql, $inputarr = false)
{
global $ADODB_COUNTRECS;
- // Move to the next recordset, or return false if there is none. In a stored proc
- // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result
- // returns false. I think this is because the last "recordset" is actually just the
- // return value of the stored proc (ie the number of rows affected).
- // 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) {
@@ -1296,80 +1284,39 @@ class ADODB_mysqli extends ADOConnection {
return false;
}
- if (is_array($sql)) {
-
- // Prepare() not supported because mysqli_stmt_execute does not return a recordset, but
- // returns as bound variables.
-
- $stmt = $sql[1];
- $a = '';
- foreach($inputarr as $v) {
- if (is_string($v)) $a .= 's';
- else if (is_integer($v)) $a .= 'i';
- else $a .= 'd';
- }
-
- /*
- * set prepared statement flags
- */
- if ($this->usePreparedStatement)
- $this->useLastInsertStatement = true;
-
- $fnarr = array_merge( array($stmt,$a) , $inputarr);
- call_user_func_array('mysqli_stmt_bind_param',$fnarr);
- 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
- */
+ 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]))
- {
+ if (is_array($inputarr[0])) {
$bulkBindArray = $inputarr;
$inputArrayCount = count($inputarr[0]) - 1;
- }
- else
- {
+ } 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
- */
+ // 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)
- {
+ 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)
- {
+ // 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) . "'",
@@ -1378,37 +1325,28 @@ class ADODB_mysqli extends ADOConnection {
return false;
}
- foreach ($bulkBindArray as $inputarr)
- {
- /*
- * Must pass references into call_user_func_array
- */
+ foreach ($bulkBindArray as $inputarr) {
+ // Must pass references into call_user_func_array
$paramsByReference = array();
- foreach($inputarr as $key => $value) {
+ foreach ($inputarr as $key => $value) {
/** @noinspection PhpArrayAccessCanBeReplacedWithForeachValueInspection */
$paramsByReference[$key] = &$inputarr[$key];
}
- /*
- * Bind the params
- */
+ // Bind the params
call_user_func_array(array($stmt, 'bind_param'), $paramsByReference);
- /*
- * Execute
- */
-
+ // 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)
+ // Did we throw an error?
+ if (!$ret) {
return false;
+ }
}
// Tells affected_rows to be compliant
@@ -1420,14 +1358,9 @@ class ADODB_mysqli extends ADOConnection {
// Turn the statement into a result set and return it
return $stmt->get_result();
- }
- else
- {
- /*
- * reset prepared statement flags, in case we set them
- * previously and didn't use them
- */
- $this->usePreparedStatement = false;
+ } else {
+ // Reset prepared statement flags, in case we set them previously and didn't use them
+ $this->usePreparedStatement = false;
$this->useLastInsertStatement = false;
// Reset error code and message
@@ -1435,19 +1368,12 @@ class ADODB_mysqli extends ADOConnection {
$this->_errorMsg = '';
}
- /*
- if (!$mysql_res = mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) {
- if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->errorMsg());
- return false;
- }
-
- return $mysql_res;
- */
-
if ($this->multiQuery) {
- $rs = mysqli_multi_query($this->_connectionID, $sql.';');
+ $rs = mysqli_multi_query($this->_connectionID, $sql . ';');
if ($rs) {
- $rs = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->_connectionID ) : @mysqli_use_result( $this->_connectionID );
+ $rs = ($ADODB_COUNTRECS)
+ ? @mysqli_store_result($this->_connectionID)
+ : @mysqli_use_result($this->_connectionID);
return $rs ?: true; // mysqli_more_results( $this->_connectionID )
}
} else {
@@ -1458,11 +1384,10 @@ class ADODB_mysqli extends ADOConnection {
}
}
- if($this->debug)
+ if ($this->debug) {
ADOConnection::outp("Query: " . $sql . " failed. " . $this->errorMsg());
-
+ }
return false;
-
}
/**
@@ -1584,12 +1509,9 @@ class ADORecordSet_mysqli extends ADORecordSet{
function __construct($queryID, $mode = false)
{
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
+ parent::__construct($queryID, $mode);
- switch ($mode) {
+ switch ($this->adodbFetchMode) {
case ADODB_FETCH_NUM:
$this->fetchMode = MYSQLI_NUM;
break;
@@ -1602,8 +1524,6 @@ class ADORecordSet_mysqli extends ADORecordSet{
$this->fetchMode = MYSQLI_BOTH;
break;
}
- $this->adodbFetchMode = $mode;
- parent::__construct($queryID);
}
function _initrs()
@@ -1645,9 +1565,15 @@ class ADORecordSet_mysqli extends ADORecordSet{
*/
function FetchField($fieldOffset = -1)
{
+ if ($fieldOffset < -1 || $fieldOffset >= $this->_numOfFields) {
+ if ($this->connection->debug) {
+ ADOConnection::outp("FetchField: field offset out of range: $fieldOffset");
+ }
+ return false;
+ }
$fieldnr = $fieldOffset;
if ($fieldOffset != -1) {
- $fieldOffset = @mysqli_field_seek($this->_queryID, $fieldnr);
+ @mysqli_field_seek($this->_queryID, $fieldnr);
}
$o = @mysqli_fetch_field($this->_queryID);
if (!$o) return false;
@@ -1860,16 +1786,16 @@ class ADORecordSet_mysqli extends ADORecordSet{
*
* @param string|object $t The type to get the MetaType character for.
* @param int $len (Optional) Redundant. Will always be set to -1.
- * @param bool|object $fieldobj (Optional)
+ * @param bool|object $fieldObj (Optional)
*
* @return string The MetaType
*/
- function metaType($t, $len = -1, $fieldobj = false)
+ 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;
}
$t = strtoupper($t);
@@ -1895,7 +1821,8 @@ class ADORecordSet_mysqli extends ADORecordSet{
case MYSQLI_TYPE_STRING :
case MYSQLI_TYPE_ENUM :
case MYSQLI_TYPE_SET :
- case 253 :
+ /** @noinspection PhpMissingBreakStatementInspection */
+ case MYSQLI_TYPE_VAR_STRING :
if ($len <= $this->blobSize) {
return 'C';
}
@@ -1915,7 +1842,7 @@ class ADORecordSet_mysqli extends ADORecordSet{
case MYSQLI_TYPE_BLOB :
case MYSQLI_TYPE_LONG_BLOB :
case MYSQLI_TYPE_MEDIUM_BLOB :
- return !empty($fieldobj->binary) ? 'B' : 'X';
+ return !empty($fieldObj->binary) ? 'B' : 'X';
case 'YEAR':
case 'DATE':
@@ -1945,7 +1872,7 @@ class ADORecordSet_mysqli extends ADORecordSet{
case MYSQLI_TYPE_LONGLONG :
case MYSQLI_TYPE_SHORT :
case MYSQLI_TYPE_TINY :
- if (!empty($fieldobj->primary_key)) {
+ if (!empty($fieldObj->primary_key)) {
return 'R';
}
return 'I';
@@ -1979,16 +1906,16 @@ class ADORecordSet_array_mysqli extends ADORecordSet_array
*
* @param string|object $t The type to get the MetaType character for.
* @param int $len (Optional) Redundant. Will always be set to -1.
- * @param bool|object $fieldobj (Optional)
+ * @param bool|object $fieldObj (Optional)
*
* @return string The MetaType
*/
- function MetaType($t, $len = -1, $fieldobj = false)
+ 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;
}
$t = strtoupper($t);
@@ -2012,7 +1939,8 @@ class ADORecordSet_array_mysqli extends ADORecordSet_array
case MYSQLI_TYPE_STRING :
case MYSQLI_TYPE_ENUM :
case MYSQLI_TYPE_SET :
- case 253 :
+ /** @noinspection PhpMissingBreakStatementInspection */
+ case MYSQLI_TYPE_VAR_STRING :
if ($len <= $this->blobSize) {
return 'C';
}
@@ -2032,7 +1960,7 @@ class ADORecordSet_array_mysqli extends ADORecordSet_array
case MYSQLI_TYPE_BLOB :
case MYSQLI_TYPE_LONG_BLOB :
case MYSQLI_TYPE_MEDIUM_BLOB :
- return !empty($fieldobj->binary) ? 'B' : 'X';
+ return !empty($fieldObj->binary) ? 'B' : 'X';
case 'YEAR':
case 'DATE':
@@ -2062,7 +1990,7 @@ class ADORecordSet_array_mysqli extends ADORecordSet_array
case MYSQLI_TYPE_LONGLONG :
case MYSQLI_TYPE_SHORT :
case MYSQLI_TYPE_TINY :
- if (!empty($fieldobj->primary_key)) {
+ if (!empty($fieldObj->primary_key)) {
return 'R';
}
return 'I';
diff --git a/drivers/adodb-netezza.inc.php b/drivers/adodb-netezza.inc.php
index dc7c58e4..76858909 100644
--- a/drivers/adodb-netezza.inc.php
+++ b/drivers/adodb-netezza.inc.php
@@ -61,7 +61,7 @@ class ADODB_netezza extends ADODB_postgres64 {
var $fmtTimeStamp = "'Y-m-d G:i:s'"; // used by DBTimeStamp as the default timestamp fmt.
var $ansiOuter = true;
var $autoRollback = true; // apparently pgsql does not autorollback properly before 4.3.4
- // http://bugs.php.net/bug.php?id=25404
+ // https://bugs.php.net/bug.php?id=25404
function MetaColumns($table,$upper=true)
diff --git a/drivers/adodb-oci8.inc.php b/drivers/adodb-oci8.inc.php
index b92281c7..f08700fd 100644
--- a/drivers/adodb-oci8.inc.php
+++ b/drivers/adodb-oci8.inc.php
@@ -69,13 +69,23 @@ class ADODB_oci8 extends ADOConnection {
var $_stmt;
var $_commit = OCI_COMMIT_ON_SUCCESS;
var $_initdate = true; // init date to YYYY-MM-DD
- var $metaTablesSQL = "select table_name,table_type from cat where table_type in ('TABLE','VIEW') and table_name not like 'BIN\$%'"; // bin$ tables are recycle bin tables
- var $metaColumnsSQL = "select cname,coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; //changed by smondino@users.sourceforge. net
- var $metaColumnsSQL2 = "select column_name,data_type,data_length, data_scale, data_precision,
- case when nullable = 'Y' then 'NULL'
- else 'NOT NULL' end as nulls,
- data_default from all_tab_cols
- where owner='%s' and table_name='%s' order by column_id"; // when there is a schema
+ var $metaTablesSQL = <<<ENDSQL
+ SELECT table_name, table_type
+ FROM user_catalog
+ WHERE table_type IN ('TABLE', 'VIEW') AND table_name NOT LIKE 'BIN\$%'
+ ENDSQL; // bin$ tables are recycle bin tables
+ var $metaColumnsSQL = <<<ENDSQL
+ SELECT column_name, data_type, data_length, data_scale, data_precision, nullable, data_default
+ FROM user_tab_columns
+ WHERE table_name = '%s'
+ ORDER BY column_id
+ ENDSQL;
+ var $metaColumnsSQL2 = <<<ENDSQL
+ SELECT column_name, data_type, data_length, data_scale, data_precision, nullable, data_default
+ FROM all_tab_columns
+ WHERE owner = '%s' AND table_name = '%s'
+ ORDER BY column_id
+ ENDSQL; // When there is a schema
var $_bindInputArray = true;
var $hasGenID = true;
var $_genIDSQL = "SELECT (%s.nextval) FROM DUAL";
@@ -95,7 +105,7 @@ END;
var $_bind = array();
var $_nestedSQL = true;
var $_getarray = false; // currently not working
- var $leftOuter = ''; // oracle wierdness, $col = $value (+) for LEFT OUTER, $col (+)= $value for RIGHT OUTER
+ var $leftOuter = ''; // oracle weirdness, $col = $value (+) for LEFT OUTER, $col (+)= $value for RIGHT OUTER
var $session_sharing_force_blob = false; // alter session on updateblob if set to true
var $firstrows = true; // enable first rows optimization on SelectLimit()
var $selectOffsetAlg1 = 1000; // when to use 1st algorithm of selectlimit.
@@ -105,8 +115,6 @@ END;
var $datetime = false; // MetaType('DATE') returns 'D' (datetime==false) or 'T' (datetime == true)
var $_refLOBs = array();
- // var $ansiOuter = true; // if oracle9
-
/*
* Legacy compatibility for sequence names for emulated auto-increments
*/
@@ -163,7 +171,7 @@ END;
}
$fld->max_length = $rs->fields[4];
}
- $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0);
+ $fld->not_null = $rs->fields[5] == 'N';
$fld->binary = (strpos($fld->type,'BLOB') !== false);
$fld->default_value = $rs->fields[6];
@@ -193,21 +201,33 @@ END;
}
/**
+ * Connect to database.
+ *
* Multiple modes of connection are supported:
*
- * a. Local Database
- * $conn->Connect(false,'scott','tiger');
+ * 1. Local Database
+ * $conn->connect(false, 'scott', 'tiger');
*
- * b. From tnsnames.ora
- * $conn->Connect($tnsname,'scott','tiger');
- * $conn->Connect(false,'scott','tiger',$tnsname);
+ * 2. From tnsnames.ora
+ * $conn->connect($tnsname, 'scott', 'tiger');
+ * OR
+ * $conn->connect(false, 'scott', 'tiger', $tnsname);
*
- * c. Server + service name
- * $conn->Connect($serveraddress,'scott,'tiger',$service_name);
+ * 3. Server + service name
+ * $conn->connect($serveraddress, 'scott, 'tiger', $service_name);
*
- * d. Server + SID
+ * 4. Server + SID
* $conn->connectSID = true;
* $conn->Connect($serveraddress,'scott,'tiger',$SID);
+ * OR
+ * $conn->Connect($serveraddress,'scott,'tiger',"SID=$SID");
+ *
+ * By default, the Session Mode will be set to OCI_DEFAULT, but it is
+ * possible to use one of other modes referenced in the
+ * {@link https://www.php.net/manual/en/function.oci-connect oci8_connect()}
+ * function's documentation, like this:
+ * $conn->setConnectionParameter('session_mode', OCI_SYSDBA);
+ * $conn->connect(...);
*
* @param string|false $argHostname DB server hostname or TNS name
* @param string $argUsername
@@ -245,45 +265,60 @@ END;
$argDatabasename = substr($argDatabasename,4);
$this->connectSID = true;
}
-
- if ($this->connectSID) {
- $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
- .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))";
- } else
- $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
- .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))";
+ $sidOrService = $this->connectSID ? 'SID' : 'SERVICE_NAME';
+ $argDatabasename = "(DESCRIPTION="
+ . "(ADDRESS=(PROTOCOL=TCP)(HOST=$argHostname)(PORT=$argHostport))"
+ . "(CONNECT_DATA=($sidOrService=$argDatabasename)))";
}
}
- //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>";
- if ($mode==1) {
- $this->_connectionID = ($this->charSet)
- ? oci_pconnect($argUsername,$argPassword, $argDatabasename,$this->charSet)
- : oci_pconnect($argUsername,$argPassword, $argDatabasename);
- if ($this->_connectionID && $this->autoRollback) {
- oci_rollback($this->_connectionID);
+ // Determine the connect function to use based on connection mode
+ switch ($mode) {
+ case 1: $ociConnectFunction = 'oci_pconnect'; break;
+ case 2: $ociConnectFunction = 'oci_new_connect'; break;
+ default: $ociConnectFunction = 'oci_connect';
+ }
+
+ // Process the connection parameters
+ $sessionMode = OCI_DEFAULT;
+ $clientIdentifier = '';
+ foreach ($this->connectionParameters as $options) {
+ foreach($options as $parameter => $value) {
+ switch ($parameter) {
+ case 'session_mode':
+ $sessionMode = $value;
+ break;
+ case 'client_identifier':
+ $clientIdentifier = $value;
+ break;
+ }
}
- } else if ($mode==2) {
- $this->_connectionID = ($this->charSet)
- ? oci_new_connect($argUsername,$argPassword, $argDatabasename,$this->charSet)
- : oci_new_connect($argUsername,$argPassword, $argDatabasename);
- } else {
- $this->_connectionID = ($this->charSet)
- ? oci_connect($argUsername,$argPassword, $argDatabasename,$this->charSet)
- : oci_connect($argUsername,$argPassword, $argDatabasename);
}
+
+ $this->_connectionID = $ociConnectFunction(
+ $argUsername,
+ $argPassword,
+ $argDatabasename,
+ $this->charSet ?: '',
+ $sessionMode
+ );
if (!$this->_connectionID) {
return false;
}
+ // Set client identifier, but see documentation for limitations
+ if ($clientIdentifier) {
+ oci_set_client_identifier($this->_connectionID, $clientIdentifier);
+ }
+
+ if ($mode == 1 && $this->autoRollback ) {
+ oci_rollback($this->_connectionID);
+ }
+
if ($this->_initdate) {
$this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'");
}
- // looks like:
- // Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production
- // $vers = oci_server_version($this->_connectionID);
- // if (strpos($vers,'8i') !== false) $this->ansiOuter = true;
return true;
}
@@ -371,7 +406,7 @@ END;
$ds = $d->format($this->fmtDate);
}
else {
- $ds = adodb_date($this->fmtDate,$d);
+ $ds = date($this->fmtDate,$d);
}
return "TO_DATE(".$ds.",'".$this->dateformat."')";
@@ -400,7 +435,7 @@ END;
$tss = $ts->format("'Y-m-d H:i:s'");
}
else {
- $tss = adodb_date("'Y-m-d H:i:s'",$ts);
+ $tss = date("'Y-m-d H:i:s'",$ts);
}
return $tss;
@@ -547,7 +582,7 @@ END;
$ok = true;
}
- return $ok ? true : false;
+ return (bool)$ok;
}
function CommitTrans($ok=true)
@@ -1252,9 +1287,9 @@ END;
* $db->Parameter($stmt,$group,'group');
* $db->Execute($stmt);
*
- * @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 array $stmt Statement returned by {@see Prepare()} or {@see PrepareSP()}.
+ * @param mixed $var PHP variable to bind to
+ * @param string $name Name of stored procedure variable name to bind to.
* @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.
@@ -1398,15 +1433,13 @@ END;
$ok = oci_execute($cursor);
return $cursor;
}
- return $stmt;
} else {
if (is_resource($stmt)) {
oci_free_statement($stmt);
return true;
}
- return $stmt;
}
- break;
+ return $stmt;
default :
return true;
@@ -1571,8 +1604,6 @@ SELECT /*+ RULE */ distinct b.column_name
* It remains for backwards compatibility.
*
* @return string Quoted string to be sent back to database
- *
- * @noinspection PhpUnusedParameterInspection
*/
function qStr($s, $magic_quotes=false)
{
@@ -1600,13 +1631,11 @@ class ADORecordset_oci8 extends ADORecordSet {
/** @var resource Cursor reference */
var $_refcursor;
- function __construct($queryID,$mode=false)
+ function __construct($queryID, $mode=false)
{
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- switch ($mode) {
+ parent::__construct($queryID, $mode);
+
+ switch ($this->adodbFetchMode) {
case ADODB_FETCH_ASSOC:
$this->fetchMode = OCI_ASSOC;
break;
@@ -1620,8 +1649,6 @@ class ADORecordset_oci8 extends ADORecordSet {
break;
}
$this->fetchMode += OCI_RETURN_NULLS + OCI_RETURN_LOBS;
- $this->adodbFetchMode = $mode;
- $this->_queryID = $queryID;
}
/**
@@ -1821,7 +1848,7 @@ class ADORecordset_oci8 extends ADORecordSet {
* @param mixed $t
* @param int $len [optional] Length of blobsize
* @param bool $fieldobj [optional][discarded]
- * @return str The metatype of the field
+ * @return string The metatype of the field
*/
function MetaType($t, $len=-1, $fieldobj=false)
{
@@ -1876,11 +1903,3 @@ class ADORecordset_oci8 extends ADORecordSet {
}
}
}
-
-class ADORecordSet_ext_oci8 extends ADORecordSet_oci8 {
-
- function MoveNext()
- {
- return adodb_movenext($this);
- }
-}
diff --git a/drivers/adodb-oci8po.inc.php b/drivers/adodb-oci8po.inc.php
index 71c203b6..3ecebebc 100644
--- a/drivers/adodb-oci8po.inc.php
+++ b/drivers/adodb-oci8po.inc.php
@@ -32,8 +32,17 @@ include_once(ADODB_DIR.'/drivers/adodb-oci8.inc.php');
class ADODB_oci8po extends ADODB_oci8 {
var $databaseType = 'oci8po';
var $dataProvider = 'oci8';
- var $metaColumnsSQL = "select lower(cname),coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; //changed by smondino@users.sourceforge. net
- var $metaTablesSQL = "select lower(table_name),table_type from cat where table_type in ('TABLE','VIEW')";
+ var $metaTablesSQL = <<<ENDSQL
+ SELECT lower(table_name), table_type
+ FROM user_catalog
+ WHERE table_type IN ('TABLE', 'VIEW') AND table_name NOT LIKE 'BIN\$%'
+ ENDSQL; // bin$ tables are recycle bin tables
+ var $metaColumnsSQL = <<<ENDSQL
+ SELECT lower(column_name), data_type, data_length, data_scale, data_precision, nullable, data_default
+ FROM user_tab_columns
+ WHERE table_name = '%s'
+ ORDER BY column_id
+ ENDSQL;
function Param($name,$type='C')
{
diff --git a/drivers/adodb-odbc.inc.php b/drivers/adodb-odbc.inc.php
index 13184d07..a52d8b02 100644
--- a/drivers/adodb-odbc.inc.php
+++ b/drivers/adodb-odbc.inc.php
@@ -613,20 +613,13 @@ class ADORecordSet_odbc extends ADORecordSet {
var $dataProvider = "odbc";
var $useFetchArray;
- function __construct($id,$mode=false)
+ function __construct($queryID, $mode=false)
{
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- $this->fetchMode = $mode;
-
- $this->_queryID = $id;
+ parent::__construct($queryID, $mode);
// the following is required for mysql odbc driver in 4.3.1 -- why?
$this->EOF = false;
$this->_currentRow = -1;
- //parent::__construct($id);
}
diff --git a/drivers/adodb-odbc_oracle.inc.php b/drivers/adodb-odbc_oracle.inc.php
index d8461e1a..8c608295 100644
--- a/drivers/adodb-odbc_oracle.inc.php
+++ b/drivers/adodb-odbc_oracle.inc.php
@@ -33,8 +33,17 @@ class ADODB_odbc_oracle extends ADODB_odbc {
var $concat_operator='||';
var $fmtDate = "'Y-m-d 00:00:00'";
var $fmtTimeStamp = "'Y-m-d h:i:sA'";
- var $metaTablesSQL = 'select table_name from cat';
- var $metaColumnsSQL = "select cname,coltype,width from col where tname='%s' order by colno";
+ var $metaTablesSQL = <<<ENDSQL
+ SELECT table_name, table_type
+ FROM user_catalog
+ WHERE table_type IN ('TABLE', 'VIEW') AND table_name NOT LIKE 'BIN\$%'
+ ENDSQL; // bin$ tables are recycle bin tables
+ var $metaColumnsSQL = <<<ENDSQL
+ SELECT column_name, data_type, data_length, data_scale, data_precision, nullable, data_default
+ FROM user_tab_columns
+ WHERE table_name = '%s'
+ ORDER BY column_id
+ ENDSQL;
var $sysDate = "TRUNC(SYSDATE)";
var $sysTimeStamp = 'SYSDATE';
@@ -42,9 +51,8 @@ class ADODB_odbc_oracle extends ADODB_odbc {
function MetaTables($ttype = false, $showSchema = false, $mask = false)
{
- $false = false;
$rs = $this->Execute($this->metaTablesSQL);
- if ($rs === false) return $false;
+ if ($rs === false) return false;
$arr = $rs->GetArray();
$arr2 = array();
for ($i=0; $i < sizeof($arr); $i++) {
@@ -60,19 +68,20 @@ class ADODB_odbc_oracle extends ADODB_odbc {
$rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
if ($rs === false) {
- $false = false;
- return $false;
+ return false;
}
$retarr = array();
- while (!$rs->EOF) { //print_r($rs->fields);
+ while (!$rs->EOF) {
$fld = new ADOFieldObject();
$fld->name = $rs->fields[0];
$fld->type = $rs->fields[1];
$fld->max_length = $rs->fields[2];
-
- if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
- else $retarr[strtoupper($fld->name)] = $fld;
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) {
+ $retarr[] = $fld;
+ } else {
+ $retarr[strtoupper($fld->name)] = $fld;
+ }
$rs->MoveNext();
}
diff --git a/drivers/adodb-odbtp.inc.php b/drivers/adodb-odbtp.inc.php
index e3f81481..46bf9c4a 100644
--- a/drivers/adodb-odbtp.inc.php
+++ b/drivers/adodb-odbtp.inc.php
@@ -81,7 +81,7 @@ class ADODB_odbtp extends ADOConnection{
if ($isfld) return "convert(date, $d, 120)";
if (is_string($d)) $d = ADORecordSet::UnixDate($d);
- $d = adodb_date($this->fmtDate,$d);
+ $d = date($this->fmtDate,$d);
return "convert(date, $d, 120)";
}
@@ -91,7 +91,7 @@ class ADODB_odbtp extends ADOConnection{
if ($isfld) return "convert(datetime, $d, 120)";
if (is_string($d)) $d = ADORecordSet::UnixDate($d);
- $d = adodb_date($this->fmtDate,$d);
+ $d = date($this->fmtDate,$d);
return "convert(datetime, $d, 120)";
}
*/
@@ -684,15 +684,6 @@ class ADORecordSet_odbtp extends ADORecordSet {
var $databaseType = 'odbtp';
var $canSeek = true;
- function __construct($queryID,$mode=false)
- {
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- $this->fetchMode = $mode;
- parent::__construct($queryID);
- }
function _initrs()
{
diff --git a/drivers/adodb-oracle.inc.php b/drivers/adodb-oracle.inc.php
index dc0462fe..7c061b07 100644
--- a/drivers/adodb-oracle.inc.php
+++ b/drivers/adodb-oracle.inc.php
@@ -41,7 +41,7 @@ class ADODB_oracle extends ADOConnection {
{
if (is_string($d)) $d = ADORecordSet::UnixDate($d);
if (is_object($d)) $ds = $d->format($this->fmtDate);
- else $ds = adodb_date($this->fmtDate,$d);
+ else $ds = date($this->fmtDate,$d);
return 'TO_DATE('.$ds.",'YYYY-MM-DD')";
}
@@ -51,7 +51,7 @@ class ADODB_oracle extends ADOConnection {
if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts);
if (is_object($ts)) $ds = $ts->format($this->fmtDate);
- else $ds = adodb_date($this->fmtTimeStamp,$ts);
+ else $ds = date($this->fmtTimeStamp,$ts);
return 'TO_DATE('.$ds.",'RRRR-MM-DD, HH:MI:SS AM')";
}
@@ -223,16 +223,9 @@ class ADORecordset_oracle extends ADORecordSet {
var $databaseType = "oracle";
var $bind = false;
- function __construct($queryID,$mode=false)
+ function __construct($queryID, $mode=false)
{
-
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- $this->fetchMode = $mode;
-
- $this->_queryID = $queryID;
+ parent::__construct($queryID, $mode);
$this->_inited = true;
$this->fields = array();
@@ -249,9 +242,7 @@ class ADORecordset_oracle extends ADORecordSet {
return $this->_queryID;
}
-
-
- /* Returns: an object containing field information.
+ /* 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. */
diff --git a/drivers/adodb-pdo.inc.php b/drivers/adodb-pdo.inc.php
index d254895e..f25006ba 100644
--- a/drivers/adodb-pdo.inc.php
+++ b/drivers/adodb-pdo.inc.php
@@ -66,6 +66,10 @@ function adodb_pdo_type($t)
class ADODB_pdo extends ADOConnection {
+ const BIND_USE_QUESTION_MARKS = 0;
+ const BIND_USE_NAMED_PARAMETERS = 1;
+ const BIND_USE_BOTH = 2;
+
var $databaseType = "pdo";
var $dataProvider = "pdo";
var $fmtDate = "'Y-m-d'";
@@ -100,6 +104,15 @@ class ADODB_pdo extends ADOConnection {
*/
public $pdoParameters = array();
+ /*
+ * Set which style is used to bind parameters
+ *
+ * BIND_USE_QUESTION_MARKS = Use only question marks
+ * BIND_USE_NAMED_PARAMETERS = Use only named parameters
+ * BIND_USE_BOTH = Use both question marks and named parameters (Default)
+ */
+ public $bindParameterStyle = self::BIND_USE_BOTH;
+
function _UpdatePDO()
{
$d = $this->_driver;
@@ -300,10 +313,10 @@ class ADODB_pdo extends ADOConnection {
return $this->_driver->MetaColumns($table,$normalize);
}
- public function metaIndexes($table,$normalize=true,$owner=false)
+ public function metaIndexes($table, $primary=true, $owner=false)
{
if (method_exists($this->_driver,'metaIndexes'))
- return $this->_driver->metaIndexes($table,$normalize,$owner);
+ return $this->_driver->metaIndexes($table, $primary, $owner);
}
/**
@@ -592,11 +605,7 @@ class ADODB_pdo extends ADOConnection {
$this->_driver->debug = $this->debug;
}
if ($inputarr) {
-
- /*
- * inputarr must be numeric
- */
- $inputarr = array_values($inputarr);
+ $inputarr = $this->conformToBindParameterStyle($stmt->queryString, $inputarr);
$ok = $stmt->execute($inputarr);
}
else {
@@ -666,6 +675,58 @@ class ADODB_pdo extends ADOConnection {
return "'" . str_replace("'", $this->replaceQuote, $s) . "'";
}
+ /**
+ * Make bind parameters conform to settings.
+ *
+ * @param string $sql
+ * @param array $inputarr
+ * @return array
+ */
+ private function conformToBindParameterStyle($sql, $inputarr)
+ {
+ switch ($this->bindParameterStyle)
+ {
+ case self::BIND_USE_QUESTION_MARKS:
+ default:
+ $inputarr = array_values($inputarr);
+ break;
+
+ case self::BIND_USE_NAMED_PARAMETERS:
+ break;
+
+ case self::BIND_USE_BOTH:
+ // inputarr must be numeric if SQL contains a question mark
+ if ($this->containsQuestionMarkPlaceholder($sql)) {
+ $inputarr = array_values($inputarr);
+
+ if ($this->debug) {
+ ADOconnection::outp('improve the performance of this query by setting the bindParameterStyle to BIND_USE_QUESTION_MARKS');
+ }
+ }
+ break;
+ }
+
+ return $inputarr;
+ }
+
+ /**
+ * Checks for the inclusion of a question mark placeholder.
+ *
+ * @param string $sql SQL string
+ * @return boolean Returns true if a question mark placeholder is included
+ */
+ private function containsQuestionMarkPlaceholder($sql)
+ {
+ $pattern = '/(.\?(:?.|$))/';
+ if (preg_match_all($pattern, $sql, $matches, PREG_SET_ORDER)) {
+ foreach ($matches as $match) {
+ if ($match[1] !== '`?`' && strpos($match[1], '??') === false) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
/**
@@ -673,14 +734,18 @@ class ADODB_pdo extends ADOConnection {
*/
class ADODB_pdo_base extends ADODB_pdo {
- var $sysDate = "'?'";
- var $sysTimeStamp = "'?'";
-
-
- function _init($parentDriver)
+ /**
+ * Initialize parent driver properties with driver-specific values.
+ *
+ * Called by {@see ADODB_pdo::_UpdatePDO()}.
+ *
+ * @param ADODB_pdo $parentDriver
+ * @return void
+ * @internal
+ */
+ protected function _init(ADODB_pdo $parentDriver)
{
$parentDriver->_bindInputArray = true;
- #$parentDriver->_connectionID->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,true);
}
function ServerInfo()
@@ -792,27 +857,25 @@ class ADORecordSet_pdo extends ADORecordSet {
/** @var PDOStatement */
var $_queryID;
- function __construct($id,$mode=false)
+ function __construct($queryID, $mode=false)
{
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- $this->adodbFetchMode = $mode;
- switch($mode) {
- case ADODB_FETCH_NUM: $mode = PDO::FETCH_NUM; break;
- case ADODB_FETCH_ASSOC: $mode = PDO::FETCH_ASSOC; break;
+ parent::__construct($queryID, $mode);
- case ADODB_FETCH_BOTH:
- default: $mode = PDO::FETCH_BOTH; break;
+ switch($this->adodbFetchMode) {
+ case ADODB_FETCH_NUM:
+ $mode = PDO::FETCH_NUM;
+ break;
+ case ADODB_FETCH_ASSOC:
+ $mode = PDO::FETCH_ASSOC;
+ break;
+ case ADODB_FETCH_BOTH:
+ default:
+ $mode = PDO::FETCH_BOTH;
+ break;
}
$this->fetchMode = $mode;
-
- $this->_queryID = $id;
- parent::__construct($id);
}
-
function Init()
{
if ($this->_inited) {
diff --git a/drivers/adodb-pdo_dblib.inc.php b/drivers/adodb-pdo_dblib.inc.php
index fa217af0..c3a3554c 100644
--- a/drivers/adodb-pdo_dblib.inc.php
+++ b/drivers/adodb-pdo_dblib.inc.php
@@ -17,25 +17,27 @@
*
* @copyright 2000-2013 John Lim
* @copyright 2019 Damien Regad, Mark Newnham and the ADOdb community
+ *
+ * @noinspection PhpComposerExtensionStubsInspection
*/
-class ADODB_pdo_dblib extends ADODB_pdo
+class ADODB_pdo_dblib extends ADODB_pdo_base
{
var $hasTop = 'top';
var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
var $sysTimeStamp = 'GetDate()';
- var $metaDatabasesSQL = "select name from sysdatabases where name <> 'master'";
- var $metaTablesSQL="select name,case when type='U' then 'T' else 'V' end from sysobjects where (type='U' or type='V') and (name not in ('sysallocations','syscolumns','syscomments','sysdepends','sysfilegroups','sysfiles','sysfiles1','sysforeignkeys','sysfulltextcatalogs','sysindexes','sysindexkeys','sysmembers','sysobjects','syspermissions','sysprotects','sysreferences','systypes','sysusers','sysalternates','sysconstraints','syssegments','REFERENTIAL_CONSTRAINTS','CHECK_CONSTRAINTS','CONSTRAINT_TABLE_USAGE','CONSTRAINT_COLUMN_USAGE','VIEWS','VIEW_TABLE_USAGE','VIEW_COLUMN_USAGE','SCHEMATA','TABLES','TABLE_CONSTRAINTS','TABLE_PRIVILEGES','COLUMNS','COLUMN_DOMAIN_USAGE','COLUMN_PRIVILEGES','DOMAINS','DOMAIN_CONSTRAINTS','KEY_COLUMN_USAGE','dtproperties'))";
-
- var $metaColumnsSQL = "SELECT c.NAME, OBJECT_NAME(c.id) as tbl_name, c.length, c.isnullable, c.status, ( CASE WHEN c.xusertype=61 THEN 0 ELSE c.xprec END), ( CASE WHEN c.xusertype=61 THEN 0 ELSE c.xscale END), ISNULL(i.is_primary_key, 0) as primary_key FROM syscolumns c INNER JOIN systypes t ON t.xusertype=c.xusertype INNER JOIN sysobjects o ON o.id=c.id LEFT JOIN sys.index_columns ic ON ic.object_id = c.id AND c.colid = ic.column_id LEFT JOIN sys.indexes i ON i.object_id = ic.object_id AND i.index_id = ic.index_id WHERE c.id = OBJECT_ID('%s') ORDER by c.colid";
+ var $metaDatabasesSQL = /** @lang text */ "select name from sysdatabases where name <> 'master'";
+ var $metaTablesSQL= /** @lang text */ "select name,case when type='U' then 'T' else 'V' end from sysobjects where (type='U' or type='V') and (name not in ('sysallocations','syscolumns','syscomments','sysdepends','sysfilegroups','sysfiles','sysfiles1','sysforeignkeys','sysfulltextcatalogs','sysindexes','sysindexkeys','sysmembers','sysobjects','syspermissions','sysprotects','sysreferences','systypes','sysusers','sysalternates','sysconstraints','syssegments','REFERENTIAL_CONSTRAINTS','CHECK_CONSTRAINTS','CONSTRAINT_TABLE_USAGE','CONSTRAINT_COLUMN_USAGE','VIEWS','VIEW_TABLE_USAGE','VIEW_COLUMN_USAGE','SCHEMATA','TABLES','TABLE_CONSTRAINTS','TABLE_PRIVILEGES','COLUMNS','COLUMN_DOMAIN_USAGE','COLUMN_PRIVILEGES','DOMAINS','DOMAIN_CONSTRAINTS','KEY_COLUMN_USAGE','dtproperties'))";
+ var $metaColumnsSQL = /** @lang text */ "SELECT c.NAME, OBJECT_NAME(c.id) as tbl_name, c.length, c.isnullable, c.status, ( CASE WHEN c.xusertype=61 THEN 0 ELSE c.xprec END), ( CASE WHEN c.xusertype=61 THEN 0 ELSE c.xscale END), ISNULL(i.is_primary_key, 0) as primary_key FROM syscolumns c INNER JOIN systypes t ON t.xusertype=c.xusertype INNER JOIN sysobjects o ON o.id=c.id LEFT JOIN sys.index_columns ic ON ic.object_id = c.id AND c.colid = ic.column_id LEFT JOIN sys.indexes i ON i.object_id = ic.object_id AND i.index_id = ic.index_id WHERE c.id = OBJECT_ID('%s') ORDER by c.colid";
+ var $fmtDate = "'Y-m-d'";
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
- function _init(ADODB_pdo $parentDriver)
+ protected function _init(ADODB_pdo $parentDriver)
{
+ parent::_init($parentDriver);
+
$parentDriver->hasTransactions = true;
- $parentDriver->_bindInputArray = true;
$parentDriver->hasInsertID = true;
- $parentDriver->fmtTimeStamp = "'Y-m-d H:i:s'";
- $parentDriver->fmtDate = "'Y-m-d'";
}
function BeginTrans()
diff --git a/drivers/adodb-pdo_firebird.inc.php b/drivers/adodb-pdo_firebird.inc.php
index 4671b396..265cde49 100644
--- a/drivers/adodb-pdo_firebird.inc.php
+++ b/drivers/adodb-pdo_firebird.inc.php
@@ -19,6 +19,8 @@
*
* @copyright 2000-2013 John Lim
* @copyright 2019 Damien Regad, Mark Newnham and the ADOdb community
+ *
+ * @noinspection SqlResolve
*/
/**
@@ -28,12 +30,12 @@ class ADODB_pdo_firebird extends ADODB_pdo_base
{
public $dialect = 3;
public $metaTablesSQL = "select lower(rdb\$relation_name) from rdb\$relations where rdb\$relation_name not like 'RDB\$%'";
- public $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";
+ public $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";
var $arrayClass = 'ADORecordSet_array_pdo_firebird';
/**
- * Gets the version iformation from the server
+ * Gets the version information from the server
*
* @return string[]
*/
@@ -69,9 +71,7 @@ class ADODB_pdo_firebird extends ADODB_pdo_base
*/
public function metaTables($ttype = false, $showSchema = false, $mask = false)
{
- $ret = ADOConnection::MetaTables($ttype, $showSchema);
-
- return $ret;
+ return ADOConnection::MetaTables($ttype, $showSchema);
}
public function metaColumns($table, $normalize = true)
@@ -184,7 +184,7 @@ class ADODB_pdo_firebird extends ADODB_pdo_base
'columns' => array()
);
}
- $sql = "SELECT * FROM RDB\$INDEX_SEGMENTS WHERE RDB\$INDEX_NAME = '" . $index . "' ORDER BY RDB\$FIELD_POSITION ASC";
+ $sql = "SELECT * FROM RDB\$INDEX_SEGMENTS WHERE RDB\$INDEX_NAME = '" . $index . "' ORDER BY RDB\$FIELD_POSITION";
$rs1 = $this->Execute($sql);
while ($row1 = $rs1->FetchRow()) {
$indexes[$index]['columns'][$row1[2]] = $row1[1];
@@ -393,15 +393,9 @@ class ADORecordSet_pdo_firebird extends ADORecordSet_pdo
public $databaseType = "pdo_firebird";
- /**
- * returns the field object
- *
- * @param int $fieldOffset Optional field offset
- *
- * @return object The ADOFieldObject describing the field
- */
public function fetchField($fieldOffset = 0)
{
+ return false;
}
}
diff --git a/drivers/adodb-pdo_mssql.inc.php b/drivers/adodb-pdo_mssql.inc.php
index ef63b654..ad94233e 100644
--- a/drivers/adodb-pdo_mssql.inc.php
+++ b/drivers/adodb-pdo_mssql.inc.php
@@ -19,18 +19,17 @@
* @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
*/
-class ADODB_pdo_mssql extends ADODB_pdo {
+class ADODB_pdo_mssql extends ADODB_pdo_base {
var $hasTop = 'top';
var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
var $sysTimeStamp = 'GetDate()';
- function _init($parentDriver)
+ protected function _init(ADODB_pdo $parentDriver)
{
-
- $parentDriver->hasTransactions = false; ## <<< BUG IN PDO mssql driver
$parentDriver->_bindInputArray = false;
+ $parentDriver->hasTransactions = false; ## <<< BUG IN PDO mssql driver
$parentDriver->hasInsertID = true;
}
diff --git a/drivers/adodb-pdo_mysql.inc.php b/drivers/adodb-pdo_mysql.inc.php
index a00c8595..98f112c1 100644
--- a/drivers/adodb-pdo_mysql.inc.php
+++ b/drivers/adodb-pdo_mysql.inc.php
@@ -17,19 +17,23 @@
*
* @copyright 2000-2013 John Lim
* @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
+ *
+ * @noinspection PhpComposerExtensionStubsInspection
*/
-class ADODB_pdo_mysql extends ADODB_pdo {
+class ADODB_pdo_mysql extends ADODB_pdo_base {
- var $metaTablesSQL = "SELECT
+ var $metaTablesSQL = /** @lang text */
+ "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 $sysDate = 'CURDATE()';
- var $sysTimeStamp = 'NOW()';
+ var $sysDate = '(CURDATE())';
+ var $sysTimeStamp = '(NOW())';
var $hasGenID = true;
+ /** @noinspection SqlWithoutWhere */
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";
@@ -38,10 +42,9 @@ class ADODB_pdo_mysql extends ADODB_pdo {
var $fmtTimeStamp = "'Y-m-d H:i:s'";
var $nameQuote = '`';
- function _init($parentDriver)
+ protected function _init(ADODB_pdo $parentDriver)
{
$parentDriver->hasTransactions = false;
- #$parentDriver->_bindInputArray = false;
$parentDriver->hasInsertID = true;
$parentDriver->_connectionID->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
}
@@ -158,14 +161,14 @@ class ADODB_pdo_mysql extends ADODB_pdo {
return $ret;
}
- /**
- * @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);
+ }
function SetTransactionMode($transaction_mode)
{
diff --git a/drivers/adodb-pdo_oci.inc.php b/drivers/adodb-pdo_oci.inc.php
index 20b47def..d7874b7c 100644
--- a/drivers/adodb-pdo_oci.inc.php
+++ b/drivers/adodb-pdo_oci.inc.php
@@ -17,6 +17,8 @@
*
* @copyright 2000-2013 John Lim
* @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
+ *
+ * @noinspection PhpComposerExtensionStubsInspection
*/
class ADODB_pdo_oci extends ADODB_pdo_base {
@@ -26,15 +28,25 @@ class ADODB_pdo_oci extends ADODB_pdo_base {
var $sysTimeStamp = 'SYSDATE';
var $NLS_DATE_FORMAT = 'YYYY-MM-DD'; // To include time, use 'RRRR-MM-DD HH24:MI:SS'
var $random = "abs(mod(DBMS_RANDOM.RANDOM,10000001)/10000000)";
- var $metaTablesSQL = "select table_name,table_type from cat where table_type in ('TABLE','VIEW')";
- var $metaColumnsSQL = "select cname,coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno";
+ var $metaTablesSQL = /** @lang text */ <<<ENDSQL
+ SELECT table_name, table_type
+ FROM user_catalog
+ WHERE table_type IN ('TABLE', 'VIEW') AND table_name NOT LIKE 'BIN\$%'
+ ENDSQL; // bin$ tables are recycle bin tables
+ var $metaColumnsSQL = /** @lang text */ <<<ENDSQL
+ SELECT column_name, data_type, data_length, data_scale, data_precision, nullable, data_default
+ FROM user_tab_columns
+ WHERE table_name = '%s'
+ ORDER BY column_id
+ ENDSQL;
var $_initdate = true;
var $_hasdual = true;
- function _init($parentDriver)
+ protected function _init(ADODB_pdo $parentDriver)
{
- $parentDriver->_bindInputArray = true;
+ parent::_init($parentDriver);
+
$parentDriver->_nestedSQL = true;
if ($this->_initdate) {
$parentDriver->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'");
@@ -58,9 +70,8 @@ class ADODB_pdo_oci extends ADODB_pdo_base {
function MetaColumns($table,$normalize=true)
{
- global $ADODB_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);
@@ -70,20 +81,22 @@ class ADODB_pdo_oci extends ADODB_pdo_base {
if (isset($savem)) $this->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
if (!$rs) {
- return $false;
+ return false;
}
$retarr = array();
- while (!$rs->EOF) { //print_r($rs->fields);
+ while (!$rs->EOF) {
$fld = new ADOFieldObject();
$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';
+ if ($rs->fields[1] == 'NUMBER') {
+ if ($rs->fields[3] == 0) {
+ $fld->type = 'INT';
+ }
$fld->max_length = $rs->fields[4];
}
- $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0);
+ $fld->not_null = $rs->fields[5] == 'N';
$fld->binary = (strpos($fld->type,'BLOB') !== false);
$fld->default_value = $rs->fields[6];
@@ -93,7 +106,7 @@ class ADODB_pdo_oci extends ADODB_pdo_base {
}
$rs->Close();
if (empty($retarr))
- return $false;
+ return false;
else
return $retarr;
}
diff --git a/drivers/adodb-pdo_pgsql.inc.php b/drivers/adodb-pdo_pgsql.inc.php
index 6c06ac10..bea00e15 100644
--- a/drivers/adodb-pdo_pgsql.inc.php
+++ b/drivers/adodb-pdo_pgsql.inc.php
@@ -19,7 +19,10 @@
* @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
*/
-class ADODB_pdo_pgsql extends ADODB_pdo {
+/**
+ * @noinspection SqlResolve
+ */
+class ADODB_pdo_pgsql extends ADODB_pdo_base {
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',
@@ -64,8 +67,9 @@ class ADODB_pdo_pgsql extends ADODB_pdo {
var $random = 'random()'; /// random function
var $concat_operator='||';
- function _init($parentDriver)
+ protected function _init(ADODB_pdo $parentDriver)
{
+ parent::_init($parentDriver);
$parentDriver->hasTransactions = false; ## <<< BUG IN PDO pgsql driver
$parentDriver->hasInsertID = true;
@@ -147,8 +151,7 @@ select viewname,'V' from pg_views where viewname like $mask";
$ADODB_FETCH_MODE = $save;
if ($rs === false) {
- $false = false;
- return $false;
+ return false;
}
if (!empty($this->metaKeySQL)) {
// If we want the primary keys, we have to issue a separate query
@@ -180,7 +183,8 @@ select viewname,'V' from pg_views where viewname like $mask";
while (!$rsdef->EOF) {
$num = $rsdef->fields['num'];
$s = $rsdef->fields['def'];
- if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */
+ if (strpos($s,'::')===false && substr($s, 0, 1) == "'") {
+ // FIXME: quoted strings hack... for now...
$s = substr($s, 1);
$s = substr($s, 0, strlen($s) - 1);
}
@@ -235,8 +239,7 @@ select viewname,'V' from pg_views where viewname like $mask";
}
$rs->Close();
if (empty($retarr)) {
- $false = false;
- return $false;
+ return false;
} else return $retarr;
}
diff --git a/drivers/adodb-pdo_sqlite.inc.php b/drivers/adodb-pdo_sqlite.inc.php
index dab1de99..f2f5653f 100644
--- a/drivers/adodb-pdo_sqlite.inc.php
+++ b/drivers/adodb-pdo_sqlite.inc.php
@@ -21,7 +21,8 @@
* @author Sid Dunayer <sdunayer@interserv.com>
*/
-class ADODB_pdo_sqlite extends ADODB_pdo {
+class ADODB_pdo_sqlite extends ADODB_pdo_base {
+ /** @noinspection SqlResolve */
var $metaTablesSQL = "SELECT name FROM sqlite_master WHERE type='table'";
var $sysDate = 'current_date';
var $sysTimeStamp = 'current_timestamp';
@@ -37,11 +38,13 @@ class ADODB_pdo_sqlite extends ADODB_pdo {
var $pdoDriver = false;
var $random='abs(random())';
- function _init($parentDriver)
+ protected function _init(ADODB_pdo $parentDriver)
{
+ parent::_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
+ // PDO SQLite driver does not support changing autocommit mode
+ $parentDriver->hasTransactions = false;
$parentDriver->hasInsertID = true;
}
diff --git a/drivers/adodb-pdo_sqlsrv.inc.php b/drivers/adodb-pdo_sqlsrv.inc.php
index de5fbba0..badc14f7 100644
--- a/drivers/adodb-pdo_sqlsrv.inc.php
+++ b/drivers/adodb-pdo_sqlsrv.inc.php
@@ -20,20 +20,22 @@
* @author Ned Andre
*/
-class ADODB_pdo_sqlsrv extends ADODB_pdo
+class ADODB_pdo_sqlsrv extends ADODB_pdo_base
{
var $hasTop = 'top';
var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
var $sysTimeStamp = 'GetDate()';
var $arrayClass = 'ADORecordSet_array_pdo_sqlsrv';
- function _init(ADODB_pdo $parentDriver)
+ var $fmtDate = "'Y-m-d'";
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
+
+ protected function _init(ADODB_pdo $parentDriver)
{
+ parent::_init($parentDriver);
+
$parentDriver->hasTransactions = true;
- $parentDriver->_bindInputArray = true;
$parentDriver->hasInsertID = true;
- $parentDriver->fmtTimeStamp = "'Y-m-d H:i:s'";
- $parentDriver->fmtDate = "'Y-m-d'";
}
function setTransactionMode( $transaction_mode )
diff --git a/drivers/adodb-postgres64.inc.php b/drivers/adodb-postgres64.inc.php
index cda1e962..b9678bd3 100644
--- a/drivers/adodb-postgres64.inc.php
+++ b/drivers/adodb-postgres64.inc.php
@@ -26,6 +26,10 @@ class ADODB_postgres64 extends ADOConnection{
var $databaseType = 'postgres64';
var $dataProvider = 'postgres';
var $hasInsertID = true;
+ /** @var PgSql\Connection|resource|false Identifier for the native database connection */
+ var $_connectionID = false;
+ /** @var PgSql\Connection|resource|false */
+ var $_queryID;
/** @var PgSql\Connection|resource|false */
var $_resultid = false;
var $concat_operator='||';
@@ -78,21 +82,21 @@ class ADODB_postgres64 extends ADOConnection{
// http://bugs.php.net/bug.php?id=25404
var $uniqueIisR = true;
- var $_bindInputArray = false; // requires postgresql 7.3+ and ability to modify database
+ var $_bindInputArray = false; // requires PostgreSQL 7.3+ and ability to modify database
var $disableBlobs = false; // set to true to disable blob checking, resulting in 2-5% improvement in performance.
/** @var int $_pnum Number of the last assigned query parameter {@see param()} */
var $_pnum = 0;
var $version;
- var $_nestedSQL = false;
+ var $_nestedSQL = true;
// 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".
// There is no code for the "+02" time zone information, so I just left that out.
// I'm not familiar enough with both ADODB as well as Postgres
- // to know what the concequences are. The other values are correct (wheren't in 0.94)
+ // to know what the consequences are. The other values are correct (weren't in 0.94)
// -- Freek Dijkstra
/**
@@ -167,7 +171,9 @@ class ADODB_postgres64 extends ADOConnection{
*/
protected function _insertID($table = '', $column = '')
{
- if ($this->_resultid === false) 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);
@@ -175,7 +181,9 @@ class ADODB_postgres64 extends ADOConnection{
function _affectedrows()
{
- if ($this->_resultid === false) return false;
+ if ($this->_resultid === false) {
+ return false;
+ }
return pg_affected_rows($this->_resultid);
}
@@ -190,13 +198,14 @@ class ADODB_postgres64 extends ADOConnection{
return pg_query($this->_connectionID, 'begin '.$this->_transmode);
}
- function RowLock($tables,$where,$col='1 as adodbignore')
+ function RowLock($table, $where, $col='1 as adodbignore')
{
- if (!$this->transCnt) $this->BeginTrans();
- return $this->GetOne("select $col from $tables where $where for update");
+ if (!$this->transCnt) {
+ $this->BeginTrans();
+ }
+ return $this->GetOne("select $col from $table where $where for update");
}
- // returns true/false.
function CommitTrans($ok=true)
{
if ($this->transOff) return true;
@@ -206,7 +215,6 @@ class ADODB_postgres64 extends ADOConnection{
return pg_query($this->_connectionID, 'commit');
}
- // returns true/false
function RollbackTrans()
{
if ($this->transOff) return true;
@@ -273,8 +281,6 @@ class ADODB_postgres64 extends ADOConnection{
}
}
-
- // 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;
@@ -354,15 +360,24 @@ class ADODB_postgres64 extends ADOConnection{
- /*
- * Load a Large Object from a file
- * - the procedure stores the object id in the table and imports the object using
- * postgres proprietary blob handling routines
- *
- * contributed by Mattia Rossi mattia@technologist.com
- * modified for safe mode by juraj chlebec
- */
- function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
+ /**
+ * Update a BLOB from a file.
+ *
+ * The procedure stores the object id in the table and imports the object using
+ * postgres proprietary blob handling routines.
+ *
+ * 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')
{
pg_query($this->_connectionID, 'begin');
@@ -378,24 +393,25 @@ class ADODB_postgres64 extends ADOConnection{
// $oid = pg_lo_import ($path);
pg_query($this->_connectionID, 'commit');
$rs = ADOConnection::UpdateBlob($table,$column,$oid,$where,$blobtype);
- $rez = !empty($rs);
- return $rez;
+ return !empty($rs);
}
- /*
- * Deletes/Unlinks a Blob from the database, otherwise it
- * will be left behind
- *
- * Returns TRUE on success or FALSE on failure.
- *
- * contributed by Todd Rogers todd#windfox.net
- */
- function BlobDelete( $blob )
+ /**
+ * Deletes/Unlinks a Blob from the database, otherwise it will be left behind.
+ *
+ * contributed by Todd Rogers todd#windfox.net
+ *
+ * @param mixed $blob
+ * @return bool True on success, false on failure.
+ *
+ * @noinspection PhpUnused
+ */
+ function BlobDelete($blob)
{
pg_query($this->_connectionID, 'begin');
$result = @pg_lo_unlink($this->_connectionID, $blob);
pg_query($this->_connectionID, 'commit');
- return( $result );
+ return $result;
}
/*
@@ -407,19 +423,21 @@ class ADODB_postgres64 extends ADOConnection{
return is_numeric($oid);
}
- /*
- * If an OID is detected, then we use pg_lo_* to open the oid file and read the
- * real blob from the db using the oid supplied as a parameter. If you are storing
- * blobs using bytea, we autodetect and process it so this function is not needed.
- *
- * contributed by Mattia Rossi mattia@technologist.com
- *
- * see http://www.postgresql.org/idocs/index.php?largeobjects.html
- *
- * Since adodb 4.54, this returns the blob, instead of sending it to stdout. Also
- * added maxsize parameter, which defaults to $db->maxblobsize if not defined.
- */
- function BlobDecode($blob,$maxsize=false,$hastrans=true)
+ /**
+ * If an OID is detected, then we use pg_lo_* to open the oid file and read the
+ * real blob from the db using the oid supplied as a parameter. If you are storing
+ * blobs using bytea, we autodetect and process it so this function is not needed.
+ *
+ * Contributed by Mattia Rossi mattia@technologist.com
+ *
+ * @link https://www.postgresql.org/docs/current/largeobjects.html
+ *
+ * @param mixed $blob
+ * @param int|false $maxsize Defaults to $db->maxblobsize if false
+ * @param bool $hastrans
+ * @return string|false The blob
+ */
+ function BlobDecode($blob, $maxsize=false, $hastrans=true)
{
if (!$this->GuessOID($blob)) return $blob;
@@ -439,7 +457,7 @@ class ADODB_postgres64 extends ADOConnection{
/**
* Encode binary value prior to DB storage.
*
- * See https://www.postgresql.org/docs/current/static/datatype-binary.html
+ * @link https://www.postgresql.org/docs/current/static/datatype-binary.html
*
* NOTE: SQL string literals (input strings) must be preceded with two
* backslashes due to the fact that they must pass through two parsers in
@@ -500,7 +518,6 @@ class ADODB_postgres64 extends ADOConnection{
global $ADODB_FETCH_MODE;
$schema = false;
- $false = false;
$this->_findschema($table,$schema);
if ($normalize) $table = strtolower($table);
@@ -514,7 +531,7 @@ class ADODB_postgres64 extends ADOConnection{
$ADODB_FETCH_MODE = $save;
if ($rs === false) {
- return $false;
+ return false;
}
if (!empty($this->metaKeySQL)) {
// If we want the primary keys, we have to issue a separate query
@@ -532,6 +549,8 @@ class ADODB_postgres64 extends ADOConnection{
$rskey->Close();
unset($rskey);
+ } else {
+ $keys = [];
}
$rsdefa = array();
@@ -584,28 +603,29 @@ class ADODB_postgres64 extends ADOConnection{
//Freek
$fld->not_null = $rs->fields[4] == 't';
-
// Freek
if (is_array($keys)) {
foreach($keys as $key) {
- if ($fld->name == $key['column_name'] AND $key['primary_key'] == 't')
+ if ($fld->name == $key['column_name'] && $key['primary_key'] == 't') {
$fld->primary_key = true;
- if ($fld->name == $key['column_name'] AND $key['unique_key'] == 't')
+ }
+ if ($fld->name == $key['column_name'] && $key['unique_key'] == 't') {
$fld->unique = true; // What name is more compatible?
+ }
}
}
- if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
- else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld;
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) {
+ $retarr[] = $fld;
+ }
+ else {
+ $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld;
+ }
$rs->MoveNext();
}
$rs->Close();
- if (empty($retarr))
- return $false;
- else
- return $retarr;
-
+ return $retarr ?: false;
}
function param($name, $type='C')
@@ -649,7 +669,7 @@ class ADODB_postgres64 extends ADOConnection{
WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))';
}
- if ($primary == FALSE) {
+ if (!$primary) {
$sql .= ' AND i.indisprimary=false;';
}
@@ -666,8 +686,7 @@ class ADODB_postgres64 extends ADOConnection{
$ADODB_FETCH_MODE = $save;
if (!is_object($rs)) {
- $false = false;
- return $false;
+ return false;
}
// Get column names indexed by attnum so we can lookup the index key
@@ -758,22 +777,6 @@ class ADODB_postgres64 extends ADOConnection{
if ($this->_connectionID === false) return false;
$this->Execute("set datestyle='ISO'");
- $info = $this->ServerInfo(false);
-
- if (version_compare($info['version'], '7.1', '>=')) {
- $this->_nestedSQL = true;
- }
-
- # PostgreSQL 9.0 changed the default output for bytea from 'escape' to 'hex'
- # 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 (version_compare($info['version'], '9.0', '>=')
- && version_compare($info['client'], '9.2', '<')
- ) {
- $this->Execute('set bytea_output=escape');
- }
-
return true;
}
@@ -920,17 +923,17 @@ class ADODB_postgres64 extends ADOConnection{
}
- /*
- * Maximum size of C field
- */
+ /**
+ * @return int Maximum size of C field
+ */
function CharMax()
{
return 1000000000; // should be 1 Gb?
}
- /*
- * Maximum size of X field
- */
+ /**
+ * @return int Maximum size of X field
+ */
function TextMax()
{
return 1000000000; // should be 1 Gb?
@@ -950,23 +953,21 @@ class ADORecordSet_postgres64 extends ADORecordSet{
function __construct($queryID, $mode=false)
{
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- switch ($mode)
- {
- case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break;
- case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break;
+ parent::__construct($queryID, $mode);
- case ADODB_FETCH_DEFAULT:
- case ADODB_FETCH_BOTH:
- default: $this->fetchMode = PGSQL_BOTH; break;
+ switch ($this->adodbFetchMode) {
+ case ADODB_FETCH_NUM:
+ $this->fetchMode = PGSQL_NUM;
+ break;
+ case ADODB_FETCH_ASSOC:
+ $this->fetchMode = PGSQL_ASSOC;
+ break;
+ case ADODB_FETCH_DEFAULT:
+ case ADODB_FETCH_BOTH:
+ default:
+ $this->fetchMode = PGSQL_BOTH;
+ break;
}
- $this->adodbFetchMode = $mode;
-
- // Parent's constructor
- parent::__construct($queryID);
}
function GetRowAssoc($upper = ADODB_ASSOC_CASE)
@@ -974,8 +975,7 @@ class ADORecordSet_postgres64 extends ADORecordSet{
if ($this->fetchMode == PGSQL_ASSOC && $upper == ADODB_ASSOC_CASE_LOWER) {
return $this->fields;
}
- $row = ADORecordSet::GetRowAssoc($upper);
- return $row;
+ return ADORecordSet::GetRowAssoc($upper);
}
function _initRS()
@@ -987,7 +987,6 @@ class ADORecordSet_postgres64 extends ADORecordSet{
// cache types for blob decode check
// apparently pg_field_type actually performs an sql query on the database to get the type.
- if (empty($this->connection->noBlobs))
for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) {
if (pg_field_type($qid,$i) == 'bytea') {
$this->_blobArr[$i] = pg_field_name($qid,$i);
@@ -1054,7 +1053,7 @@ class ADORecordSet_postgres64 extends ADORecordSet{
}
}
if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) {
- foreach($this->_blobArr as $k => $v) {
+ foreach($this->_blobArr as $v) {
$this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]);
}
}
@@ -1095,7 +1094,7 @@ class ADORecordSet_postgres64 extends ADORecordSet{
return pg_free_result($this->_queryID);
}
- function MetaType($t,$len=-1,$fieldobj=false)
+ function MetaType($t,$len=-1, $fieldObj=false)
{
if (is_object($t)) {
$fieldobj = $t;
@@ -1105,71 +1104,81 @@ class ADORecordSet_postgres64 extends ADORecordSet{
$t = strtoupper($t);
- if (array_key_exists($t,$this->connection->customActualTypes))
- return $this->connection->customActualTypes[$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':
- case 'CHARACTER':
- case 'VARCHAR':
- case 'NAME':
- case 'BPCHAR':
- case '_VARCHAR':
- case 'CIDR':
- case 'INET':
- case 'MACADDR':
- case 'UUID':
- if ($len <= $this->blobSize) return 'C';
-
- case 'TEXT':
- return 'X';
+ case 'MONEY': // stupid, postgres expects money to be a string
+ case 'INTERVAL':
+ case 'CHAR':
+ case 'CHARACTER':
+ case 'VARCHAR':
+ case 'NAME':
+ case 'BPCHAR':
+ case '_VARCHAR':
+ case 'CIDR':
+ case 'INET':
+ case 'MACADDR':
+ /** @noinspection PhpMissingBreakStatementInspection */
+ case 'UUID':
+ if ($len <= $this->blobSize) {
+ return 'C';
+ }
+ // Fall-through
- case 'IMAGE': // user defined type
- case 'BLOB': // user defined type
- case 'BIT': // This is a bit string, not a single bit, so don't return 'L'
- case 'VARBIT':
- case 'BYTEA':
- return 'B';
+ case 'TEXT':
+ return 'X';
- case 'BOOL':
- case 'BOOLEAN':
- return 'L';
+ case 'IMAGE': // user defined type
+ case 'BLOB': // user defined type
+ case 'BIT': // This is a bit string, not a single bit, so don't return 'L'
+ case 'VARBIT':
+ case 'BYTEA':
+ return 'B';
- case 'DATE':
- return 'D';
+ case 'BOOL':
+ case 'BOOLEAN':
+ return 'L';
+ case 'DATE':
+ return 'D';
- case 'TIMESTAMP WITHOUT TIME ZONE':
- case 'TIME':
- case 'DATETIME':
- case 'TIMESTAMP':
- case 'TIMESTAMPTZ':
- return 'T';
+ case 'TIMESTAMP WITHOUT TIME ZONE':
+ case 'TIME':
+ case 'DATETIME':
+ case 'TIMESTAMP':
+ case 'TIMESTAMPTZ':
+ return 'T';
- case 'SMALLINT':
- case 'BIGINT':
- case 'INTEGER':
- case 'INT8':
- case 'INT4':
- case 'INT2':
- if (isset($fieldobj) &&
- empty($fieldobj->primary_key) && (!$this->connection->uniqueIisR || empty($fieldobj->unique))) return 'I';
+ case 'SMALLINT':
+ case 'BIGINT':
+ case 'INTEGER':
+ case 'INT8':
+ case 'INT4':
+ /** @noinspection PhpMissingBreakStatementInspection */
+ case 'INT2':
+ if (isset($fieldobj)
+ && empty($fieldobj->primary_key)
+ && (!$this->connection->uniqueIisR || empty($fieldobj->unique))
+ ) {
+ return 'I';
+ }
+ // Fall-through
- case 'OID':
- case 'SERIAL':
- return 'R';
+ case 'OID':
+ case 'SERIAL':
+ return 'R';
- case 'NUMERIC':
- case 'DECIMAL':
- case 'FLOAT4':
- case 'FLOAT8':
- return 'N';
+ case 'NUMERIC':
+ case 'DECIMAL':
+ case 'FLOAT4':
+ case 'FLOAT8':
+ return 'N';
- default:
- return ADODB_DEFAULT_METATYPE;
- }
+ default:
+ return ADODB_DEFAULT_METATYPE;
+ }
}
}
diff --git a/drivers/adodb-sqlite.inc.php b/drivers/adodb-sqlite.inc.php
index d41829c0..e9fab6dc 100644
--- a/drivers/adodb-sqlite.inc.php
+++ b/drivers/adodb-sqlite.inc.php
@@ -36,8 +36,8 @@ class ADODB_sqlite 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('Y-m-d')";
+ var $sysTimeStamp = "date('Y-m-d H:i:s')";
var $fmtTimeStamp = "'Y-m-d H:i:s'";
function ServerInfo()
@@ -164,14 +164,24 @@ class ADODB_sqlite extends ADOConnection {
function SQLDate($fmt, $col=false)
{
$fmt = $this->qstr($fmt);
- return ($col) ? "adodb_date2($fmt,$col)" : "adodb_date($fmt)";
+ return ($col) ? "adodb_date($fmt,$col)" : "adodb_date($fmt)";
}
function _createFunctions()
{
- @sqlite_create_function($this->_connectionID, 'adodb_date', 'adodb_date', 1);
- @sqlite_create_function($this->_connectionID, 'adodb_date2', 'adodb_date2', 2);
+ // Register date conversion function for SQLDate() method
+ // Replaces the legacy adodb_date() functions removed in 5.23.0
+ @sqlite_create_function($this->_connectionID, 'adodb_date',
+ function (string $fmt, $date = null) : string {
+ if ($date === null || $date === false) {
+ return date($fmt);
+ }
+
+ // If it's an int then assume a Unix timestamp, otherwise convert it
+ return date($fmt, is_int($date) ? $date : strtotime($date));
+ }
+ );
}
@@ -425,14 +435,11 @@ class ADORecordset_sqlite extends ADORecordSet {
var $databaseType = "sqlite";
var $bind = false;
- function __construct($queryID,$mode=false)
+ function __construct($queryID, $mode=false)
{
+ parent::__construct($queryID, $mode);
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- switch($mode) {
+ switch ($this->adodbFetchMode) {
case ADODB_FETCH_NUM:
$this->fetchMode = SQLITE_NUM;
break;
@@ -443,9 +450,6 @@ class ADORecordset_sqlite extends ADORecordSet {
$this->fetchMode = SQLITE_BOTH;
break;
}
- $this->adodbFetchMode = $mode;
-
- $this->_queryID = $queryID;
$this->_inited = true;
$this->fields = array();
@@ -462,7 +466,6 @@ class ADORecordset_sqlite extends ADORecordSet {
return $this->_queryID;
}
-
function FetchField($fieldOffset = -1)
{
$fld = new ADOFieldObject;
diff --git a/drivers/adodb-sqlite3.inc.php b/drivers/adodb-sqlite3.inc.php
index 026e0392..696e2990 100644
--- a/drivers/adodb-sqlite3.inc.php
+++ b/drivers/adodb-sqlite3.inc.php
@@ -42,11 +42,22 @@ class ADODB_sqlite3 extends ADOConnection {
var $sysDate = "DATE('now','localtime')";
var $sysTimeStamp = "DATETIME('now','localtime')";
var $fmtTimeStamp = "'Y-m-d H:i:s'";
+ var $_genSeqSQL = "create table %s (id integer)";
+ var $_dropSeqSQL = 'drop table %s';
- /** @var SQLite3 */
+ /**
+ * The SQLite3 connection object
+ *
+ * @var SQLite3
+ */
var $_connectionID;
- function ServerInfo()
+ /**
+ * Returns an array with the server information
+ *
+ * @return array
+ */
+ function serverInfo()
{
$version = SQLite3::version();
$arr['version'] = $version['versionString'];
@@ -54,7 +65,24 @@ class ADODB_sqlite3 extends ADOConnection {
return $arr;
}
- function BeginTrans()
+ /**
+ * Return string with a database specific IFNULL statement
+ *
+ * @param string $field Field name to check for null
+ * @param string $ifNull Value to return if $field is null
+ *
+ * @return string
+ */
+ function ifNull( $field, $ifNull ) {
+ return " IFNULL($field, $ifNull) "; // if SQLite 3.X
+ }
+
+ /**
+ * Begin a transaction
+ *
+ * @return bool
+ */
+ function beginTrans()
{
if ($this->transOff) {
return true;
@@ -64,7 +92,14 @@ class ADODB_sqlite3 extends ADOConnection {
return true;
}
- function CommitTrans($ok=true)
+ /**
+ * Commit a transaction
+ *
+ * @param bool $ok If false, will rollback the transaction
+ *
+ * @return bool
+ */
+ function commitTrans($ok=true)
{
if ($this->transOff) {
return true;
@@ -79,7 +114,12 @@ class ADODB_sqlite3 extends ADOConnection {
return !empty($ret);
}
- function RollbackTrans()
+ /**
+ * Rollback a transaction
+ *
+ * @return bool
+ */
+ function rollbackTrans()
{
if ($this->transOff) {
return true;
@@ -91,11 +131,19 @@ class ADODB_sqlite3 extends ADOConnection {
return !empty($ret);
}
+ /**
+ * Returns the ADOdb metatype for a given SQLite type
+ *
+ * @param string|ADOFieldObject $t The type to convert
+ * @param int $len The length of the field (not used)
+ * @param bool $fieldobj If true, $t is an ADOFieldObject
+ *
+ * @return string The ADOdb metatype
+ */
function metaType($t,$len=-1,$fieldobj=false)
{
- if (is_object($t))
- {
+ if (is_object($t)) {
$fieldobj = $t;
$t = $fieldobj->type;
}
@@ -160,8 +208,16 @@ class ADODB_sqlite3 extends ADOConnection {
return $subclass[$subt];
}
- // mark newnham
- function MetaColumns($table, $normalize=true)
+
+ /**
+ * Returns the metadata for a table
+ *
+ * @param string $table The table name
+ * @param bool $normalize If true, will return the field names in uppercase
+ *
+ * @return array|false An array of ADOFieldObject objects or false on failure
+ */
+ function metaColumns($table, $normalize=true)
{
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
@@ -183,6 +239,9 @@ class ADODB_sqlite3 extends ADOConnection {
$arr = array();
while ($r = $rs->FetchRow()) {
+ // Metacolumns returns column names in lowercase
+ $r = array_change_key_case($r, CASE_LOWER);
+
$type = explode('(', $r['type']);
$size = '';
if (sizeof($type) == 2) {
@@ -209,6 +268,16 @@ class ADODB_sqlite3 extends ADOConnection {
return $arr;
}
+ /**
+ * Returns the foreign keys for a table
+ *
+ * @param string $table The table name
+ * @param string $owner The owner of the table (not used)
+ * @param bool $upper If true, will return uppercase table names
+ * @param bool $associative If true, will return an associative array
+ *
+ * @return array An array of foreign keys or false on failure
+ */
public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false)
{
global $ADODB_FETCH_MODE;
@@ -249,88 +318,170 @@ class ADODB_sqlite3 extends ADOConnection {
return $fkeyList;
}
+ /**
+ * Initialize the driver
+ *
+ * @param ADOConnection $parentDriver The parent connection object
+ *
+ * @return void
+ */
function _init($parentDriver)
{
$parentDriver->hasTransactions = false;
$parentDriver->hasInsertID = true;
}
+ /**
+ * Returns the last inserted ID
+ *
+ * @param string $table The table name (not used)
+ * @param string $column The column name (not used)
+ *
+ * @return int The last inserted ID
+ */
protected function _insertID($table = '', $column = '')
{
return $this->_connectionID->lastInsertRowID();
}
+ /**
+ * Returns the number of affected rows by the last query
+ *
+ * @return int The number of affected rows
+ */
function _affectedrows()
{
return $this->_connectionID->changes();
}
+ /**
+ * Sets the last error message and code
+ *
+ * This is called after a failed query to set the error message and code
+ *
+ * @return void
+ */
protected function lastError()
{
$this->_errorMsg = $this->_connectionID->lastErrorMsg();
$this->_errorCode = $this->_connectionID->lastErrorCode();
}
- function ErrorMsg()
- {
+ /**
+ * Returns the last error message
+ *
+ * @return string The last error message
+ */
+ function errorMsg()
+ {
return $this->_errorMsg;
}
- function ErrorNo()
+ /**
+ * Returns the last error code
+ *
+ * @return int The last error code
+ */
+ function errorNo()
{
return $this->_errorCode;
}
- function SQLDate($fmt, $col=false)
+ /**
+ * Returns a formatted date string for SQLite
+ *
+ * This function formats the date according to the SQLite strftime function
+ * and ensures proper casing for certain fields.
+ *
+ * @param string $fmt The format string
+ * @param bool $col If true, will use the column name in the format
+ *
+ * @return string The formatted date string
+ */
+ function sqlDate($fmt, $col=false)
{
- /*
- * In order to map the values correctly, we must ensure the proper
- * casing for certain fields
- * Y must be UC, because y is a 2 digit year
- * d must be LC, because D is 3 char day
- * A must be UC because a is non-portable am
- * Q must be UC because q means nothing
- */
- $fromChars = array('y','D','a','q');
- $toChars = array('Y','d','A','Q');
- $fmt = str_replace($fromChars,$toChars,$fmt);
+ // In order to map the values correctly, we must ensure the proper
+ // casing for certain fields:
+ // - Y must be UC, because y is a 2 digit year
+ // - d must be LC, because D is 3 char day
+ // - A must be UC because a is non-portable am
+ // - Q must be UC because q means nothing
+ $fromChars = array('y', 'D', 'a', 'q');
+ $toChars = array('Y', 'd', 'A', 'Q');
+ $fmt = str_replace($fromChars, $toChars, $fmt);
$fmt = $this->qstr($fmt);
- return ($col) ? "adodb_date2($fmt,$col)" : "adodb_date($fmt)";
- }
-
- function _createFunctions()
- {
- $this->_connectionID->createFunction('adodb_date', 'adodb_date', 1);
- $this->_connectionID->createFunction('adodb_date2', 'adodb_date2', 2);
+ return $col ? "adodb_date($fmt,$col)" : "adodb_date($fmt)";
}
- /** @noinspection PhpUnusedParameterInspection */
+ /**
+ * Connects to the SQLite database
+ *
+ * @param string $argHostname The hostname or database file path
+ * @param string $argUsername The username (not used)
+ * @param string $argPassword The password (not used)
+ * @param string $argDatabasename The database name (not used)
+ *
+ * @noinspection PhpUnusedParameterInspection
+ *
+ * @return bool True on success, false on failure
+ */
function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
{
if (empty($argHostname) && $argDatabasename) {
$argHostname = $argDatabasename;
}
$this->_connectionID = new SQLite3($argHostname);
- $this->_createFunctions();
+
+ // Register date conversion function for SQLDate() method
+ // Replaces the legacy adodb_date() functions removed in 5.23.0
+ $this->_connectionID->createFunction('adodb_date',
+ function (string $fmt, $date = null) : string {
+ if ($date === null || $date === false) {
+ return date($fmt);
+ }
+
+ // If it's an int then assume a Unix timestamp, otherwise convert it
+ return date($fmt, is_int($date) ? $date : strtotime($date));
+ }
+ );
return true;
}
+ /**
+ * Connects to the SQLite database using a persistent connection
+ *
+ * @param string $argHostname The hostname or database file path
+ * @param string $argUsername The username (not used)
+ * @param string $argPassword The password (not used)
+ * @param string $argDatabasename The database name (not used)
+ *
+ * @noinspection PhpUnusedParameterInspection
+ *
+ * @return bool True on success, false on failure
+ */
function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
{
// There's no permanent connect in SQLite3
return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
}
+ /**
+ * Executes a query on the SQLite database
+ *
+ * @param string $sql The SQL query to execute
+ * @param mixed $inputarr An array of input parameters (not used)
+ *
+ * @return SQLite3Result|bool The result set or true on success, false on failure
+ */
function _query($sql,$inputarr=false)
{
$rez = $this->_connectionID->query($sql);
if ($rez === false) {
$this->lastError();
- }
- // If no data was returned, we don't need to create a real recordset
- elseif ($rez->numColumns() == 0) {
+ } elseif ($rez->numColumns() == 0) {
+ // If no data was returned, we don't need to create a real recordset
$rez->finalize();
$rez = true;
}
@@ -338,7 +489,21 @@ class ADODB_sqlite3 extends ADOConnection {
return $rez;
}
- function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
+ /**
+ * Executes a query with a limit and offset
+ *
+ * This function modifies the SQL query to include a LIMIT and OFFSET clause
+ * based on the provided parameters.
+ *
+ * @param string $sql The SQL query to execute
+ * @param int $nrows The number of rows to return (default -1 for no limit)
+ * @param int $offset The offset to start returning rows from (default -1 for no offset)
+ * @param mixed $inputarr An array of input parameters (not used)
+ * @param int $secs2cache Number of seconds to cache the result (default 0 for no caching)
+ *
+ * @return SQLite3Result|bool The result set or true on success, false on failure
+ */
+ function selectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
{
$nrows = (int) $nrows;
$offset = (int) $offset;
@@ -353,15 +518,19 @@ class ADODB_sqlite3 extends ADOConnection {
return $rs;
}
- /*
- This algorithm is not very efficient, but works even if table locking
- is not available.
-
- Will return false if unable to generate an ID after $MAXLOOPS attempts.
+ /**
+ * Generates a unique ID using a sequence table
+ *
+ * This function uses a sequence table to generate unique IDs. If the sequence
+ * table does not exist, it will create it. The function will return false if
+ * it is unable to generate a unique ID after a specified number of attempts.
+ *
+ * @param string $seqname The name of the sequence table (default 'adodbseq')
+ * @param int $startID The starting ID value (default 1)
+ *
+ * @return int|false The generated unique ID or false on failure
*/
- var $_genSeqSQL = "create table %s (id integer)";
-
- function GenID($seqname='adodbseq', $startID=1)
+ function genID($seqname='adodbseq', $startID=1)
{
// if you have to modify the parameter below, your database is overloaded,
// or you need to implement generation of id's yourself!
@@ -392,6 +561,18 @@ class ADODB_sqlite3 extends ADOConnection {
return false;
}
+ /**
+ * Creates a sequence table
+ *
+ * This function creates a sequence table with the specified name and starts
+ * the ID at the specified value. If the sequence table already exists, it will
+ * return false.
+ *
+ * @param string $seqname The name of the sequence table (default 'adodbseq')
+ * @param int $startID The starting ID value (default 1)
+ *
+ * @return bool True on success, false on failure
+ */
function createSequence($seqname='adodbseq', $startID=1)
{
if (empty($this->_genSeqSQL)) {
@@ -405,8 +586,17 @@ class ADODB_sqlite3 extends ADOConnection {
return $this->Execute("insert into $seqname values($startID)");
}
- var $_dropSeqSQL = 'drop table %s';
- function DropSequence($seqname = 'adodbseq')
+ /**
+ * Drops a sequence table
+ *
+ * This function drops the specified sequence table. If the sequence table does
+ * not exist or if the drop SQL is not set, it will return false.
+ *
+ * @param string $seqname The name of the sequence table (default 'adodbseq')
+ *
+ * @return bool True on success, false on failure
+ */
+ function dropSequence($seqname = 'adodbseq')
{
if (empty($this->_dropSeqSQL)) {
return false;
@@ -414,12 +604,30 @@ class ADODB_sqlite3 extends ADOConnection {
return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
}
- // returns true or false
+ /**
+ * Closes the SQLite connection
+ *
+ * This function closes the SQLite connection and returns true on success.
+ *
+ * @return bool True on success, false on failure
+ */
function _close()
{
return $this->_connectionID->close();
}
+ /**
+ * Returns the indexes for a table
+ *
+ * This function retrieves the indexes for a given table from the SQLite master table.
+ * It can also return the primary key index if requested.
+ *
+ * @param string $table The table name
+ * @param bool $primary If true, will include the primary key index
+ * @param bool $owner Not used, included for compatibility
+ *
+ * @return array|false An array of indexes or false on failure
+ */
function metaIndexes($table, $primary = false, $owner = false)
{
// save old fetch mode
@@ -559,8 +767,8 @@ class ADODB_sqlite3 extends ADOConnection {
* 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 $table The table name
+ * @param string $column The column name to update
* @param string $val Blob value to set
* @param mixed $where An array of parameters (key => value pairs),
* or a string (where clause).
@@ -636,8 +844,8 @@ class ADODB_sqlite3 extends ADOConnection {
/**
* SQLite update for blob from a file
*
- * @param string $table
- * @param string $column
+ * @param string $table The table name
+ * @param string $column The column name to update
* @param string $path Filename containing blob data
* @param mixed $where {@see updateBlob()}
* @param string $blobtype ignored
@@ -665,22 +873,37 @@ class ADODB_sqlite3 extends ADOConnection {
Class Name: Recordset
--------------------------------------------------------------------------------------*/
+/**
+ * Class ADORecordset_sqlite3
+ *
+ * This class extends ADORecordSet to provide SQLite3 specific functionality.
+ * It handles fetching records, field metadata, and other recordset operations.
+ */
class ADORecordset_sqlite3 extends ADORecordSet {
var $databaseType = "sqlite3";
var $bind = false;
- /** @var SQLite3Result */
+ /**
+ * The SQLite3Result object
+ *
+ * @var SQLite3Result
+ */
var $_queryID;
- /** @noinspection PhpMissingParentConstructorInspection */
- function __construct($queryID,$mode=false)
+
+ /**
+ * Constructor for the ADORecordset_sqlite3 class
+ *
+ * @param SQLite3Result $queryID The SQLite3Result object
+ * @param bool $mode The fetch mode (default false)
+ *
+ * @noinspection PhpMissingParentConstructorInspection
+ */
+ function __construct($queryID, $mode=false)
{
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- switch($mode) {
+ parent::__construct($queryID, $mode);
+ switch($this->adodbFetchMode) {
case ADODB_FETCH_NUM:
$this->fetchMode = SQLITE3_NUM;
break;
@@ -691,9 +914,6 @@ class ADORecordset_sqlite3 extends ADORecordSet {
$this->fetchMode = SQLITE3_BOTH;
break;
}
- $this->adodbFetchMode = $mode;
-
- $this->_queryID = $queryID;
$this->_inited = true;
$this->fields = array();
@@ -710,8 +930,17 @@ class ADORecordset_sqlite3 extends ADORecordSet {
return $this->_queryID;
}
-
- function FetchField($fieldOffset = -1)
+ /**
+ * Returns the field object for a given field offset
+ *
+ * This function retrieves the field object for a specific field offset.
+ * It creates a new ADOFieldObject and sets its name and type.
+ *
+ * @param int $fieldOffset The offset of the field (default -1 for the first field)
+ *
+ * @return ADOFieldObject The field object
+ */
+ function fetchField($fieldOffset = -1)
{
$fld = new ADOFieldObject;
$fld->name = $this->_queryID->columnName($fieldOffset);
@@ -720,13 +949,32 @@ class ADORecordset_sqlite3 extends ADORecordSet {
return $fld;
}
+ /**
+ * Initializes the recordset by setting the number of fields
+ *
+ * This function is called after the query has been executed to set the
+ * number of fields in the recordset.
+ *
+ * @return void
+ */
function _initrs()
{
$this->_numOfFields = $this->_queryID->numColumns();
}
- function Fields($colname)
+ /**
+ * Returns the value of a field by its name
+ *
+ * This function retrieves the value of a field by its name. If the fetch mode
+ * is not numeric, it will return the value directly. If it is numeric, it will
+ * use a binding array to map the column names to their respective indices.
+ *
+ * @param string $colname The name of the column
+ *
+ * @return mixed The value of the field
+ */
+ function fields($colname)
{
if ($this->fetchMode != SQLITE3_NUM) {
return $this->fields[$colname];
@@ -742,6 +990,16 @@ class ADORecordset_sqlite3 extends ADORecordSet {
return $this->fields[$this->bind[strtoupper($colname)]];
}
+ /**
+ * Returns the number of rows in the recordset
+ *
+ * This function returns the number of rows in the recordset. If the recordset
+ * is empty, it will return 0.
+ *
+ * @param array $row ignored for SQLite3
+ *
+ * @return int The number of rows in the recordset
+ */
function _seek($row)
{
// sqlite3 does not implement seek
@@ -751,12 +1009,31 @@ class ADORecordset_sqlite3 extends ADORecordSet {
return false;
}
+ /**
+ * Uses the SQLite3 fetchArray method to retrieve the next row.
+ *
+ * @param bool $ignore_fields discarded for SQLite3.
+ *
+ * @return bool
+ */
function _fetch($ignore_fields=false)
{
$this->fields = $this->_queryID->fetchArray($this->fetchMode);
+ if (!empty($this->fields) && ADODB_ASSOC_CASE != ADODB_ASSOC_CASE_NATIVE) {
+ $this->fields = array_change_key_case($this->fields, ADODB_ASSOC_CASE);
+ }
+
return !empty($this->fields);
}
+ /**
+ * Closes the recordset
+ *
+ * This function is called to close the recordset. It does not perform any
+ * specific actions for SQLite3, as the connection is managed by the ADOConnection class.
+ *
+ * @return void
+ */
function _close()
{
}
diff --git a/drivers/adodb-sybase.inc.php b/drivers/adodb-sybase.inc.php
index 699025f2..6c6a2101 100644
--- a/drivers/adodb-sybase.inc.php
+++ b/drivers/adodb-sybase.inc.php
@@ -315,15 +315,11 @@ class ADORecordset_sybase extends ADORecordSet {
// _mths works only in non-localised system
var $_mths = array('JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);
- function __construct($id,$mode=false)
+ function __construct($queryID, $mode=false)
{
- if ($mode === false) {
- global $ADODB_FETCH_MODE;
- $mode = $ADODB_FETCH_MODE;
- }
- if (!$mode) $this->fetchMode = ADODB_FETCH_ASSOC;
- else $this->fetchMode = $mode;
- parent::__construct($id);
+ parent::__construct($queryID, $mode);
+
+ $this->fetchMode = $this->adodbFetchMode ?: ADODB_FETCH_ASSOC;
}
/* Returns: an object containing field information.
@@ -412,7 +408,7 @@ class ADORecordSet_array_sybase extends ADORecordSet_array {
$themth = $ADODB_sybase_mths[$themth];
if ($themth <= 0) return false;
// h-m-s-MM-DD-YY
- return adodb_mktime(0,0,0,$themth,$rr[2],$rr[3]);
+ return mktime(0,0,0,$themth,$rr[2],$rr[3]);
}
static function UnixTimeStamp($v)
@@ -439,6 +435,6 @@ class ADORecordSet_array_sybase extends ADORecordSet_array {
break;
}
// h-m-s-MM-DD-YY
- return adodb_mktime($rr[4],$rr[5],0,$themth,$rr[2],$rr[3]);
+ return mktime($rr[4],$rr[5],0,$themth,$rr[2],$rr[3]);
}
}