DB_odbc();
// set type to db2
$this->phptype = 'db2';
// set special options
$this->setOption('portability',DB_PORTABILITY_LOWERCASE);
}
/**
* overrides DB_odbc::getSpecialQuery() and returns query that returns
* the tablename in lowercase.
*
* Returns the query needed to get some backend info
* @param string $type What kind of info you want to retrieve
* @return string The SQL query string
*/
function getSpecialQuery($type)
{
switch ($type) {
case 'databases':
if (!function_exists('odbc_data_source')) {
return null;
}
$res = @odbc_data_source($this->connection, SQL_FETCH_FIRST);
if (is_array($res)) {
$out = array($res['server']);
while($res = @odbc_data_source($this->connection,
SQL_FETCH_NEXT))
{
$out[] = $res['server'];
}
return $out;
} else {
return $this->odbcRaiseError();
}
break;
case 'tables':
case 'schema.tables':
$keep = 'TABLE';
break;
case 'views':
$keep = 'VIEW';
break;
case 'sequences':
return "SELECT lower(seqname) FROM syscat.sequences WHERE seqschema = '".strtoupper($this->dsn['username'])."' FOR READ ONLY";
default:
return null;
}
/*
* Removing non-conforming items in the while loop rather than
* in the odbc_tables() call because some backends choke on this:
* odbc_tables($this->connection, '', '', '', 'TABLE')
*/
$res = @odbc_tables($this->connection);
if (!$res) {
return $this->odbcRaiseError();
}
$out = array();
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
while ($row = odbc_fetch_array($res)) {
if (($row['TABLE_TYPE'] != $keep) || ($row['TABLE_SCHEM'] != strtoupper($this->dsn['username']))) {
continue;
}
if ($type == 'schema.tables') {
$out[] = $case_func($row['TABLE_SCHEM']) . '.' . $case_func($row['TABLE_NAME']);
} else {
$out[] = $case_func($row['TABLE_NAME']);
}
}
return $out;
}
/**
* overrides DB_odbc::tableInfo() and adds support for primary key flags
* needed by DataObjects. It also substitutes some datatypes that aren't
* known by DataObjects.
*
* Returns information about a table or a result set.
*
* @param object|string $result DB_result object from a query or a
* string containing the name of a table.
* While this also accepts a query result
* resource identifier, this behavior is
* deprecated.
* @param int $mode a valid tableInfo mode
*
* @return array an associative array with the information requested.
* A DB_Error object on failure.
*
* @see DB_common::tableInfo()
* @since Method available since Release 1.7.0
*/
function tableInfo($result, $mode = null)
{
if (is_string($result)) {
/*
* Probably received a table name.
* Create a result resource identifier.
*/
$id = @odbc_exec($this->connection, "SELECT tabname,colname,typename,length,nulls,keyseq FROM syscat.columns WHERE tabname = '".strtoupper($result)."' FOR READ ONLY");
if (!$id) {
return $this->odbcRaiseError();
}
$got_string = true;
} elseif (isset($result->result)) {
/*
* Probably received a result object.
* Extract the result resource identifier.
*/
$id = $result->result;
$got_string = false;
} else {
/*
* Probably received a result resource identifier.
* Copy it.
* Deprecated. Here for compatibility only.
*/
$id = $result;
$got_string = false;
}
if (!is_resource($id)) {
return $this->odbcRaiseError(DB_ERROR_NEED_MORE_DATA);
}
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
$case_func = 'strtolower';
} else {
$case_func = 'strval';
}
$count = 0;
$res = array();
while ( $aColumn = odbc_fetch_array($id) ) {
$res[$count] = array(
'table' => $got_string ? $case_func($result) : $aColumn[TABNNAME],
'name' => $case_func($aColumn['COLNAME']),
'type' => preg_replace("/CLOB/","LONGTEXT",$aColumn['TYPENAME']),
'len' => $aColumn['LENGTH'],
'flags' => ($aColumn['NULLS'] == "Y") ? '' : 'not_null '
);
if ($aColumn['KEYSEQ'])
$res[$count]['flags'] .= 'primary_key';
if ($mode & DB_TABLEINFO_ORDER) {
$res['order'][$res[$count]['name']] = $count;
}
if ($mode & DB_TABLEINFO_ORDERTABLE) {
$res['ordertable'][$res[$count]['table']][$res[$count]['name']] = $count;
}
$count++;
}
if ($mode) {
$res['num_fields'] = $count;
}
// free the result only if we were called on a table
if ($got_string) {
@odbc_free_result($id);
}
return $res;
}
// {{{ nextId()
/**
* Overrides DB_odbc::nextId
*
* @param string $seq_name name of the sequence
* @param boolean $ondemand when true, the seqence is automatically
* created if it does not exist
*
* @return int the next id number in the sequence.
* A DB_Error object on failure.
*
* @see DB_common::nextID(), DB_common::getSequenceName(),
* DB_db2_SGL::createSequence(), DB_db2_SGL::dropSequence()
*/
function nextId($seq_name, $ondemand = true)
{
$seqname = $this->getSequenceName($seq_name);
$repeat = 0;
do {
$this->expectError(DB_ERROR_NOSUCHTABLE);
$result =& $this->query("SELECT NEXTVAL FOR ${seqname} FROM sysibm.sysdummy1");
$this->popExpect();
if ($ondemand && DB::isError($result) &&
$result->getCode() == DB_ERROR_NOSUCHTABLE) {
$repeat = 1;
$result = $this->createSequence($seq_name);
if (DB::isError($result)) {
return $this->raiseError($result);
}
} else {
$repeat = 0;
}
} while ($repeat);
if (DB::isError($result)) {
return $this->raiseError($result);
}
$arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
return $arr[0];
}
/**
* Overrides DB_odbc::createSequence
*
* @param string $seq_name name of the new sequence
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::createSequence(), DB_common::getSequenceName(),
* DB_db2_SGL::nextID(), DB_db2_SGL::dropSequence()
*/
function createSequence($seq_name)
{
return $this->query('CREATE SEQUENCE '
. $this->getSequenceName($seq_name));
}
// }}}
// {{{ dropSequence()
/**
* Overrides DB_odbc::dropSequence
*
* @param string $seq_name name of the sequence to be deleted
*
* @return int DB_OK on success. A DB_Error object on failure.
*
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
* DB_odbc::nextID(), DB_odbc::createSequence()
*/
function dropSequence($seq_name)
{
return $this->query('DROP SEQUENCE '
. $this->getSequenceName($seq_name));
}
// }}}
// {{{ quoteIdentifier()
/**
* overrides DB_common::quoteIdentifier().
*
* Quote a string so it can be safely used as a table / column name
*
* Quoting style depends on which dbsyntax was passed in the DSN.
*
* Use 'mssql' as the dbsyntax in the DB DSN only if you've unchecked
* "Use ANSI quoted identifiers" when setting up the ODBC data source.
*
* @param string $str identifier name to be quoted
*
* @return string quoted identifier string
*
* @since 1.6.0
* @access public
*/
function quoteIdentifier($str)
{
if (preg_match("/^\".*\"$/",$str)) return $str;
return '"' . str_replace('"', '""', strtoupper($str)) . '"';
}
// }}}
// {{{ prepare()
/**
* Prepares a query for multiple execution with execute()
*
* Creates a query that can be run multiple times. Each time it is run,
* the placeholders, if any, will be replaced by the contents of
* execute()'s $data argument.
*
* Three types of placeholders can be used:
* + ? scalar value (i.e. strings, integers). The system
* will automatically quote and escape the data.
* + ! value is inserted 'as is'
* + & requires a file name. The file's contents get
* inserted into the query (i.e. saving binary
* data in a db)
*
* Example 1.
*
* $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)');
* $data = array(
* "John's text",
* "'it''s good'",
* 'filename.txt'
* );
* $res = $db->execute($sth, $data);
*
*
* Use backslashes to escape placeholder characters if you don't want
* them to be interpreted as placeholders:
*
* "UPDATE foo SET col=? WHERE col='over \& under'" ** * With some database backends, this is emulated. * * {@internal ibase and oci8 have their own prepare() methods.}} * * @param string $query the query to be prepared * * @return mixed DB statement resource on success. A DB_Error object * on failure. * * @see DB_common::execute() */ function prepare($query) { $tokens = preg_split('/((?last_query = $query; $query = $this->modifyQuery($query); if (!$stmt = @odbc_prepare($this->connection, $query)) { return $this->odbcRaiseError(); } $this->prepare_types[(int)$stmt] = $types; $this->manip_query[(int)$stmt] = DB::isManip($query); return $stmt; } // }}} // {{{ execute() /** * Executes a DB statement prepared with prepare(). * * To determine how many rows of a result set get buffered using * ocisetprefetch(), see the "result_buffering" option in setOptions(). * This option was added in Release 1.7.0. * * @param resource $stmt a DB statement resource returned from prepare() * @param mixed $data array, string or numeric data to be used in * execution of the statement. Quantity of items * passed must match quantity of placeholders in * query: meaning 1 for non-array items or the * quantity of elements in the array. * * @return mixed returns an oic8 result resource for successful SELECT * queries, DB_OK for other successful queries. * A DB error object is returned on failure. * * @see DB_oci8::prepare() */ function &execute($stmt, $data = array()) { $data = (array)$data; $this->last_parameters = $data; $this->_data = $data; $types =& $this->prepare_types[(int)$stmt]; if (count($types) != count($data)) { $tmp =& $this->raiseError(DB_ERROR_MISMATCH); return $tmp; } $i = 0; foreach ($data as $key => $value) { if ($types[$i] == DB_PARAM_MISC) { /* * Oracle doesn't seem to have the ability to pass a * parameter along unchanged, so strip off quotes from start * and end, plus turn two single quotes to one single quote, * in order to avoid the quotes getting escaped by * Oracle and ending up in the database. */ $data[$key] = preg_replace("/^'(.*)'$/", "\\1", $data[$key]); $data[$key] = str_replace("''", "'", $data[$key]); } elseif ($types[$i] == DB_PARAM_OPAQUE) { $fp = @fopen($data[$key], 'rb'); if (!$fp) { $tmp =& $this->raiseError(DB_ERROR_ACCESS_VIOLATION); return $tmp; } $data[$key] = fread($fp, filesize($data[$key])); fclose($fp); } $i++; } $success = @odbc_execute($stmt, $data); if (!$success) { $tmp = $this->odbcRaiseError($stmt); return $tmp; } $this->last_stmt = $stmt; if ($this->manip_query[(int)$stmt]) { $tmp = DB_OK; } else { $tmp =& new DB_result($this, $stmt); } return $tmp; } // }}} } ?>