Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
<?php
/**
< @version v5.20.16 12-Jan-2020 < @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved. < @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community < < This is a version of the ADODB driver for DB2. It uses the 'ibm_db2' PECL extension < for PHP (http://pecl.php.net/package/ibm_db2), which in turn requires DB2 V8.2.2 or < higher. < < Originally tested with PHP 5.1.1 and Apache 2.0.55 on Windows XP SP2. < More recently tested with PHP 5.1.2 and Apache 2.0.55 on Windows XP SP2. < < This file was ported from "adodb-odbc.inc.php" by Larry Menard, "larry.menard#rogers.com". < I ripped out what I believed to be a lot of redundant or obsolete code, but there are < probably still some remnants of the ODBC support in this file; I'm relying on reviewers < of this code to point out any other things that can be removed.
> * IBM DB2 Native Client driver. > * > * Originally DB2 drivers were dependent on an ODBC driver, and some installations > * may still use that. To use an ODBC driver connection, use the odbc_db2 > * ADOdb driver. For Linux, you need the 'ibm_db2' PECL extension for PHP, > * For Windows, you need to locate an appropriate version of the php_ibm_db2.dll, > * as well as the IBM data server client software. > * This is basically a full rewrite of the original driver, for information > * 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 > * > * This file is part of ADOdb, a Database Abstraction Layer library for PHP. > * > * @package ADOdb > * @link https://adodb.org Project's web site and documentation > * @link https://github.com/ADOdb/ADOdb Source code and issue tracker > * > * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause > * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option, > * any later version. This means you can use it in proprietary products. > * See the LICENSE.md file distributed with this source code for details. > * @license BSD-3-Clause > * @license LGPL-2.1-or-later > * > * @copyright 2000-2013 John Lim > * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community > * @author Mark Newnham
*/ // security - hide paths if (!defined('ADODB_DIR')) die(); define("_ADODB_DB2_LAYER", 2 );
< /*-------------------------------------------------------------------------------------- < --------------------------------------------------------------------------------------*/ < < < <
class ADODB_db2 extends ADOConnection { var $databaseType = "db2"; var $fmtDate = "'Y-m-d'"; var $concat_operator = '||'; 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 $binmode = DB2_BINARY;
< var $useFetchArray = false; // setting this to true will make array elements in FETCH_ASSOC mode case-sensitive < // breaking backward-compat < var $_bindInputArray = false;
> /* > * 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";
> 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 $_haserrorfunctions = true;
var $_lastAffectedRows = 0;
< var $uCaseTables = true; // for meta* functions, uppercase table names
var $hasInsertID = true;
> var $hasGenID = true; > > /* function _insertid() > * Character used to wrap column and table names for escaping special { > * characters in column and table names as well as forcing upper and return ADOConnection::GetOne('VALUES IDENTITY_VAL_LOCAL()'); > * lower case } > */ > public $nameQuote = '"'; function __construct() > { > /* $this->_haserrorfunctions = ADODB_PHPVER >= 0x4050; > * Holds information about the stored procedure request } > * currently being built > */ // returns true or false > private $storedProcedureParameters = false; function _connect($argDSN, $argUsername, $argPassword, $argDatabasename) >
{
> function __construct() {}
< function _insertid()
> protected function _insertID($table = '', $column = '')
< function __construct()
> public function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
< $this->_haserrorfunctions = ADODB_PHPVER >= 0x4050;
> return $this->doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename);
< // returns true or false < function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
> public function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
// Replaces the odbc_binmode() call that was in Execute()
> return $this->doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename,true); ini_set('ibm_db2.binmode', $this->binmode); > } > if ($argDatabasename && empty($argDSN)) { > private function doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename, $persistent=false) > { if (stripos($argDatabasename,'UID=') && stripos($argDatabasename,'PWD=')) $this->_connectionID = db2_connect($argDatabasename,null,null); >
< ADOConnection::outp("Warning: The old ODBC based DB2 driver has been renamed 'odbc_db2'. This ADOdb driver calls PHP's native db2 extension which is not installed.");
> ADOConnection::outp("DB2 extension not installed.");
< // This needs to be set before the connect(). < // Replaces the odbc_binmode() call that was in Execute()
> > $connectionParameters = $this->unpackParameters($argDSN, > $argUsername, > $argPassword, > $argDatabasename); > > if ($connectionParameters == null) > { > /* > * Error thrown > */ > return null; > } > > $argDSN = $connectionParameters['dsn']; > $argUsername = $connectionParameters['uid']; > $argPassword = $connectionParameters['pwd']; > $argDatabasename = $connectionParameters['database']; > $useCataloguedConnection = $connectionParameters['catalogue']; > > if ($this->debug){ > 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); > } > /* > * This needs to be set before the connect(). > */
< if ($argDatabasename && empty($argDSN)) {
> if ($persistent) > $db2Function = 'db2_pconnect'; > else > $db2Function = 'db2_connect';
< if (stripos($argDatabasename,'UID=') && stripos($argDatabasename,'PWD=')) $this->_connectionID = db2_connect($argDatabasename,null,null); < else $this->_connectionID = db2_connect($argDatabasename,$argUsername,$argPassword); < } else { < if ($argDatabasename) $schema = $argDatabasename; < if (stripos($argDSN,'UID=') && stripos($argDSN,'PWD=')) $this->_connectionID = db2_connect($argDSN,null,null); < else $this->_connectionID = db2_connect($argDSN,$argUsername,$argPassword);
> /* > * We need to flatten out the connectionParameters > */ > > $db2Options = array(); > if ($this->connectionParameters) > { > foreach($this->connectionParameters as $p) > foreach($p as $k=>$v) > $db2Options[$k] = $v;
< // For db2_connect(), there is an optional 4th arg. If present, it must be < // an array of valid options. So far, we don't use them.
> if ($useCataloguedConnection) > $this->_connectionID = $db2Function($argDatabasename, > $argUsername, > $argPassword, > $db2Options); > else > $this->_connectionID = $db2Function($argDSN, > null, > null, > $db2Options); >
< if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
< if ($this->_connectionID && isset($schema)) $this->Execute("SET SCHEMA=$schema");
> if ($this->_connectionID && $this->connectStmt) > $this->execute($this->connectStmt); >
return $this->_connectionID != false;
>
}
< // returns true or false < function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
> /** > * 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 (!function_exists('db2_connect')) return null;
< // This needs to be set before the connect(). < // Replaces the odbc_binmode() call that was in Execute() < ini_set('ibm_db2.binmode', $this->binmode);
< $this->_errorMsg = '';
> $connectionParameters = array('dsn'=>'', > 'uid'=>'', > 'pwd'=>'', > 'database'=>'', > 'catalogue'=>true > );
< if ($argDatabasename && empty($argDSN)) {
> /* > * 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 (stripos($argDatabasename,'UID=') && stripos($argDatabasename,'PWD=')) $this->_connectionID = db2_pconnect($argDatabasename,null,null); < else $this->_connectionID = db2_pconnect($argDatabasename,$argUsername,$argPassword); < } else { < if ($argDatabasename) $schema = $argDatabasename; < if (stripos($argDSN,'UID=') && stripos($argDSN,'PWD=')) $this->_connectionID = db2_pconnect($argDSN,null,null); < else $this->_connectionID = db2_pconnect($argDSN,$argUsername,$argPassword);
> if (!$argDSN && !$argDatabasename) > { > $errorMessage = 'Supply either catalogued or uncatalogued connection parameters'; > $this->_errorMsg = $errorMessage; > if ($this->debug) > ADOConnection::outp($errorMessage); > return null;
}
< $this->_errorMsg = @db2_conn_errormsg(); < if ($this->_connectionID && $this->autoRollback) @db2_rollback($this->_connectionID); < if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
> $useCataloguedConnection = true; > $schemaName = '';
< if ($this->_connectionID && isset($schema)) $this->Execute("SET SCHEMA=$schema"); < return $this->_connectionID != 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); > > } > $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->isDsn($argDSN) && $this->isDsn($argDatabasename)) > { > /* > * Switch them around for next test > */ > $temp = $argDSN; > $argDsn = $argDatabasename; > $argDatabasenME = $temp; > } > > if ($this->isDsn($argDSN)) > { > > 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 (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; > > } > else > { > $errorMessage = 'Uncatalogued connection parameters '; > $errorMessage.= 'must contain a database= argument'; > > if ($this->debug) > ADOConnection::outp($errorMessage); > return null; > } > } > > if ($argDSN && !$argDatabasename && $useCataloguedConnection) > { > $argDatabasename = $argDSN; > $argDSN = ''; > } > > > if ($useCataloguedConnection > && (!$argDatabasename > || !$argUsername > || !$argPassword)) > { > > $errorMessage = 'For catalogued connections, provide '; > $errorMessage.= 'database, username and password'; > $this->_errorMsg = $errorMessage; > if ($this->debug) > ADOConnection::outp($errorMessage); > return null; > > } > > if ($argDatabasename) > $this->database = $argDatabasename; > elseif (!$this->database) > $this->database = $this->getDatabasenameFromDsn($argDSN); > > > $connectionParameters = array('dsn'=>$argDSN, > 'uid'=>$argUsername, > 'pwd'=>$argPassword, > 'database'=>$argDatabasename, > 'catalogue'=>$useCataloguedConnection > ); > > return $connectionParameters; > > } > > /** > * 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 < function DBTimeStamp($ts, $isfld = false)
> > /** > * Gets the database name from the DSN > * > * @param string $dsnString > * > * @return string > */ > private function getDatabasenameFromDsn($dsnString){ > > $dsnArray = preg_split('/[;=]+/',$dsnString); > $dbIndex = array_search('database',$dsnArray); > > return $dsnArray[$dbIndex + 1]; > } > > > /** > * 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);
> if (is_string($ts)) $ts = ADORecordSet::unixTimeStamp($ts);
return 'TO_DATE('.adodb_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 < function SQLDate($fmt, $col=false)
> /** > * 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)
{
< // use right() and replace() ?
if (!$col) $col = $this->sysDate; /* 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')"; $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; }
< function ServerInfo()
> function serverInfo()
{
< $row = $this->GetRow("SELECT service_level, fixpack_num FROM TABLE(sysproc.env_get_inst_info()) < as INSTANCEINFO");
> $sql = "SELECT service_level, fixpack_num > FROM TABLE(sysproc.env_get_inst_info()) > AS INSTANCEINFO"; > $row = $this->GetRow($sql);
if ($row) { $info['version'] = $row[0].':'.$row[1]; $info['fixpack'] = $row[1]; $info['description'] = ''; } else {
< return ADOConnection::ServerInfo();
> return ADOConnection::serverInfo();
} return $info; }
< function CreateSequence($seqname='adodbseq',$start=1)
> function createSequence($seqname='adodbseq',$start=1)
{
< if (empty($this->_genSeqSQL)) return false; < $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$start)); < if (!$ok) return false;
> if (empty($this->_genSeqSQL)) > return false; > > $ok = $this->execute(sprintf($this->_genSeqSQL,$seqname,$start)); > if (!$ok) > return false;
return true; }
< function DropSequence($seqname = 'adodbseq')
> function dropSequence($seqname='adodbseq')
{ if (empty($this->_dropSeqSQL)) return false;
< return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
> return $this->execute(sprintf($this->_dropSeqSQL,$seqname));
}
< function SelectLimit($sql, $nrows = -1, $offset = -1, $inputArr = false, $secs2cache = 0)
> function selectLimit($sql,$nrows=-1,$offset=-1,$inputArr=false,$secs2cache=0) > { > $nrows = (integer) $nrows; > > if ($offset <= 0) > { > if ($nrows >= 0) > $sql .= " FETCH FIRST $nrows ROWS ONLY "; > > $rs = $this->execute($sql,$inputArr); > > } > else
{
< $nrows = (int) $nrows; < $offset = (int) $offset; < if ($offset <= 0) { < // could also use " OPTIMIZE FOR $nrows ROWS " < if ($nrows >= 0) $sql .= " FETCH FIRST $nrows ROWS ONLY "; < $rs = $this->Execute($sql,$inputArr); < } else {
if ($offset > 0 && $nrows < 0);
< else {
> > else > {
$nrows += $offset; $sql .= " FETCH FIRST $nrows ROWS ONLY "; }
< $rs = ADOConnection::SelectLimit($sql,-1,$offset,$inputArr);
> > /* > * DB2 has no native support for mid table offset > */ > $rs = ADOConnection::selectLimit($sql,$nrows,$offset,$inputArr); >
} 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. < */ < function GenID($seq='adodbseq',$start=1)
> function errorMsg()
{
< // if you have to modify the parameter below, your database is overloaded, < // or you need to implement generation of id's yourself! < $num = $this->GetOne("VALUES NEXTVAL FOR $seq"); < return $num; < }
> if ($this->_errorMsg !== false) > return $this->_errorMsg;
> if (empty($this->_connectionID)) > return @db2_conn_errormsg();
< function ErrorMsg() < { < if ($this->_haserrorfunctions) { < if ($this->_errorMsg !== false) return $this->_errorMsg; < if (empty($this->_connectionID)) return @db2_conn_errormsg();
return @db2_conn_errormsg($this->_connectionID);
< } else return ADOConnection::ErrorMsg();
}
< function ErrorNo()
> function errorNo()
{
< if ($this->_haserrorfunctions) { < if ($this->_errorCode !== false) { < // bug in 4.0.6, error number can be corrupted string (should be 6 digits) < return (strlen($this->_errorCode)<=2) ? 0 : $this->_errorCode; < }
> if ($this->_errorCode !== false) > return $this->_errorCode; >
< if (empty($this->_connectionID)) $e = @db2_conn_error(); < else $e = @db2_conn_error($this->_connectionID);
> if (empty($this->_connectionID)) > $e = @db2_conn_error(); > > else > $e = @db2_conn_error($this->_connectionID);
< // bug in 4.0.6, error number can be corrupted string (should be 6 digits) < // so we check and patch < if (strlen($e)<=2) return 0;
return $e;
< } else return ADOConnection::ErrorNo();
}
< function BeginTrans()
> function beginTrans()
{
< if (!$this->hasTransactions) return false; < if ($this->transOff) return true;
> if (!$this->hasTransactions) > return false; > if ($this->transOff) > return true; >
$this->transCnt += 1;
>
$this->_autocommit = false;
>
return db2_autocommit($this->_connectionID,false); } function CommitTrans($ok=true) {
< if ($this->transOff) return true; < if (!$ok) return $this->RollbackTrans(); < if ($this->transCnt) $this->transCnt -= 1;
> if ($this->transOff) > return true; > > if (!$ok) > return $this->RollbackTrans(); > > if ($this->transCnt) > $this->transCnt -= 1; >
$this->_autocommit = true;
< $ret = db2_commit($this->_connectionID); < db2_autocommit($this->_connectionID,true);
> $ret = @db2_commit($this->_connectionID); > @db2_autocommit($this->_connectionID,true);
return $ret; } 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);
> $ret = @db2_rollback($this->_connectionID); > @db2_autocommit($this->_connectionID,true);
return $ret; }
< function MetaPrimaryKeys($table, $owner = false)
> /** > * 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)
{
> global $ADODB_FETCH_MODE; > $primaryKeys = array(); >
< if ($this->uCaseTables) $table = strtoupper($table);
$schema = ''; $this->_findschema($table,$schema);
> $table = $this->getTableCasedValue($table); $savem = $ADODB_FETCH_MODE; >
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
< $qid = @db2_primarykeys($this->_connectionID,'',$schema,$table);
> $this->setFetchMode(ADODB_FETCH_NUM); >
< if (!$qid) {
> $sql = "SELECT * > FROM syscat.indexes > WHERE tabname='$table'"; > > $rows = $this->getAll($sql); > > $this->setFetchMode($savem);
$ADODB_FETCH_MODE = $savem;
> return false; > if (empty($rows))
< } < $rs = new ADORecordSet_db2($qid); < $ADODB_FETCH_MODE = $savem;
< if (!$rs) return false;
> foreach ($rows as $r) > { > if ($r[7] != 'P') > continue;
< $arr = $rs->GetArray(); < $rs->Close(); < $arr2 = array(); < for ($i=0; $i < sizeof($arr); $i++) { < if ($arr[$i][3]) $arr2[] = $arr[$i][3];
> $cols = explode('+',$r[6]); > foreach ($cols as $colIndex=>$col) > { > if ($colIndex == 0) > continue; > $columnName = $this->getMetaCasedValue($col); > $primaryKeys[] = $columnName; > } > break;
}
< return $arr2;
> return $primaryKeys;
}
< function MetaForeignKeys($table, $owner = FALSE, $upper = FALSE, $asociative = FALSE )
> /** > * 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)
{
>
global $ADODB_FETCH_MODE;
< if ($this->uCaseTables) $table = strtoupper($table);
$schema = ''; $this->_findschema($table,$schema); $savem = $ADODB_FETCH_MODE; $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
< $qid = @db2_foreign_keys($this->_connectionID,'',$schema,$table); < if (!$qid) {
> > $this->setFetchMode(ADODB_FETCH_NUM); > > $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'"; > > $results = $this->getAll($sql); >
$ADODB_FETCH_MODE = $savem;
> $this->setFetchMode($savem); return false; > } > if (empty($results))
$rs = new ADORecordSet_db2($qid);
> > $foreignKeys = array(); $ADODB_FETCH_MODE = $savem; > /* > foreach ($results as $r) $rs->fields indices > { 0 PKTABLE_CAT > $parentTable = trim($this->getMetaCasedValue($r[2])); 1 PKTABLE_SCHEM > $keyName = trim($this->getMetaCasedValue($r[1])); 2 PKTABLE_NAME > $foreignKeys[$parentTable] = $keyName; 3 PKCOLUMN_NAME > } 4 FKTABLE_CAT > 5 FKTABLE_SCHEM > return $foreignKeys; 6 FKTABLE_NAME > } 7 FKCOLUMN_NAME > */ > /** if (!$rs) return false; > * Returns a list of tables > * $foreign_keys = array(); > * @param string $ttype (optional) while (!$rs->EOF) { > * @param string $schema (optional) if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) { > * @param string $mask (optional) if (!is_array($foreign_keys[$rs->fields[5].'.'.$rs->fields[6]])) > * $foreign_keys[$rs->fields[5].'.'.$rs->fields[6]] = array(); > * @return array $foreign_keys[$rs->fields[5].'.'.$rs->fields[6]][$rs->fields[7]] = $rs->fields[3]; > */ } > public function metaTables($ttype=false,$schema=false,$mask=false) $rs->MoveNext(); > { } > > global $ADODB_FETCH_MODE; $rs->Close(); > return $foreign_key; > $savem = $ADODB_FETCH_MODE; } > $ADODB_FETCH_MODE = ADODB_FETCH_NUM; > > /* function MetaTables($ttype = false, $schema = false, $mask = false) > * Values for TABLE_TYPE { > * --------------------------- global $ADODB_FETCH_MODE; > * ALIAS, HIERARCHY TABLE, INOPERATIVE VIEW, NICKNAME, > * MATERIALIZED QUERY TABLE, SYSTEM TABLE, TABLE, $savem = $ADODB_FETCH_MODE; > * TYPED TABLE, TYPED VIEW, and VIEW $ADODB_FETCH_MODE = ADODB_FETCH_NUM; > * $qid = db2_tables($this->_connectionID); > * If $ttype passed as '', match 'TABLE' and 'VIEW' > * If $ttype passed as 'T' it is assumed to be 'TABLE' $rs = new ADORecordSet_db2($qid); > * if $ttype passed as 'V' it is assumed to be 'VIEW' > */ $ADODB_FETCH_MODE = $savem; > $ttype = strtoupper($ttype); if (!$rs) { > if ($ttype) { $false = false; > /* return $false; > * @todo We could do valid type checking or array type } > */ > if ($ttype == 'V') $arr = $rs->GetArray(); > $ttype = 'VIEW'; $rs->Close(); > if ($ttype == 'T') $arr2 = array(); > $ttype = 'TABLE';
> if ($ttype) { > if (!$schema) $isview = strncmp($ttype,'V',1) === 0; > $schema = '%'; } > for ($i=0; $i < sizeof($arr); $i++) { > if (!$mask) if (!$arr[$i][2]) continue; > $mask = '%'; $type = $arr[$i][3]; > $owner = $arr[$i][1]; > $qid = @db2_tables($this->_connectionID,NULL,$schema,$mask,$ttype); $schemaval = ($schema) ? $arr[$i][1].'.' : ''; >
if ($ttype) {
> if ($isview) { > if (!$rs) if (strncmp($type,'V',1) === 0) $arr2[] = $schemaval.$arr[$i][2]; > return false; } else if (strncmp($owner,'SYS',3) !== 0) $arr2[] = $schemaval.$arr[$i][2]; > } else if (strncmp($owner,'SYS',3) !== 0) $arr2[] = $schemaval.$arr[$i][2]; > $arr = $rs->getArray(); } > return $arr2; > $rs->Close(); } > > $tableList = array(); /* >
< $rs->fields indices < 0 PKTABLE_CAT < 1 PKTABLE_SCHEM < 2 PKTABLE_NAME < 3 PKCOLUMN_NAME < 4 FKTABLE_CAT < 5 FKTABLE_SCHEM < 6 FKTABLE_NAME < 7 FKCOLUMN_NAME
> * 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 (!$rs) return false;
< $foreign_keys = array(); < while (!$rs->EOF) { < if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) { < if (!is_array($foreign_keys[$rs->fields[5].'.'.$rs->fields[6]])) < $foreign_keys[$rs->fields[5].'.'.$rs->fields[6]] = array(); < $foreign_keys[$rs->fields[5].'.'.$rs->fields[6]][$rs->fields[7]] = $rs->fields[3];
> for ($i=0; $i < sizeof($arr); $i++) > { > > $tableRow = $arr[$i]; > $tableName = $tableRow[2]; > $tableType = $tableRow[3]; > > if (!$tableName) > continue; > > if ($ttype == '' && (strcmp($tableType,'TABLE') <> 0 && strcmp($tableType,'VIEW') <> 0)) > continue; > > /* > * Set metacasing if required > */ > $tableName = $this->getMetaCasedValue($tableName); > > /* > * If we requested a schema, we prepend the schema > name to the table name > */ > if (strcmp($schema,'%') <> 0) > $tableName = $schema . '.' . $tableName; > > $tableList[] = $tableName; >
< $rs->MoveNext();
> return $tableList;
< $rs->Close(); < return $foreign_key; < }
> /** > * 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); >
#define SQL_TYPE_TIME 92
> $savem = $ADODB_FETCH_MODE; #define SQL_TYPE_TIMESTAMP 93 > $ADODB_FETCH_MODE = ADODB_FETCH_NUM; > $this->setFetchMode(ADODB_FETCH_NUM); #define SQL_UNICODE (-95) > #define SQL_UNICODE_VARCHAR (-96) > $sql = "SELECT * #define SQL_UNICODE_LONGVARCHAR (-97) > FROM syscat.indexes */ > WHERE tabname='$table'"; function DB2Types($t) > { > $rows = $this->getAll($sql); switch ((integer)$t) { > case 1: > $this->setFetchMode($savem); case 12: > $ADODB_FETCH_MODE = $savem; case 0: > case -95: > if (empty($rows)) case -96: > return false;
< function MetaTables($ttype = false, $schema = false, $mask = false)
> foreach ($rows as $r)
case -97:
> case -1: //text > $primaryIndex = $r[7] == 'P'?1:0; return 'X'; > if (!$primary) case -4: //image > /* return 'B'; > * Primary key not requested, ignore that one > */ case 9: > if ($r[7] == 'P') case 91: > continue; return 'D'; > > $indexName = $this->getMetaCasedValue($r[1]); case 10: > if (!isset($indices[$indexName])) case 11: > { case 92: > $unique = ($r[7] == 'U')?1:0; case 93: > $indices[$indexName] = array('unique'=>$unique, return 'T'; > 'primary'=>$primaryIndex, > 'columns'=>array() case 4: > ); case 5: > } case -6: > $cols = explode('+',$r[6]); return 'I'; > foreach ($cols as $colIndex=>$col) > { case -11: // uniqidentifier > if ($colIndex == 0) return 'R'; > continue; case -7: //bit > $columnName = $this->getMetaCasedValue($col); return 'L'; > $indices[$indexName]['columns'][] = $columnName; > } default: > return 'N'; > } } > } > return $indices; > function MetaColumns($table, $normalize=true) > } { > global $ADODB_FETCH_MODE; > /** > * List procedures or functions in an array. $false = false; > * if ($this->uCaseTables) $table = strtoupper($table); > * We interrogate syscat.routines instead of calling the PHP $schema = ''; > * function procedures because ADOdb requires the type of procedure $this->_findschema($table,$schema); > * this is not available in the php function > * $savem = $ADODB_FETCH_MODE; > * @param string $procedureNamePattern (optional) $ADODB_FETCH_MODE = ADODB_FETCH_NUM; > * @param string $catalog (optional) > * @param string $schemaPattern (optional) $colname = "%"; > $qid = db2_columns($this->_connectionID, "", $schema, $table, $colname); > * @return array of procedures on current database. if (empty($qid)) return $false; > * > */ $rs = new ADORecordSet_db2($qid); > public function metaProcedures($procedureNamePattern = null, $catalog = null, $schemaPattern = null) { $ADODB_FETCH_MODE = $savem; > >
if (!$rs) return $false;
> $metaProcedures = array(); $rs->_fetch(); > $procedureSQL = ''; > $catalogSQL = ''; $retarr = array(); > $schemaSQL = ''; >
< $qid = db2_tables($this->_connectionID);
< $rs = new ADORecordSet_db2($qid);
> 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);
< if (!$rs) { < $false = false; < return $false; < }
< $arr = $rs->GetArray(); < $rs->Close(); < $arr2 = array();
> if (!$result) > return false;
< if ($ttype) { < $isview = strncmp($ttype,'V',1) === 0;
> 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] > );
< for ($i=0; $i < sizeof($arr); $i++) { < if (!$arr[$i][2]) continue; < $type = $arr[$i][3]; < $owner = $arr[$i][1]; < $schemaval = ($schema) ? $arr[$i][1].'.' : ''; < if ($ttype) { < if ($isview) { < if (strncmp($type,'V',1) === 0) $arr2[] = $schemaval.$arr[$i][2]; < } else if (strncmp($owner,'SYS',3) !== 0) $arr2[] = $schemaval.$arr[$i][2]; < } else if (strncmp($owner,'SYS',3) !== 0) $arr2[] = $schemaval.$arr[$i][2];
> > return $metaProcedures; >
< return $arr2;
> > /** > * 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; >
// access uses precision to store length for char/varchar
> if ($fld->type == 'C' or $fld->type == 'X') { > if ($rs->fields[4] <= -95) // UNICODE >
< function MetaColumns($table, $normalize=true)
> public function metaColumns($table, $normalize=true)
< $false = false; < if ($this->uCaseTables) $table = strtoupper($table); < $schema = ''; < $this->_findschema($table,$schema); <
< $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
$fld->primary_key = false;
> $schema = '%'; $retarr[strtoupper($fld->name)] = $fld; > $this->_findschema($table,$schema); } else if (sizeof($retarr)>0) > $table = $this->getTableCasedValue($table);
< $qid = db2_columns($this->_connectionID, "", $schema, $table, $colname); < if (empty($qid)) return $false;
> $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; > }
< $ADODB_FETCH_MODE = $savem;
< if (!$rs) return $false;
> if (!$rs) > return false; >
if (empty($retarr)) $retarr = false;
> 12 Column Default > 13 SQL Data Type $qid = db2_primary_keys($this->_connectionID, "", $schema, $table); > 14 SQL DateTime SubType if (empty($qid)) return $false; > 15 Max length in Octets > 16 Ordinal Position $rs = new ADORecordSet_db2($qid); > 17 Is NULLABLE
< while (!$rs->EOF) { < if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) {
> while (!$rs->EOF) > { > if ($rs->fields[2] == $table) > { >
if (!$rs) return $retarr;
>
$rs->_fetch();
>
< $retarr[strtoupper($fld->name)] = $fld; < } else if (sizeof($retarr)>0)
> > //$columnName = $this->getMetaCasedValue($fld->name); > $columnName = strtoupper($fld->name); > $retarr[$columnName] = $fld; > > } > else if (sizeof($retarr)>0)
$rs->fields indices
>
0 TABLE_CAT
>
1 TABLE_SCHEM
>
< if (empty($retarr)) $retarr = false;
> if (empty($retarr)) > $retarr = false;
< $qid = db2_primary_keys($this->_connectionID, "", $schema, $table); < if (empty($qid)) return $false;
> /* > * Now we find out if the column is part of a primary key > */ > > $qid = @db2_primary_keys($this->_connectionID, "", $schema, $table); > if (empty($qid)) > return false;
< $ADODB_FETCH_MODE = $savem;
< if (!$rs) return $retarr;
> if (!$rs) > { > $ADODB_FETCH_MODE = $savem; > return $retarr; > }
while (!$rs->EOF) {
< if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) {
> 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)
> } > else if (sizeof($retarr)>0)
break;
>
$rs->MoveNext(); } $rs->Close();
< if (empty($retarr)) $retarr = false;
> $ADODB_FETCH_MODE = $savem; > > if (empty($retarr)) > return false; > > /* > * If the fetch mode is numeric, return as numeric array > */ > if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) > $retarr = array_values($retarr); >
return $retarr; }
> /** > * In this version if prepareSp, we just check to make sure function Prepare($sql) > * that the name of the stored procedure is correct { > * If true, we returns an array if (! $this->_bindInputArray) return $sql; // no binding > * else false $stmt = db2_prepare($this->_connectionID,$sql); > * if (!$stmt) { > * @param string $procedureName // we don't know whether db2 driver is parsing prepared stmts, so just return sql > * @param mixed $parameters (not used in db2 connections) return $sql; > * @return mixed[] } > */ return array($sql,$stmt,false); > function prepareSp($procedureName,$parameters=false) { } > > global $ADODB_FETCH_MODE; /* returns queryID or false */ > function _query($sql,$inputarr=false) > $this->storedProcedureParameters = array('name'=>'', { > 'resource'=>false, $last_php_error = $this->resetLastError(); > 'in'=>array(), $this->_errorMsg = ''; > 'out'=>array(), > 'index'=>array(), if ($inputarr) { > 'parameters'=>array(), if (is_array($sql)) { > 'keyvalue' => array()); $stmtid = $sql[1]; > } else { > //$procedureName = strtoupper($procedureName); $stmtid = db2_prepare($this->_connectionID,$sql); > //$procedureName = $this->getTableCasedValue($procedureName); > if ($stmtid == false) { > $savem = $ADODB_FETCH_MODE; $this->_errorMsg = $this->getChangedErrorMsg($last_php_error); > $ADODB_FETCH_MODE = ADODB_FETCH_NUM; return false; > } > $qid = db2_procedures($this->_connectionID, NULL , '%' , $procedureName ); } > > $ADODB_FETCH_MODE = $savem; if (! db2_execute($stmtid,$inputarr)) { > if ($this->_haserrorfunctions) { > if (!$qid) $this->_errorMsg = db2_stmt_errormsg(); > { $this->_errorCode = db2_stmt_error(); > if ($this->debug) } > ADOConnection::outp(sprintf('No Procedure of name %s available',$procedureName)); return false; > return false; } > } > } else if (is_array($sql)) { > $stmtid = $sql[1]; > if (!db2_execute($stmtid)) { > $this->storedProcedureParameters['name'] = $procedureName; if ($this->_haserrorfunctions) { > /* $this->_errorMsg = db2_stmt_errormsg(); > * Now we know we have a valid procedure name, lets see if it requires $this->_errorCode = db2_stmt_error(); > * parameters } > */ return false; > $savem = $ADODB_FETCH_MODE; } > $ADODB_FETCH_MODE = ADODB_FETCH_NUM; } else > $stmtid = @db2_exec($this->_connectionID,$sql); > $qid = db2_procedure_columns($this->_connectionID, NULL , '%' , $procedureName , NULL ); > $this->_lastAffectedRows = 0; > $ADODB_FETCH_MODE = $savem; if ($stmtid) { > if (@db2_num_fields($stmtid) == 0) { > if (!$qid) $this->_lastAffectedRows = db2_num_rows($stmtid); > { $stmtid = true; > if ($this->debug) } else { > ADOConnection::outp(sprintf('No columns of name %s available',$procedureName)); $this->_lastAffectedRows = 0; > return false; } > } > $rs = new ADORecordSet_db2($qid); if ($this->_haserrorfunctions) { > if (!$rs) $this->_errorMsg = ''; > return false; $this->_errorCode = 0; > } else { > $preparedStatement = 'CALL %s(%s)'; $this->_errorMsg = $this->getChangedErrorMsg($last_php_error); > $parameterMarkers = array(); } > while (!$rs->EOF) } else { > { if ($this->_haserrorfunctions) { > $parameterName = $rs->fields[3]; $this->_errorMsg = db2_stmt_errormsg(); > if ($parameterName == '') $this->_errorCode = db2_stmt_error(); > { } else { > $rs->moveNext(); $this->_errorMsg = $this->getChangedErrorMsg($last_php_error); > continue; } > } } > $parameterType = $rs->fields[4]; return $stmtid; > $ordinalPosition = $rs->fields[17]; } > switch($parameterType) > { /* > case DB2_PARAM_IN: Insert a null into the blob field of the table first. > case DB2_PARAM_INOUT: Then use UpdateBlob to store the blob. > $this->storedProcedureParameters['in'][$parameterName] = ''; > break; Usage: > case DB2_PARAM_INOUT: > case DB2_PARAM_OUT: $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); > $this->storedProcedureParameters['out'][$parameterName] = ''; $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1'); > break; */ > } function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') > $this->storedProcedureParameters['index'][$parameterName] = $ordinalPosition; { > $this->storedProcedureParameters['parameters'][$ordinalPosition] = $rs->fields; return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false; > $rs->moveNext(); } > > } // returns true or false > $parameterCount = count($this->storedProcedureParameters['index']); function _close() > $parameterMarkers = array_fill(0,$parameterCount,'?'); { > $ret = @db2_close($this->_connectionID); > /* $this->_connectionID = false; > * We now know how many parameters to bind to the stored procedure return $ret; > */ } > $parameterList = implode(',',$parameterMarkers); > function _affectedrows() > $sql = sprintf($preparedStatement,$procedureName,$parameterList); { > return $this->_lastAffectedRows; > $spResource = @db2_prepare($this->_connectionID,$sql); } > > if (!$spResource) } > { > $errorMessage = @db2_conn_errormsg($this->_connectionID); /*-------------------------------------------------------------------------------------- > $this->_errorMsg = $errorMessage; Class Name: Recordset > --------------------------------------------------------------------------------------*/ > if ($this->debug) > ADOConnection::outp($errorMessage); class ADORecordSet_db2 extends ADORecordSet { > > return false; var $bind = false; > } var $databaseType = "db2"; > var $dataProvider = "db2"; > $this->storedProcedureParameters['resource'] = $spResource; var $useFetchArray; > > if ($this->debug) function __construct($id,$mode=false) > { { > if ($mode === false) { > ADOConnection::outp('The following parameters will be used in the SP call'); global $ADODB_FETCH_MODE; > ADOConnection::outp(print_r($this->storedProcedureParameters)); $mode = $ADODB_FETCH_MODE; > } } > /* $this->fetchMode = $mode; > * We now have a stored parameter resource > * to bind to. The spResource and sql that is returned are $this->_queryID = $id; > * not usable, its for dummy compatibility. Everything } > * will be handled by the storedProcedureParameters > * array > */ // returns the field object > return array($sql,$spResource); function FetchField($offset = -1) > { > } $o= new ADOFieldObject(); > $o->name = @db2_field_name($this->_queryID,$offset); > private function storedProcedureParameter(&$stmt, $o->type = @db2_field_type($this->_queryID,$offset); > &$var, $o->max_length = db2_field_width($this->_queryID,$offset); > $name, if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name); > $isOutput=false, else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name); > $maxLen=4000, return $o; > $type=false) } > { > /* Use associative array to get fields array */ > function Fields($colname) > $name = strtoupper($name); { > if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname]; > /* if (!$this->bind) { > * Must exist in the list of parameter names for the type $this->bind = array(); > */ for ($i=0; $i < $this->_numOfFields; $i++) { > if ($isOutput $o = $this->FetchField($i); > && !isset( $this->storedProcedureParameters['out'][$name])) $this->bind[strtoupper($o->name)] = $i; > { } > $errorMessage = sprintf('%s is not a valid OUT parameter name',$name); } > > $this->_errorMsg = $errorMessage; return $this->fields[$this->bind[strtoupper($colname)]]; > if ($this->debug) } > ADOConnection::outp($errorMessage); > return false; > } function _initrs() > { > if (!$isOutput global $ADODB_COUNTRECS; > && !isset( $this->storedProcedureParameters['in'][$name])) $this->_numOfRows = ($ADODB_COUNTRECS) ? @db2_num_rows($this->_queryID) : -1; > { $this->_numOfFields = @db2_num_fields($this->_queryID); > $errorMessage = sprintf('%s is not a valid IN parameter name',$name); // some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0 > if ($this->_numOfRows == 0) $this->_numOfRows = -1; > $this->_errorMsg = $errorMessage; } > if ($this->debug) > ADOConnection::outp($errorMessage); function _seek($row) > return false; { > } return false; > } > /* > * We will use these values to bind to when we execute // speed up SelectLimit() by switching to ADODB_FETCH_NUM as ADODB_FETCH_ASSOC is emulated > * the query function GetArrayLimit($nrows,$offset=-1) > */ { > $this->storedProcedureParameters['keyvalue'][$name] = &$var; if ($offset <= 0) { > $rs = $this->GetArray($nrows); > return true; return $rs; > } > } $savem = $this->fetchMode; > $this->fetchMode = ADODB_FETCH_NUM; > /** $this->Move($offset); > * Executes a prepared stored procedure. $this->fetchMode = $savem; > * > * The function uses the previously accumulated information and if ($this->fetchMode & ADODB_FETCH_ASSOC) { > * resources in the $storedProcedureParameters array $this->fields = $this->GetRowAssoc(); > * } > * @return mixed The statement id if successful, or false > */ $results = array(); > private function executeStoredProcedure() $cnt = 0; > { while (!$this->EOF && $nrows != $cnt) { > $results[$cnt++] = $this->fields; > /* $this->MoveNext(); > * Get the previously built resource } > */ > $stmtid = $this->storedProcedureParameters['resource']; return $results; > } > /* > * Bind our variables to the DB2 procedure > */ function MoveNext() > foreach ($this->storedProcedureParameters['keyvalue'] as $spName=>$spValue){ { > if ($this->_numOfRows != 0 && !$this->EOF) { > /* $this->_currentRow++; > * Get the ordinal position, required for binding > */ $this->fields = @db2_fetch_array($this->_queryID); > $ordinalPosition = $this->storedProcedureParameters['index'][$spName]; if ($this->fields) { > if ($this->fetchMode & ADODB_FETCH_ASSOC) { > /* $this->fields = $this->GetRowAssoc(); > * Get the db2 column dictionary for the parameter } > */ return true; > $columnDictionary = $this->storedProcedureParameters['parameters'][$ordinalPosition]; } > $parameterType = $columnDictionary[4]; } > $dataType = $columnDictionary[5]; $this->fields = false; > $precision = $columnDictionary[10]; $this->EOF = true; > $scale = $columnDictionary[9]; return false; > } > $ok = @db2_bind_param ($this->storedProcedureParameters['resource'], > $ordinalPosition , function _fetch() > $spName, { > $parameterType, > $dataType, $this->fields = db2_fetch_array($this->_queryID); > $precision, if ($this->fields) { > $scale if ($this->fetchMode & ADODB_FETCH_ASSOC) { > ); $this->fields = $this->GetRowAssoc(); > } > if (!$ok) return true; > { } > $this->_errorMsg = @db2_stmt_errormsg(); $this->fields = false; > $this->_errorCode = @db2_stmt_error(); return false; > } > if ($this->debug) > ADOConnection::outp($this->_errorMsg); function _close() > return false; { > } return @db2_free_result($this->_queryID); > } > if ($this->debug) > ADOConnection::outp("Correctly Bound parameter $spName to procedure"); } > > /* > * Build a variable in the current environment that matches > * the parameter name > */ > ${$spName} = $spValue; > > } > > /* > * All bound, execute > */
< function Prepare($sql)
> if (!@db2_execute($stmtid))
> $this->_errorMsg = @db2_stmt_errormsg(); > $this->_errorCode = @db2_stmt_error(); > > if ($this->debug) > ADOConnection::outp($this->_errorMsg); > return false; > } > > /* > * 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; > } > > return $stmtid; > } > > /** > * > * 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) > { > > /* > * 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); > > } > > /* > * We are going to add a parameter to a prepared statement > */ > if ($this->debug) > ADOConnection::outp("Adding parameter to prepared statement"); > } > > > /** > * Prepares a prepared SQL statement, not used for stored procedures > * > * @param string $sql > * > * @return mixed > */ > function prepare($sql) > { >
< $stmt = db2_prepare($this->_connectionID,$sql);
> > $stmt = @db2_prepare($this->_connectionID,$sql);
< /* returns queryID or false */ < function _query($sql,$inputarr=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)
< $last_php_error = $this->resetLastError(); < $this->_errorMsg = '';
> $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; > > case ADODB_ASSOC_CASE_LOWER: > $db2Options = array('db2_attr_case'=>DB2_CASE_LOWER); > $setOption = @db2_set_option($this->_connectionID,$db2Options,1); > break; > > default: > $db2Options = array('db2_attr_case'=>DB2_CASE_NATURAL); > $setOption = @db2_set_option($this->_connectionID,$db2Options,1); > }
< if ($inputarr) { < if (is_array($sql)) {
> if ($inputarr) > { > if (is_array($sql)) > {
< } else { < $stmtid = db2_prepare($this->_connectionID,$sql);
> } > else > { > $stmtid = @db2_prepare($this->_connectionID,$sql); > > if ($stmtid == false) > { > $this->_errorMsg = @db2_stmt_errormsg(); > $this->_errorCode = @db2_stmt_error(); > > if ($this->debug) > ADOConnection::outp($this->_errorMsg);
< if ($stmtid == false) { < $this->_errorMsg = $this->getChangedErrorMsg($last_php_error);
< if (! db2_execute($stmtid,$inputarr)) { < if ($this->_haserrorfunctions) { < $this->_errorMsg = db2_stmt_errormsg(); < $this->_errorCode = db2_stmt_error(); < }
> if (! @db2_execute($stmtid,$inputarr)) > { > $this->_errorMsg = @db2_stmt_errormsg(); > $this->_errorCode = @db2_stmt_error(); > if ($this->debug) > ADOConnection::outp($this->_errorMsg);
< } else if (is_array($sql)) { < $stmtid = $sql[1]; < if (!db2_execute($stmtid)) { < if ($this->_haserrorfunctions) { < $this->_errorMsg = db2_stmt_errormsg(); < $this->_errorCode = db2_stmt_error();
> else if (is_array($sql)) > { > > /* > * 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(); > > /* > * 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); > > 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);
< } else < $stmtid = @db2_exec($this->_connectionID,$sql);
> } > > if (!@db2_execute($stmtid)) > { > $this->_errorMsg = @db2_stmt_errormsg(); > $this->_errorCode = @db2_stmt_error(); > if ($this->debug) > ADOConnection::outp($this->_errorMsg); > return false; > } > > return $stmtid; > } > else > {
> $stmtid = @db2_exec($this->_connectionID,$sql); > }
< if ($stmtid) { < if (@db2_num_fields($stmtid) == 0) {
> if ($stmtid) > { > if (@db2_num_fields($stmtid) == 0) > {
< } else {
> } > else > {
< if ($this->_haserrorfunctions) {
< } else { < $this->_errorMsg = $this->getChangedErrorMsg($last_php_error); < } < } else { < if ($this->_haserrorfunctions) { < $this->_errorMsg = db2_stmt_errormsg(); < $this->_errorCode = db2_stmt_error(); < } else { < $this->_errorMsg = $this->getChangedErrorMsg($last_php_error);
>
> else > { > > $this->_errorMsg = @db2_stmt_errormsg(); > $this->_errorCode = @db2_stmt_error(); >
< $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
> $conn->execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
< function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
> function updateBlob($table,$column,$val,$where,$blobtype='BLOB')
< return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
> return $this->execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
> /** > * 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; > } >
< function FetchField($offset = -1)
> function fetchField($offset = 0)
< $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);
> $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); > */
< function Fields($colname)
> function fields($colname)
< if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
> > if ($this->fetchMode & ADODB_FETCH_ASSOC) { > return $this->fields[$colname]; > } >
>
>
< if ($this->_numOfRows == 0) $this->_numOfRows = -1;
> > if ($this->_numOfRows == 0) > $this->_numOfRows = -1;
< // speed up SelectLimit() by switching to ADODB_FETCH_NUM as ADODB_FETCH_ASSOC is emulated < function GetArrayLimit($nrows,$offset=-1)
> function getArrayLimit($nrows,$offset=0)
< $savem = $this->fetchMode; < $this->fetchMode = ADODB_FETCH_NUM;
>
< $this->fetchMode = $savem;
< if ($this->fetchMode & ADODB_FETCH_ASSOC) { < $this->fields = $this->GetRowAssoc(); < }
< < function MoveNext()
> function moveNext()
< if ($this->_numOfRows != 0 && !$this->EOF) {
> if ($this->EOF || $this->_numOfRows == 0) > return false; >
< $this->fields = @db2_fetch_array($this->_queryID); < if ($this->fields) { < if ($this->fetchMode & ADODB_FETCH_ASSOC) { < $this->fields = $this->GetRowAssoc();
> $this->processCoreFetch(); > return $this->processMoveRecord(); >
< return true;
> > private function processCoreFetch() > { > switch ($this->fetchMode){ > case ADODB_FETCH_ASSOC: > > /* > * 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;
< $this->fields = false;
> > private function processMoveRecord() > { > if (!$this->fields){
> return true; > } >
< < $this->fields = db2_fetch_array($this->_queryID); < if ($this->fields) { < if ($this->fetchMode & ADODB_FETCH_ASSOC) { < $this->fields = $this->GetRowAssoc(); < }
> $this->processCoreFetch(); > if ($this->fields)
< }
>
< return @db2_free_result($this->_queryID);
> $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; > }