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: Lorenzo Alberton <l.alberton@quipo.it> |// +----------------------------------------------------------------------+//// $Id: ibase.php,v 1.9.4.29 2004/03/31 20:00:55 quipo Exp $require_once 'MDB/Common.php';/*** MDB FireBird/InterBase driver** Notes:* - when fetching in associative mode all keys are lowercased.** - Currently, the driver relies on the Interbase server to use SQL dialect 3* that was introduced with Interbase 6. Some versions of Interbase server,* like the Super Server, do not seem to work by default with dialect 3.* This may lead to errors when trying to create tables using Interbase SQL* data types that are only available when using this dialect version.** - Interbase does not support per field index sorting support. Indexes are* either ascending, descending or both even when they are defined from more* than one field. Currently Metabase Interbase driver uses the index sorting* type given by the first field of the index for which it is specified the* sorting type.** - The numRows method is emulated by fetching all the rows into memory.* Avoid using it if for queries with large result sets.** - Interbase does not provide direct support for returning result setsrestrictedto a given range. Such support is emulated in the MDB ibase driver.** - Current Interbase versions do not support altering table field DEFAULT* values and NOT NULL constraint. Text fields' length may only be raised in* increments defined by Interbase, so the Metabase Interbase does not support* altering text field length yet.** - createDatabase and dropDatabase are not supported** - MDB creates Interbase blobs before executing a prepared queries to insert* or update large object fields. If such queries fail to execute, MDB* Interbase driver class is not able to reclaim the database space allocated* for the large object values because there is currently no PHP function to do so.** @package MDB* @category Database* @author Lorenzo Alberton <l.alberton@quipo.it>*/class MDB_ibase extends MDB_Common{var $connection = 0;var $connected_host;var $connected_port;var $selected_database = '';var $selected_database_file = '';var $opened_persistent = '';var $transaction_id = 0;var $escape_quotes = "'";var $decimal_factor = 1.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();var $query_parameters = array();var $query_parameter_values = array();// }}}// {{{ constructor/*** Constructor*/function MDB_ibase(){$this->MDB_Common();$this->phptype = 'ibase';$this->dbsyntax = 'ibase';$this->supported['Sequences'] = 1;$this->supported['Indexes'] = 1;$this->supported['SummaryFunctions'] = 1;$this->supported['OrderByText'] = 1;$this->supported['Transactions'] = 1;$this->supported['CurrId'] = 0;$this->supported['AffectedRows'] = 0;$this->supported['SelectRowRanges'] = 1;$this->supported['LOBs'] = 1;$this->supported['Replace'] = 1;$this->supported['SubSelects'] = 1;$this->decimal_factor = pow(10.0, $this->decimal_places);$this->options['DatabasePath'] = '';$this->options['DatabaseExtension'] = '.gdb';$this->options['DBAUser'] = FALSE;$this->options['DBAPassword'] = FALSE;$this->errorcode_map = array(-104 => MDB_ERROR_SYNTAX,-150 => MDB_ERROR_ACCESS_VIOLATION,-151 => MDB_ERROR_ACCESS_VIOLATION,-155 => MDB_ERROR_NOSUCHTABLE,88 => MDB_ERROR_NOSUCHTABLE,-157 => MDB_ERROR_NOSUCHFIELD,-158 => MDB_ERROR_VALUE_COUNT_ON_ROW,-170 => MDB_ERROR_MISMATCH,-171 => MDB_ERROR_MISMATCH,-172 => MDB_ERROR_INVALID,-204 => MDB_ERROR_INVALID,-205 => MDB_ERROR_NOSUCHFIELD,-206 => MDB_ERROR_NOSUCHFIELD,-208 => MDB_ERROR_INVALID,-219 => MDB_ERROR_NOSUCHTABLE,-297 => MDB_ERROR_CONSTRAINT,-530 => MDB_ERROR_CONSTRAINT,-551 => MDB_ERROR_ACCESS_VIOLATION,-552 => MDB_ERROR_ACCESS_VIOLATION,-607 => MDB_ERROR_NOSUCHTABLE,-803 => MDB_ERROR_CONSTRAINT,-913 => MDB_ERROR_DEADLOCK,-922 => MDB_ERROR_NOSUCHDB,-923 => MDB_ERROR_CONNECT_FAILED,-924 => MDB_ERROR_CONNECT_FAILED);}// }}}// {{{ errorCode()/*** Map native error codes to DB's portable ones. Requires that* the DB implementation's constructor fills in the $errorcode_map* property.** @param $nativecode the native error code, as returned by the backend* database extension (string or integer)* @return int a portable MDB error code, or FALSE if this DB* implementation has no mapping for the given error code.*/function errorCode($errormsg){// memo for the interbase php module hackers: we need something similar// to mysql_errno() to retrieve error codes instead of this ugly hackif (preg_match('/^([^0-9\-]+)([0-9\-]+)\s+(.*)$/', $errormsg, $match)) {$errno = (int)$match[2];} else {$errno = NULL;}switch ($errno) {case -204:if (is_int(strpos($match[3], 'Table unknown'))) {return MDB_ERROR_NOSUCHTABLE;}break;default:if (isset($this->errorcode_map[$errno])) {return($this->errorcode_map[$errno]);}static $error_regexps;if (empty($error_regexps)) {$error_regexps = array('/[tT]able not found/' => MDB_ERROR_NOSUCHTABLE,'/[tT]able unknown/' => MDB_ERROR_NOSUCHTABLE,'/[tT]able .* already exists/' => MDB_ERROR_ALREADY_EXISTS,'/validation error for column .* value "\*\*\* null/' => MDB_ERROR_CONSTRAINT_NOT_NULL,'/violation of [\w ]+ constraint/' => MDB_ERROR_CONSTRAINT,'/conversion error from string/' => MDB_ERROR_INVALID_NUMBER,'/no permission for/' => MDB_ERROR_ACCESS_VIOLATION,'/arithmetic exception, numeric overflow, or string truncation/' => MDB_ERROR_DIVZERO,'/deadlock/' => MDB_ERROR_DEADLOCK,'/attempt to store duplicate value/' => MDB_ERROR_CONSTRAINT);}foreach ($error_regexps as $regexp => $code) {if (preg_match($regexp, $errormsg)) {return $code;}}}// Fall back to MDB_ERROR if there was no mapping.return MDB_ERROR;}// }}}// {{{ ibaseRaiseError()/*** 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 ibaseRaiseError($errno = NULL, $message = NULL){$error = $this->errorNative();return($this->raiseError($this->errorCode($error), NULL, NULL,$message, $error));}// }}}// {{{ errorNative()/*** Get the native error code of the last error (if any) that* occured on the current connection.** @access public* @return int native ibase error code*/function errorNative(){return @ibase_errmsg();}// }}}// {{{ 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.* @return mixed MDB_OK on success, a MDB error on failure* @access public*/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.** @return mixed MDB_OK on success, a MDB error on failure* @access public*/function commit(){$this->debug('Commit Transaction');if ($this->auto_commit) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Commit: transaction changes are being auto commited'));}return @ibase_commit($this->connection);}// }}}// {{{ 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.** @return mixed MDB_OK on success, a MDB error on failure* @access public*/function rollback(){$this->debug('Rollback Transaction');if ($this->auto_commit) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Rollback: transactions can not be rolled back when changes are auto commited'));}//return ibase_rollback($this->connection);if ($this->transaction_id && !@ibase_rollback($this->connection)) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Rollback: Could not rollback a pending transaction: '.@ibase_errmsg()));}if (!$this->transaction_id = @ibase_trans(IBASE_COMMITTED, $this->connection)) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Rollback: Could not start a new transaction: '.@ibase_errmsg()));}return MDB_OK;}// }}}// {{{ getDatabaseFile()function getDatabaseFile($database_name){if (isset($this->options['DatabasePath'])) {$this->database_path = $this->options['DatabasePath'];}if (isset($this->options['DatabaseExtension'])) {$this->database_extension = $this->options['DatabaseExtension'];}//$this->database_path = (isset($this->options['DatabasePath']) ? $this->options['DatabasePath'] : '');//$this->database_extension = (isset($this->options['DatabaseExtension']) ? $this->options['DatabaseExtension'] : '.gdb');//$database_path = (isset($this->options['DatabasePath']) ? $this->options['DatabasePath'] : '');//$database_extension = (isset($this->options['DatabaseExtension']) ? $this->options['DatabaseExtension'] : '.gdb');return $this->database_path.$database_name.$this->database_extension;}// }}}// {{{ _doConnect()/*** Does the grunt work of connecting to the database** @return mixed connection resource on success, MDB_Error on failure* @access private**/function _doConnect($database_name, $persistent){$function = ($persistent ? 'ibase_pconnect' : 'ibase_connect');if (!function_exists($function)) {return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,'doConnect: FireBird/InterBase support is not available in this PHP configuration'));}$dbhost = $this->host ?($this->host . ':' . $database_name) :$database_name;$params = array();$params[] = $dbhost;$params[] = !empty($this->user) ? $this->user : NULL;$params[] = !empty($this->password) ? $this->password : NULL;$connection = @call_user_func_array($function, $params);if ($connection > 0) {@ibase_timefmt("%Y-%m-%d %H:%M:%S", IBASE_TIMESTAMP);@ibase_timefmt("%Y-%m-%d", IBASE_DATE);return $connection;}if (isset($php_errormsg)) {$error_msg = $php_errormsg;} else {$error_msg = 'Could not connect to FireBird/InterBase server';}return($this->raiseError(MDB_ERROR_CONNECT_FAILED, NULL, NULL,'doConnect: '.$error_msg));}// }}}// {{{ connect()/*** Connect to the database** @return TRUE on success, MDB_Error on failure* @access public**/function connect(){$port = (isset($this->options['port']) ? $this->options['port'] : '');$database_file = $this->getDatabaseFile($this->database_name);if ($this->connection != 0) {if (!strcmp($this->connected_host, $this->host)&& !strcmp($this->connected_port, $port)&& !strcmp($this->selected_database_file, $database_file)&& ($this->opened_persistent == $this->options['persistent'])){return MDB_OK;}@ibase_close($this->connection);$this->affected_rows = -1;$this->connection = 0;}$connection = $this->_doConnect($database_file, $this->options['persistent']);if (MDB::isError($connection)) {return $connection;}$this->connection = $connection;//the if below was added after PEAR::DB. Review me!!if ($this->dbsyntax == 'fbird') {$this->supported['limit'] = 'alter';}if (!$this->auto_commit && MDB::isError($trans_result = $this->_doQuery('BEGIN'))) {@ibase_close($this->connection);$this->connection = 0;$this->affected_rows = -1;return $trans_result;}$this->connected_host = $this->host;$this->connected_port = $port;$this->selected_database_file = $database_file;$this->opened_persistent = $this->options['persistent'];return MDB_OK;}// }}}// {{{ _close()/*** Close the database connection** @return boolean* @access private**/function _close(){if ($this->connection != 0) {if (!$this->auto_commit) {$this->_doQuery('END');}@ibase_close($this->connection);$this->connection = 0;$this->affected_rows = -1;unset($GLOBALS['_MDB_databases'][$this->database]);return true;}return false;}// }}}// {{{ _doQuery()/*** Execute a query* @param string $query the SQL query* @return mixed result identifier if query executed, else MDB_error* @access private**/function _doQuery($query, $first=0, $limit=0, $prepared_query=0) // function _doQuery($query){$connection = ($this->auto_commit ? $this->connection : $this->transaction_id);if ($prepared_query&& isset($this->query_parameters[$prepared_query])&& count($this->query_parameters[$prepared_query]) > 2){$this->query_parameters[$prepared_query][0] = $connection;$this->query_parameters[$prepared_query][1] = $query;$result = @call_user_func_array("ibase_query", $this->query_parameters[$prepared_query]);} else {//Not Prepared Query$result = @ibase_query($connection, $query);while (@ibase_errmsg() == 'Query argument missed') { //ibase_errcode() only available in PHP5//connection lost, try again...$this->connect();//rollback the failed transaction to prevent deadlock and execute the query againif ($this->transaction_id) {$this->rollback();}$result = @ibase_query($this->connection, $query);}}if ($result) {if (!MDB::isManip($query)) {$result_value = intval($result);$this->current_row[$result_value] = -1;if ($limit > 0) {$this->limits[$result_value] = array($first, $limit, 0);}$this->highest_fetched_row[$result_value] = -1;} else {$this->affected_rows = -1;}} else {return ($this->raiseError(MDB_ERROR, NULL, NULL,'_doQuery: Could not execute query ("'.$query.'"): ' . @ibase_errmsg()));}return $result;}// }}}// {{{ query()/*** Send a query to the database and return any results** @param string $query the SQL query* @param array $types array that contains the types of the columns in* the result set* @return mixed result identifier if query executed, else MDB_error* @access public**/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;$connected = $this->connect();if (MDB::isError($connected)) {return $connected;}if (!MDB::isError($result = $this->_doQuery($query, $first, $limit, 0))) {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->ibaseRaiseError();}// }}}// {{{ _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 (!is_array(@ibase_fetch_row($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 = @ibase_num_fields($result);for ($column=0; $column < $columns; $column++) {$column_info = @ibase_field_info($result, $column);$field_name = $column_info['name'];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){if (!isset($this->highest_fetched_row[intval($result)])) {return($this->raiseError(MDB_ERROR, NULL, NULL,'Number of columns: it was specified an inexisting result set'));}return @ibase_num_fields($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 (is_array($this->row_buffer[$result_value] = @ibase_fetch_row($result))) {return false;}$this->row_buffer[$result_value] = false;return true;}// }}}// {{{ 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 $field field number where the data can be found* @return mixed string on success, a MDB error on failure* @access public*/function fetch($result, $rownum, $field){$fetchmode = is_numeric($field) ? MDB_FETCHMODE_ORDERED : MDB_FETCHMODE_ASSOC;$row = $this->fetchInto($result, $fetchmode, $rownum);if (MDB::isError($row)) {return $row;}if (!array_key_exists($field, $row)) {return null;}return $row[$field];}// }}}// {{{ 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&& is_array($buffer = @ibase_fetch_row($result))) {++$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;}foreach ($row as $key => $value_with_space) {if (!is_null($value_with_space)) {$row[$key] = rtrim($value_with_space, ' ');}}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;}// }}}// {{{ _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'])) {$this->lobs[$lob]['Value'] = $this->fetch($this->lobs[$lob]['Result'],$this->lobs[$lob]['Row'],$this->lobs[$lob]['Field']);if (!$this->lobs[$lob]['Handle'] = @ibase_blob_open($this->lobs[$lob]['Value'])) {unset($this->lobs[$lob]['Value']);return($this->raiseError(MDB_ERROR, NULL, NULL,'Retrieve LOB: Could not open fetched large object field' . @ibase_errmsg()));}}return MDB_OK;}// }}}// {{{ endOfResultLob()/*** Determine whether it was reached the end of the large object and* therefore there is no more data to be read for the its input stream.** @param int $lob handle to a lob created by the createLob() function* @return mixed TRUE or FALSE on success, a MDB error on failure* @access public*/function endOfResultLob($lob){if (MDB::isError($lobresult = $this->_retrieveLob($lob))) {return($lobresult);}return(isset($this->lobs[$lob]['EndOfLOB']));}// }}}// {{{ _readResultLob()/*** Read data from large object input stream.** @param int $lob handle to a lob created by the createLob() function* @param blob $data reference to a variable that will hold data to be* read from the large object input stream* @param int $length integer value that indicates the largest ammount of* data to be read from the large object input stream.* @return mixed length on success, a MDB error on failure* @access private*/function _readResultLob($lob, &$data, $length){if (MDB::isError($lobresult = $this->_retrieveLob($lob))) {return $lobresult;}$data = @ibase_blob_get($this->lobs[$lob]['Handle'], $length);if (!is_string($data)) {$this->raiseError(MDB_ERROR, NULL, NULL,'Read Result LOB: ' . @ibase_errmsg());}if (($length = strlen($data)) == 0) {$this->lobs[$lob]['EndOfLOB'] = 1;}return $length;}// }}}// {{{ _destroyResultLob()/*** Free any resources allocated during the lifetime of the large object* handler object.** @param int $lob handle to a lob created by the createLob() function* @access private*/function _destroyResultLob($lob){if (isset($this->lobs[$lob])) {if (isset($this->lobs[$lob]['Value'])) {@ibase_blob_close($this->lobs[$lob]['Handle']);}$this->lobs[$lob] = '';}}// }}}// {{{ 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);}// }}}// {{{ 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 or a MDB error on failure* @access public*/function convertResult($value, $type){switch ($type) {case MDB_TYPE_DECIMAL:return sprintf('%.'.$this->decimal_places.'f', doubleval($value)/$this->decimal_factor);case MDB_TYPE_TIMESTAMP:return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS'));default:return $this->_baseConvertResult($value, $type);}}// }}}// {{{ 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));}// }}}// {{{ 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->rows[$result_value][$this->highest_fetched_row[$result_value]])|| $this->rows[$result_value][$this->highest_fetched_row[$result_value]] !== false) {if (isset($this->limits[$result_value])) {if (MDB::isError($skipfirstrow = $this->_skipLimitOffset($result))) {//$this->rows[$result_value] = 0;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])&& (is_array($buffer = @ibase_fetch_row($result)))) {++$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 boolean 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->rows[$result_value])) {unset($this->rows[$result_value]);}if (isset($this->result_types[$result_value])) {unset($this->result_types[$result_value]);}if (is_resource($result)) {return @ibase_free_result($result);}return true;}// }}}// {{{ getTypeDeclaration()/*** Obtain DBMS specific SQL code portion needed to declare an text type* field to be used in statements like CREATE TABLE.** @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 getTypeDeclaration($field){switch($field['type']){case 'text':return('VARCHAR ('.(isset($field['length']) ? $field['length'] : (isset($this->options['DefaultTextFieldLength']) ? $this->options['DefaultTextFieldLength'] : 4000)).')');case 'clob':return 'BLOB SUB_TYPE 1';case 'blob':return 'BLOB SUB_TYPE 0';case 'integer':return 'INTEGER';case 'boolean':return 'CHAR (1)';case 'date':return 'DATE';case 'time':return 'TIME';case 'timestamp':return 'TIMESTAMP';case 'float':return 'DOUBLE PRECISION';case 'decimal':return 'DECIMAL(18,'.$this->decimal_places.')';}return '';}// }}}// {{{ 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.' '.$this->getTypeDeclaration($field).(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.' '.$this->getTypeDeclaration($field).(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 "'.$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 "'.$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' : ''));}// }}}// {{{ _getLobValue()/*** 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 $lob* @return string text string that represents the given argument value in* a DBMS specific format.* @access private*/function _getLobValue($prepared_query, $parameter, $lob){if (MDB::isError($connect = $this->connect())) {return $connect;}$value = ''; // DEAL WITH MEif (!$this->transaction_id = @ibase_trans(IBASE_COMMITTED, $this->connection)) {return($this->raiseError(MDB_ERROR, NULL, NULL, '_getLobValue: Could not start a new transaction: '.@ibase_errmsg()));}if (($lo = @ibase_blob_create($this->auto_commit ? $this->connection : $this->transaction_id))) {while (!$this->endOfLob($lob)) {if (MDB::isError($result = $this->readLob($lob, $data, $this->options['lob_buffer_length']))) {break;}if (@ibase_blob_add($lo, $data) === false) {$result = $this->raiseError(MDB_ERROR, NULL, NULL,'_getLobValue - Could not add data to a large object: ' . @ibase_errmsg());break;}}if (MDB::isError($result)) {@ibase_blob_cancel($lo);} else {$value = @ibase_blob_close($lo);}} else {$result = $this->raiseError(MDB_ERROR, NULL, NULL,'Get LOB field value' . @ibase_errmsg());}if (!isset($this->query_parameters[$prepared_query])) {$this->query_parameters[$prepared_query] = array(0, '');$this->query_parameter_values[$prepared_query] = array();}$query_parameter = count($this->query_parameters[$prepared_query]);$this->query_parameter_values[$prepared_query][$parameter] = $query_parameter;$this->query_parameters[$prepared_query][$query_parameter] = $value;$value = '?';if (!$this->auto_commit) {$this->commit();}return $value;}// }}}// {{{ 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 $this->_getLobValue($prepared_query, $parameter, $clob);}// }}}// {{{ freeLobValue()/*** free a large object** @param resource $prepared_query query handle from prepare()* @param string $lob* @param string $value* @return MDB_OK* @access public*/function freeLobValue($prepared_query, $lob, &$value){$query_parameter=$this->query_parameter_values[$prepared_query][$lob];unset($this->query_parameters[$prepared_query][$query_parameter]);unset($this->query_parameter_values[$prepared_query][$lob]);if (count($this->query_parameter_values[$prepared_query]) == 0) {unset($this->query_parameters[$prepared_query]);unset($this->query_parameter_values[$prepared_query]);}unset($value);}// }}}// {{{ freeClobValue()/*** free a character large object** @param resource $prepared_query query handle from prepare()* @param string $clob* @param string $value* @return MDB_OK* @access public*/function freeClobValue($prepared_query, $clob, &$value){$this->freeLobValue($prepared_query, $clob, $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 $this->_getLobValue($prepared_query, $parameter, $blob);}// }}}// {{{ freeBlobValue()/*** free a binary large object** @param resource $prepared_query query handle from prepare()* @param string $blob* @param string $value* @return MDB_OK* @access public*/function freeBlobValue($prepared_query, $blob, &$value){$this->freeLobValue($prepared_query, $blob, $value);}// }}}// {{{ 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' : $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' : strval(round($value*$this->decimal_factor)));}// }}}// {{{ affectedRows()/*** returns the affected rows of a query** @return mixed MDB Error Object or number of rows* @access public*/function affectedRows(){if (function_exists('ibase_affected_rows')) { //PHP5 only$affected_rows = @ibase_affected_rows($this->connection);if ($affected_rows === false) {return $this->raiseError(MDB_ERROR_NEED_MORE_DATA);}return $affected_rows;}return parent::affectedRows();}// }}}// {{{ 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);$sequence_name = strtoupper($this->getSequenceName($seq_name));$this->expectError(MDB_ERROR_NOSUCHTABLE);$query = "SELECT GEN_ID($sequence_name, 1) as the_value FROM RDB\$DATABASE";$result = $this->_doQuery($query);$this->popExpect();if ($ondemand && MDB::isError($result)) {$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 = strtoupper($this->getSequenceName($seq_name));//$sequence_name = $this->getSequenceName($seq_name);$query = "SELECT RDB\$GENERATOR_ID FROM RDB\$GENERATORS WHERE RDB\$GENERATOR_NAME='$sequence_name'";if (MDB::isError($result = $this->queryOne($query))) {return($this->raiseError(MDB_ERROR, NULL, NULL,'currId: Unable to select from ' . $seqname) );}if (!is_numeric($result)) {//var_dump($result); ==> nullreturn($this->raiseError(MDB_ERROR, NULL, NULL,'currId: could not find value in sequence table'));}return $result;}// }}}// {{{ nextResult()/*** Move the internal ibase result pointer to the next available result** @param $result a valid ibase 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 mixed $resource FireBird/InterBase result identifier or table name* @param mixed $mode depends on implementation* @return array an nested array, or a MDB error* @access public*/function tableInfo($result, $mode = NULL){$count = 0;$id = 0;$res = array();/*** depending on $mode, metadata returns the following values:** - mode is FALSE (default):* $result[]:* [0]['table'] table name* [0]['name'] field name* [0]['type'] field type* [0]['len'] field length* [0]['flags'] field flags** - mode is MDB_TABLEINFO_ORDER* $result[]:* ['num_fields'] number of metadata records* [0]['table'] table name* [0]['name'] field name* [0]['type'] field type* [0]['len'] field length* [0]['flags'] field flags* ['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['meta']['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 MDB_TABLEINFO_ORDER and* MDB_TABLEINFO_ORDERTABLE with MDB_TABLEINFO_ORDER |* MDB_TABLEINFO_ORDERTABLE * or with MDB_TABLEINFO_FULL**/// if $result is a string, then we want information about a// table without a resultsetif (is_string($result)) {$id = @ibase_query($this->connection,"SELECT * FROM $result");if (empty($id)) {return $this->ibaseRaiseError();}} else { // else we want information about a resultset$id = $result;if (empty($id)) {return $this->ibaseRaiseError();}}$count = @ibase_num_fields($id);// made this IF due to performance (one if is faster than $count if's)if (empty($mode)) {for ($i=0; $i<$count; $i++) {$info = @ibase_field_info($id, $i);//$res[$i]['table'] = (is_string($result)) ? $result : '';$res[$i]['table'] = (is_string($result)) ? $result : $info['relation'];$res[$i]['name'] = $info['name'];$res[$i]['type'] = $info['type'];$res[$i]['len'] = $info['length'];//$res[$i]['flags'] = (is_string($result)) ? $this->_ibaseFieldFlags($info['name'], $result) : '';$res[$i]['flags'] = (is_string($result)) ? $this->_ibaseFieldFlags($id, $i, $result) : '';}} else { // full$res['num_fields'] = $count;for ($i=0; $i<$count; $i++) {$info = @ibase_field_info($id, $i);//$res[$i]['table'] = (is_string($result)) ? $result : '';$res[$i]['table'] = (is_string($result)) ? $result : $info['relation'];$res[$i]['name'] = $info['name'];$res[$i]['type'] = $info['type'];$res[$i]['len'] = $info['length'];//$res[$i]['flags'] = (is_string($result)) ? $this->_ibaseFieldFlags($info['name'], $result) : '';$res[$i]['flags'] = (is_string($result)) ? $this->_ibaseFieldFlags($id, $i, $result) : '';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;}}}// free the result only if we were called on a tableif (is_string($result) && is_resource($id)) {@ibase_free_result($id);}return $res;}// }}}// {{{ _ibaseFieldFlags()/*** get the Flags of a Field** @param int $resource FireBird/InterBase result identifier* @param int $num_field the field number* @return string The flags of the field ('not_null', 'default_xx', 'primary_key',* 'unique' and 'multiple_key' are supported)* @access private**/function _ibaseFieldFlags($resource, $num_field, $table_name){$field_name = @ibase_field_info($resource, $num_field);$field_name = @$field_name['name'];$sql = 'SELECT R.RDB$CONSTRAINT_TYPE CTYPE'.' FROM RDB$INDEX_SEGMENTS I'.' JOIN RDB$RELATION_CONSTRAINTS R ON I.RDB$INDEX_NAME=R.RDB$INDEX_NAME'.' WHERE I.RDB$FIELD_NAME=\''.$field_name.'\''.' AND UPPER(R.RDB$RELATION_NAME)=\''.strtoupper($table_name).'\'';$result = @ibase_query($this->connection, $sql);if (empty($result)) {return $this->ibaseRaiseError();}$flags = '';if ($obj = @ibase_fetch_object($result)) {@ibase_free_result($result);if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'PRIMARY KEY') {$flags = 'primary_key ';}if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'UNIQUE') {$flags .= 'unique_key ';}}$sql = 'SELECT R.RDB$NULL_FLAG AS NFLAG,'.' R.RDB$DEFAULT_SOURCE AS DSOURCE,'.' F.RDB$FIELD_TYPE AS FTYPE,'.' F.RDB$COMPUTED_SOURCE AS CSOURCE'.' FROM RDB$RELATION_FIELDS R '.' JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME'.' WHERE UPPER(R.RDB$RELATION_NAME)=\''.strtoupper($table_name).'\''.' AND R.RDB$FIELD_NAME=\''.$field_name.'\'';$result = @ibase_query($this->connection, $sql);if (empty($result)) {return $this->ibaseRaiseError();}if ($obj = @ibase_fetch_object($result)) {@ibase_free_result($result);if (isset($obj->NFLAG)) {$flags .= 'not_null ';}if (isset($obj->DSOURCE)) {$flags .= 'default ';}if (isset($obj->CSOURCE)) {$flags .= 'computed ';}if (isset($obj->FTYPE) && $obj->FTYPE == 261) {$flags .= 'blob ';}}return trim($flags);}}?>