<?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;
> }