Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php// +----------------------------------------------------------------------+// | PHP Version 4 |// +----------------------------------------------------------------------+// | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, |// | Stig. S. Bakken, Lukas Smith |// | All rights reserved. |// +----------------------------------------------------------------------+// | MDB is a merge of PEAR DB and Metabases that provides a unified DB |// | API as well as database abstraction for PHP applications. |// | This LICENSE is in the BSD license style. |// | |// | Redistribution and use in source and binary forms, with or without |// | modification, are permitted provided that the following conditions |// | are met: |// | |// | Redistributions of source code must retain the above copyright |// | notice, this list of conditions and the following disclaimer. |// | |// | Redistributions in binary form must reproduce the above copyright |// | notice, this list of conditions and the following disclaimer in the |// | documentation and/or other materials provided with the distribution. |// | |// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |// | Lukas Smith nor the names of his contributors may be used to endorse |// | or promote products derived from this software without specific prior|// | written permission. |// | |// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |// | POSSIBILITY OF SUCH DAMAGE. |// +----------------------------------------------------------------------+// | Author: Lukas Smith <smith@backendmedia.com> |// +----------------------------------------------------------------------+// $Id: oci8.php,v 1.21.4.24 2004/03/31 16:02:40 lsmith Exp $require_once('MDB/Common.php');/*** MDB OCI8 driver** Notes:* - when fetching in associative mode all keys are uppercased which is not the* intenteded behavior. Due to BC issues this will not be changed in MDB 1.x* however.** - createDatabase and dropDatabase are not supported** - Text fields with unspecified length limit are created as VARCHAR with an* optional limit that may not exceed 4000 characters.** - date fields are emulated with date fields with time set to 00:00:00.time fields are emulated with date fields with the day set to 0001-01-01.** - The numRows method is emulated by fetching all the rows into memory.* Avoid using it if for queries with large result sets.** - Oracle does not provide direct support for returning result sets restrictedto a given range. Such support is emulated in the MDB oci8 driver.** - Storing data in large object fields has to be done in two phases: first thefields are initialized using a INSERT or UPDATE query that sets the fieldsto an empty value, then the data values are uploaded to the large objectsreturned by reference from the executed queries.* Besides the fact that only INSERT and UPDATE queries are supported toupload large object data values, only UPDATE queries that affect only onerow will set the large object fields correctly.** - The driver alterTable method does not implement table or column renaming.** @package MDB* @category Database* @author Lukas Smith <smith@backendmedia.com>*/class MDB_oci8 extends MDB_Common {var $connection = 0;var $connected_user;var $connected_password;var $escape_quotes = "'";var $uncommitedqueries = 0;var $results = array();var $current_row = array();var $columns = array();var $rows = array();var $limits = array();var $row_buffer = array();var $highest_fetched_row = array();// {{{ constructor/*** Constructor*/function MDB_oci8(){$this->MDB_Common();$this->phptype = 'oci8';$this->dbsyntax = 'oci8';$this->supported['Sequences'] = 1;$this->supported['Indexes'] = 1;$this->supported['SummaryFunctions'] = 1;$this->supported['OrderByText'] = 1;$this->supported['CurrId'] = 1;$this->supported["AffectedRows"]= 1;$this->supported['Transactions'] = 1;$this->supported['SelectRowRanges'] = 1;$this->supported['LOBs'] = 1;$this->supported['Replace'] = 1;$this->supported['SubSelects'] = 1;$this->options['DBAUser'] = FALSE;$this->options['DBAPassword'] = FALSE;$this->errorcode_map = array(1 => MDB_ERROR_CONSTRAINT,900 => MDB_ERROR_SYNTAX,904 => MDB_ERROR_NOSUCHFIELD,921 => MDB_ERROR_SYNTAX,923 => MDB_ERROR_SYNTAX,942 => MDB_ERROR_NOSUCHTABLE,955 => MDB_ERROR_ALREADY_EXISTS,1400 => MDB_ERROR_CONSTRAINT_NOT_NULL,1407 => MDB_ERROR_CONSTRAINT_NOT_NULL,1476 => MDB_ERROR_DIVZERO,1722 => MDB_ERROR_INVALID_NUMBER,2289 => MDB_ERROR_NOSUCHTABLE,2291 => MDB_ERROR_CONSTRAINT,2449 => MDB_ERROR_CONSTRAINT,);}// }}}// {{{ errorNative()/*** Get the native error code of the last error (if any) that* occured on the current connection.** @access public* @return int native oci8 error code*/function errorNative($statement = NULL){if (is_resource($statement)) {$error = @OCIError($statement);} else {$error = @OCIError($this->connection);}if (is_array($error)) {return($error['code']);}return(FALSE);}// }}}// {{{ oci8RaiseError()/*** This method is used to communicate an error and invoke error* callbacks etc. Basically a wrapper for MDB::raiseError* that checks for native error msgs.** @param integer $errno error code* @param string $message userinfo message* @return object a PEAR error object* @access public* @see PEAR_Error*/function oci8RaiseError($errno = NULL, $message = NULL){if ($errno === NULL) {if ($this->connection) {$error = @OCIError($this->connection);} else {$error = @OCIError();}return($this->raiseError($this->errorCode($error['code']),NULL, NULL, $message, $error['message']));} elseif (is_resource($errno)) {$error = @OCIError($errno);return($this->raiseError($this->errorCode($error['code']),NULL, NULL, $message, $error['message']));}return($this->raiseError($this->errorCode($errno), NULL, NULL, $message));}// }}}// {{{ autoCommit()/*** Define whether database changes done on the database be automatically* committed. This function may also implicitly start or end a transaction.** @param boolean $auto_commit flag that indicates whether the database* changes should be committed right after* executing every query statement. If this* argument is 0 a transaction implicitly* started. Otherwise, if a transaction is* in progress it is ended by committing any* database changes that were pending.* @access public* @return mixed MDB_OK on success, a MDB error on failure*/function autoCommit($auto_commit){$this->debug('AutoCommit: '.($auto_commit ? 'On' : 'Off'));if ($this->auto_commit == $auto_commit) {return(MDB_OK);}if ($this->connection && $auto_commit && MDB::isError($commit = $this->commit())) {return($commit);}$this->auto_commit = $auto_commit;$this->in_transaction = !$auto_commit;return(MDB_OK);}// }}}// {{{ commit()/*** Commit the database changes done during a transaction that is in* progress. This function may only be called when auto-committing is* disabled, otherwise it will fail. Therefore, a new transaction is* implicitly started after committing the pending changes.** @access public* @return mixed MDB_OK on success, a MDB error on failure*/function commit(){$this->debug('Commit Transaction');if (!isset($this->supported['Transactions'])) {return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,'Commit transactions: transactions are not in use'));}if ($this->auto_commit) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Commit transactions: transaction changes are being auto commited'));}if ($this->uncommitedqueries) {if (!@OCICommit($this->connection)) {return($this->oci8RaiseError(NULL,'Commit transactions: Could not commit pending transaction: '."$message. Error: ".$error['code'].' ('.$error['message'].')'));}$this->uncommitedqueries = 0;}return(MDB_OK);}// }}}// {{{ rollback()/*** Cancel any database changes done during a transaction that is in* progress. This function may only be called when auto-committing is* disabled, otherwise it will fail. Therefore, a new transaction is* implicitly started after canceling the pending changes.** @access public* @return mixed MDB_OK on success, a MDB error on failure*/function rollback(){$this->debug('Rollback Transaction');if ($this->auto_commit) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Rollback transactions: transactions can not be rolled back when changes are auto commited'));}if ($this->uncommitedqueries) {if (!@OCIRollback($this->connection)) {return($this->oci8RaiseError(NULL,'Rollback transaction: Could not rollback pending transaction'));}$this->uncommitedqueries = 0;}return(MDB_OK);}// }}}// {{{ connect()/*** Connect to the database** @return TRUE on success, MDB_Error on failure*/function connect($user = NULL , $password = NULL, $persistent = NULL){if($user === NULL) {$user = $this->user;}if($password === NULL) {$password = $this->password;}if($persistent === NULL) {$persistent = $this->getOption('persistent');}if (isset($this->host)) {$sid = $this->host;} else {$sid = getenv('ORACLE_SID');}if(!strcmp($sid, '')) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Connect: it was not specified a valid Oracle Service IDentifier (SID)'));}if($this->connection != 0) {if (!strcmp($this->connected_user, $user)&& !strcmp($this->connected_password, $password)&& $this->opened_persistent == $persistent){return(MDB_OK);}$this->_close();}if(!PEAR::loadExtension($this->phptype)) {return(PEAR::raiseError(NULL, MDB_ERROR_NOT_FOUND,NULL, NULL, 'extension '.$this->phptype.' is not compiled into PHP','MDB_Error', TRUE));}if (isset($this->options['HOME'])) {putenv('ORACLE_HOME='.$this->options['HOME']);}putenv('ORACLE_SID='.$sid);$function = ($persistent ? 'OCIPLogon' : 'OCINLogon');if (!function_exists($function)) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Connect: Oracle OCI API support is not available in this PHP configuration'));}if (!($this->connection = @$function($user, $password, $sid))) {return($this->oci8RaiseError(NULL,'Connect: Could not connect to Oracle server'));}if (MDB::isError($doquery = $this->_doQuery("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'"))) {$this->_close();return($doquery);}if (MDB::isError($doquery = $this->_doQuery("ALTER SESSION SET NLS_NUMERIC_CHARACTERS='. '"))) {$this->_close();return($doquery);}$this->connected_user = $user;$this->connected_password = $password;$this->opened_persistent = $persistent;return(MDB_OK);}// }}}// {{{ _close()/*** all the RDBMS specific things needed close a DB connection** @access private*/function _close(){if ($this->connection != 0) {@OCILogOff($this->connection);$this->connection = 0;$this->affected_rows = -1;$this->uncommitedqueries = 0;}}// }}}// {{{ _doQuery()/*** all the RDBMS specific things needed close a DB connection** @access private*/function _doQuery($query, $first = 0, $limit = 0, $prepared_query = 0){$lobs = 0;$success = MDB_OK;$result = 0;$descriptors = array();if ($prepared_query) {$columns = '';$variables = '';for(reset($this->clobs[$prepared_query]), $clob = 0;$clob < count($this->clobs[$prepared_query]);$clob++, next($this->clobs[$prepared_query])){$position = key($this->clobs[$prepared_query]);if (gettype($descriptors[$position] = @OCINewDescriptor($this->connection, OCI_D_LOB)) != 'object') {$success = $this->raiseError(MDB_ERROR, NULL, NULL,'Do query: Could not create descriptor for clob parameter');break;}$columns.= ($lobs == 0 ? ' RETURNING ' : ',').$this->prepared_queries[$prepared_query-1]['Fields'][$position-1];$variables.= ($lobs == 0 ? ' INTO ' : ',').':clob'.$position;$lobs++;}if (!MDB::isError($success)) {for(reset($this->blobs[$prepared_query]), $blob = 0;$blob < count($this->blobs[$prepared_query]);$blob++, next($this->blobs[$prepared_query])) {$position = key($this->blobs[$prepared_query]);if (gettype($descriptors[$position] = @OCINewDescriptor($this->connection, OCI_D_LOB)) != 'object') {$success = $this->raiseError(MDB_ERROR, NULL, NULL,'Do query: Could not create descriptor for blob parameter');break;}$columns.= ($lobs == 0 ? ' RETURNING ' : ',').$this->prepared_queries[$prepared_query-1]['Fields'][$position-1];$variables.= ($lobs == 0 ? ' INTO ' : ',').':blob'.$position;$lobs++;}$query.= $columns.$variables;}}if (!MDB::isError($success)) {if (($statement = @OCIParse($this->connection, $query))) {if ($lobs) {for(reset($this->clobs[$prepared_query]), $clob = 0;$clob < count($this->clobs[$prepared_query]);$clob++, next($this->clobs[$prepared_query])) {$position = key($this->clobs[$prepared_query]);if (!@OCIBindByName($statement, ':clob'.$position, $descriptors[$position], -1, OCI_B_CLOB)) {$success = $this->oci8RaiseError(NULL,'Do query: Could not bind clob upload descriptor');break;}}if (!MDB::isError($success)) {for(reset($this->blobs[$prepared_query]), $blob = 0;$blob < count($this->blobs[$prepared_query]);$blob++, next($this->blobs[$prepared_query])){$position = key($this->blobs[$prepared_query]);if (!@OCIBindByName($statement, ':blob'.$position, $descriptors[$position], -1, OCI_B_BLOB)) {$success = $this->oci8RaiseError(NULL,'Do query: Could not bind blob upload descriptor');break;}}}}if (!MDB::isError($success)) {if (($result = @OCIExecute($statement, ($lobs == 0 && $this->auto_commit) ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT))) {if ($lobs) {for(reset($this->clobs[$prepared_query]), $clob = 0;$clob < count($this->clobs[$prepared_query]);$clob++, next($this->clobs[$prepared_query])){$position = key($this->clobs[$prepared_query]);$clob_stream = $this->prepared_queries[$prepared_query-1]['Values'][$position-1];for($value = '';!$this->endOfLOB($clob_stream);) {if ($this->readLOB($clob_stream, $data, $this->getOption('lob_buffer_length')) < 0) {$success = $this->raiseError();break;}$value.= $data;}if (!MDB::isError($success) && !$descriptors[$position]->save($value)) {$success = $this->oci8RaiseError(NULL,'Do query: Could not upload clob data');}}if (!MDB::isError($success)) {for(reset($this->blobs[$prepared_query]), $blob = 0;$blob < count($this->blobs[$prepared_query]);$blob++, next($this->blobs[$prepared_query])) {$position = key($this->blobs[$prepared_query]);$blob_stream = $this->prepared_queries[$prepared_query-1]['Values'][$position-1];for($value = '';!$this->endOfLOB($blob_stream);) {if ($this->readLOB($blob_stream, $data, $this->getOption('lob_buffer_length')) < 0) {$success = $this->raiseError();break;}$value.= $data;}if (!MDB::isError($success) && !$descriptors[$position]->save($value)) {$success = $this->oci8RaiseError(NULL,'Do query: Could not upload blob data');}}}}if ($this->auto_commit) {if ($lobs) {if (MDB::isError($success)) {if (!@OCIRollback($this->connection)) {$success = $this->oci8RaiseError(NULL,'Do query: '.$success->getUserinfo().' and then could not rollback LOB updating transaction');}} else {if (!@OCICommit($this->connection)) {$success = $this->oci8RaiseError(NULL,'Do query: Could not commit pending LOB updating transaction');}}}} else {$this->uncommitedqueries++;}if (!MDB::isError($success)) {switch (@OCIStatementType($statement)) {case 'SELECT':$result_value = intval($statement);$this->current_row[$result_value] = -1;if ($limit > 0) {$this->limits[$result_value] = array($first, $limit, 0);}$this->highest_fetched_row[$result_value] = -1;break;default:$this->affected_rows = @OCIRowCount($statement);@OCIFreeCursor($statement);break;}$result = $statement;}} else {return($this->oci8RaiseError($statement, 'Do query: Could not execute query'));}}} else {return($this->oci8RaiseError(NULL, 'Do query: Could not parse query'));}}for(reset($descriptors), $descriptor = 0;$descriptor < count($descriptors);$descriptor++, next($descriptors)){@OCIFreeDesc($descriptors[key($descriptors)]);}return($result);}// }}}// {{{ query()/*** Send a query to the database and return any results** @access public* @param string $query the SQL query* @param array $types array that contains the types of the columns in* the result set* @return mixed a result handle or MDB_OK on success, a MDB error on failure*/function query($query, $types = NULL){$this->debug("Query: $query");$this->last_query = $query;$first = $this->first_selected_row;$limit = $this->selected_row_limit;$this->first_selected_row = $this->selected_row_limit = 0;if (MDB::isError($connect = $this->connect())) {return($connect);}if(!MDB::isError($result = $this->_doQuery($query, $first, $limit))) {if ($types != NULL) {if (!is_array($types)) {$types = array($types);}if (MDB::isError($err = $this->setResultTypes($result, $types))) {$this->freeResult($result);return($err);}}return($result);}return($this->oci8RaiseError());}// }}}// {{{ _executePreparedQuery()/*** Execute a prepared query statement.** @param int $prepared_query argument is a handle that was returned by* the function prepareQuery()* @param string $query query to be executed* @param array $types array that contains the types of the columns in* the result set* @return mixed a result handle or MDB_OK on success, a MDB error on failure* @access private*/function _executePreparedQuery($prepared_query, $query){$first = $this->first_selected_row;$limit = $this->selected_row_limit;$this->first_selected_row = $this->selected_row_limit = 0;if (MDB::isError($connect = $this->connect())) {return($connect);}return($this->_doQuery($query, $first, $limit, $prepared_query));}// }}}// {{{ _skipLimitOffset()/*** Skip the first row of a result set.** @param resource $result* @return mixed a result handle or MDB_OK on success, a MDB error on failure* @access private*/function _skipLimitOffset($result){$result_value = intval($result);$first = $this->limits[$result_value][0];for(;$this->limits[$result_value][2] < $first;$this->limits[$result_value][2]++) {if (!@OCIFetch($result)) {$this->limits[$result_value][2] = $first;return($this->raiseError(MDB_ERROR, NULL, NULL,'Skip first rows: could not skip a query result row'));}}return(MDB_OK);}// }}}// {{{ getColumnNames()/*** Retrieve the names of columns returned by the DBMS in a query result.** @param resource $result result identifier* @return mixed an associative array variable* that will hold the names of columns.The* indexes of the array are the column names* mapped to lower case and the values are the* respective numbers of the columns starting* from 0. Some DBMS may not return any* columns when the result set does not* contain any rows.** a MDB error on failure* @access public*/function getColumnNames($result){$result_value = intval($result);if (!isset($this->highest_fetched_row[$result_value])) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Get column names: it was specified an inexisting result set'));}if (!isset($this->columns[$result_value])) {$this->columns[$result_value] = array();$columns = @OCINumCols($result);for($column = 0; $column < $columns; $column++) {$field_name = @OCIColumnName($result, $column + 1);if ($this->options['optimize'] == 'portability') {$field_name = strtolower($field_name);}$this->columns[$result_value][$field_name] = $column;}}return($this->columns[$result_value]);}// }}}// {{{ numCols()/*** Count the number of columns returned by the DBMS in a query result.** @param resource $result result identifier* @return mixed integer value with the number of columns, a MDB error* on failure* @access public*/function numCols($result){$result_value = intval($result);if (!isset($this->highest_fetched_row[$result_value])) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Number of columns: it was specified an inexisting result set'));}return(@OCINumCols($result));}// }}}// {{{ endOfResult()/*** check if the end of the result set has been reached** @param resource $result result identifier* @return mixed TRUE or FALSE on sucess, a MDB error on failure* @access public*/function endOfResult($result){$result_value = intval($result);if (!isset($this->current_row[$result_value])) {return($this->raiseError(MDB_ERROR, NULL, NULL,'End of result: attempted to check the end of an unknown result'));}if (isset($this->results[$result_value]) && end($this->results[$result_value]) === FALSE) {return(($this->highest_fetched_row[$result_value]-1) <= $this->current_row[$result_value]);}if (isset($this->row_buffer[$result_value])) {return(!$this->row_buffer[$result_value]);}if (isset($this->limits[$result_value])) {if (MDB::isError($this->_skipLimitOffset($result))|| ($this->current_row[$result_value]) > $this->limits[$result_value][1]) {return(TRUE);}}if (@OCIFetchInto($result, $this->row_buffer[$result_value], OCI_RETURN_NULLS)) {return(FALSE);}$this->row_buffer[$result_value] = FALSE;return(TRUE);}// }}}// {{{ _retrieveLob()/*** fetch a lob value from a result set** @param int $lob handle to a lob created by the createLob() function* @return mixed MDB_OK on success, a MDB error on failure* @access private*/function _retrieveLob($lob){if (!isset($this->lobs[$lob])) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Retrieve LOB: it was not specified a valid lob'));}if (!isset($this->lobs[$lob]['Value'])) {unset($lob_object);$result = $this->lobs[$lob]['Result'];$row = $this->lobs[$lob]['Row'];$field = $this->lobs[$lob]['Field'];$lob_object = $this->fetch($result, $row, $field);if (MDB::isError($lob_object)) {return $lob_object;}if (gettype($lob_object) != 'object') {return($this->raiseError(MDB_ERROR, NULL, NULL,'Retrieve LOB: attemped to retrieve LOB from non existing or NULL column'));}$this->lobs[$lob]['Value'] = $lob_object->load();}return(MDB_OK);}// }}}// {{{ fetch()/*** fetch value from a result set** @param resource $result result identifier* @param int $rownum number of the row where the data can be found* @param int $colnum field number where the data can be found* @return mixed string on success, a MDB error on failure* @access public*/function fetch($result, $rownum, $colnum){$fetchmode = is_numeric($colnum) ? MDB_FETCHMODE_ORDERED : MDB_FETCHMODE_ASSOC;$row = $this->fetchInto($result, $fetchmode, $rownum);if (MDB::isError($row)) {return($row);}if (!array_key_exists($colnum, $row)) {return(NULL);}return($row[$colnum]);}// }}}// {{{ fetchClob()/*** fetch a clob value from a result set** @param resource $result result identifier* @param int $row number of the row where the data can be found* @param int $field field number where the data can be found* @return mixed content of the specified data cell, a MDB error on failure,* a MDB error on failure* @access public*/function fetchClob($result, $row, $field){return($this->fetchLOB($result, $row, $field));}// }}}// {{{ fetchBlob()/*** fetch a blob value from a result set** @param resource $result result identifier* @param int $row number of the row where the data can be found* @param int $field field number where the data can be found* @return mixed content of the specified data cell, a MDB error on failure* @access public*/function fetchBlob($result, $row, $field){return($this->fetchLOB($result, $row, $field));}// }}}// {{{ resultIsNull()/*** Determine whether the value of a query result located in given row and* field is a NULL.** @param resource $result result identifier* @param int $rownum number of the row where the data can be found* @param int $field field number where the data can be found* @return mixed TRUE or FALSE on success, a MDB error on failure* @access public*/function resultIsNull($result, $rownum, $field){$value = $this->fetch($result, $rownum, $field);if (MDB::isError($value)) {return($value);}return(!isset($value));}// }}}// {{{ convertResult()/*** convert a value to a RDBMS indepdenant MDB type** @param mixed $value value to be converted* @param int $type constant that specifies which type to convert to* @return mixed converted value* @access public*/function convertResult($value, $type){switch ($type) {case MDB_TYPE_DATE:return(substr($value, 0, strlen('YYYY-MM-DD')));case MDB_TYPE_TIME:return(substr($value, strlen('YYYY-MM-DD '), strlen('HH:MI:SS')));default:return($this->_baseConvertResult($value, $type));}}// }}}// {{{ numRows()/*** returns the number of rows in a result object** @param ressource $result a valid result ressouce pointer* @return mixed MDB_Error or the number of rows* @access public*/function numRows($result){$result_value = intval($result);if (!isset($this->current_row[$result_value])) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Number of rows: attemped to obtain the number of rows contained in an unknown query result'));}if (!isset($this->results[$result_value][$this->highest_fetched_row[$result_value]])|| $this->results[$result_value][$this->highest_fetched_row[$result_value]] !== FALSE) {if (isset($this->limits[$result_value])) {if (MDB::isError($skipfirstrow = $this->_skipLimitOffset($result))) {return($skipfirstrow);}}if (isset($this->row_buffer[$result_value])) {++$this->highest_fetched_row[$result_value];$this->results[$result_value][$this->highest_fetched_row[$result_value]]= $this->row_buffer[$result_value];unset($this->row_buffer[$result_value]);}if (!isset($this->results[$result_value][$this->highest_fetched_row[$result_value]])|| $this->results[$result_value][$this->highest_fetched_row[$result_value]] !== FALSE) {while((!isset($this->limits[$result_value])|| ($this->highest_fetched_row[$result_value]+1) < $this->limits[$result_value][1])&& @OCIFetchInto($result, $buffer, OCI_RETURN_NULLS)) {++$this->highest_fetched_row[$result_value];$this->results[$result_value][$this->highest_fetched_row[$result_value]] = $buffer;}++$this->highest_fetched_row[$result_value];$this->results[$result_value][$this->highest_fetched_row[$result_value]] = FALSE;}}return(max(0, $this->highest_fetched_row[$result_value]));}// }}}// {{{ freeResult()/*** Free the internal resources associated with $result.** @param $result result identifier* @return bool TRUE on success, FALSE if $result is invalid* @access public*/function freeResult($result){$result_value = intval($result);if (!isset($this->current_row[$result_value])) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Free result: attemped to free an unknown query result'));}if(isset($this->highest_fetched_row[$result_value])) {unset($this->highest_fetched_row[$result_value]);}if(isset($this->row_buffer[$result_value])) {unset($this->row_buffer[$result_value]);}if(isset($this->limits[$result_value])) {unset($this->limits[$result_value]);}if(isset($this->current_row[$result_value])) {unset($this->current_row[$result_value]);}if(isset($this->results[$result_value])) {unset($this->results[$result_value]);}if(isset($this->columns[$result_value])) {unset($this->columns[$result_value]);}if(isset($this->result_types[$result_value])) {unset($this->result_types[$result_value]);}return(@OCIFreeCursor($result));}// }}}// {{{ getTypeDeclaration()/*** Obtain DBMS specific native datatype as a string** @param string $field associative array with the name of the properties* of the field being declared as array indexes. Currently, the types* of supported field properties are as follows:** @return string with the correct RDBMS native type* @access public*/function getTypeDeclaration($field){switch ($field['type']) {case 'integer':return('INT');case 'text':return('VARCHAR ('.(isset($field['length'])? $field['length'] : (isset($this->options['DefaultTextFieldLength'])? $this->options['DefaultTextFieldLength'] : 4000)).')');case 'boolean':return('CHAR (1)');case 'date':case 'time':case 'timestamp':return('DATE');case 'float':return('NUMBER');case 'decimal':return('NUMBER(*,'.$this->decimal_places.')');}return('');}// }}}// {{{ getIntegerDeclaration()/*** Obtain DBMS specific SQL code portion needed to declare an integer type* field to be used in statements like CREATE TABLE.** @param string $name name the field to be declared.* @param string $field associative array with the name of the properties* of the field being declared as array indexes. Id* ently, the types* of supported field properties are as follows:** unsigned* Boolean flag that indicates whether the field should be* declared as unsigned integer if possible.** default* Integer value to be used as default for this field.** notnull* Boolean flag that indicates whether this field is constrained* to not be set to NULL.* @return string DBMS specific SQL code portion that should be used to* declare the specified field.* @access public*/function getIntegerDeclaration($name, $field){if (isset($field['unsigned']))$this->warning = "unsigned integer field \"$name\" is being declared as signed integer";return("$name ".$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT '.$field['default'] : '').(isset($field['notnull']) ? ' NOT NULL' : ''));}// }}}// {{{ getTextDeclaration()/*** Obtain DBMS specific SQL code portion needed to declare an text type* field to be used in statements like CREATE TABLE.** @param string $name name the field to be declared.* @param string $field associative array with the name of the properties* of the field being declared as array indexes. Currently, the types* of supported field properties are as follows:** length* Integer value that determines the maximum length of the text* field. If this argument is missing the field should be* declared to have the longest length allowed by the DBMS.** default* Text value to be used as default for this field.** notnull* Boolean flag that indicates whether this field is constrained* to not be set to NULL.* @return string DBMS specific SQL code portion that should be used to* declare the specified field.* @access public*/function getTextDeclaration($name, $field){return("$name ".$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT '.$this->getTextValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : ''));}// }}}// {{{ getClobDeclaration()/*** Obtain DBMS specific SQL code portion needed to declare an character* large object type field to be used in statements like CREATE TABLE.** @param string $name name the field to be declared.* @param string $field associative array with the name of the properties* of the field being declared as array indexes. Currently, the types* of supported field properties are as follows:** length* Integer value that determines the maximum length of the large* object field. If this argument is missing the field should be* declared to have the longest length allowed by the DBMS.** notnull* Boolean flag that indicates whether this field is constrained* to not be set to NULL.* @return string DBMS specific SQL code portion that should be used to* declare the specified field.* @access public*/function getClobDeclaration($name, $field){return("$name CLOB".(isset($field['notnull']) ? ' NOT NULL' : ''));}// }}}// {{{ getBlobDeclaration()/*** Obtain DBMS specific SQL code portion needed to declare an binary large* object type field to be used in statements like CREATE TABLE.** @param string $name name the field to be declared.* @param string $field associative array with the name of the properties* of the field being declared as array indexes. Currently, the types* of supported field properties are as follows:** length* Integer value that determines the maximum length of the large* object field. If this argument is missing the field should be* declared to have the longest length allowed by the DBMS.** notnull* Boolean flag that indicates whether this field is constrained* to not be set to NULL.* @return string DBMS specific SQL code portion that should be used to* declare the specified field.* @access public*/function getBlobDeclaration($name, $field){return("$name BLOB".(isset($field['notnull']) ? ' NOT NULL' : ''));}// }}}// {{{ getBooleanDeclaration()/*** Obtain DBMS specific SQL code portion needed to declare a boolean type* field to be used in statements like CREATE TABLE.** @param string $name name the field to be declared.* @param string $field associative array with the name of the properties* of the field being declared as array indexes. Currently, the types* of supported field properties are as follows:** default* Boolean value to be used as default for this field.** notnullL* Boolean flag that indicates whether this field is constrained* to not be set to NULL.* @return string DBMS specific SQL code portion that should be used to* declare the specified field.* @access public*/function getBooleanDeclaration($name, $field){return("$name ".$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT '.$this->getBooleanValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : ''));}// }}}// {{{ getDateDeclaration()/*** Obtain DBMS specific SQL code portion needed to declare a date type* field to be used in statements like CREATE TABLE.** @param string $name name the field to be declared.* @param string $field associative array with the name of the properties* of the field being declared as array indexes. Currently, the types* of supported field properties are as follows:** default* Date value to be used as default for this field.** notnull* Boolean flag that indicates whether this field is constrained* to not be set to NULL.* @return string DBMS specific SQL code portion that should be used to* declare the specified field.* @access public*/function getDateDeclaration($name, $field){return("$name ".$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT '.$this->getDateValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : ''));}// }}}// {{{ getTimestampDeclaration()/*** Obtain DBMS specific SQL code portion needed to declare a timestamp* field to be used in statements like CREATE TABLE.** @param string $name name the field to be declared.* @param string $field associative array with the name of the properties* of the field being declared as array indexes. Currently, the types* of supported field properties are as follows:** default* Timestamp value to be used as default for this field.** notnull* Boolean flag that indicates whether this field is constrained* to not be set to NULL.* @return string DBMS specific SQL code portion that should be used to* declare the specified field.* @access public*/function getTimestampDeclaration($name, $field){return("$name ".$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT '.$this->getTimestampValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : ''));}// }}}// {{{ getTimeDeclaration()/*** Obtain DBMS specific SQL code portion needed to declare a time* field to be used in statements like CREATE TABLE.** @param string $name name the field to be declared.* @param string $field associative array with the name of the properties* of the field being declared as array indexes. Currently, the types* of supported field properties are as follows:** default* Time value to be used as default for this field.** notnull* Boolean flag that indicates whether this field is constrained* to not be set to NULL.* @return string DBMS specific SQL code portion that should be used to* declare the specified field.* @access public*/function getTimeDeclaration($name, $field){return("$name ".$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT '.$this->getTimeValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : ''));}// }}}// {{{ getFloatDeclaration()/*** Obtain DBMS specific SQL code portion needed to declare a float type* field to be used in statements like CREATE TABLE.** @param string $name name the field to be declared.* @param string $field associative array with the name of the properties* of the field being declared as array indexes. Currently, the types* of supported field properties are as follows:** default* Float value to be used as default for this field.** notnull* Boolean flag that indicates whether this field is constrained* to not be set to NULL.* @return string DBMS specific SQL code portion that should be used to* declare the specified field.* @access public*/function getFloatDeclaration($name, $field){return("$name ".$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT '.$this->getFloatValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : ''));}// }}}// {{{ getDecimalDeclaration()/*** Obtain DBMS specific SQL code portion needed to declare a decimal type* field to be used in statements like CREATE TABLE.** @param string $name name the field to be declared.* @param string $field associative array with the name of the properties* of the field being declared as array indexes. Currently, the types* of supported field properties are as follows:** default* Decimal value to be used as default for this field.** notnull* Boolean flag that indicates whether this field is constrained* to not be set to NULL.* @return string DBMS specific SQL code portion that should be used to* declare the specified field.* @access public*/function getDecimalDeclaration($name, $field){return("$name ".$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT '.$this->getDecimalValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : ''));}// }}}// {{{ getClobValue()/*** Convert a text value into a DBMS specific format that is suitable to* compose query statements.** @param resource $prepared_query query handle from prepare()* @param $parameter* @param $clob* @return string text string that represents the given argument value in* a DBMS specific format.* @access public*/function getClobValue($prepared_query, $parameter, $clob){return('EMPTY_CLOB()');}// }}}// {{{ freeClobValue()/*** free a character large object** @param resource $prepared_query query handle from prepare()* @param string $blob* @param string $value* @access public*/function freeClobValue($prepared_query, $clob, &$value){unset($value);}// }}}// {{{ getBlobValue()/*** Convert a text value into a DBMS specific format that is suitable to* compose query statements.** @param resource $prepared_query query handle from prepare()* @param $parameter* @param $blob* @return string text string that represents the given argument value in* a DBMS specific format.* @access public*/function getBlobValue($prepared_query, $parameter, $blob){return('EMPTY_BLOB()');}// }}}// {{{ freeBlobValue()/*** free a binary large object** @param resource $prepared_query query handle from prepare()* @param string $blob* @param string $value* @access public*/function freeBlobValue($prepared_query, $blob, &$value){unset($value);}// }}}// {{{ getDateValue()/*** Convert a text value into a DBMS specific format that is suitable to* compose query statements.** @param string $value text string value that is intended to be converted.* @return string text string that represents the given argument value in* a DBMS specific format.* @access public*/function getDateValue($value){return(($value === NULL) ? 'NULL' : "TO_DATE('$value','YYYY-MM-DD')");}// }}}// {{{ getTimestampValue()/*** Convert a text value into a DBMS specific format that is suitable to* compose query statements.** @param string $value text string value that is intended to be converted.* @return string text string that represents the given argument value in* a DBMS specific format.* @access public*/function getTimestampValue($value){return(($value === NULL) ? 'NULL' : "TO_DATE('$value','YYYY-MM-DD HH24:MI:SS')");}// }}}// {{{ getTimeValue()/*** Convert a text value into a DBMS specific format that is suitable to* compose query statements.** @param string $value text string value that is intended to be converted.* @return string text string that represents the given argument value in* a DBMS specific format.* @access public*/function getTimeValue($value){return(($value === NULL) ? 'NULL' : "TO_DATE('0001-01-01 $value','YYYY-MM-DD HH24:MI:SS')");}// }}}// {{{ getFloatValue()/*** Convert a text value into a DBMS specific format that is suitable to* compose query statements.** @param string $value text string value that is intended to be converted.* @return string text string that represents the given argument value in* a DBMS specific format.* @access public*/function getFloatValue($value){return(($value === NULL) ? 'NULL' : (float)$value);}// }}}// {{{ getDecimalValue()/*** Convert a text value into a DBMS specific format that is suitable to* compose query statements.** @param string $value text string value that is intended to be converted.* @return string text string that represents the given argument value in* a DBMS specific format.* @access public*/function getDecimalValue($value){return(($value === NULL) ? 'NULL' : $value);}// }}}// {{{ nextId()/*** returns the next free id of a sequence** @param string $seq_name name of the sequence* @param boolean $ondemand when TRUE the seqence is* automatic created, if it* not exists* @return mixed MDB_Error or id* @access public*/function nextId($seq_name, $ondemand = TRUE){if (MDB::isError($connect = $this->connect())) {return($connect);}$sequence_name = $this->getSequenceName($seq_name);$this->expectError(MDB_ERROR_NOSUCHTABLE);$result = $this->_doQuery("SELECT $sequence_name.nextval FROM DUAL");$this->popExpect();if ($ondemand && MDB::isError($result)&& $result->getCode() == MDB_ERROR_NOSUCHTABLE){$result = $this->createSequence($seq_name, 1);if (MDB::isError($result)) {return $result;}return $this->nextId($seq_name, false);}return($this->fetchOne($result));}// }}}// {{{ currId()/*** returns the current id of a sequence** @param string $seq_name name of the sequence* @return mixed MDB_Error or id* @access public*/function currId($seq_name){$sequence_name = $this->getSequenceName($seq_name);$result = $this->_doQuery("SELECT $sequence_name.currval FROM DUAL");if (MDB::isError($result)) {return($this->raiseError(MDB_ERROR, NULL, NULL,'currId: unable to select from ' . $seq_name) );}$result = $this->fetchOne($result);if (!is_numeric($result)) {return($this->raiseError(MDB_ERROR, NULL, NULL,'currId: could not find value in sequence table'));}return($result);}// }}}// {{{ fetchInto()/*** Fetch a row and return data in an array.** @param resource $result result identifier* @param int $fetchmode how the array data should be indexed* @param int $rownum the row number to fetch* @return mixed data array or NULL on success, a MDB error on failure* @access public*/function fetchInto($result, $fetchmode = MDB_FETCHMODE_DEFAULT, $rownum = NULL){$result_value = intval($result);if (!isset($this->current_row[$result_value])) {return($this->raiseError(MDB_ERROR, NULL, NULL,'fetchInto: attemped to fetch on an unknown query result'));}if ($fetchmode == MDB_FETCHMODE_DEFAULT) {$fetchmode = $this->fetchmode;}if (is_null($rownum)) {$rownum = $this->current_row[$result_value] + 1;}if (!isset($this->results[$result_value][$rownum])&& (!isset($this->results[$result_value][$this->highest_fetched_row[$result_value]])|| $this->results[$result_value][$this->highest_fetched_row[$result_value]] !== FALSE)) {if (isset($this->limits[$result_value])) {// upper limitif ($rownum > $this->limits[$result_value][1]) {// are all previous rows fetched so that we can set the end// of the result set and not have any "holes" in between?if ($rownum == 0|| (isset($this->results[$result_value])&& count($this->results[$result_value]) == $rownum)) {$this->highest_fetched_row[$result_value] = $rownum;$this->current_row[$result_value] = $rownum;$this->results[$result_value][$rownum] = FALSE;}if($this->options['autofree']) {$this->freeResult($result);}return(NULL);}// offset skippingif (MDB::isError($this->_skipLimitOffset($result))) {$this->current_row[$result_value] = 0;$this->results[$result_value] = array(FALSE);if($this->options['autofree']) {$this->freeResult($result);}return(NULL);}}if (isset($this->row_buffer[$result_value])) {++$this->current_row[$result_value];$this->results[$result_value][$this->current_row[$result_value]] =$this->row_buffer[$result_value];unset($this->row_buffer[$result_value]);}if (!isset($this->results[$result_value][$rownum])&& (!isset($this->results[$result_value][$this->highest_fetched_row[$result_value]])|| $this->results[$result_value][$this->highest_fetched_row[$result_value]] !== FALSE)) {while($this->current_row[$result_value] < $rownum&& @OCIFetchInto($result, $buffer, OCI_RETURN_NULLS)) {++$this->current_row[$result_value];$this->results[$result_value][$this->current_row[$result_value]] = $buffer;}// end of result set reachedif ($this->current_row[$result_value] < $rownum) {++$this->current_row[$result_value];$this->results[$result_value][$this->current_row[$result_value]] = FALSE;}}$this->highest_fetched_row[$result_value] =max($this->highest_fetched_row[$result_value],$this->current_row[$result_value]);} else {++$this->current_row[$result_value];}if (isset($this->results[$result_value][$rownum])&& $this->results[$result_value][$rownum]) {$row = $this->results[$result_value][$rownum];} else {if($this->options['autofree']) {$this->freeResult($result);}return(NULL);}if ($fetchmode & MDB_FETCHMODE_ASSOC) {$column_names = $this->getColumnNames($result);foreach($column_names as $name => $i) {$column_names[$name] = $row[$i];}$row = $column_names;}if (isset($this->result_types[$result_value])) {$row = $this->convertResultRow($result, $row);}return($row);}// }}}// {{{ nextResult()/*** Move the internal oracle result pointer to the next available result* Currently not supported** @param $result a oracle valid result resource* @return TRUE if a result is available otherwise return FALSE* @access public*/function nextResult($result){return(FALSE);}// }}}// {{{ tableInfo()/*** returns meta data about the result set** @param resource $result result identifier* @param mixed $mode depends on implementation* @return array an nested array, or a MDB error* @access public*/function tableInfo($result, $mode = NULL){$count = 0;$res = array();/*** depending on $mode, metadata returns the following values:** - mode is FALSE (default):* $res[]:* [0]['table'] table name* [0]['name'] field name* [0]['type'] field type* [0]['len'] field length* [0]['nullable'] field can be NULL (boolean)* [0]['format'] field precision if NUMBER* [0]['default'] field default value** - mode is MDB_TABLEINFO_ORDER* $res[]:* ['num_fields'] number of fields* [0]['table'] table name* [0]['name'] field name* [0]['type'] field type* [0]['len'] field length* [0]['nullable'] field can be NULL (boolean)* [0]['format'] field precision if NUMBER* [0]['default'] field default value* ['order'][field name] index of field named 'field name'* The last one is used, if you have a field name, but no index.* Test: if (isset($result['order']['myfield'])) { ...** - mode is MDB_TABLEINFO_ORDERTABLE* the same as above. but additionally* ['ordertable'][table name][field name] index of field* named 'field name'** this is, because if you have fields from different* tables with the same field name * they override each* other with MDB_TABLEINFO_ORDER** you can combine DB_TABLEINFO_ORDER and* MDB_TABLEINFO_ORDERTABLE with MDB_TABLEINFO_ORDER |* MDB_TABLEINFO_ORDERTABLE * or with MDB_TABLEINFO_FULL*/// if $result is a string, we collect info for a table onlyif (is_string($result)) {if (MDB::isError($connect = $this->connect())) {return($connect);}$result = strtoupper($result);$q_fields = "select column_name, data_type, data_length, data_precision,nullable, data_default from user_tab_columnswhere table_name='$result' order by column_id";if (!$stmt = @OCIParse($this->connection, $q_fields)) {return($this->oci8RaiseError());}if (!@OCIExecute($stmt, OCI_DEFAULT)) {return($this->oci8RaiseError($stmt));} while (@OCIFetch($stmt)) {$res[$count]['table'] = strtolower($result);$res[$count]['name'] = strtolower(@OCIResult($stmt, 1));$res[$count]['type'] = strtolower(@OCIResult($stmt, 2));$res[$count]['len'] = @OCIResult($stmt, 3);$res[$count]['format'] = @OCIResult($stmt, 4);$res[$count]['nullable'] = (@OCIResult($stmt, 5) == 'Y') ? TRUE : FALSE;$res[$count]['default'] = @OCIResult($stmt, 6);if ($mode & MDB_TABLEINFO_ORDER) {$res['order'][$res[$count]['name']] = $count;}if ($mode & MDB_TABLEINFO_ORDERTABLE) {$res['ordertable'][$res[$count]['table']][$res[$count]['name']] = $count;}$count++;}if ($mode) {$res['num_fields'] = $count;}@OCIFreeStatement($stmt);} else { // else we want information about a resultset#if ($result === $this->last_stmt) {$count = @OCINumCols($result);for ($i = 0; $i < $count; $i++) {$res[$i]['name'] = strtolower(@OCIColumnName($result, $i + 1));$res[$i]['type'] = strtolower(@OCIColumnType($result, $i + 1));$res[$i]['len'] = @OCIColumnSize($result, $i + 1);$q_fields = "SELECT table_name, data_precision, nullable, data_default from user_tab_columns WHERE column_name='".$res[$i]['name']."'";if (!$stmt = @OCIParse($this->connection, $q_fields)) {return($this->oci8RaiseError());}if (!@OCIExecute($stmt, OCI_DEFAULT)) {return($this->oci8RaiseError($stmt));}@OCIFetch($stmt);$res[$i]['table'] = strtolower(@OCIResult($stmt, 1));$res[$i]['format'] = @OCIResult($stmt, 2);$res[$i]['nullable'] = (@OCIResult($stmt, 3) == 'Y') ? TRUE : FALSE;$res[$i]['default'] = @OCIResult($stmt, 4);@OCIFreeStatement($stmt);if ($mode & MDB_TABLEINFO_ORDER) {$res['order'][$res[$i]['name']] = $i;}if ($mode & MDB_TABLEINFO_ORDERTABLE) {$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;}}if ($mode) {$res['num_fields'] = $count;}#} else {# return($this->raiseError(MDB_ERROR_NOT_CAPABLE));#}}return($res);}}?>