[ Index ]
 

Code source de PHP PEAR 1.4.5

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

title

Body

[fermer]

/MDB/ -> pgsql.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: Paul Cooper <pgc@ucecom.com>                                 |
  43  // +----------------------------------------------------------------------+
  44  //
  45  // $Id: pgsql.php,v 1.62.4.20 2004/03/12 16:19:30 lsmith Exp $
  46  
  47  require_once ('MDB/Common.php');
  48  
  49  /**
  50   * MDB PostGreSQL driver
  51   *
  52   * Notes:
  53   * - Creation of new databases is based on database template1.
  54   *
  55   * - The decimal type fields are emulated with integer fields.
  56   *
  57   * - PostgreSQL stores large objects in files managed by the server.
  58   *   Tables with large object fields only store identifiers pointing to those
  59   *   files. If you delete or update rows of those tables, the actual large
  60   *   object files are not deleted from the server file system. Therefore you may
  61   *   need to reclaim large object field space by deleting those files manually.
  62   *
  63   * @package MDB
  64   * @category Database
  65   * @author  Paul Cooper <pgc@ucecom.com>
  66   */
  67  
  68  class MDB_pgsql extends MDB_Common
  69  {
  70      var $connection = 0;
  71      var $connected_host;
  72      var $connected_port;
  73      var $selected_database = '';
  74      var $opened_persistent = '';
  75  
  76      var $escape_quotes = "\\";
  77      var $decimal_factor = 1.0;
  78  
  79      var $highest_fetched_row = array();
  80      var $columns = array();
  81  
  82      // }}}
  83      // {{{ constructor
  84  
  85      /**
  86      * Constructor
  87      */
  88      function MDB_pgsql()
  89      {
  90          $this->MDB_Common();
  91          $this->phptype = 'pgsql';
  92          $this->dbsyntax = 'pgsql';
  93  
  94          $this->supported['Sequences'] = 1;
  95          $this->supported['Indexes'] = 1;
  96          $this->supported['SummaryFunctions'] = 1;
  97          $this->supported['OrderByText'] = 1;
  98          $this->supported['Transactions'] = 1;
  99          $this->supported['CurrId'] = 1;
 100          $this->supported['SelectRowRanges'] = 1;
 101          $this->supported['LOBs'] = 1;
 102          $this->supported['Replace'] = 1;
 103          $this->supported['SubSelects'] = 1;
 104  
 105          $this->decimal_factor = pow(10.0, $this->decimal_places);
 106      }
 107  
 108      // }}}
 109      // {{{ errorCode()
 110  
 111      /**
 112       * Map native error codes to DB's portable ones.  Requires that
 113       * the DB implementation's constructor fills in the $errorcode_map
 114       * property.
 115       *
 116       * @param $nativecode the native error code, as returned by the backend
 117       * database extension (string or integer)
 118       * @return int a portable MDB error code, or FALSE if this DB
 119       * implementation has no mapping for the given error code.
 120       */
 121      function errorCode($errormsg)
 122      {
 123          static $error_regexps;
 124          if (empty($error_regexps)) {
 125              $error_regexps = array(
 126                  '/([Tt]able does not exist\.|[Rr]elation [\"\'].*[\"\'] does not exist|[Ss]equence does not exist|[Cc]lass ".+" not found)$/' => MDB_ERROR_NOSUCHTABLE,
 127                  '/[Tt]able [\"\'].*[\"\'] does not exist/' => MDB_ERROR_NOSUCHTABLE,
 128                  '/[Rr]elation [\"\'].*[\"\'] already exists|[Cc]annot insert a duplicate key into (a )?unique index.*/' => MDB_ERROR_ALREADY_EXISTS,
 129                  '/divide by zero$/'                     => MDB_ERROR_DIVZERO,
 130                  '/pg_atoi: error in .*: can\'t parse /' => MDB_ERROR_INVALID_NUMBER,
 131                  '/ttribute [\"\'].*[\"\'] not found$|[Rr]elation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => MDB_ERROR_NOSUCHFIELD,
 132                  '/parser: parse error at or near \"/'   => MDB_ERROR_SYNTAX,
 133                  '/syntax error at/'                     => MDB_ERROR_SYNTAX,
 134                  '/violates not-null constraint/'        => MDB_ERROR_CONSTRAINT_NOT_NULL,
 135                  '/violates [\w ]+ constraint/'          => MDB_ERROR_CONSTRAINT,
 136                  '/referential integrity violation/'     => MDB_ERROR_CONSTRAINT,
 137                  '/deadlock detected/'                   => MDB_ERROR_DEADLOCK
 138              );
 139          }
 140          foreach ($error_regexps as $regexp => $code) {
 141              if (preg_match($regexp, $errormsg)) {
 142                  return($code);
 143              }
 144          }
 145          // Fall back to MDB_ERROR if there was no mapping.
 146          return(MDB_ERROR);
 147      }
 148  
 149      // }}}
 150      // {{{ pgsqlRaiseError()
 151  
 152      /**
 153       * This method is used to communicate an error and invoke error
 154       * callbacks etc.  Basically a wrapper for MDB::raiseError
 155       * that checks for native error msgs.
 156       *
 157       * @param integer $errno error code
 158       * @param string  $message userinfo message
 159       * @return object a PEAR error object
 160       * @access public
 161       * @see PEAR_Error
 162       */
 163      function pgsqlRaiseError($errno = NULL, $message = NULL)
 164      {
 165          if ($this->connection) {
 166              $error = @pg_errormessage($this->connection);
 167          } else {
 168              $error = @pg_errormessage();
 169          }
 170          return($this->raiseError($this->errorCode($error), NULL, NULL, $message, $error));
 171      }
 172  
 173      // }}}
 174      // {{{ errorNative()
 175  
 176      /**
 177       * Get the native error code of the last error (if any) that
 178       * occured on the current connection.
 179       *
 180       * @access public
 181       *
 182       * @return int native pgsql error code
 183       */
 184      function errorNative()
 185      {
 186          return @pg_errormessage($this->connection);
 187      }
 188  
 189  
 190      // }}}
 191      // {{{ autoCommit()
 192  
 193      /**
 194       * Define whether database changes done on the database be automatically
 195       * committed. This function may also implicitly start or end a transaction.
 196       *
 197       * @param boolean $auto_commit flag that indicates whether the database
 198       *     changes should be committed right after executing every query
 199       *     statement. If this argument is 0 a transaction implicitly started.
 200       *     Otherwise, if a transaction is in progress it is ended by committing
 201       *     any database changes that were pending.
 202       * @return mixed MDB_OK on success, a MDB error on failure
 203       * @access public
 204       */
 205      function autoCommit($auto_commit)
 206      {
 207          $this->debug('AutoCommit: '.($auto_commit ? 'On' : 'Off'));
 208          if ($this->auto_commit == $auto_commit) {
 209              return(MDB_OK);
 210          }
 211          if ($this->connection) {
 212              if (MDB::isError($result = $this->_doQuery($auto_commit ? 'END' : 'BEGIN')))
 213                  return($result);
 214          }
 215          $this->auto_commit = $auto_commit;
 216          $this->in_transaction = !$auto_commit;
 217          return(MDB_OK);
 218      }
 219  
 220      // }}}
 221      // {{{ commit()
 222  
 223      /**
 224       * Commit the database changes done during a transaction that is in
 225       * progress. This function may only be called when auto-committing is
 226       * disabled, otherwise it will fail. Therefore, a new transaction is
 227       * implicitly started after committing the pending changes.
 228       *
 229       * @return mixed MDB_OK on success, a MDB error on failure
 230       * @access public
 231       */
 232      function commit()
 233      {
 234           $this->debug('Commit Transaction');
 235          if ($this->auto_commit) {
 236              return($this->raiseError(MDB_ERROR, NULL, NULL, 'Commit: transaction changes are being auto commited'));
 237          }
 238          return($this->_doQuery('COMMIT') && $this->_doQuery('BEGIN'));
 239      }
 240  
 241      // }}}
 242      // {{{ rollback()
 243  
 244      /**
 245       * Cancel any database changes done during a transaction that is in
 246       * progress. This function may only be called when auto-committing is
 247       * disabled, otherwise it will fail. Therefore, a new transaction is
 248       * implicitly started after canceling the pending changes.
 249       *
 250       * @return mixed MDB_OK on success, a MDB error on failure
 251       * @access public
 252       */
 253      function rollback()
 254      {
 255           $this->debug('Rollback Transaction');
 256          if ($this->auto_commit) {
 257              return($this->raiseError(MDB_ERROR, NULL, NULL, 'Rollback: transactions can not be rolled back when changes are auto commited'));
 258          }
 259          return($this->_doQuery('ROLLBACK') && $this->_doQuery('BEGIN'));
 260      }
 261  
 262      // }}}
 263      // {{{ _doConnect()
 264  
 265      /**
 266       * Does the grunt work of connecting to the database
 267       *
 268       * @return mixed connection resource on success, MDB_Error on failure
 269       * @access private
 270       **/
 271      function _doConnect($database_name, $persistent)
 272      {
 273          $function = ($persistent ? 'pg_pconnect' : 'pg_connect');
 274          if (!function_exists($function)) {
 275              return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, 'doConnect: PostgreSQL support is not available in this PHP configuration'));
 276          }
 277          $port = (isset($this->port) ? $this->port : '');
 278          if ($database_name == '') {
 279              $database_name = 'template1';
 280          }
 281          $connect_string = 'dbname='.$database_name;
 282          if ($this->host != '') {
 283              $connect_string .= ' host='.$this->host;
 284          }
 285          if ($port != '') {
 286              $connect_string .= ' port='.strval($port);
 287          }
 288          if ($this->user != '') {
 289              $connect_string .= ' user='.$this->user;
 290          }
 291          if ($this->password != '') {
 292              $connect_string .= ' password='.$this->password;
 293          }
 294          putenv('PGDATESTYLE=ISO');
 295          if (($connection = @$function($connect_string)) > 0) {
 296              return($connection);
 297          }
 298          if (isset($php_errormsg)) {
 299              $error_msg = $php_errormsg;
 300          } else {
 301              $error_msg = 'Could not connect to PostgreSQL server';
 302          }
 303          return($this->raiseError(MDB_ERROR_CONNECT_FAILED, NULL, NULL, 'doConnect: '.$error_msg));
 304      }
 305  
 306      // }}}
 307      // {{{ connect()
 308  
 309      /**
 310       * Connect to the database
 311       *
 312       * @return TRUE on success, MDB_Error on failure
 313       * @access public
 314       **/
 315      function connect()
 316      {
 317          $port = (isset($this->options['port']) ? $this->options['port'] : '');
 318          if($this->connection != 0) {
 319              if (!strcmp($this->connected_host, $this->host)
 320                  && !strcmp($this->connected_port, $port)
 321                  && !strcmp($this->selected_database, $this->database_name)
 322                  && ($this->opened_persistent == $this->options['persistent']))
 323              {
 324                  return(MDB_OK);
 325              }
 326              @pg_close($this->connection);
 327              $this->affected_rows = -1;
 328              $this->connection = 0;
 329          }
 330  
 331          if(!PEAR::loadExtension($this->phptype)) {
 332              return(PEAR::raiseError(NULL, MDB_ERROR_NOT_FOUND,
 333                  NULL, NULL, 'extension '.$this->phptype.' is not compiled into PHP',
 334                  'MDB_Error', TRUE));
 335          }
 336  
 337          if(function_exists('pg_cmdTuples')) {
 338              $connection = $this->_doConnect('template1', 0);
 339              if (!MDB::isError($connection)) {
 340                  if (($result = @pg_exec($connection, 'BEGIN'))) {
 341                      $error_reporting = error_reporting(63);
 342                      @pg_cmdtuples($result);
 343                      if (!isset($php_errormsg) || strcmp($php_errormsg, 'This compilation does not support pg_cmdtuples()')) {
 344                          $this->supported['AffectedRows'] = 1;
 345                      }
 346                      error_reporting($error_reporting);
 347                  } else {
 348                      $err = $this->raiseError(MDB_ERROR, NULL, NULL, 'Setup: '.@pg_errormessage($connection));
 349                  }
 350                  @pg_close($connection);
 351              } else {
 352                  $err = $this->raiseError(MDB_ERROR, NULL, NULL, 'Setup: could not execute BEGIN');
 353              }
 354              if (isset($err) && MDB::isError($err)) {
 355                  return($err);
 356              }
 357          }
 358          $connection = $this->_doConnect($this->database_name, $this->options['persistent']);
 359          if (MDB::isError($connection)) {
 360              return($connection);
 361          }
 362          $this->connection = $connection;
 363  
 364          if (!$this->auto_commit && MDB::isError($trans_result = $this->_doQuery('BEGIN'))) {
 365              pg_Close($this->connection);
 366              $this->connection = 0;
 367              $this->affected_rows = -1;
 368              return($trans_result);
 369          }
 370          $this->connected_host = $this->host;
 371          $this->connected_port = $port;
 372          $this->selected_database = $this->database_name;
 373          $this->opened_persistent = $this->options['persistent'];
 374          return(MDB_OK);
 375      }
 376  
 377      // }}}
 378      // {{{ _close()
 379      /**
 380       * Close the database connection
 381       *
 382       * @return boolean
 383       * @access private
 384       **/
 385      function _close()
 386      {
 387          if ($this->connection != 0) {
 388              if (!$this->auto_commit) {
 389                  $this->_doQuery('END');
 390              }
 391              @pg_close($this->connection);
 392              $this->connection = 0;
 393              $this->affected_rows = -1;
 394  
 395              unset($GLOBALS['_MDB_databases'][$this->database]);
 396              return(MDB_OK);
 397          }
 398          return(MDB_ERROR);
 399      }
 400  
 401      // }}}
 402      // {{{ _doQuery()
 403  
 404      /**
 405       * Execute a query
 406       * @param string $query the SQL query
 407       * @return mixed result identifier if query executed, else MDB_error
 408       * @access private
 409       **/
 410      function _doQuery($query)
 411      {
 412          if (($result = @pg_Exec($this->connection, $query))) {
 413              $this->affected_rows = (isset($this->supported['AffectedRows']) ? @pg_cmdtuples($result) : -1);
 414          } else {
 415              $error = @pg_errormessage($this->connection);
 416              return($this->pgsqlRaiseError());
 417          }
 418          return($result);
 419      }
 420  
 421      // }}}
 422      // {{{ _standaloneQuery()
 423  
 424      /**
 425       * execute a query
 426       *
 427       * @param string $query
 428       * @return
 429       * @access private
 430       */
 431      function _standaloneQuery($query)
 432      {
 433          if (($connection = $this->_doConnect('template1', 0)) == 0) {
 434              return($this->raiseError(MDB_ERROR_CONNECT_FAILED, NULL, NULL, '_standaloneQuery: Cannot connect to template1'));
 435          }
 436          if (!($result = @pg_Exec($connection, $query))) {
 437              $this->raiseError(MDB_ERROR, NULL, NULL, '_standaloneQuery: ' . @pg_errormessage($connection));
 438          }
 439          pg_Close($connection);
 440          return($result);
 441      }
 442  
 443      // }}}
 444      // {{{ query()
 445  
 446      /**
 447       * Send a query to the database and return any results
 448       *
 449       * @param string $query the SQL query
 450       * @param array $types array that contains the types of the columns in
 451       *                         the result set
 452       * @return mixed result identifier if query executed, else MDB_error
 453       * @access public
 454       **/
 455      function query($query, $types = NULL)
 456      {
 457          $this->debug("Query: $query");
 458          $ismanip = MDB::isManip($query);
 459          $this->last_query = $query;
 460          $first = $this->first_selected_row;
 461          $limit = $this->selected_row_limit;
 462          $this->first_selected_row = $this->selected_row_limit = 0;
 463          $connected = $this->connect();
 464          if (MDB::isError($connected)) {
 465              return($connected);
 466          }
 467  
 468          if (!$ismanip && $limit > 0) {
 469               if ($this->auto_commit && MDB::isError($this->_doQuery('BEGIN'))) {
 470                   return($this->raiseError(MDB_ERROR));
 471               }
 472               $result = $this->_doQuery('DECLARE select_cursor SCROLL CURSOR FOR '.$query);
 473               if (!MDB::isError($result)) {
 474                   if ($first > 0 && MDB::isError($result = $this->_doQuery("MOVE FORWARD $first FROM select_cursor"))) {
 475                       $this->freeResult($result);
 476                       return($result);
 477                   }
 478                   if (MDB::isError($result = $this->_doQuery("FETCH FORWARD $limit FROM select_cursor"))) {
 479                       $this->freeResult($result);
 480                       return($result);
 481                   }
 482               } else {
 483                   return($result);
 484               }
 485               if ($this->auto_commit && MDB::isError($result2 = $this->_doQuery('END'))) {
 486                   $this->freeResult($result);
 487                   return($result2);
 488               }
 489           } else {
 490              $result = $this->_doQuery($query);
 491              if (MDB::isError($result)) {
 492                  return($result);
 493              }
 494          }
 495          if ($ismanip) {
 496              $this->affected_rows = @pg_cmdtuples($result);
 497              return(MDB_OK);
 498          } elseif ((preg_match('/^\s*\(?\s*SELECT\s+/si', $query)
 499                  && !preg_match('/^\s*\(?\s*SELECT\s+INTO\s/si', $query)
 500              ) || preg_match('/^\s*EXPLAIN/si',$query )
 501          ) {
 502              /* PostgreSQL commands:
 503                 ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY,
 504                 CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH,
 505                 GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET,
 506                 REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW,
 507                 UNLISTEN, UPDATE, VACUUM
 508              */
 509              $result_value = intval($result);
 510              $this->highest_fetched_row[$result_value] = -1;
 511              if ($types != NULL) {
 512                  if (!is_array($types)) {
 513                      $types = array($types);
 514                  }
 515                  if (MDB::isError($err = $this->setResultTypes($result, $types))) {
 516                      $this->freeResult($result);
 517                      return($err);
 518                  }
 519              }
 520              return($result);
 521          } else {
 522              $this->affected_rows = 0;
 523              return(MDB_OK);
 524          }
 525          return($this->raiseError(MDB_ERROR));
 526      }
 527  
 528      // }}}
 529      // {{{ getColumnNames()
 530  
 531      /**
 532       * Retrieve the names of columns returned by the DBMS in a query result.
 533       *
 534       * @param resource $result  result identifier
 535       * @return mixed associative array variable
 536       *      that holds the names of columns. The indexes of the array are
 537       *      the column names mapped to lower case and the values are the
 538       *      respective numbers of the columns starting from 0. Some DBMS may
 539       *      not return any columns when the result set does not contain any
 540       *      rows.
 541       *     a MDB error on failure
 542       * @access public
 543       */
 544      function getColumnNames($result)
 545      {
 546          $result_value = intval($result);
 547          if (!isset($this->highest_fetched_row[$result_value])) {
 548              return($this->raiseError(MDB_ERROR, NULL, NULL, 'Get Column Names: specified an nonexistant result set'));
 549          }
 550          if (!isset($this->columns[$result_value])) {
 551              $this->columns[$result_value] = array();
 552              $columns = @pg_numfields($result);
 553              for($column = 0; $column < $columns; $column++) {
 554                  $field_name = @pg_fieldname($result, $column);
 555                  if ($this->options['optimize'] == 'portability') {
 556                      $field_name = strtolower($field_name);
 557                  }
 558                  $this->columns[$result_value][$field_name] = $column;
 559              }
 560          }
 561          return($this->columns[$result_value]);
 562      }
 563  
 564      // }}}
 565      // {{{ numCols()
 566  
 567      /**
 568       * Count the number of columns returned by the DBMS in a query result.
 569       *
 570       * @param resource $result result identifier
 571       * @return mixed integer value with the number of columns, a MDB error
 572       *      on failure
 573       * @access public
 574       */
 575      function numCols($result)
 576      {
 577          $result_value = intval($result);
 578          if (!isset($this->highest_fetched_row[$result_value])) {
 579              return($this->raiseError(MDB_ERROR, NULL, NULL, 'numCols: specified an nonexistant result set'));
 580          }
 581          return(pg_numfields($result));
 582      }
 583  
 584      // }}}
 585      // {{{ endOfResult()
 586  
 587      /**
 588      * check if the end of the result set has been reached
 589      *
 590      * @param resource    $result result identifier
 591      * @return mixed TRUE or FALSE on sucess, a MDB error on failure
 592      * @access public
 593      */
 594      function endOfResult($result)
 595      {
 596          $result_value = intval($result);
 597          if (!isset($this->highest_fetched_row[$result_value])) {
 598              return($this->raiseError(MDB_ERROR, NULL, NULL, 'End of result attempted to check the end of an unknown result'));
 599          }
 600          return($this->highest_fetched_row[$result_value] >= $this->numRows($result) - 1);
 601      }
 602  
 603      // }}}
 604      // {{{ fetch()
 605  
 606      /**
 607       * fetch value from a result set
 608       *
 609       * @param resource $result result identifier
 610       * @param int $row number of the row where the data can be found
 611       * @param int $field field number where the data can be found
 612       * @return mixed string on success, a MDB error on failure
 613       * @access public
 614       */
 615      function fetch($result, $row, $field)
 616      {
 617          $result_value = intval($result);
 618          $this->highest_fetched_row[$result_value] = max($this->highest_fetched_row[$result_value], $row);
 619          $res = @pg_result($result, $row, $field);
 620          if ($res === FALSE && $res != NULL) {
 621              return($this->pgsqlRaiseError());
 622          }
 623          return($res);
 624      }
 625  
 626      // }}}
 627      // {{{ _retrieveLob()
 628  
 629      /**
 630       * fetch a float value from a result set
 631       *
 632       * @param int $lob handle to a lob created by the createLob() function
 633       * @return mixed MDB_OK on success, a MDB error on failure
 634       * @access private
 635       */
 636      function _retrieveLob($lob)
 637      {
 638          if (!isset($this->lobs[$lob])) {
 639              return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL,
 640                  'Retrieve LOB: did not specified a valid lob'));
 641          }
 642          if (!isset($this->lobs[$lob]['Value'])) {
 643              if ($this->auto_commit) {
 644                  if (!@pg_exec($this->connection, 'BEGIN')) {
 645                      return($this->raiseError(MDB_ERROR,  NULL, NULL,
 646                          'Retrieve LOB: ' . @pg_errormessage($this->connection)));
 647                  }
 648                  $this->lobs[$lob]['InTransaction'] = 1;
 649              }
 650              $this->lobs[$lob]['Value'] = $this->fetch($this->lobs[$lob]['Result'], $this->lobs[$lob]['Row'], $this->lobs[$lob]['Field']);
 651              if (!($this->lobs[$lob]['Handle'] = @pg_loopen($this->connection, $this->lobs[$lob]['Value'], 'r'))) {
 652                  if (isset($this->lobs[$lob]['InTransaction'])) {
 653                      @pg_exec($this->connection, 'END');
 654                      unset($this->lobs[$lob]['InTransaction']);
 655                  }
 656                  unset($this->lobs[$lob]['Value']);
 657                  return($this->raiseError(MDB_ERROR, NULL, NULL,
 658                      'Retrieve LOB: ' . @pg_errormessage($this->connection)));
 659              }
 660          }
 661          return(MDB_OK);
 662      }
 663  
 664      // }}}
 665      // {{{ endOfResultLob()
 666  
 667      /**
 668       * Determine whether it was reached the end of the large object and
 669       * therefore there is no more data to be read for the its input stream.
 670       *
 671       * @param int    $lob handle to a lob created by the createLob() function
 672       * @return mixed TRUE or FALSE on success, a MDB error on failure
 673       * @access public
 674       */
 675      function endOfResultLob($lob)
 676      {
 677          $lobresult = $this->_retrieveLob($lob);
 678          if (MDB::isError($lobresult)) {
 679              return($lobresult);
 680          }
 681          return(isset($this->lobs[$lob]['EndOfLOB']));
 682      }
 683  
 684      // }}}
 685      // {{{ _readResultLob()
 686  
 687      /**
 688       * Read data from large object input stream.
 689       *
 690       * @param int $lob handle to a lob created by the createLob() function
 691       * @param blob $data reference to a variable that will hold data to be
 692       *      read from the large object input stream
 693       * @param int $length integer value that indicates the largest ammount of
 694       *      data to be read from the large object input stream.
 695       * @return mixed length on success, a MDB error on failure
 696       * @access private
 697       */
 698      function _readResultLob($lob, &$data, $length)
 699      {
 700          $lobresult = $this->_retrieveLob($lob);
 701          if (MDB::isError($lobresult)) {
 702              return($lobresult);
 703          }
 704          $data = @pg_loread($this->lobs[$lob]['Handle'], $length);
 705          if (gettype($data) != 'string') {
 706              $this->raiseError(MDB_ERROR, NULL, NULL,
 707                  'Read Result LOB: ' . @pg_errormessage($this->connection));
 708          }
 709          if (($length = strlen($data)) == 0) {
 710              $this->lobs[$lob]['EndOfLOB'] = 1;
 711          }
 712          return($length);
 713      }
 714  
 715      // }}}
 716      // {{{ _destroyResultLob()
 717  
 718      /**
 719       * Free any resources allocated during the lifetime of the large object
 720       * handler object.
 721       *
 722       * @param int $lob handle to a lob created by the createLob() function
 723       * @access private
 724       */
 725      function _destroyResultLob($lob)
 726      {
 727          if (isset($this->lobs[$lob])) {
 728              if (isset($this->lobs[$lob]['Value'])) {
 729                  @pg_loclose($this->lobs[$lob]['Handle']);
 730                  if (isset($this->lobs[$lob]['InTransaction'])) {
 731                      @pg_exec($this->connection, 'END');
 732                  }
 733              }
 734              $this->lobs[$lob] = '';
 735          }
 736      }
 737  
 738      // }}}
 739      // {{{ fetchClob()
 740  
 741      /**
 742       * fetch a clob value from a result set
 743       *
 744       * @param resource $result result identifier
 745       * @param int $row number of the row where the data can be found
 746       * @param int $field field number where the data can be found
 747       * @return mixed content of the specified data cell, a MDB error on failure,
 748       *       a MDB error on failure
 749       * @access public
 750       */
 751      function fetchClob($result, $row, $field)
 752      {
 753          return($this->fetchLob($result, $row, $field));
 754      }
 755  
 756      // }}}
 757      // {{{ fetchBlob()
 758  
 759      /**
 760       * fetch a blob value from a result set
 761       *
 762       * @param resource $result result identifier
 763       * @param int $row number of the row where the data can be found
 764       * @param int $field field number where the data can be found
 765       * @return mixed content of the specified data cell, a MDB error on failure
 766       * @access public
 767       */
 768      function fetchBlob($result, $row, $field)
 769      {
 770          return($this->fetchLob($result, $row, $field));
 771      }
 772  
 773      // }}}
 774      // {{{ convertResult()
 775  
 776      /**
 777       * convert a value to a RDBMS indepdenant MDB type
 778       *
 779       * @param mixed $value value to be converted
 780       * @param int $type constant that specifies which type to convert to
 781       * @return mixed converted value or a MDB error on failure
 782       * @access public
 783       */
 784      function convertResult($value, $type)
 785      {
 786          switch ($type) {
 787              case MDB_TYPE_DECIMAL:
 788                  return(sprintf('%.'.$this->decimal_places.'f',doubleval($value)/$this->decimal_factor));
 789              case MDB_TYPE_TIMESTAMP:
 790                  return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS'));
 791              default:
 792                  return($this->_baseConvertResult($value, $type));
 793          }
 794      }
 795  
 796      // }}}
 797      // {{{ resultIsNull()
 798  
 799      /**
 800       * Determine whether the value of a query result located in given row and
 801       *   field is a NULL.
 802       *
 803       * @param resource    $result result identifier
 804       * @param int    $row    number of the row where the data can be found
 805       * @param int    $field    field number where the data can be found
 806       * @return mixed TRUE or FALSE on success, a MDB error on failure
 807       * @access public
 808       */
 809      function resultIsNull($result, $row, $field)
 810      {
 811          $result_value = intval($result);
 812          $this->highest_fetched_row[$result_value] = max($this->highest_fetched_row[$result_value], $row);
 813          return(@pg_fieldisnull($result, $row, $field));
 814      }
 815  
 816      // }}}
 817      // {{{ numRows()
 818  
 819      /**
 820       * returns the number of rows in a result object
 821       *
 822       * @param ressource $result a valid result ressouce pointer
 823       * @return mixed MDB_Error or the number of rows
 824       * @access public
 825       */
 826      function numRows($result)
 827      {
 828          return(@pg_numrows($result));
 829      }
 830  
 831      // }}}
 832      // {{{ freeResult()
 833  
 834      /**
 835       * Free the internal resources associated with $result.
 836       *
 837       * @param $result result identifier
 838       * @return boolean TRUE on success, FALSE if $result is invalid
 839       * @access public
 840       */
 841      function freeResult($result)
 842      {
 843          $result_value = intval($result);
 844          if(isset($this->highest_fetched_row[$result_value])) {
 845              unset($this->highest_fetched_row[$result_value]);
 846          }
 847          if(isset($this->columns[$result_value])) {
 848              unset($this->columns[$result_value]);
 849          }
 850          if(isset($this->result_types[$result_value])) {
 851              unset($this->result_types[$result_value]);
 852          }
 853          return(@pg_freeresult($result));
 854      }
 855  
 856      // }}}
 857      // {{{ getTextDeclaration()
 858  
 859      /**
 860       * Obtain DBMS specific SQL code portion needed to declare an text type
 861       * field to be used in statements like CREATE TABLE.
 862       *
 863       * @param string $name   name the field to be declared.
 864       * @param string $field  associative array with the name of the properties
 865       *      of the field being declared as array indexes. Currently, the types
 866       *      of supported field properties are as follows:
 867       *
 868       *      length
 869       *          Integer value that determines the maximum length of the text
 870       *          field. If this argument is missing the field should be
 871       *          declared to have the longest length allowed by the DBMS.
 872       *
 873       *      default
 874       *          Text value to be used as default for this field.
 875       *
 876       *      notnull
 877       *          Boolean flag that indicates whether this field is constrained
 878       *          to not be set to NULL.
 879       * @return string  DBMS specific SQL code portion that should be used to
 880       *      declare the specified field.
 881       * @access public
 882       */
 883      function getTextDeclaration($name, $field)
 884      {
 885          return((isset($field['length']) ? "$name VARCHAR (" . $field['length'] . ')' : "$name TEXT") . (isset($field['default']) ? " DEFAULT '" . $field['default'] . "'" : '') . (isset($field['notnull']) ? ' NOT NULL' : ''));
 886      }
 887  
 888      // }}}
 889      // {{{ getClobDeclaration()
 890  
 891      /**
 892       * Obtain DBMS specific SQL code portion needed to declare an character
 893       * large object type field to be used in statements like CREATE TABLE.
 894       *
 895       * @param string $name   name the field to be declared.
 896       * @param string $field  associative array with the name of the properties
 897       *      of the field being declared as array indexes. Currently, the types
 898       *      of supported field properties are as follows:
 899       *
 900       *      length
 901       *          Integer value that determines the maximum length of the large
 902       *          object field. If this argument is missing the field should be
 903       *          declared to have the longest length allowed by the DBMS.
 904       *
 905       *      notnull
 906       *          Boolean flag that indicates whether this field is constrained
 907       *          to not be set to NULL.
 908       * @return string  DBMS specific SQL code portion that should be used to
 909       *      declare the specified field.
 910       * @access public
 911       */
 912      function getClobDeclaration($name, $field)
 913      {
 914          return("$name OID".(isset($field['notnull']) ? ' NOT NULL' : ''));
 915      }
 916  
 917      // }}}
 918      // {{{ getBlobDeclaration()
 919  
 920      /**
 921       * Obtain DBMS specific SQL code portion needed to declare an binary large
 922       * object type field to be used in statements like CREATE TABLE.
 923       *
 924       * @param string $name   name the field to be declared.
 925       * @param string $field  associative array with the name of the properties
 926       *      of the field being declared as array indexes. Currently, the types
 927       *      of supported field properties are as follows:
 928       *
 929       *      length
 930       *          Integer value that determines the maximum length of the large
 931       *          object field. If this argument is missing the field should be
 932       *          declared to have the longest length allowed by the DBMS.
 933       *
 934       *      notnull
 935       *          Boolean flag that indicates whether this field is constrained
 936       *          to not be set to NULL.
 937       * @return string  DBMS specific SQL code portion that should be used to
 938       *      declare the specified field.
 939       * @access public
 940       */
 941      function getBlobDeclaration($name, $field)
 942      {
 943          return("$name OID".(isset($field['notnull']) ? ' NOT NULL' : ''));
 944      }
 945  
 946      // }}}
 947      // {{{ getDateDeclaration()
 948  
 949      /**
 950       * Obtain DBMS specific SQL code portion needed to declare a date type
 951       * field to be used in statements like CREATE TABLE.
 952       *
 953       * @param string $name   name the field to be declared.
 954       * @param string $field  associative array with the name of the properties
 955       *      of the field being declared as array indexes. Currently, the types
 956       *      of supported field properties are as follows:
 957       *
 958       *      default
 959       *          Date value to be used as default for this field.
 960       *
 961       *      notnull
 962       *          Boolean flag that indicates whether this field is constrained
 963       *          to not be set to NULL.
 964       * @return string  DBMS specific SQL code portion that should be used to
 965       *      declare the specified field.
 966       * @access public
 967       */
 968      function getDateDeclaration($name, $field)
 969      {
 970          return($name.' DATE'.(isset($field['default']) ? ' DEFAULT \''.$field['default'] . "'" : '').(isset($field['notnull']) ? ' NOT NULL' : ''));
 971      }
 972  
 973      // }}}
 974      // {{{ getTimeDeclaration()
 975  
 976      /**
 977       * Obtain DBMS specific SQL code portion needed to declare a time
 978       * field to be used in statements like CREATE TABLE.
 979       *
 980       * @param string $name   name the field to be declared.
 981       * @param string $field  associative array with the name of the properties
 982       *      of the field being declared as array indexes. Currently, the types
 983       *      of supported field properties are as follows:
 984       *
 985       *      default
 986       *          Time value to be used as default for this field.
 987       *
 988       *      notnull
 989       *          Boolean flag that indicates whether this field is constrained
 990       *          to not be set to NULL.
 991       * @return string  DBMS specific SQL code portion that should be used to
 992       *      declare the specified field.
 993       * @access public
 994       */
 995      function getTimeDeclaration($name, $field)
 996      {
 997          return($name.' TIME'.(isset($field['default']) ? ' DEFAULT \''.$field['default'].'\'' : '').(isset($field['notnull']) ? ' NOT NULL' : ''));
 998      }
 999  
1000      // }}}
1001      // {{{ getFloatDeclaration()
1002  
1003      /**
1004       * Obtain DBMS specific SQL code portion needed to declare a float type
1005       * field to be used in statements like CREATE TABLE.
1006       *
1007       * @param string $name   name the field to be declared.
1008       * @param string $field  associative array with the name of the properties
1009       *      of the field being declared as array indexes. Currently, the types
1010       *      of supported field properties are as follows:
1011       *
1012       *      default
1013       *          Float value to be used as default for this field.
1014       *
1015       *      notnull
1016       *          Boolean flag that indicates whether this field is constrained
1017       *          to not be set to NULL.
1018       * @return string  DBMS specific SQL code portion that should be used to
1019       *      declare the specified field.
1020       * @access public
1021       */
1022      function getFloatDeclaration($name, $field)
1023      {
1024          return("$name FLOAT8 ".(isset($field['default']) ? ' DEFAULT '.$this->getFloatValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : ''));
1025      }
1026  
1027      // }}}
1028      // {{{ getDecimalDeclaration()
1029  
1030      /**
1031       * Obtain DBMS specific SQL code portion needed to declare a decimal type
1032       * field to be used in statements like CREATE TABLE.
1033       *
1034       * @param string $name   name the field to be declared.
1035       * @param string $field  associative array with the name of the properties
1036       *      of the field being declared as array indexes. Currently, the types
1037       *      of supported field properties are as follows:
1038       *
1039       *      default
1040       *          Decimal value to be used as default for this field.
1041       *
1042       *      notnull
1043       *          Boolean flag that indicates whether this field is constrained
1044       *          to not be set to NULL.
1045       * @return string  DBMS specific SQL code portion that should be used to
1046       *      declare the specified field.
1047       * @access public
1048       */
1049      function getDecimalDeclaration($name, $field)
1050      {
1051          return("$name INT8 ".(isset($field['default']) ? ' DEFAULT '.$this->getDecimalValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : ''));
1052      }
1053  
1054      // }}}
1055      // {{{ _getLobValue()
1056  
1057      /**
1058       * Convert a text value into a DBMS specific format that is suitable to
1059       * compose query statements.
1060       *
1061       * @param resource  $prepared_query query handle from prepare()
1062       * @param           $parameter
1063       * @param           $lob
1064       * @return string text string that represents the given argument value in
1065       *      a DBMS specific format.
1066       * @access private
1067       */
1068      function _getLobValue($prepared_query, $parameter, $lob)
1069      {
1070          $connect = $this->connect();
1071          if (MDB::isError($connect)) {
1072              return($connect);
1073          }
1074          if ($this->auto_commit && !@pg_exec($this->connection, 'BEGIN')) {
1075              return($this->raiseError(MDB_ERROR, NULL, NULL,
1076                  '_getLobValue: error starting transaction'));
1077          }
1078          if (($lo = @pg_locreate($this->connection))) {
1079              if (($handle = @pg_loopen($this->connection, $lo, 'w'))) {
1080                  while (!$this->endOfLob($lob)) {
1081                      $result = $this->readLob($lob, $data, $this->options['lob_buffer_length']);
1082                      if (MDB::isError($result)) {
1083                          break;
1084                      }
1085                      if (!@pg_lowrite($handle, $data)) {
1086                          $result = $this->raiseError(MDB_ERROR, NULL, NULL,
1087                              'Get LOB field value: ' . @pg_errormessage($this->connection));
1088                          break;
1089                      }
1090                  }
1091                  @pg_loclose($handle);
1092                  if (!MDB::isError($result)) {
1093                      $value = strval($lo);
1094                  }
1095              } else {
1096                  $result = $this->raiseError(MDB_ERROR, NULL, NULL,
1097                      'Get LOB field value: ' . @pg_errormessage($this->connection));
1098              }
1099              if (MDB::isError($result)) {
1100                  $result = @pg_lounlink($this->connection, $lo);
1101              }
1102          } else {
1103              $result = $this->raiseError(MDB_ERROR, NULL, NULL, 'Get LOB field value: ' . pg_ErrorMessage($this->connection));
1104          }
1105          if ($this->auto_commit) {
1106              @pg_exec($this->connection, 'END');
1107          }
1108          if (MDB::isError($result)) {
1109              return($result);
1110          }
1111          return($value);
1112      }
1113  
1114      // }}}
1115      // {{{ getClobValue()
1116  
1117      /**
1118       * Convert a text value into a DBMS specific format that is suitable to
1119       * compose query statements.
1120       *
1121       * @param resource  $prepared_query query handle from prepare()
1122       * @param           $parameter
1123       * @param           $clob
1124       * @return string text string that represents the given argument value in
1125       *      a DBMS specific format.
1126       * @access public
1127       */
1128      function getClobValue($prepared_query, $parameter, $clob)
1129      {
1130          return($this->_getLobValue($prepared_query, $parameter, $clob));
1131      }
1132  
1133      // }}}
1134      // {{{ getBlobValue()
1135  
1136      /**
1137       * Convert a text value into a DBMS specific format that is suitable to
1138       * compose query statements.
1139       *
1140       * @param resource  $prepared_query query handle from prepare()
1141       * @param           $parameter
1142       * @param           $blob
1143       * @return string text string that represents the given argument value in
1144       *      a DBMS specific format.
1145       * @access public
1146       */
1147      function getBlobValue($prepared_query, $parameter, $blob)
1148      {
1149          return($this->_getLobValue($prepared_query, $parameter, $blob));
1150      }
1151  
1152      // }}}
1153      // {{{ getFloatValue()
1154  
1155      /**
1156       * Convert a text value into a DBMS specific format that is suitable to
1157       * compose query statements.
1158       *
1159       * @param string $value text string value that is intended to be converted.
1160       * @return string text string that represents the given argument value in
1161       *      a DBMS specific format.
1162       * @access public
1163       */
1164      function getFloatValue($value)
1165      {
1166          return(($value === NULL) ? 'NULL' : $value);
1167      }
1168  
1169      // }}}
1170      // {{{ getDecimalValue()
1171  
1172      /**
1173       * Convert a text value into a DBMS specific format that is suitable to
1174       * compose query statements.
1175       *
1176       * @param string $value text string value that is intended to be converted.
1177       * @return string text string that represents the given argument value in
1178       *      a DBMS specific format.
1179       * @access public
1180       */
1181      function getDecimalValue($value)
1182      {
1183          return(($value === NULL) ? 'NULL' : strval(round($value*$this->decimal_factor)));
1184      }
1185  
1186      // }}}
1187      // {{{ nextId()
1188  
1189      /**
1190       * returns the next free id of a sequence
1191       *
1192       * @param string  $seq_name name of the sequence
1193       * @param boolean $ondemand when TRUE the seqence is
1194       *                          automatic created, if it
1195       *                          not exists
1196       * @return mixed MDB_Error or id
1197       * @access public
1198       */
1199      function nextId($seq_name, $ondemand = TRUE)
1200      {
1201          $seqname = $this->getSequenceName($seq_name);
1202          $repeat = 0;
1203          do {
1204              $this->pushErrorHandling(PEAR_ERROR_RETURN);
1205              $result = $this->query("SELECT NEXTVAL('$seqname')");
1206              $this->popErrorHandling();
1207              if ($ondemand && MDB::isError($result) && $result->getCode() == MDB_ERROR_NOSUCHTABLE) {
1208                  $repeat = 1;
1209                  $result = $this->createSequence($seq_name);
1210                  if (MDB::isError($result)) {
1211                      return($this->raiseError($result));
1212                  }
1213              } else {
1214                  $repeat = 0;
1215              }
1216          } while ($repeat);
1217          if (MDB::isError($result)) {
1218              return($this->raiseError($result));
1219          }
1220          return($this->fetchOne($result));
1221      }
1222  
1223      // }}}
1224      // {{{ currId()
1225  
1226      /**
1227       * returns the current id of a sequence
1228       *
1229       * @param string  $seq_name name of the sequence
1230       * @return mixed MDB_Error or id
1231       * @access public
1232       */
1233      function currId($seq_name)
1234      {
1235          $seqname = $this->getSequenceName($seq_name);
1236          if (MDB::isError($result = $this->queryOne("SELECT last_value FROM $seqname"))) {
1237              return($this->raiseError(MDB_ERROR, NULL, NULL, 'currId: Unable to select from ' . $seqname) );
1238          }
1239          if (!is_numeric($result)) {
1240              return($this->raiseError(MDB_ERROR, NULL, NULL, 'currId: could not find value in sequence table'));
1241          }
1242          return($result);
1243      }
1244  
1245      // }}}
1246      // {{{ fetchInto()
1247  
1248      /**
1249       * Fetch a row and return data in an array.
1250       *
1251       * @param resource $result result identifier
1252       * @param int $fetchmode ignored
1253       * @param int $rownum the row number to fetch
1254       * @return mixed data array or NULL on success, a MDB error on failure
1255       * @access public
1256       */
1257      function fetchInto($result, $fetchmode = MDB_FETCHMODE_DEFAULT, $rownum = NULL)
1258      {
1259          $result_value = intval($result);
1260          if ($fetchmode == MDB_FETCHMODE_DEFAULT) {
1261              $fetchmode = $this->fetchmode;
1262          }
1263  
1264          if (is_null($rownum)) {
1265              ++$this->highest_fetched_row[$result_value];
1266          } else {
1267              $this->highest_fetched_row[$result_value] =
1268                  max($this->highest_fetched_row[$result_value], $rownum);
1269          }
1270  
1271          if ($fetchmode & MDB_FETCHMODE_ASSOC) {
1272              $row = @pg_fetch_array($result, $rownum, PGSQL_ASSOC);
1273              if (is_array($row) && $this->options['optimize'] == 'portability') {
1274                  $row = array_change_key_case($row, CASE_LOWER);
1275              }
1276          } else {
1277              $row = @pg_fetch_row($result, $rownum);
1278          }
1279  
1280          if (!$row) {
1281              if ($this->options['autofree']) {
1282                  $this->freeResult($result);
1283              }
1284              return(NULL);
1285          }
1286          if (isset($this->result_types[$result_value])) {
1287              $row = $this->convertResultRow($result, $row);
1288          }
1289          return($row);
1290      }
1291  
1292      // }}}
1293      // {{{ nextResult()
1294  
1295      /**
1296       * Move the internal pgsql result pointer to the next available result
1297       *
1298       * @param a valid fbsql result resource
1299       * @return true if a result is available otherwise return false
1300       * @access public
1301       */
1302      function nextResult($result)
1303      {
1304          return(FALSE);
1305      }
1306  
1307      // }}}
1308      // {{{ tableInfo()
1309  
1310      /**
1311       * returns meta data about the result set
1312       *
1313       * @param  mixed $resource PostgreSQL result identifier or table name
1314       * @param mixed $mode depends on implementation
1315       * @return array an nested array, or a MDB error
1316       * @access public
1317       */
1318      function tableInfo($result, $mode = NULL)
1319      {
1320          $count = 0;
1321          $id = 0;
1322          $res = array();
1323  
1324          /**
1325           * depending on $mode, metadata returns the following values:
1326           *
1327           * - mode is FALSE (default):
1328           * $result[]:
1329           *    [0]['table']  table name
1330           *    [0]['name']   field name
1331           *    [0]['type']   field type
1332           *    [0]['len']    field length
1333           *    [0]['flags']  field flags
1334           *
1335           * - mode is MDB_TABLEINFO_ORDER
1336           * $result[]:
1337           *    ['num_fields'] number of metadata records
1338           *    [0]['table']  table name
1339           *    [0]['name']   field name
1340           *    [0]['type']   field type
1341           *    [0]['len']    field length
1342           *    [0]['flags']  field flags
1343           *    ['order'][field name]  index of field named 'field name'
1344           *    The last one is used, if you have a field name, but no index.
1345           *    Test:  if (isset($result['meta']['myfield'])) { ...
1346           *
1347           * - mode is MDB_TABLEINFO_ORDERTABLE
1348           *     the same as above. but additionally
1349           *    ['ordertable'][table name][field name] index of field
1350           *       named 'field name'
1351           *
1352           *       this is, because if you have fields from different
1353           *       tables with the same field name * they override each
1354           *       other with MDB_TABLEINFO_ORDER
1355           *
1356           *       you can combine MDB_TABLEINFO_ORDER and
1357           *       MDB_TABLEINFO_ORDERTABLE with MDB_TABLEINFO_ORDER |
1358           *       MDB_TABLEINFO_ORDERTABLE * or with MDB_TABLEINFO_FULL
1359           **/
1360  
1361          // if $result is a string, then we want information about a
1362          // table without a resultset
1363          if (is_string($result)) {
1364              $id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0");
1365              if (empty($id)) {
1366                  return($this->pgsqlRaiseError());
1367              }
1368          } else { // else we want information about a resultset
1369              $id = $result;
1370              if (empty($id)) {
1371                  return($this->pgsqlRaiseError());
1372              }
1373          }
1374  
1375          $count = @pg_numfields($id);
1376  
1377          // made this IF due to performance (one if is faster than $count if's)
1378          if (empty($mode)) {
1379              for ($i = 0; $i < $count; $i++) {
1380                  $res[$i]['table'] = (is_string($result)) ? $result : '';
1381                  $res[$i]['name'] = @pg_fieldname ($id, $i);
1382                  $res[$i]['type'] = @pg_fieldtype ($id, $i);
1383                  $res[$i]['len'] = @pg_fieldsize ($id, $i);
1384                  $res[$i]['flags'] = (is_string($result)) ? $this->_pgFieldflags($id, $i, $result) : '';
1385              }
1386          } else { // full
1387              $res['num_fields'] = $count;
1388  
1389              for ($i = 0; $i < $count; $i++) {
1390                  $res[$i]['table'] = (is_string($result)) ? $result : '';
1391                  $res[$i]['name'] = @pg_fieldname ($id, $i);
1392                  $res[$i]['type'] = @pg_fieldtype ($id, $i);
1393                  $res[$i]['len'] = @pg_fieldsize ($id, $i);
1394                  $res[$i]['flags'] = (is_string($result)) ? $this->_pgFieldFlags($id, $i, $result) : '';
1395                  if ($mode & MDB_TABLEINFO_ORDER) {
1396                      $res['order'][$res[$i]['name']] = $i;
1397                  }
1398                  if ($mode & MDB_TABLEINFO_ORDERTABLE) {
1399                      $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
1400                  }
1401              }
1402          }
1403  
1404          // free the result only if we were called on a table
1405          if (is_string($result) && is_resource($id)) {
1406              @pg_freeresult($id);
1407          }
1408          return($res);
1409      }
1410  
1411      // }}}
1412      // {{{ _pgFieldFlags()
1413  
1414      /**
1415       * Flags of a Field
1416       *
1417       * @param int $resource PostgreSQL result identifier
1418       * @param int $num_field the field number
1419       * @return string The flags of the field ('not_null', 'default_xx', 'primary_key',
1420       *                 'unique' and 'multiple_key' are supported)
1421       * @access private
1422       **/
1423      function _pgFieldFlags($resource, $num_field, $table_name)
1424      {
1425          $field_name = @pg_fieldname($resource, $num_field);
1426  
1427          $result = pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef
1428              FROM pg_attribute f, pg_class tab, pg_type typ
1429              WHERE tab.relname = typ.typname
1430              AND typ.typrelid = f.attrelid
1431              AND f.attname = '$field_name'
1432              AND tab.relname = '$table_name'");
1433          if (@pg_numrows($result) > 0) {
1434              $row = @pg_fetch_row($result, 0);
1435              $flags = ($row[0] == 't') ? 'not_null ' : '';
1436  
1437              if ($row[1] == 't') {
1438                  $result = @pg_exec($this->connection, "SELECT a.adsrc
1439                      FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a
1440                      WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid
1441                      AND f.attrelid = a.adrelid AND f.attname = '$field_name'
1442                      AND tab.relname = '$table_name'");
1443                  $row = @pg_fetch_row($result, 0);
1444                  $num = str_replace('\'', '', $row[0]);
1445  
1446                  $flags .= "default_$num ";
1447              }
1448          }
1449          $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey
1450              FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i
1451              WHERE tab.relname = typ.typname
1452              AND typ.typrelid = f.attrelid
1453              AND f.attrelid = i.indrelid
1454              AND f.attname = '$field_name'
1455              AND tab.relname = '$table_name'");
1456          $count = @pg_numrows($result);
1457  
1458          for ($i = 0; $i < $count ; $i++) {
1459              $row = @pg_fetch_row($result, $i);
1460              $keys = explode(' ', $row[2]);
1461  
1462              if (in_array($num_field + 1, $keys)) {
1463                  $flags .= ($row[0] == 't') ? 'unique ' : '';
1464                  $flags .= ($row[1] == 't') ? 'primary ' : '';
1465                  if (count($keys) > 1)
1466                      $flags .= 'multiple_key ';
1467              }
1468          }
1469  
1470          return trim($flags);
1471      }
1472  }
1473  
1474  ?>


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