[ Index ]
 

Code source de PHP PEAR 1.4.5

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/MDB/ -> ibase.php (source)

   1  <?php
   2  // +----------------------------------------------------------------------+
   3  // | PHP Version 4                                                        |
   4  // +----------------------------------------------------------------------+
   5  // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
   6  // | Stig. S. Bakken, Lukas Smith                                         |
   7  // | All rights reserved.                                                 |
   8  // +----------------------------------------------------------------------+
   9  // | MDB is a merge of PEAR DB and Metabases that provides a unified DB   |
  10  // | API as well as database abstraction for PHP applications.            |
  11  // | This LICENSE is in the BSD license style.                            |
  12  // |                                                                      |
  13  // | Redistribution and use in source and binary forms, with or without   |
  14  // | modification, are permitted provided that the following conditions   |
  15  // | are met:                                                             |
  16  // |                                                                      |
  17  // | Redistributions of source code must retain the above copyright       |
  18  // | notice, this list of conditions and the following disclaimer.        |
  19  // |                                                                      |
  20  // | Redistributions in binary form must reproduce the above copyright    |
  21  // | notice, this list of conditions and the following disclaimer in the  |
  22  // | documentation and/or other materials provided with the distribution. |
  23  // |                                                                      |
  24  // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
  25  // | Lukas Smith nor the names of his contributors may be used to endorse |
  26  // | or promote products derived from this software without specific prior|
  27  // | written permission.                                                  |
  28  // |                                                                      |
  29  // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
  30  // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
  31  // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
  32  // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
  33  // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
  34  // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  35  // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
  36  // |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
  37  // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
  38  // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
  39  // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
  40  // | POSSIBILITY OF SUCH DAMAGE.                                          |
  41  // +----------------------------------------------------------------------+
  42  // | Author: Lorenzo Alberton <l.alberton@quipo.it>                       |
  43  // +----------------------------------------------------------------------+
  44  //
  45  // $Id: ibase.php,v 1.9.4.29 2004/03/31 20:00:55 quipo Exp $
  46  
  47  require_once  'MDB/Common.php';
  48  
  49  /**
  50   * MDB FireBird/InterBase driver
  51   *
  52   * Notes:
  53   * - when fetching in associative mode all keys are lowercased.
  54   *
  55   * - Currently, the driver relies on the Interbase server to use SQL dialect 3
  56   *   that was introduced with Interbase 6. Some versions of Interbase server,
  57   *   like the Super Server, do not seem to work by default with dialect 3.
  58   *   This may lead to errors when trying to create tables using Interbase SQL
  59   *   data types that are only available when using this dialect version.
  60   *
  61   * - Interbase does not support per field index sorting support. Indexes are
  62   *   either ascending, descending or both even when they are defined from more
  63   *   than one field. Currently Metabase Interbase driver uses the index sorting
  64   *   type given by the first field of the index for which it is specified the
  65   *   sorting type.
  66   *
  67   * - The numRows method is emulated by fetching all the rows into memory.
  68   *   Avoid using it if for queries with large result sets.
  69   *
  70   * - Interbase does not provide direct support for returning result sets
  71       restrictedto a given range. Such support is emulated in the MDB ibase driver.
  72   *
  73   * - Current Interbase versions do not support altering table field DEFAULT
  74   *   values and NOT NULL constraint. Text fields' length may only be raised in
  75   *   increments defined by Interbase, so the Metabase Interbase does not support
  76   *   altering text field length yet.
  77   *
  78   * - createDatabase and dropDatabase are not supported
  79   *
  80   * - MDB creates Interbase blobs before executing a prepared queries to insert
  81   *   or update large object fields. If such queries fail to execute, MDB
  82   *   Interbase driver class is not able to reclaim the database space allocated
  83   *   for the large object values because there is currently no PHP function to do so.
  84   *
  85   * @package MDB
  86   * @category Database
  87   * @author  Lorenzo Alberton <l.alberton@quipo.it>
  88   */
  89  
  90  class MDB_ibase extends MDB_Common
  91  {
  92      var $connection = 0;
  93      var $connected_host;
  94      var $connected_port;
  95      var $selected_database = '';
  96      var $selected_database_file = '';
  97      var $opened_persistent = '';
  98      var $transaction_id = 0;
  99  
 100      var $escape_quotes = "'";
 101      var $decimal_factor = 1.0;
 102  
 103      var $results = array();
 104      var $current_row = array();
 105      var $columns = array();
 106      var $rows = array();
 107      var $limits = array();
 108      var $row_buffer = array();
 109      var $highest_fetched_row = array();
 110      var $query_parameters = array();
 111      var $query_parameter_values = array();
 112  
 113      // }}}
 114      // {{{ constructor
 115  
 116      /**
 117       * Constructor
 118       */
 119      function MDB_ibase()
 120      {
 121          $this->MDB_Common();
 122          $this->phptype  = 'ibase';
 123          $this->dbsyntax = 'ibase';
 124  
 125          $this->supported['Sequences'] = 1;
 126          $this->supported['Indexes'] = 1;
 127          $this->supported['SummaryFunctions'] = 1;
 128          $this->supported['OrderByText'] = 1;
 129          $this->supported['Transactions'] = 1;
 130          $this->supported['CurrId'] = 0;
 131          $this->supported['AffectedRows'] = 0;
 132          $this->supported['SelectRowRanges'] = 1;
 133          $this->supported['LOBs'] = 1;
 134          $this->supported['Replace'] = 1;
 135          $this->supported['SubSelects'] = 1;
 136  
 137          $this->decimal_factor = pow(10.0, $this->decimal_places);
 138  
 139          $this->options['DatabasePath'] = '';
 140          $this->options['DatabaseExtension'] = '.gdb';
 141          $this->options['DBAUser'] = FALSE;
 142          $this->options['DBAPassword'] = FALSE;
 143  
 144          $this->errorcode_map = array(
 145              -104 => MDB_ERROR_SYNTAX,
 146              -150 => MDB_ERROR_ACCESS_VIOLATION,
 147              -151 => MDB_ERROR_ACCESS_VIOLATION,
 148              -155 => MDB_ERROR_NOSUCHTABLE,
 149                88 => MDB_ERROR_NOSUCHTABLE,
 150              -157 => MDB_ERROR_NOSUCHFIELD,
 151              -158 => MDB_ERROR_VALUE_COUNT_ON_ROW,
 152              -170 => MDB_ERROR_MISMATCH,
 153              -171 => MDB_ERROR_MISMATCH,
 154              -172 => MDB_ERROR_INVALID,
 155              -204 => MDB_ERROR_INVALID,
 156              -205 => MDB_ERROR_NOSUCHFIELD,
 157              -206 => MDB_ERROR_NOSUCHFIELD,
 158              -208 => MDB_ERROR_INVALID,
 159              -219 => MDB_ERROR_NOSUCHTABLE,
 160              -297 => MDB_ERROR_CONSTRAINT,
 161              -530 => MDB_ERROR_CONSTRAINT,
 162              -551 => MDB_ERROR_ACCESS_VIOLATION,
 163              -552 => MDB_ERROR_ACCESS_VIOLATION,
 164              -607 => MDB_ERROR_NOSUCHTABLE,
 165              -803 => MDB_ERROR_CONSTRAINT,
 166              -913 => MDB_ERROR_DEADLOCK,
 167              -922 => MDB_ERROR_NOSUCHDB,
 168              -923 => MDB_ERROR_CONNECT_FAILED,
 169              -924 => MDB_ERROR_CONNECT_FAILED
 170          );
 171  
 172      }
 173  
 174      // }}}
 175      // {{{ errorCode()
 176  
 177      /**
 178       * Map native error codes to DB's portable ones.  Requires that
 179       * the DB implementation's constructor fills in the $errorcode_map
 180       * property.
 181       *
 182       * @param $nativecode the native error code, as returned by the backend
 183       * database extension (string or integer)
 184       * @return int a portable MDB error code, or FALSE if this DB
 185       * implementation has no mapping for the given error code.
 186       */
 187      function errorCode($errormsg)
 188      {
 189          // memo for the interbase php module hackers: we need something similar
 190          // to mysql_errno() to retrieve error codes instead of this ugly hack
 191          if (preg_match('/^([^0-9\-]+)([0-9\-]+)\s+(.*)$/', $errormsg, $match)) {
 192              $errno = (int)$match[2];
 193          } else {
 194              $errno = NULL;
 195          }
 196          switch ($errno) {
 197              case -204:
 198                  if (is_int(strpos($match[3], 'Table unknown'))) {
 199                      return MDB_ERROR_NOSUCHTABLE;
 200                  }
 201              break;
 202              default:
 203                  if (isset($this->errorcode_map[$errno])) {
 204                      return($this->errorcode_map[$errno]);
 205                  }
 206                  static $error_regexps;
 207                  if (empty($error_regexps)) {
 208                      $error_regexps = array(
 209                          '/[tT]able not found/' => MDB_ERROR_NOSUCHTABLE,
 210                          '/[tT]able unknown/' => MDB_ERROR_NOSUCHTABLE,
 211                          '/[tT]able .* already exists/' => MDB_ERROR_ALREADY_EXISTS,
 212                          '/validation error for column .* value "\*\*\* null/' => MDB_ERROR_CONSTRAINT_NOT_NULL,
 213                          '/violation of [\w ]+ constraint/' => MDB_ERROR_CONSTRAINT,
 214                          '/conversion error from string/' => MDB_ERROR_INVALID_NUMBER,
 215                          '/no permission for/' => MDB_ERROR_ACCESS_VIOLATION,
 216                          '/arithmetic exception, numeric overflow, or string truncation/' => MDB_ERROR_DIVZERO,
 217                          '/deadlock/' => MDB_ERROR_DEADLOCK,
 218                          '/attempt to store duplicate value/' => MDB_ERROR_CONSTRAINT
 219                      );
 220                  }
 221                  foreach ($error_regexps as $regexp => $code) {
 222                      if (preg_match($regexp, $errormsg)) {
 223                          return $code;
 224                      }
 225                  }
 226          }
 227          // Fall back to MDB_ERROR if there was no mapping.
 228          return MDB_ERROR;
 229      }
 230  
 231      // }}}
 232      // {{{ ibaseRaiseError()
 233  
 234      /**
 235       * This method is used to communicate an error and invoke error
 236       * callbacks etc.  Basically a wrapper for MDB::raiseError
 237       * that checks for native error msgs.
 238       *
 239       * @param integer $errno error code
 240       * @param string  $message userinfo message
 241       * @return object a PEAR error object
 242       * @access public
 243       * @see PEAR_Error
 244       */
 245      function ibaseRaiseError($errno = NULL, $message = NULL)
 246      {
 247          $error = $this->errorNative();
 248          return($this->raiseError($this->errorCode($error), NULL, NULL,
 249              $message, $error));
 250      }
 251  
 252      // }}}
 253      // {{{ errorNative()
 254  
 255      /**
 256       * Get the native error code of the last error (if any) that
 257       * occured on the current connection.
 258       *
 259       * @access public
 260       * @return int native ibase error code
 261       */
 262      function errorNative()
 263      {
 264          return @ibase_errmsg();
 265      }
 266  
 267      // }}}
 268      // {{{ autoCommit()
 269  
 270      /**
 271       * Define whether database changes done on the database be automatically
 272       * committed. This function may also implicitly start or end a transaction.
 273       *
 274       * @param boolean $auto_commit flag that indicates whether the database
 275       *     changes should be committed right after executing every query
 276       *     statement. If this argument is 0 a transaction implicitly started.
 277       *     Otherwise, if a transaction is in progress it is ended by committing
 278       *     any database changes that were pending.
 279       * @return mixed MDB_OK on success, a MDB error on failure
 280       * @access public
 281       */
 282      function autoCommit($auto_commit)
 283      {
 284          $this->debug('AutoCommit: '.($auto_commit ? 'On' : 'Off'));
 285          if ((!$this->auto_commit) == (!$auto_commit)) {
 286              return MDB_OK;
 287          }
 288          if ($this->connection && $auto_commit && MDB::isError($commit = $this->commit())) {
 289              return($commit);
 290          }
 291          $this->auto_commit = $auto_commit;
 292          $this->in_transaction = !$auto_commit;
 293          return MDB_OK;
 294      }
 295  
 296      // }}}
 297      // {{{ commit()
 298  
 299      /**
 300       * Commit the database changes done during a transaction that is in
 301       * progress. This function may only be called when auto-committing is
 302       * disabled, otherwise it will fail. Therefore, a new transaction is
 303       * implicitly started after committing the pending changes.
 304       *
 305       * @return mixed MDB_OK on success, a MDB error on failure
 306       * @access public
 307       */
 308      function commit()
 309      {
 310          $this->debug('Commit Transaction');
 311          if ($this->auto_commit) {
 312              return($this->raiseError(MDB_ERROR, NULL, NULL,
 313                  'Commit: transaction changes are being auto commited'));
 314          }
 315          return @ibase_commit($this->connection);
 316      }
 317  
 318      // }}}
 319      // {{{ rollback()
 320  
 321      /**
 322       * Cancel any database changes done during a transaction that is in
 323       * progress. This function may only be called when auto-committing is
 324       * disabled, otherwise it will fail. Therefore, a new transaction is
 325       * implicitly started after canceling the pending changes.
 326       *
 327       * @return mixed MDB_OK on success, a MDB error on failure
 328       * @access public
 329       */
 330      function rollback()
 331      {
 332          $this->debug('Rollback Transaction');
 333          if ($this->auto_commit) {
 334              return($this->raiseError(MDB_ERROR, NULL, NULL,
 335                  'Rollback: transactions can not be rolled back when changes are auto commited'));
 336          }
 337  
 338          //return ibase_rollback($this->connection);
 339  
 340          if ($this->transaction_id && !@ibase_rollback($this->connection)) {
 341              return($this->raiseError(MDB_ERROR, NULL, NULL,
 342                  'Rollback: Could not rollback a pending transaction: '.@ibase_errmsg()));
 343          }
 344          if (!$this->transaction_id = @ibase_trans(IBASE_COMMITTED, $this->connection)) {
 345              return($this->raiseError(MDB_ERROR, NULL, NULL,
 346                  'Rollback: Could not start a new transaction: '.@ibase_errmsg()));
 347          }
 348          return MDB_OK;
 349      }
 350  
 351      // }}}
 352      // {{{ getDatabaseFile()
 353  
 354      function getDatabaseFile($database_name)
 355      {
 356          if (isset($this->options['DatabasePath'])) {
 357              $this->database_path = $this->options['DatabasePath'];
 358          }
 359          if (isset($this->options['DatabaseExtension'])) {
 360              $this->database_extension = $this->options['DatabaseExtension'];
 361          }
 362          //$this->database_path = (isset($this->options['DatabasePath']) ? $this->options['DatabasePath'] : '');
 363          //$this->database_extension = (isset($this->options['DatabaseExtension']) ? $this->options['DatabaseExtension'] : '.gdb');
 364  
 365          //$database_path = (isset($this->options['DatabasePath']) ? $this->options['DatabasePath'] : '');
 366          //$database_extension = (isset($this->options['DatabaseExtension']) ? $this->options['DatabaseExtension'] : '.gdb');
 367          return $this->database_path.$database_name.$this->database_extension;
 368      }
 369  
 370      // }}}
 371      // {{{ _doConnect()
 372  
 373      /**
 374       * Does the grunt work of connecting to the database
 375       *
 376       * @return mixed connection resource on success, MDB_Error on failure
 377       * @access private
 378       **/
 379      function _doConnect($database_name, $persistent)
 380      {
 381          $function = ($persistent ? 'ibase_pconnect' : 'ibase_connect');
 382          if (!function_exists($function)) {
 383              return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL,
 384                  'doConnect: FireBird/InterBase support is not available in this PHP configuration'));
 385          }
 386  
 387          $dbhost = $this->host ?
 388                    ($this->host . ':' . $database_name) :
 389                    $database_name;
 390  
 391          $params = array();
 392          $params[] = $dbhost;
 393          $params[] = !empty($this->user) ? $this->user : NULL;
 394          $params[] = !empty($this->password) ? $this->password : NULL;
 395  
 396          $connection = @call_user_func_array($function, $params);
 397          if ($connection > 0) {
 398              @ibase_timefmt("%Y-%m-%d %H:%M:%S", IBASE_TIMESTAMP);
 399              @ibase_timefmt("%Y-%m-%d", IBASE_DATE);
 400              return $connection;
 401          }
 402          if (isset($php_errormsg)) {
 403              $error_msg = $php_errormsg;
 404          } else {
 405              $error_msg = 'Could not connect to FireBird/InterBase server';
 406          }
 407          return($this->raiseError(MDB_ERROR_CONNECT_FAILED, NULL, NULL,
 408              'doConnect: '.$error_msg));
 409      }
 410  
 411      // }}}
 412      // {{{ connect()
 413  
 414      /**
 415       * Connect to the database
 416       *
 417       * @return TRUE on success, MDB_Error on failure
 418       * @access public
 419       **/
 420      function connect()
 421      {
 422          $port = (isset($this->options['port']) ? $this->options['port'] : '');
 423  
 424          $database_file = $this->getDatabaseFile($this->database_name);
 425  
 426          if ($this->connection != 0) {
 427              if (!strcmp($this->connected_host, $this->host)
 428                  && !strcmp($this->connected_port, $port)
 429                  && !strcmp($this->selected_database_file, $database_file)
 430                  && ($this->opened_persistent == $this->options['persistent']))
 431              {
 432                  return MDB_OK;
 433              }
 434              @ibase_close($this->connection);
 435              $this->affected_rows = -1;
 436              $this->connection = 0;
 437          }
 438          $connection = $this->_doConnect($database_file, $this->options['persistent']);
 439          if (MDB::isError($connection)) {
 440              return $connection;
 441          }
 442          $this->connection = $connection;
 443  
 444          //the if below was added after PEAR::DB. Review me!!
 445          if ($this->dbsyntax == 'fbird') {
 446              $this->supported['limit'] = 'alter';
 447          }
 448  
 449          if (!$this->auto_commit && MDB::isError($trans_result = $this->_doQuery('BEGIN'))) {
 450              @ibase_close($this->connection);
 451              $this->connection = 0;
 452              $this->affected_rows = -1;
 453              return $trans_result;
 454          }
 455          $this->connected_host = $this->host;
 456          $this->connected_port = $port;
 457          $this->selected_database_file = $database_file;
 458          $this->opened_persistent = $this->options['persistent'];
 459          return MDB_OK;
 460      }
 461  
 462      // }}}
 463      // {{{ _close()
 464      /**
 465       * Close the database connection
 466       *
 467       * @return boolean
 468       * @access private
 469       **/
 470      function _close()
 471      {
 472          if ($this->connection != 0) {
 473              if (!$this->auto_commit) {
 474                  $this->_doQuery('END');
 475              }
 476              @ibase_close($this->connection);
 477              $this->connection = 0;
 478              $this->affected_rows = -1;
 479  
 480              unset($GLOBALS['_MDB_databases'][$this->database]);
 481              return true;
 482          }
 483          return false;
 484      }
 485  
 486      // }}}
 487      // {{{ _doQuery()
 488  
 489      /**
 490       * Execute a query
 491       * @param string $query the SQL query
 492       * @return mixed result identifier if query executed, else MDB_error
 493       * @access private
 494       **/
 495      function _doQuery($query, $first=0, $limit=0, $prepared_query=0)  // function _doQuery($query)
 496      {
 497          $connection = ($this->auto_commit ? $this->connection : $this->transaction_id);
 498          if ($prepared_query
 499              && isset($this->query_parameters[$prepared_query])
 500              && count($this->query_parameters[$prepared_query]) > 2)
 501          {
 502  
 503              $this->query_parameters[$prepared_query][0] = $connection;
 504              $this->query_parameters[$prepared_query][1] = $query;
 505              $result = @call_user_func_array("ibase_query", $this->query_parameters[$prepared_query]);
 506          } else {
 507              //Not Prepared Query
 508              $result = @ibase_query($connection, $query);
 509              while (@ibase_errmsg() == 'Query argument missed') { //ibase_errcode() only available in PHP5
 510                  //connection lost, try again...
 511                  $this->connect();
 512                  //rollback the failed transaction to prevent deadlock and execute the query again
 513                  if ($this->transaction_id) {
 514                      $this->rollback();
 515                  }
 516                  $result = @ibase_query($this->connection, $query);
 517              }
 518          }
 519          if ($result) {
 520              if (!MDB::isManip($query)) {
 521                  $result_value = intval($result);
 522                  $this->current_row[$result_value] = -1;
 523                  if ($limit > 0) {
 524                      $this->limits[$result_value] = array($first, $limit, 0);
 525                  }
 526                  $this->highest_fetched_row[$result_value] = -1;
 527              } else {
 528                  $this->affected_rows = -1;
 529              }
 530          } else {
 531              return ($this->raiseError(MDB_ERROR, NULL, NULL,
 532                  '_doQuery: Could not execute query ("'.$query.'"): ' . @ibase_errmsg()));
 533          }
 534          return $result;
 535      }
 536  
 537      // }}}
 538      // {{{ query()
 539  
 540      /**
 541       * Send a query to the database and return any results
 542       *
 543       * @param string $query the SQL query
 544       * @param array $types array that contains the types of the columns in
 545       *                         the result set
 546       * @return mixed result identifier if query executed, else MDB_error
 547       * @access public
 548       **/
 549      function query($query, $types = NULL)
 550      {
 551          $this->debug('Query: '.$query);
 552          $this->last_query = $query;
 553          $first = $this->first_selected_row;
 554          $limit = $this->selected_row_limit;
 555          $this->first_selected_row = $this->selected_row_limit = 0;
 556          $connected = $this->connect();
 557          if (MDB::isError($connected)) {
 558              return $connected;
 559          }
 560  
 561          if (!MDB::isError($result = $this->_doQuery($query, $first, $limit, 0))) {
 562              if ($types != NULL) {
 563                  if (!is_array($types)) {
 564                      $types = array($types);
 565                  }
 566                  if (MDB::isError($err = $this->setResultTypes($result, $types))) {
 567                      $this->freeResult($result);
 568                      return $err;
 569                  }
 570              }
 571              return $result;
 572          }
 573          return $this->ibaseRaiseError();
 574  
 575      }
 576  
 577      // }}}
 578      // {{{ _executePreparedQuery()
 579  
 580      /**
 581       * Execute a prepared query statement.
 582       *
 583       * @param int $prepared_query argument is a handle that was returned by
 584       *       the function prepareQuery()
 585       * @param string $query query to be executed
 586       * @param array $types array that contains the types of the columns in
 587       *       the result set
 588       * @return mixed a result handle or MDB_OK on success, a MDB error on failure
 589       * @access private
 590       */
 591      function _executePreparedQuery($prepared_query, $query)
 592      {
 593          $first = $this->first_selected_row;
 594          $limit = $this->selected_row_limit;
 595          $this->first_selected_row = $this->selected_row_limit = 0;
 596          if (MDB::isError($connect = $this->connect())) {
 597              return $connect;
 598          }
 599          return($this->_doQuery($query, $first, $limit, $prepared_query));
 600      }
 601  
 602      // }}}
 603      // {{{ _skipLimitOffset()
 604  
 605      /**
 606       * Skip the first row of a result set.
 607       *
 608       * @param resource $result
 609       * @return mixed a result handle or MDB_OK on success, a MDB error on failure
 610       * @access private
 611       */
 612      function _skipLimitOffset($result)
 613      {
 614          $result_value = intval($result);
 615          $first = $this->limits[$result_value][0];
 616          for (; $this->limits[$result_value][2] < $first; $this->limits[$result_value][2]++) {
 617              if (!is_array(@ibase_fetch_row($result))) {
 618                  $this->limits[$result_value][2] = $first;
 619                  return($this->raiseError(MDB_ERROR, NULL, NULL,
 620                      'Skip first rows: could not skip a query result row'));
 621              }
 622          }
 623          return MDB_OK;
 624      }
 625  
 626      // }}}
 627      // {{{ getColumnNames()
 628  
 629      /**
 630       * Retrieve the names of columns returned by the DBMS in a query result.
 631       *
 632       * @param resource $result  result identifier
 633       * @return mixed an associative array variable
 634       *                               that will hold the names of columns.The
 635       *                               indexes of the array are the column names
 636       *                               mapped to lower case and the values are the
 637       *                               respective numbers of the columns starting
 638       *                               from 0. Some DBMS may not return any
 639       *                               columns when the result set does not
 640       *                               contain any rows.
 641       *
 642       *                               a MDB error on failure
 643       * @access public
 644       */
 645      function getColumnNames($result)
 646      {
 647          $result_value = intval($result);
 648          if (!isset($this->highest_fetched_row[$result_value])) {
 649              return($this->raiseError(MDB_ERROR, NULL, NULL,
 650                  'Get column names: it was specified an inexisting result set'));
 651          }
 652          if (!isset($this->columns[$result_value])) {
 653              $this->columns[$result_value] = array();
 654              $columns = @ibase_num_fields($result);
 655              for ($column=0; $column < $columns; $column++) {
 656                  $column_info = @ibase_field_info($result, $column);
 657                  $field_name = $column_info['name'];
 658                  if ($this->options['optimize'] == 'portability') {
 659                      $field_name = strtolower($field_name);
 660                  }
 661                  $this->columns[$result_value][$field_name] = $column;
 662              }
 663          }
 664          return $this->columns[$result_value];
 665      }
 666  
 667      // }}}
 668      // {{{ numCols()
 669  
 670      /**
 671       * Count the number of columns returned by the DBMS in a query result.
 672       *
 673       * @param resource $result result identifier
 674       * @return mixed integer value with the number of columns, a MDB error
 675       *      on failure
 676       * @access public
 677       */
 678      function numCols($result)
 679      {
 680          if (!isset($this->highest_fetched_row[intval($result)])) {
 681              return($this->raiseError(MDB_ERROR, NULL, NULL,
 682                  'Number of columns: it was specified an inexisting result set'));
 683          }
 684          return @ibase_num_fields($result);
 685      }
 686  
 687      // }}}
 688      // {{{ endOfResult()
 689  
 690      /**
 691       * check if the end of the result set has been reached
 692       *
 693       * @param resource    $result result identifier
 694       * @return mixed TRUE or FALSE on sucess, a MDB error on failure
 695       * @access public
 696       */
 697      function endOfResult($result)
 698      {
 699          $result_value = intval($result);
 700          if (!isset($this->current_row[$result_value])) {
 701              return($this->raiseError(MDB_ERROR, NULL, NULL,
 702                  'End of result: attempted to check the end of an unknown result'));
 703          }
 704          if (isset($this->results[$result_value]) && end($this->results[$result_value]) === false) {
 705              return(($this->highest_fetched_row[$result_value]-1) <= $this->current_row[$result_value]);
 706          }
 707          if (isset($this->row_buffer[$result_value])) {
 708              return(!$this->row_buffer[$result_value]);
 709          }
 710          if (isset($this->limits[$result_value])) {
 711              if (MDB::isError($this->_skipLimitOffset($result))
 712                  || ($this->current_row[$result_value]) > $this->limits[$result_value][1]
 713              ) {
 714                  return true;
 715              }
 716          }
 717          if (is_array($this->row_buffer[$result_value] = @ibase_fetch_row($result))) {
 718              return false;
 719          }
 720          $this->row_buffer[$result_value] = false;
 721          return true;
 722      }
 723  
 724      // }}}
 725      // {{{ fetch()
 726  
 727      /**
 728       * fetch value from a result set
 729       *
 730       * @param resource $result result identifier
 731       * @param int $rownum number of the row where the data can be found
 732       * @param int $field field number where the data can be found
 733       * @return mixed string on success, a MDB error on failure
 734       * @access public
 735       */
 736      function fetch($result, $rownum, $field)
 737      {
 738          $fetchmode = is_numeric($field) ? MDB_FETCHMODE_ORDERED : MDB_FETCHMODE_ASSOC;
 739          $row = $this->fetchInto($result, $fetchmode, $rownum);
 740          if (MDB::isError($row)) {
 741              return $row;
 742          }
 743          if (!array_key_exists($field, $row)) {
 744              return null;
 745          }
 746          return $row[$field];
 747      }
 748  
 749      // }}}
 750      // {{{ fetchInto()
 751  
 752      /**
 753       * Fetch a row and return data in an array.
 754       *
 755       * @param resource $result result identifier
 756       * @param int $fetchmode how the array data should be indexed
 757       * @param int $rownum the row number to fetch
 758       * @return mixed data array or NULL on success, a MDB error on failure
 759       * @access public
 760       */
 761      function fetchInto($result, $fetchmode=MDB_FETCHMODE_DEFAULT, $rownum=null)
 762      {
 763          $result_value = intval($result);
 764          if (!isset($this->current_row[$result_value])) {
 765              return($this->raiseError(MDB_ERROR, NULL, NULL,
 766                  'fetchInto: attemped to fetch on an unknown query result'));
 767          }
 768          if ($fetchmode == MDB_FETCHMODE_DEFAULT) {
 769              $fetchmode = $this->fetchmode;
 770          }
 771          if (is_null($rownum)) {
 772              $rownum = $this->current_row[$result_value] + 1;
 773          }
 774          if (!isset($this->results[$result_value][$rownum])
 775              && (!isset($this->results[$result_value][$this->highest_fetched_row[$result_value]])
 776                  || $this->results[$result_value][$this->highest_fetched_row[$result_value]] !== false)
 777          ) {
 778              if (isset($this->limits[$result_value])) {
 779                  //upper limit
 780                  if ($rownum > $this->limits[$result_value][1]) {
 781                      // are all previous rows fetched so that we can set the end
 782                      // of the result set and not have any "holes" in between?
 783                      if ($rownum == 0
 784                          || (isset($this->results[$result_value])
 785                              && count($this->results[$result_value]) == $rownum)
 786                      ) {
 787                          $this->highest_fetched_row[$result_value] = $rownum;
 788                          $this->current_row[$result_value] = $rownum;
 789                          $this->results[$result_value][$rownum] = false;
 790                      }
 791                      if ($this->options['autofree']) {
 792                          $this->freeResult($result);
 793                      }
 794                      return null;
 795                  }
 796                  // offset skipping
 797                  if (MDB::isError($this->_skipLimitOffset($result))) {
 798                      $this->current_row[$result_value] = 0;
 799                      $this->results[$result_value] = array(false);
 800                      if ($this->options['autofree']) {
 801                          $this->freeResult($result);
 802                      }
 803                      return null;
 804                  }
 805              }
 806              if (isset($this->row_buffer[$result_value])) {
 807                  ++$this->current_row[$result_value];
 808                  $this->results[$result_value][$this->current_row[$result_value]] =
 809                      $this->row_buffer[$result_value];
 810                  unset($this->row_buffer[$result_value]);
 811              }
 812              if (!isset($this->results[$result_value][$rownum])
 813                  && (!isset($this->results[$result_value][$this->highest_fetched_row[$result_value]])
 814                      || $this->results[$result_value][$this->highest_fetched_row[$result_value]] !== false)
 815              ) {
 816                  while ($this->current_row[$result_value] < $rownum
 817                      && is_array($buffer = @ibase_fetch_row($result))
 818                  ) {
 819                      ++$this->current_row[$result_value];
 820                      $this->results[$result_value][$this->current_row[$result_value]] = $buffer;
 821                  }
 822                  // end of result set reached
 823                  if ($this->current_row[$result_value] < $rownum) {
 824                      ++$this->current_row[$result_value];
 825                      $this->results[$result_value][$this->current_row[$result_value]] = false;
 826                  }
 827              }
 828              $this->highest_fetched_row[$result_value] =
 829                  max($this->highest_fetched_row[$result_value],
 830                      $this->current_row[$result_value]);
 831          } else {
 832              ++$this->current_row[$result_value];
 833          }
 834          if (isset($this->results[$result_value][$rownum])
 835              && $this->results[$result_value][$rownum]
 836          ) {
 837              $row = $this->results[$result_value][$rownum];
 838          } else {
 839              if ($this->options['autofree']) {
 840                  $this->freeResult($result);
 841              }
 842              return null;
 843          }
 844          foreach ($row as $key => $value_with_space) {
 845              if (!is_null($value_with_space)) {
 846                  $row[$key] = rtrim($value_with_space, ' ');
 847              }
 848          }
 849          if ($fetchmode & MDB_FETCHMODE_ASSOC) {
 850              $column_names = $this->getColumnNames($result);
 851              foreach ($column_names as $name => $i) {
 852                  $column_names[$name] = $row[$i];
 853              }
 854              $row = $column_names;
 855          }
 856          if (isset($this->result_types[$result_value])) {
 857              $row = $this->convertResultRow($result, $row);
 858          }
 859          return $row;
 860      }
 861  
 862      // }}}
 863      // {{{ _retrieveLob()
 864  
 865      /**
 866       * fetch a lob value from a result set
 867       *
 868       * @param int $lob handle to a lob created by the createLob() function
 869       * @return mixed MDB_OK on success, a MDB error on failure
 870       * @access private
 871       */
 872      function _retrieveLob($lob)
 873      {
 874          if (!isset($this->lobs[$lob])) {
 875              return($this->raiseError(MDB_ERROR, NULL, NULL,
 876                  'Retrieve LOB: it was not specified a valid lob'));
 877          }
 878  
 879          if (!isset($this->lobs[$lob]['Value'])) {
 880              $this->lobs[$lob]['Value'] = $this->fetch($this->lobs[$lob]['Result'],
 881                                                        $this->lobs[$lob]['Row'],
 882                                                        $this->lobs[$lob]['Field']);
 883  
 884              if (!$this->lobs[$lob]['Handle'] = @ibase_blob_open($this->lobs[$lob]['Value'])) {
 885                  unset($this->lobs[$lob]['Value']);
 886                  return($this->raiseError(MDB_ERROR, NULL, NULL,
 887                      'Retrieve LOB: Could not open fetched large object field' . @ibase_errmsg()));
 888              }
 889          }
 890          return MDB_OK;
 891      }
 892  
 893      // }}}
 894      // {{{ endOfResultLob()
 895  
 896      /**
 897       * Determine whether it was reached the end of the large object and
 898       * therefore there is no more data to be read for the its input stream.
 899       *
 900       * @param int    $lob handle to a lob created by the createLob() function
 901       * @return mixed TRUE or FALSE on success, a MDB error on failure
 902       * @access public
 903       */
 904      function endOfResultLob($lob)
 905      {
 906          if (MDB::isError($lobresult = $this->_retrieveLob($lob))) {
 907              return($lobresult);
 908          }
 909          return(isset($this->lobs[$lob]['EndOfLOB']));
 910      }
 911  
 912      // }}}
 913      // {{{ _readResultLob()
 914  
 915      /**
 916       * Read data from large object input stream.
 917       *
 918       * @param int $lob handle to a lob created by the createLob() function
 919       * @param blob $data reference to a variable that will hold data to be
 920       *      read from the large object input stream
 921       * @param int $length integer value that indicates the largest ammount of
 922       *      data to be read from the large object input stream.
 923       * @return mixed length on success, a MDB error on failure
 924       * @access private
 925       */
 926      function _readResultLob($lob, &$data, $length)
 927      {
 928          if (MDB::isError($lobresult = $this->_retrieveLob($lob))) {
 929              return $lobresult;
 930          }
 931          $data = @ibase_blob_get($this->lobs[$lob]['Handle'], $length);
 932          if (!is_string($data)) {
 933              $this->raiseError(MDB_ERROR, NULL, NULL,
 934                  'Read Result LOB: ' . @ibase_errmsg());
 935          }
 936          if (($length = strlen($data)) == 0) {
 937              $this->lobs[$lob]['EndOfLOB'] = 1;
 938          }
 939          return $length;
 940      }
 941  
 942      // }}}
 943      // {{{ _destroyResultLob()
 944  
 945      /**
 946       * Free any resources allocated during the lifetime of the large object
 947       * handler object.
 948       *
 949       * @param int $lob handle to a lob created by the createLob() function
 950       * @access private
 951       */
 952      function _destroyResultLob($lob)
 953      {
 954          if (isset($this->lobs[$lob])) {
 955              if (isset($this->lobs[$lob]['Value'])) {
 956                 @ibase_blob_close($this->lobs[$lob]['Handle']);
 957              }
 958              $this->lobs[$lob] = '';
 959          }
 960      }
 961  
 962      // }}}
 963      // {{{ fetchClob()
 964  
 965      /**
 966       * fetch a clob value from a result set
 967       *
 968       * @param resource $result result identifier
 969       * @param int $row number of the row where the data can be found
 970       * @param int $field field number where the data can be found
 971       * @return mixed content of the specified data cell, a MDB error on failure,
 972       *       a MDB error on failure
 973       * @access public
 974       */
 975      function fetchClob($result, $row, $field)
 976      {
 977          return $this->fetchLob($result, $row, $field);
 978      }
 979  
 980      // }}}
 981      // {{{ fetchBlob()
 982  
 983      /**
 984       * fetch a blob value from a result set
 985       *
 986       * @param resource $result result identifier
 987       * @param int $row number of the row where the data can be found
 988       * @param int $field field number where the data can be found
 989       * @return mixed content of the specified data cell, a MDB error on failure
 990       * @access public
 991       */
 992      function fetchBlob($result, $row, $field)
 993      {
 994          return $this->fetchLob($result, $row, $field);
 995      }
 996  
 997      // }}}
 998      // {{{ convertResult()
 999  
1000      /**
1001       * convert a value to a RDBMS indepdenant MDB type
1002       *
1003       * @param mixed $value value to be converted
1004       * @param int $type constant that specifies which type to convert to
1005       * @return mixed converted value or a MDB error on failure
1006       * @access public
1007       */
1008      function convertResult($value, $type)
1009      {
1010          switch ($type) {
1011              case MDB_TYPE_DECIMAL:
1012                  return sprintf('%.'.$this->decimal_places.'f', doubleval($value)/$this->decimal_factor);
1013              case MDB_TYPE_TIMESTAMP:
1014                  return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS'));
1015              default:
1016                  return $this->_baseConvertResult($value, $type);
1017          }
1018      }
1019  
1020      // }}}
1021      // {{{ resultIsNull()
1022  
1023      /**
1024       * Determine whether the value of a query result located in given row and
1025       *    field is a NULL.
1026       *
1027       * @param resource $result result identifier
1028       * @param int $rownum number of the row where the data can be found
1029       * @param int $field field number where the data can be found
1030       * @return mixed TRUE or FALSE on success, a MDB error on failure
1031       * @access public
1032       */
1033      function resultIsNull($result, $rownum, $field)
1034      {
1035          $value = $this->fetch($result, $rownum, $field);
1036          if (MDB::isError($value)) {
1037              return $value;
1038          }
1039          return(!isset($value));
1040      }
1041  
1042      // }}}
1043      // {{{ numRows()
1044  
1045      /**
1046       * returns the number of rows in a result object
1047       *
1048       * @param ressource $result a valid result ressouce pointer
1049       * @return mixed MDB_Error or the number of rows
1050       * @access public
1051       */
1052      function numRows($result)
1053      {
1054          $result_value = intval($result);
1055          if (!isset($this->current_row[$result_value])) {
1056              return($this->raiseError(MDB_ERROR, NULL, NULL,
1057                  'Number of rows: attemped to obtain the number of rows contained in an unknown query result'));
1058          }
1059          if (!isset($this->rows[$result_value][$this->highest_fetched_row[$result_value]])
1060              || $this->rows[$result_value][$this->highest_fetched_row[$result_value]] !== false
1061          ) {
1062              if (isset($this->limits[$result_value])) {
1063                  if (MDB::isError($skipfirstrow = $this->_skipLimitOffset($result))) {
1064                      //$this->rows[$result_value] = 0;
1065                      return $skipfirstrow;
1066                  }
1067              }
1068              if (isset($this->row_buffer[$result_value])) {
1069                  ++$this->highest_fetched_row[$result_value];
1070                  $this->results[$result_value][$this->highest_fetched_row[$result_value]]
1071                      = $this->row_buffer[$result_value];
1072                  unset($this->row_buffer[$result_value]);
1073              }
1074              if (!isset($this->results[$result_value][$this->highest_fetched_row[$result_value]])
1075                  || $this->results[$result_value][$this->highest_fetched_row[$result_value]] !== false
1076              ) {
1077                  while((!isset($this->limits[$result_value])
1078                      || ($this->highest_fetched_row[$result_value]+1) < $this->limits[$result_value][1]
1079                  )
1080                      && (is_array($buffer = @ibase_fetch_row($result)))
1081                  ) {
1082                      ++$this->highest_fetched_row[$result_value];
1083                      $this->results[$result_value][$this->highest_fetched_row[$result_value]] = $buffer;
1084                  }
1085                  ++$this->highest_fetched_row[$result_value];
1086                  $this->results[$result_value][$this->highest_fetched_row[$result_value]] = false;
1087              }
1088          }
1089          return(max(0, $this->highest_fetched_row[$result_value]));
1090      }
1091  
1092      // }}}
1093      // {{{ freeResult()
1094  
1095      /**
1096       * Free the internal resources associated with $result.
1097       *
1098       * @param $result result identifier
1099       * @return boolean TRUE on success, FALSE if $result is invalid
1100       * @access public
1101       */
1102      function freeResult($result)
1103      {
1104          $result_value = intval($result);
1105          if (!isset($this->current_row[$result_value])) {
1106             return($this->raiseError(MDB_ERROR, NULL, NULL,
1107                 'Free result: attemped to free an unknown query result'));
1108          }
1109          if (isset($this->highest_fetched_row[$result_value])) {
1110              unset($this->highest_fetched_row[$result_value]);
1111          }
1112          if (isset($this->row_buffer[$result_value])) {
1113              unset($this->row_buffer[$result_value]);
1114          }
1115          if (isset($this->limits[$result_value])) {
1116              unset($this->limits[$result_value]);
1117          }
1118          if (isset($this->current_row[$result_value])) {
1119              unset($this->current_row[$result_value]);
1120          }
1121          if (isset($this->results[$result_value])) {
1122              unset($this->results[$result_value]);
1123          }
1124          if (isset($this->columns[$result_value])) {
1125              unset($this->columns[$result_value]);
1126          }
1127          if (isset($this->rows[$result_value])) {
1128              unset($this->rows[$result_value]);
1129          }
1130          if (isset($this->result_types[$result_value])) {
1131              unset($this->result_types[$result_value]);
1132          }
1133          if (is_resource($result)) {
1134              return @ibase_free_result($result);
1135          }
1136          return true;
1137      }
1138      // }}}
1139      // {{{ getTypeDeclaration()
1140  
1141      /**
1142       * Obtain DBMS specific SQL code portion needed to declare an text type
1143       * field to be used in statements like CREATE TABLE.
1144       *
1145       * @param string $field  associative array with the name of the properties
1146       *      of the field being declared as array indexes. Currently, the types
1147       *      of supported field properties are as follows:
1148       *
1149       *      length
1150       *          Integer value that determines the maximum length of the text
1151       *          field. If this argument is missing the field should be
1152       *          declared to have the longest length allowed by the DBMS.
1153       *
1154       *      default
1155       *          Text value to be used as default for this field.
1156       *
1157       *      notnull
1158       *          Boolean flag that indicates whether this field is constrained
1159       *          to not be set to null.
1160       * @return string  DBMS specific SQL code portion that should be used to
1161       *      declare the specified field.
1162       * @access public
1163       */
1164      function getTypeDeclaration($field)
1165      {
1166          switch($field['type'])
1167          {
1168              case 'text':
1169                  return('VARCHAR ('.(isset($field['length']) ? $field['length'] : (isset($this->options['DefaultTextFieldLength']) ? $this->options['DefaultTextFieldLength'] : 4000)).')');
1170              case 'clob':
1171                  return 'BLOB SUB_TYPE 1';
1172              case 'blob':
1173                  return 'BLOB SUB_TYPE 0';
1174              case 'integer':
1175                  return 'INTEGER';
1176              case 'boolean':
1177                  return 'CHAR (1)';
1178              case 'date':
1179                  return 'DATE';
1180              case 'time':
1181                  return 'TIME';
1182              case 'timestamp':
1183                  return 'TIMESTAMP';
1184              case 'float':
1185                  return 'DOUBLE PRECISION';
1186              case 'decimal':
1187                  return 'DECIMAL(18,'.$this->decimal_places.')';
1188          }
1189          return '';
1190      }
1191  
1192      // }}}
1193      // {{{ getTextDeclaration()
1194  
1195      /**
1196       * Obtain DBMS specific SQL code portion needed to declare an text type
1197       * field to be used in statements like CREATE TABLE.
1198       *
1199       * @param string $name   name the field to be declared.
1200       * @param string $field  associative array with the name of the properties
1201       *      of the field being declared as array indexes. Currently, the types
1202       *      of supported field properties are as follows:
1203       *
1204       *      length
1205       *          Integer value that determines the maximum length of the text
1206       *          field. If this argument is missing the field should be
1207       *          declared to have the longest length allowed by the DBMS.
1208       *
1209       *      default
1210       *          Text value to be used as default for this field.
1211       *
1212       *      notnull
1213       *          Boolean flag that indicates whether this field is constrained
1214       *          to not be set to NULL.
1215       * @return string  DBMS specific SQL code portion that should be used to
1216       *      declare the specified field.
1217       * @access public
1218       */
1219      function getTextDeclaration($name, $field)
1220      {
1221          return($name.' '.$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT '.$this->getTextValue($field['default']) : '').(IsSet($field['notnull']) ? ' NOT NULL' : ''));
1222      }
1223  
1224      // }}}
1225      // {{{ getClobDeclaration()
1226  
1227      /**
1228       * Obtain DBMS specific SQL code portion needed to declare an character
1229       * large object type field to be used in statements like CREATE TABLE.
1230       *
1231       * @param string $name   name the field to be declared.
1232       * @param string $field  associative array with the name of the properties
1233       *      of the field being declared as array indexes. Currently, the types
1234       *      of supported field properties are as follows:
1235       *
1236       *      length
1237       *          Integer value that determines the maximum length of the large
1238       *          object field. If this argument is missing the field should be
1239       *          declared to have the longest length allowed by the DBMS.
1240       *
1241       *      notnull
1242       *          Boolean flag that indicates whether this field is constrained
1243       *          to not be set to NULL.
1244       * @return string  DBMS specific SQL code portion that should be used to
1245       *      declare the specified field.
1246       * @access public
1247       */
1248      function getClobDeclaration($name, $field)
1249      {
1250          return($name.' '.$this->getTypeDeclaration($field).(isset($field['notnull']) ? ' NOT NULL' : ''));
1251      }
1252  
1253      // }}}
1254      // {{{ getBlobDeclaration()
1255  
1256      /**
1257       * Obtain DBMS specific SQL code portion needed to declare an binary large
1258       * object type field to be used in statements like CREATE TABLE.
1259       *
1260       * @param string $name   name the field to be declared.
1261       * @param string $field  associative array with the name of the properties
1262       *      of the field being declared as array indexes. Currently, the types
1263       *      of supported field properties are as follows:
1264       *
1265       *      length
1266       *          Integer value that determines the maximum length of the large
1267       *          object field. If this argument is missing the field should be
1268       *          declared to have the longest length allowed by the DBMS.
1269       *
1270       *      notnull
1271       *          Boolean flag that indicates whether this field is constrained
1272       *          to not be set to NULL.
1273       * @return string  DBMS specific SQL code portion that should be used to
1274       *      declare the specified field.
1275       * @access public
1276       */
1277      function getBlobDeclaration($name, $field)
1278      {
1279          return($name.' '.$this->getTypeDeclaration($field).(isset($field['notnull']) ? ' NOT NULL' : ''));
1280      }
1281  
1282      // }}}
1283      // {{{ getDateDeclaration()
1284  
1285      /**
1286       * Obtain DBMS specific SQL code portion needed to declare a date type
1287       * field to be used in statements like CREATE TABLE.
1288       *
1289       * @param string $name   name the field to be declared.
1290       * @param string $field  associative array with the name of the properties
1291       *      of the field being declared as array indexes. Currently, the types
1292       *      of supported field properties are as follows:
1293       *
1294       *      default
1295       *          Date value to be used as default for this field.
1296       *
1297       *      notnull
1298       *          Boolean flag that indicates whether this field is constrained
1299       *          to not be set to NULL.
1300       * @return string  DBMS specific SQL code portion that should be used to
1301       *      declare the specified field.
1302       * @access public
1303       */
1304      function getDateDeclaration($name, $field)
1305      {
1306          return($name.' '.$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT "'.$field['default'].'"' : '').(isset($field['notnull']) ? ' NOT NULL' : ''));
1307      }
1308  
1309      // }}}
1310      // {{{ getTimeDeclaration()
1311  
1312      /**
1313       * Obtain DBMS specific SQL code portion needed to declare a time
1314       * field to be used in statements like CREATE TABLE.
1315       *
1316       * @param string $name   name the field to be declared.
1317       * @param string $field  associative array with the name of the properties
1318       *      of the field being declared as array indexes. Currently, the types
1319       *      of supported field properties are as follows:
1320       *
1321       *      default
1322       *          Time value to be used as default for this field.
1323       *
1324       *      notnull
1325       *          Boolean flag that indicates whether this field is constrained
1326       *          to not be set to NULL.
1327       * @return string  DBMS specific SQL code portion that should be used to
1328       *      declare the specified field.
1329       * @access public
1330       */
1331      function getTimeDeclaration($name, $field)
1332      {
1333          return($name.' '.$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT "'.$field['default'].'"' : '').(isset($field['notnull']) ? ' NOT NULL' : ''));
1334      }
1335  
1336      // }}}
1337      // {{{ getFloatDeclaration()
1338  
1339      /**
1340       * Obtain DBMS specific SQL code portion needed to declare a float type
1341       * field to be used in statements like CREATE TABLE.
1342       *
1343       * @param string $name   name the field to be declared.
1344       * @param string $field  associative array with the name of the properties
1345       *      of the field being declared as array indexes. Currently, the types
1346       *      of supported field properties are as follows:
1347       *
1348       *      default
1349       *          Float value to be used as default for this field.
1350       *
1351       *      notnull
1352       *          Boolean flag that indicates whether this field is constrained
1353       *          to not be set to NULL.
1354       * @return string  DBMS specific SQL code portion that should be used to
1355       *      declare the specified field.
1356       * @access public
1357       */
1358      function getFloatDeclaration($name, $field)
1359      {
1360          return($name.' '.$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT '.$this->getFloatValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : ''));
1361      }
1362  
1363      // }}}
1364      // {{{ getDecimalDeclaration()
1365  
1366      /**
1367       * Obtain DBMS specific SQL code portion needed to declare a decimal type
1368       * field to be used in statements like CREATE TABLE.
1369       *
1370       * @param string $name   name the field to be declared.
1371       * @param string $field  associative array with the name of the properties
1372       *      of the field being declared as array indexes. Currently, the types
1373       *      of supported field properties are as follows:
1374       *
1375       *      default
1376       *          Decimal value to be used as default for this field.
1377       *
1378       *      notnull
1379       *          Boolean flag that indicates whether this field is constrained
1380       *          to not be set to NULL.
1381       * @return string  DBMS specific SQL code portion that should be used to
1382       *      declare the specified field.
1383       * @access public
1384       */
1385      function getDecimalDeclaration($name, $field)
1386      {
1387          return($name.' '.$this->getTypeDeclaration($field).(isset($field['default']) ? ' DEFAULT '.$this->getDecimalValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : ''));
1388      }
1389  
1390      // }}}
1391      // {{{ _getLobValue()
1392  
1393      /**
1394       * Convert a text value into a DBMS specific format that is suitable to
1395       * compose query statements.
1396       *
1397       * @param resource  $prepared_query query handle from prepare()
1398       * @param           $parameter
1399       * @param           $lob
1400       * @return string text string that represents the given argument value in
1401       *      a DBMS specific format.
1402       * @access private
1403       */
1404      function _getLobValue($prepared_query, $parameter, $lob)
1405      {
1406          if (MDB::isError($connect = $this->connect())) {
1407              return $connect;
1408          }
1409          $value   = '';  // DEAL WITH ME
1410          if (!$this->transaction_id = @ibase_trans(IBASE_COMMITTED, $this->connection)) {
1411              return($this->raiseError(MDB_ERROR, NULL, NULL, '_getLobValue: Could not start a new transaction: '.@ibase_errmsg()));
1412          }
1413  
1414          if (($lo = @ibase_blob_create($this->auto_commit ? $this->connection : $this->transaction_id))) {
1415              while (!$this->endOfLob($lob)) {
1416                  if (MDB::isError($result = $this->readLob($lob, $data, $this->options['lob_buffer_length']))) {
1417                      break;
1418                  }
1419                  if (@ibase_blob_add($lo, $data) === false) {
1420                      $result = $this->raiseError(MDB_ERROR, NULL, NULL,
1421                          '_getLobValue - Could not add data to a large object: ' . @ibase_errmsg());
1422                      break;
1423                  }
1424              }
1425              if (MDB::isError($result)) {
1426                  @ibase_blob_cancel($lo);
1427              } else {
1428                  $value = @ibase_blob_close($lo);
1429              }
1430          } else {
1431              $result = $this->raiseError(MDB_ERROR, NULL, NULL,
1432                  'Get LOB field value' . @ibase_errmsg());
1433          }
1434          if (!isset($this->query_parameters[$prepared_query])) {
1435              $this->query_parameters[$prepared_query]       = array(0, '');
1436              $this->query_parameter_values[$prepared_query] = array();
1437          }
1438          $query_parameter = count($this->query_parameters[$prepared_query]);
1439          $this->query_parameter_values[$prepared_query][$parameter] = $query_parameter;
1440          $this->query_parameters[$prepared_query][$query_parameter] = $value;
1441          $value = '?';
1442  
1443          if (!$this->auto_commit) {
1444              $this->commit();
1445          }
1446          return $value;
1447      }
1448  
1449      // }}}
1450      // {{{ getClobValue()
1451  
1452      /**
1453       * Convert a text value into a DBMS specific format that is suitable to
1454       * compose query statements.
1455       *
1456       * @param resource  $prepared_query query handle from prepare()
1457       * @param           $parameter
1458       * @param           $clob
1459       * @return string text string that represents the given argument value in
1460       *      a DBMS specific format.
1461       * @access public
1462       */
1463      function getClobValue($prepared_query, $parameter, $clob)
1464      {
1465          return $this->_getLobValue($prepared_query, $parameter, $clob);
1466      }
1467  
1468  
1469      // }}}
1470      // {{{ freeLobValue()
1471  
1472      /**
1473       * free a large object
1474       *
1475       * @param resource  $prepared_query query handle from prepare()
1476       * @param string    $lob
1477       * @param string    $value
1478       * @return MDB_OK
1479       * @access public
1480       */
1481      function freeLobValue($prepared_query, $lob, &$value)
1482      {
1483          $query_parameter=$this->query_parameter_values[$prepared_query][$lob];
1484  
1485          unset($this->query_parameters[$prepared_query][$query_parameter]);
1486          unset($this->query_parameter_values[$prepared_query][$lob]);
1487          if (count($this->query_parameter_values[$prepared_query]) == 0) {
1488              unset($this->query_parameters[$prepared_query]);
1489              unset($this->query_parameter_values[$prepared_query]);
1490          }
1491          unset($value);
1492      }
1493  
1494      // }}}
1495      // {{{ freeClobValue()
1496  
1497      /**
1498       * free a character large object
1499       *
1500       * @param resource  $prepared_query query handle from prepare()
1501       * @param string    $clob
1502       * @param string    $value
1503       * @return MDB_OK
1504       * @access public
1505       */
1506      function freeClobValue($prepared_query, $clob, &$value)
1507      {
1508          $this->freeLobValue($prepared_query, $clob, $value);
1509      }
1510  
1511      // }}}
1512      // {{{ getBlobValue()
1513  
1514      /**
1515       * Convert a text value into a DBMS specific format that is suitable to
1516       * compose query statements.
1517       *
1518       * @param resource  $prepared_query query handle from prepare()
1519       * @param           $parameter
1520       * @param           $blob
1521       * @return string text string that represents the given argument value in
1522       *      a DBMS specific format.
1523       * @access public
1524       */
1525      function getBlobValue($prepared_query, $parameter, $blob)
1526      {
1527          return $this->_getLobValue($prepared_query, $parameter, $blob);
1528      }
1529  
1530      // }}}
1531      // {{{ freeBlobValue()
1532  
1533      /**
1534       * free a binary large object
1535       *
1536       * @param resource  $prepared_query query handle from prepare()
1537       * @param string    $blob
1538       * @param string    $value
1539       * @return MDB_OK
1540       * @access public
1541       */
1542      function freeBlobValue($prepared_query, $blob, &$value)
1543      {
1544          $this->freeLobValue($prepared_query, $blob, $value);
1545      }
1546  
1547      // }}}
1548      // {{{ getFloatValue()
1549  
1550      /**
1551       * Convert a text value into a DBMS specific format that is suitable to
1552       * compose query statements.
1553       *
1554       * @param string $value text string value that is intended to be converted.
1555       * @return string text string that represents the given argument value in
1556       *      a DBMS specific format.
1557       * @access public
1558       */
1559      function getFloatValue($value)
1560      {
1561          return (($value === null) ? 'NULL' : $value);
1562      }
1563  
1564      // }}}
1565      // {{{ getDecimalValue()
1566  
1567      /**
1568       * Convert a text value into a DBMS specific format that is suitable to
1569       * compose query statements.
1570       *
1571       * @param string $value text string value that is intended to be converted.
1572       * @return string text string that represents the given argument value in
1573       *      a DBMS specific format.
1574       * @access public
1575       */
1576      function getDecimalValue($value)
1577      {
1578          return (($value === null) ? 'NULL' : strval(round($value*$this->decimal_factor)));
1579      }
1580  
1581      // }}}
1582      // {{{ affectedRows()
1583  
1584      /**
1585       * returns the affected rows of a query
1586       *
1587       * @return mixed MDB Error Object or number of rows
1588       * @access public
1589       */
1590      function affectedRows()
1591      {
1592          if (function_exists('ibase_affected_rows')) { //PHP5 only
1593              $affected_rows = @ibase_affected_rows($this->connection);
1594              if ($affected_rows === false) {
1595                  return $this->raiseError(MDB_ERROR_NEED_MORE_DATA);
1596              }
1597              return $affected_rows;
1598          }
1599          return parent::affectedRows();
1600      }
1601  
1602      // }}}
1603      // {{{ nextId()
1604  
1605      /**
1606       * returns the next free id of a sequence
1607       *
1608       * @param string  $seq_name name of the sequence
1609       * @param boolean $ondemand when TRUE the seqence is
1610       *                          automatic created, if it
1611       *                          not exists
1612       * @return mixed MDB_Error or id
1613       * @access public
1614       */
1615      function nextId($seq_name, $ondemand = true)
1616      {
1617          if (MDB::isError($connect = $this->connect())) {
1618              return $connect;
1619          }
1620          //$sequence_name = $this->getSequenceName($seq_name);
1621          $sequence_name = strtoupper($this->getSequenceName($seq_name));
1622          $this->expectError(MDB_ERROR_NOSUCHTABLE);
1623          $query = "SELECT GEN_ID($sequence_name, 1) as the_value FROM RDB\$DATABASE";
1624          $result = $this->_doQuery($query);
1625          $this->popExpect();
1626          if ($ondemand && MDB::isError($result)) {
1627              $result = $this->createSequence($seq_name, 1);
1628              if (MDB::isError($result)) {
1629                  return $result;
1630              }
1631              return $this->nextId($seq_name, false);
1632          }
1633          return $this->fetchOne($result);
1634      }
1635  
1636      // }}}
1637      // {{{ currId()
1638  
1639      /**
1640       * returns the current id of a sequence
1641       *
1642       * @param string  $seq_name name of the sequence
1643       * @return mixed MDB_Error or id
1644       * @access public
1645       */
1646      function currId($seq_name)
1647      {
1648          $sequence_name = strtoupper($this->getSequenceName($seq_name));
1649          //$sequence_name = $this->getSequenceName($seq_name);
1650          $query = "SELECT RDB\$GENERATOR_ID FROM RDB\$GENERATORS WHERE RDB\$GENERATOR_NAME='$sequence_name'";
1651          if (MDB::isError($result = $this->queryOne($query))) {
1652              return($this->raiseError(MDB_ERROR, NULL, NULL,
1653                  'currId: Unable to select from ' . $seqname) );
1654          }
1655          if (!is_numeric($result)) {
1656              //var_dump($result); ==> null
1657              return($this->raiseError(MDB_ERROR, NULL, NULL,
1658                  'currId: could not find value in sequence table'));
1659          }
1660          return $result;
1661      }
1662  
1663      // }}}
1664      // {{{ nextResult()
1665  
1666      /**
1667       * Move the internal ibase result pointer to the next available result
1668       *
1669       * @param $result a valid ibase result resource
1670       * @return TRUE if a result is available otherwise return FALSE
1671       * @access public
1672       */
1673      function nextResult($result)
1674      {
1675          return false;
1676      }
1677  
1678      // }}}
1679      // {{{ tableInfo()
1680  
1681      /**
1682       * returns meta data about the result set
1683       *
1684       * @param  mixed $resource FireBird/InterBase result identifier or table name
1685       * @param mixed $mode depends on implementation
1686       * @return array an nested array, or a MDB error
1687       * @access public
1688       */
1689      function tableInfo($result, $mode = NULL)
1690      {
1691          $count = 0;
1692          $id = 0;
1693          $res = array();
1694  
1695          /**
1696           * depending on $mode, metadata returns the following values:
1697           *
1698           * - mode is FALSE (default):
1699           * $result[]:
1700           *    [0]['table']  table name
1701           *    [0]['name']   field name
1702           *    [0]['type']   field type
1703           *    [0]['len']    field length
1704           *    [0]['flags']  field flags
1705           *
1706           * - mode is MDB_TABLEINFO_ORDER
1707           * $result[]:
1708           *    ['num_fields'] number of metadata records
1709           *    [0]['table']  table name
1710           *    [0]['name']   field name
1711           *    [0]['type']   field type
1712           *    [0]['len']    field length
1713           *    [0]['flags']  field flags
1714           *    ['order'][field name]  index of field named 'field name'
1715           *    The last one is used, if you have a field name, but no index.
1716           *    Test:  if (isset($result['meta']['myfield'])) { ...
1717           *
1718           * - mode is MDB_TABLEINFO_ORDERTABLE
1719           *     the same as above. but additionally
1720           *    ['ordertable'][table name][field name] index of field
1721           *       named 'field name'
1722           *
1723           *       this is, because if you have fields from different
1724           *       tables with the same field name * they override each
1725           *       other with MDB_TABLEINFO_ORDER
1726           *
1727           *       you can combine MDB_TABLEINFO_ORDER and
1728           *       MDB_TABLEINFO_ORDERTABLE with MDB_TABLEINFO_ORDER |
1729           *       MDB_TABLEINFO_ORDERTABLE * or with MDB_TABLEINFO_FULL
1730           **/
1731  
1732          // if $result is a string, then we want information about a
1733          // table without a resultset
1734          if (is_string($result)) {
1735              $id = @ibase_query($this->connection,"SELECT * FROM $result");
1736              if (empty($id)) {
1737                  return $this->ibaseRaiseError();
1738              }
1739          } else { // else we want information about a resultset
1740              $id = $result;
1741              if (empty($id)) {
1742                  return $this->ibaseRaiseError();
1743              }
1744          }
1745  
1746          $count = @ibase_num_fields($id);
1747  
1748          // made this IF due to performance (one if is faster than $count if's)
1749          if (empty($mode)) {
1750              for ($i=0; $i<$count; $i++) {
1751                  $info = @ibase_field_info($id, $i);
1752                  //$res[$i]['table'] = (is_string($result)) ? $result : '';
1753                  $res[$i]['table'] = (is_string($result)) ? $result : $info['relation'];
1754                  $res[$i]['name']  = $info['name'];
1755                  $res[$i]['type']  = $info['type'];
1756                  $res[$i]['len']   = $info['length'];
1757                  //$res[$i]['flags'] = (is_string($result)) ? $this->_ibaseFieldFlags($info['name'], $result) : '';
1758                  $res[$i]['flags'] = (is_string($result)) ? $this->_ibaseFieldFlags($id, $i, $result) : '';
1759              }
1760          } else { // full
1761              $res['num_fields'] = $count;
1762  
1763              for ($i=0; $i<$count; $i++) {
1764                  $info = @ibase_field_info($id, $i);
1765                  //$res[$i]['table'] = (is_string($result)) ? $result : '';
1766                  $res[$i]['table'] = (is_string($result)) ? $result : $info['relation'];
1767                  $res[$i]['name']  = $info['name'];
1768                  $res[$i]['type']  = $info['type'];
1769                  $res[$i]['len']   = $info['length'];
1770                  //$res[$i]['flags'] = (is_string($result)) ? $this->_ibaseFieldFlags($info['name'], $result) : '';
1771                  $res[$i]['flags'] = (is_string($result)) ? $this->_ibaseFieldFlags($id, $i, $result) : '';
1772                  if ($mode & MDB_TABLEINFO_ORDER) {
1773                      $res['order'][$res[$i]['name']] = $i;
1774                  }
1775                  if ($mode & MDB_TABLEINFO_ORDERTABLE) {
1776                      $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
1777                  }
1778              }
1779          }
1780  
1781          // free the result only if we were called on a table
1782          if (is_string($result) && is_resource($id)) {
1783              @ibase_free_result($id);
1784          }
1785          return $res;
1786      }
1787  
1788      // }}}
1789      // {{{ _ibaseFieldFlags()
1790  
1791      /**
1792       * get the Flags of a Field
1793       *
1794       * @param int $resource FireBird/InterBase result identifier
1795       * @param int $num_field the field number
1796       * @return string The flags of the field ('not_null', 'default_xx', 'primary_key',
1797       *                 'unique' and 'multiple_key' are supported)
1798       * @access private
1799       **/
1800      function _ibaseFieldFlags($resource, $num_field, $table_name)
1801      {
1802          $field_name = @ibase_field_info($resource, $num_field);
1803          $field_name = @$field_name['name'];
1804          $sql = 'SELECT  R.RDB$CONSTRAINT_TYPE CTYPE'
1805                 .' FROM  RDB$INDEX_SEGMENTS I'
1806                 .' JOIN  RDB$RELATION_CONSTRAINTS R ON I.RDB$INDEX_NAME=R.RDB$INDEX_NAME'
1807                .' WHERE  I.RDB$FIELD_NAME=\''.$field_name.'\''
1808                   .' AND UPPER(R.RDB$RELATION_NAME)=\''.strtoupper($table_name).'\'';
1809          $result = @ibase_query($this->connection, $sql);
1810          if (empty($result)) {
1811              return $this->ibaseRaiseError();
1812          }
1813          $flags = '';
1814          if ($obj = @ibase_fetch_object($result)) {
1815              @ibase_free_result($result);
1816              if (isset($obj->CTYPE)  && trim($obj->CTYPE) == 'PRIMARY KEY') {
1817                  $flags = 'primary_key ';
1818              }
1819              if (isset($obj->CTYPE)  && trim($obj->CTYPE) == 'UNIQUE') {
1820                  $flags .= 'unique_key ';
1821              }
1822          }
1823  
1824          $sql = 'SELECT  R.RDB$NULL_FLAG AS NFLAG,'
1825                       .' R.RDB$DEFAULT_SOURCE AS DSOURCE,'
1826                       .' F.RDB$FIELD_TYPE AS FTYPE,'
1827                       .' F.RDB$COMPUTED_SOURCE AS CSOURCE'
1828                 .' FROM  RDB$RELATION_FIELDS R '
1829                 .' JOIN  RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME'
1830                .' WHERE  UPPER(R.RDB$RELATION_NAME)=\''.strtoupper($table_name).'\''
1831                  .' AND  R.RDB$FIELD_NAME=\''.$field_name.'\'';
1832          $result = @ibase_query($this->connection, $sql);
1833          if (empty($result)) {
1834              return $this->ibaseRaiseError();
1835          }
1836          if ($obj = @ibase_fetch_object($result)) {
1837              @ibase_free_result($result);
1838              if (isset($obj->NFLAG)) {
1839                  $flags .= 'not_null ';
1840              }
1841              if (isset($obj->DSOURCE)) {
1842                  $flags .= 'default ';
1843              }
1844              if (isset($obj->CSOURCE)) {
1845                  $flags .= 'computed ';
1846              }
1847              if (isset($obj->FTYPE)  && $obj->FTYPE == 261) {
1848                  $flags .= 'blob ';
1849              }
1850          }
1851  
1852           return trim($flags);
1853      }
1854  }
1855  
1856  ?>


Généré le : Sun Feb 25 14:08:00 2007 par Balluche grâce à PHPXref 0.7