[ Index ]
 

Code source de PHP PEAR 1.4.5

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

title

Body

[fermer]

/DB/ -> pgsql.php (source)

   1  <?php
   2  
   3  /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   4  
   5  /**
   6   * The PEAR DB driver for PHP's pgsql extension
   7   * for interacting with PostgreSQL databases
   8   *
   9   * PHP versions 4 and 5
  10   *
  11   * LICENSE: This source file is subject to version 3.0 of the PHP license
  12   * that is available through the world-wide-web at the following URI:
  13   * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  14   * the PHP License and are unable to obtain it through the web, please
  15   * send a note to license@php.net so we can mail you a copy immediately.
  16   *
  17   * @category   Database
  18   * @package    DB
  19   * @author     Rui Hirokawa <hirokawa@php.net>
  20   * @author     Stig Bakken <ssb@php.net>
  21   * @author     Daniel Convissor <danielc@php.net>
  22   * @copyright  1997-2005 The PHP Group
  23   * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  24   * @version    CVS: $Id: pgsql.php,v 1.134 2007/01/12 05:45:09 aharvey Exp $
  25   * @link       http://pear.php.net/package/DB
  26   */
  27  
  28  /**
  29   * Obtain the DB_common class so it can be extended from
  30   */
  31  require_once  'DB/common.php';
  32  
  33  /**
  34   * The methods PEAR DB uses to interact with PHP's pgsql extension
  35   * for interacting with PostgreSQL databases
  36   *
  37   * These methods overload the ones declared in DB_common.
  38   *
  39   * @category   Database
  40   * @package    DB
  41   * @author     Rui Hirokawa <hirokawa@php.net>
  42   * @author     Stig Bakken <ssb@php.net>
  43   * @author     Daniel Convissor <danielc@php.net>
  44   * @copyright  1997-2005 The PHP Group
  45   * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  46   * @version    Release: 1.7.9
  47   * @link       http://pear.php.net/package/DB
  48   */
  49  class DB_pgsql extends DB_common
  50  {
  51      // {{{ properties
  52  
  53      /**
  54       * The DB driver type (mysql, oci8, odbc, etc.)
  55       * @var string
  56       */
  57      var $phptype = 'pgsql';
  58  
  59      /**
  60       * The database syntax variant to be used (db2, access, etc.), if any
  61       * @var string
  62       */
  63      var $dbsyntax = 'pgsql';
  64  
  65      /**
  66       * The capabilities of this DB implementation
  67       *
  68       * The 'new_link' element contains the PHP version that first provided
  69       * new_link support for this DBMS.  Contains false if it's unsupported.
  70       *
  71       * Meaning of the 'limit' element:
  72       *   + 'emulate' = emulate with fetch row by number
  73       *   + 'alter'   = alter the query
  74       *   + false     = skip rows
  75       *
  76       * @var array
  77       */
  78      var $features = array(
  79          'limit'         => 'alter',
  80          'new_link'      => '4.3.0',
  81          'numrows'       => true,
  82          'pconnect'      => true,
  83          'prepare'       => false,
  84          'ssl'           => true,
  85          'transactions'  => true,
  86      );
  87  
  88      /**
  89       * A mapping of native error codes to DB error codes
  90       * @var array
  91       */
  92      var $errorcode_map = array(
  93      );
  94  
  95      /**
  96       * The raw database connection created by PHP
  97       * @var resource
  98       */
  99      var $connection;
 100  
 101      /**
 102       * The DSN information for connecting to a database
 103       * @var array
 104       */
 105      var $dsn = array();
 106  
 107  
 108      /**
 109       * Should data manipulation queries be committed automatically?
 110       * @var bool
 111       * @access private
 112       */
 113      var $autocommit = true;
 114  
 115      /**
 116       * The quantity of transactions begun
 117       *
 118       * {@internal  While this is private, it can't actually be designated
 119       * private in PHP 5 because it is directly accessed in the test suite.}}
 120       *
 121       * @var integer
 122       * @access private
 123       */
 124      var $transaction_opcount = 0;
 125  
 126      /**
 127       * The number of rows affected by a data manipulation query
 128       * @var integer
 129       */
 130      var $affected = 0;
 131  
 132      /**
 133       * The current row being looked at in fetchInto()
 134       * @var array
 135       * @access private
 136       */
 137      var $row = array();
 138  
 139      /**
 140       * The number of rows in a given result set
 141       * @var array
 142       * @access private
 143       */
 144      var $_num_rows = array();
 145  
 146  
 147      // }}}
 148      // {{{ constructor
 149  
 150      /**
 151       * This constructor calls <kbd>$this->DB_common()</kbd>
 152       *
 153       * @return void
 154       */
 155      function DB_pgsql()
 156      {
 157          $this->DB_common();
 158      }
 159  
 160      // }}}
 161      // {{{ connect()
 162  
 163      /**
 164       * Connect to the database server, log in and open the database
 165       *
 166       * Don't call this method directly.  Use DB::connect() instead.
 167       *
 168       * PEAR DB's pgsql driver supports the following extra DSN options:
 169       *   + connect_timeout  How many seconds to wait for a connection to
 170       *                       be established.  Available since PEAR DB 1.7.0.
 171       *   + new_link         If set to true, causes subsequent calls to
 172       *                       connect() to return a new connection link
 173       *                       instead of the existing one.  WARNING: this is
 174       *                       not portable to other DBMS's.  Available only
 175       *                       if PHP is >= 4.3.0 and PEAR DB is >= 1.7.0.
 176       *   + options          Command line options to be sent to the server.
 177       *                       Available since PEAR DB 1.6.4.
 178       *   + service          Specifies a service name in pg_service.conf that
 179       *                       holds additional connection parameters.
 180       *                       Available since PEAR DB 1.7.0.
 181       *   + sslmode          How should SSL be used when connecting?  Values:
 182       *                       disable, allow, prefer or require.
 183       *                       Available since PEAR DB 1.7.0.
 184       *   + tty              This was used to specify where to send server
 185       *                       debug output.  Available since PEAR DB 1.6.4.
 186       *
 187       * Example of connecting to a new link via a socket:
 188       * <code>
 189       * require_once 'DB.php';
 190       * 
 191       * $dsn = 'pgsql://user:pass@unix(/tmp)/dbname?new_link=true';
 192       * $options = array(
 193       *     'portability' => DB_PORTABILITY_ALL,
 194       * );
 195       * 
 196       * $db =& DB::connect($dsn, $options);
 197       * if (PEAR::isError($db)) {
 198       *     die($db->getMessage());
 199       * }
 200       * </code>
 201       *
 202       * @param array $dsn         the data source name
 203       * @param bool  $persistent  should the connection be persistent?
 204       *
 205       * @return int  DB_OK on success. A DB_Error object on failure.
 206       *
 207       * @link http://www.postgresql.org/docs/current/static/libpq.html#LIBPQ-CONNECT
 208       */
 209      function connect($dsn, $persistent = false)
 210      {
 211          if (!PEAR::loadExtension('pgsql')) {
 212              return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
 213          }
 214  
 215          $this->dsn = $dsn;
 216          if ($dsn['dbsyntax']) {
 217              $this->dbsyntax = $dsn['dbsyntax'];
 218          }
 219  
 220          $protocol = $dsn['protocol'] ? $dsn['protocol'] : 'tcp';
 221  
 222          $params = array('');
 223          if ($protocol == 'tcp') {
 224              if ($dsn['hostspec']) {
 225                  $params[0] .= 'host=' . $dsn['hostspec'];
 226              }
 227              if ($dsn['port']) {
 228                  $params[0] .= ' port=' . $dsn['port'];
 229              }
 230          } elseif ($protocol == 'unix') {
 231              // Allow for pg socket in non-standard locations.
 232              if ($dsn['socket']) {
 233                  $params[0] .= 'host=' . $dsn['socket'];
 234              }
 235              if ($dsn['port']) {
 236                  $params[0] .= ' port=' . $dsn['port'];
 237              }
 238          }
 239          if ($dsn['database']) {
 240              $params[0] .= ' dbname=\'' . addslashes($dsn['database']) . '\'';
 241          }
 242          if ($dsn['username']) {
 243              $params[0] .= ' user=\'' . addslashes($dsn['username']) . '\'';
 244          }
 245          if ($dsn['password']) {
 246              $params[0] .= ' password=\'' . addslashes($dsn['password']) . '\'';
 247          }
 248          if (!empty($dsn['options'])) {
 249              $params[0] .= ' options=' . $dsn['options'];
 250          }
 251          if (!empty($dsn['tty'])) {
 252              $params[0] .= ' tty=' . $dsn['tty'];
 253          }
 254          if (!empty($dsn['connect_timeout'])) {
 255              $params[0] .= ' connect_timeout=' . $dsn['connect_timeout'];
 256          }
 257          if (!empty($dsn['sslmode'])) {
 258              $params[0] .= ' sslmode=' . $dsn['sslmode'];
 259          }
 260          if (!empty($dsn['service'])) {
 261              $params[0] .= ' service=' . $dsn['service'];
 262          }
 263  
 264          if (isset($dsn['new_link'])
 265              && ($dsn['new_link'] == 'true' || $dsn['new_link'] === true))
 266          {
 267              if (version_compare(phpversion(), '4.3.0', '>=')) {
 268                  $params[] = PGSQL_CONNECT_FORCE_NEW;
 269              }
 270          }
 271  
 272          $connect_function = $persistent ? 'pg_pconnect' : 'pg_connect';
 273  
 274          $ini = ini_get('track_errors');
 275          $php_errormsg = '';
 276          if ($ini) {
 277              $this->connection = @call_user_func_array($connect_function,
 278                                                        $params);
 279          } else {
 280              @ini_set('track_errors', 1);
 281              $this->connection = @call_user_func_array($connect_function,
 282                                                        $params);
 283              @ini_set('track_errors', $ini);
 284          }
 285  
 286          if (!$this->connection) {
 287              return $this->raiseError(DB_ERROR_CONNECT_FAILED,
 288                                       null, null, null,
 289                                       $php_errormsg);
 290          }
 291          return DB_OK;
 292      }
 293  
 294      // }}}
 295      // {{{ disconnect()
 296  
 297      /**
 298       * Disconnects from the database server
 299       *
 300       * @return bool  TRUE on success, FALSE on failure
 301       */
 302      function disconnect()
 303      {
 304          $ret = @pg_close($this->connection);
 305          $this->connection = null;
 306          return $ret;
 307      }
 308  
 309      // }}}
 310      // {{{ simpleQuery()
 311  
 312      /**
 313       * Sends a query to the database server
 314       *
 315       * @param string  the SQL query string
 316       *
 317       * @return mixed  + a PHP result resrouce for successful SELECT queries
 318       *                + the DB_OK constant for other successful queries
 319       *                + a DB_Error object on failure
 320       */
 321      function simpleQuery($query)
 322      {
 323          $ismanip = $this->_checkManip($query);
 324          $this->last_query = $query;
 325          $query = $this->modifyQuery($query);
 326          if (!$this->autocommit && $ismanip) {
 327              if ($this->transaction_opcount == 0) {
 328                  $result = @pg_exec($this->connection, 'begin;');
 329                  if (!$result) {
 330                      return $this->pgsqlRaiseError();
 331                  }
 332              }
 333              $this->transaction_opcount++;
 334          }
 335          $result = @pg_exec($this->connection, $query);
 336          if (!$result) {
 337              return $this->pgsqlRaiseError();
 338          }
 339  
 340          /*
 341           * Determine whether queries produce affected rows, result or nothing.
 342           *
 343           * This logic was introduced in version 1.1 of the file by ssb,
 344           * though the regex has been modified slightly since then.
 345           *
 346           * PostgreSQL commands:
 347           * ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY,
 348           * CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH,
 349           * GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET,
 350           * REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW,
 351           * UNLISTEN, UPDATE, VACUUM
 352           */
 353          if ($ismanip) {
 354              $this->affected = @pg_affected_rows($result);
 355              return DB_OK;
 356          } elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|FETCH|SHOW)\s/si',
 357                               $query))
 358          {
 359              $this->row[(int)$result] = 0; // reset the row counter.
 360              $numrows = $this->numRows($result);
 361              if (is_object($numrows)) {
 362                  return $numrows;
 363              }
 364              $this->_num_rows[(int)$result] = $numrows;
 365              $this->affected = 0;
 366              return $result;
 367          } else {
 368              $this->affected = 0;
 369              return DB_OK;
 370          }
 371      }
 372  
 373      // }}}
 374      // {{{ nextResult()
 375  
 376      /**
 377       * Move the internal pgsql result pointer to the next available result
 378       *
 379       * @param a valid fbsql result resource
 380       *
 381       * @access public
 382       *
 383       * @return true if a result is available otherwise return false
 384       */
 385      function nextResult($result)
 386      {
 387          return false;
 388      }
 389  
 390      // }}}
 391      // {{{ fetchInto()
 392  
 393      /**
 394       * Places a row from the result set into the given array
 395       *
 396       * Formating of the array and the data therein are configurable.
 397       * See DB_result::fetchInto() for more information.
 398       *
 399       * This method is not meant to be called directly.  Use
 400       * DB_result::fetchInto() instead.  It can't be declared "protected"
 401       * because DB_result is a separate object.
 402       *
 403       * @param resource $result    the query result resource
 404       * @param array    $arr       the referenced array to put the data in
 405       * @param int      $fetchmode how the resulting array should be indexed
 406       * @param int      $rownum    the row number to fetch (0 = first row)
 407       *
 408       * @return mixed  DB_OK on success, NULL when the end of a result set is
 409       *                 reached or on failure
 410       *
 411       * @see DB_result::fetchInto()
 412       */
 413      function fetchInto($result, &$arr, $fetchmode, $rownum = null)
 414      {
 415          $result_int = (int)$result;
 416          $rownum = ($rownum !== null) ? $rownum : $this->row[$result_int];
 417          if ($rownum >= $this->_num_rows[$result_int]) {
 418              return null;
 419          }
 420          if ($fetchmode & DB_FETCHMODE_ASSOC) {
 421              $arr = @pg_fetch_array($result, $rownum, PGSQL_ASSOC);
 422              if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
 423                  $arr = array_change_key_case($arr, CASE_LOWER);
 424              }
 425          } else {
 426              $arr = @pg_fetch_row($result, $rownum);
 427          }
 428          if (!$arr) {
 429              return null;
 430          }
 431          if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
 432              $this->_rtrimArrayValues($arr);
 433          }
 434          if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
 435              $this->_convertNullArrayValuesToEmpty($arr);
 436          }
 437          $this->row[$result_int] = ++$rownum;
 438          return DB_OK;
 439      }
 440  
 441      // }}}
 442      // {{{ freeResult()
 443  
 444      /**
 445       * Deletes the result set and frees the memory occupied by the result set
 446       *
 447       * This method is not meant to be called directly.  Use
 448       * DB_result::free() instead.  It can't be declared "protected"
 449       * because DB_result is a separate object.
 450       *
 451       * @param resource $result  PHP's query result resource
 452       *
 453       * @return bool  TRUE on success, FALSE if $result is invalid
 454       *
 455       * @see DB_result::free()
 456       */
 457      function freeResult($result)
 458      {
 459          if (is_resource($result)) {
 460              unset($this->row[(int)$result]);
 461              unset($this->_num_rows[(int)$result]);
 462              $this->affected = 0;
 463              return @pg_freeresult($result);
 464          }
 465          return false;
 466      }
 467  
 468      // }}}
 469      // {{{ quote()
 470  
 471      /**
 472       * @deprecated  Deprecated in release 1.6.0
 473       * @internal
 474       */
 475      function quote($str)
 476      {
 477          return $this->quoteSmart($str);
 478      }
 479  
 480      // }}}
 481      // {{{ quoteBoolean()
 482  
 483      /**
 484       * Formats a boolean value for use within a query in a locale-independent
 485       * manner.
 486       *
 487       * @param boolean the boolean value to be quoted.
 488       * @return string the quoted string.
 489       * @see DB_common::quoteSmart()
 490       * @since Method available since release 1.7.8.
 491       */
 492      function quoteBoolean($boolean) {
 493          return $boolean ? 'TRUE' : 'FALSE';
 494      }
 495       
 496      // }}}
 497      // {{{ escapeSimple()
 498  
 499      /**
 500       * Escapes a string according to the current DBMS's standards
 501       *
 502       * {@internal PostgreSQL treats a backslash as an escape character,
 503       * so they are escaped as well.
 504       *
 505       * @param string $str  the string to be escaped
 506       *
 507       * @return string  the escaped string
 508       *
 509       * @see DB_common::quoteSmart()
 510       * @since Method available since Release 1.6.0
 511       */
 512      function escapeSimple($str)
 513      {
 514          if (function_exists('pg_escape_string')) {
 515              return pg_escape_string($str);
 516          } else {
 517              return str_replace("'", "''", str_replace('\\', '\\\\', $str));
 518          }
 519      }
 520  
 521      // }}}
 522      // {{{ numCols()
 523  
 524      /**
 525       * Gets the number of columns in a result set
 526       *
 527       * This method is not meant to be called directly.  Use
 528       * DB_result::numCols() instead.  It can't be declared "protected"
 529       * because DB_result is a separate object.
 530       *
 531       * @param resource $result  PHP's query result resource
 532       *
 533       * @return int  the number of columns.  A DB_Error object on failure.
 534       *
 535       * @see DB_result::numCols()
 536       */
 537      function numCols($result)
 538      {
 539          $cols = @pg_numfields($result);
 540          if (!$cols) {
 541              return $this->pgsqlRaiseError();
 542          }
 543          return $cols;
 544      }
 545  
 546      // }}}
 547      // {{{ numRows()
 548  
 549      /**
 550       * Gets the number of rows in a result set
 551       *
 552       * This method is not meant to be called directly.  Use
 553       * DB_result::numRows() instead.  It can't be declared "protected"
 554       * because DB_result is a separate object.
 555       *
 556       * @param resource $result  PHP's query result resource
 557       *
 558       * @return int  the number of rows.  A DB_Error object on failure.
 559       *
 560       * @see DB_result::numRows()
 561       */
 562      function numRows($result)
 563      {
 564          $rows = @pg_numrows($result);
 565          if ($rows === null) {
 566              return $this->pgsqlRaiseError();
 567          }
 568          return $rows;
 569      }
 570  
 571      // }}}
 572      // {{{ autoCommit()
 573  
 574      /**
 575       * Enables or disables automatic commits
 576       *
 577       * @param bool $onoff  true turns it on, false turns it off
 578       *
 579       * @return int  DB_OK on success.  A DB_Error object if the driver
 580       *               doesn't support auto-committing transactions.
 581       */
 582      function autoCommit($onoff = false)
 583      {
 584          // XXX if $this->transaction_opcount > 0, we should probably
 585          // issue a warning here.
 586          $this->autocommit = $onoff ? true : false;
 587          return DB_OK;
 588      }
 589  
 590      // }}}
 591      // {{{ commit()
 592  
 593      /**
 594       * Commits the current transaction
 595       *
 596       * @return int  DB_OK on success.  A DB_Error object on failure.
 597       */
 598      function commit()
 599      {
 600          if ($this->transaction_opcount > 0) {
 601              // (disabled) hack to shut up error messages from libpq.a
 602              //@fclose(@fopen("php://stderr", "w"));
 603              $result = @pg_exec($this->connection, 'end;');
 604              $this->transaction_opcount = 0;
 605              if (!$result) {
 606                  return $this->pgsqlRaiseError();
 607              }
 608          }
 609          return DB_OK;
 610      }
 611  
 612      // }}}
 613      // {{{ rollback()
 614  
 615      /**
 616       * Reverts the current transaction
 617       *
 618       * @return int  DB_OK on success.  A DB_Error object on failure.
 619       */
 620      function rollback()
 621      {
 622          if ($this->transaction_opcount > 0) {
 623              $result = @pg_exec($this->connection, 'abort;');
 624              $this->transaction_opcount = 0;
 625              if (!$result) {
 626                  return $this->pgsqlRaiseError();
 627              }
 628          }
 629          return DB_OK;
 630      }
 631  
 632      // }}}
 633      // {{{ affectedRows()
 634  
 635      /**
 636       * Determines the number of rows affected by a data maniuplation query
 637       *
 638       * 0 is returned for queries that don't manipulate data.
 639       *
 640       * @return int  the number of rows.  A DB_Error object on failure.
 641       */
 642      function affectedRows()
 643      {
 644          return $this->affected;
 645      }
 646  
 647      // }}}
 648      // {{{ nextId()
 649  
 650      /**
 651       * Returns the next free id in a sequence
 652       *
 653       * @param string  $seq_name  name of the sequence
 654       * @param boolean $ondemand  when true, the seqence is automatically
 655       *                            created if it does not exist
 656       *
 657       * @return int  the next id number in the sequence.
 658       *               A DB_Error object on failure.
 659       *
 660       * @see DB_common::nextID(), DB_common::getSequenceName(),
 661       *      DB_pgsql::createSequence(), DB_pgsql::dropSequence()
 662       */
 663      function nextId($seq_name, $ondemand = true)
 664      {
 665          $seqname = $this->getSequenceName($seq_name);
 666          $repeat = false;
 667          do {
 668              $this->pushErrorHandling(PEAR_ERROR_RETURN);
 669              $result =& $this->query("SELECT NEXTVAL('$seqname}')");
 670              $this->popErrorHandling();
 671              if ($ondemand && DB::isError($result) &&
 672                  $result->getCode() == DB_ERROR_NOSUCHTABLE) {
 673                  $repeat = true;
 674                  $this->pushErrorHandling(PEAR_ERROR_RETURN);
 675                  $result = $this->createSequence($seq_name);
 676                  $this->popErrorHandling();
 677                  if (DB::isError($result)) {
 678                      return $this->raiseError($result);
 679                  }
 680              } else {
 681                  $repeat = false;
 682              }
 683          } while ($repeat);
 684          if (DB::isError($result)) {
 685              return $this->raiseError($result);
 686          }
 687          $arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
 688          $result->free();
 689          return $arr[0];
 690      }
 691  
 692      // }}}
 693      // {{{ createSequence()
 694  
 695      /**
 696       * Creates a new sequence
 697       *
 698       * @param string $seq_name  name of the new sequence
 699       *
 700       * @return int  DB_OK on success.  A DB_Error object on failure.
 701       *
 702       * @see DB_common::createSequence(), DB_common::getSequenceName(),
 703       *      DB_pgsql::nextID(), DB_pgsql::dropSequence()
 704       */
 705      function createSequence($seq_name)
 706      {
 707          $seqname = $this->getSequenceName($seq_name);
 708          $result = $this->query("CREATE SEQUENCE $seqname}");
 709          return $result;
 710      }
 711  
 712      // }}}
 713      // {{{ dropSequence()
 714  
 715      /**
 716       * Deletes a sequence
 717       *
 718       * @param string $seq_name  name of the sequence to be deleted
 719       *
 720       * @return int  DB_OK on success.  A DB_Error object on failure.
 721       *
 722       * @see DB_common::dropSequence(), DB_common::getSequenceName(),
 723       *      DB_pgsql::nextID(), DB_pgsql::createSequence()
 724       */
 725      function dropSequence($seq_name)
 726      {
 727          return $this->query('DROP SEQUENCE '
 728                              . $this->getSequenceName($seq_name));
 729      }
 730  
 731      // }}}
 732      // {{{ modifyLimitQuery()
 733  
 734      /**
 735       * Adds LIMIT clauses to a query string according to current DBMS standards
 736       *
 737       * @param string $query   the query to modify
 738       * @param int    $from    the row to start to fetching (0 = the first row)
 739       * @param int    $count   the numbers of rows to fetch
 740       * @param mixed  $params  array, string or numeric data to be used in
 741       *                         execution of the statement.  Quantity of items
 742       *                         passed must match quantity of placeholders in
 743       *                         query:  meaning 1 placeholder for non-array
 744       *                         parameters or 1 placeholder per array element.
 745       *
 746       * @return string  the query string with LIMIT clauses added
 747       *
 748       * @access protected
 749       */
 750      function modifyLimitQuery($query, $from, $count, $params = array())
 751      {
 752          return "$query LIMIT $count OFFSET $from";
 753      }
 754  
 755      // }}}
 756      // {{{ pgsqlRaiseError()
 757  
 758      /**
 759       * Produces a DB_Error object regarding the current problem
 760       *
 761       * @param int $errno  if the error is being manually raised pass a
 762       *                     DB_ERROR* constant here.  If this isn't passed
 763       *                     the error information gathered from the DBMS.
 764       *
 765       * @return object  the DB_Error object
 766       *
 767       * @see DB_common::raiseError(),
 768       *      DB_pgsql::errorNative(), DB_pgsql::errorCode()
 769       */
 770      function pgsqlRaiseError($errno = null)
 771      {
 772          $native = $this->errorNative();
 773          if (!$native) {
 774              $native = 'Database connection has been lost.';
 775              $errno = DB_ERROR_CONNECT_FAILED;
 776          }
 777          if ($errno === null) {
 778              $errno = $this->errorCode($native);
 779          }
 780          return $this->raiseError($errno, null, null, null, $native);
 781      }
 782  
 783      // }}}
 784      // {{{ errorNative()
 785  
 786      /**
 787       * Gets the DBMS' native error message produced by the last query
 788       *
 789       * {@internal Error messages are used instead of error codes 
 790       * in order to support older versions of PostgreSQL.}}
 791       *
 792       * @return string  the DBMS' error message
 793       */
 794      function errorNative()
 795      {
 796          return @pg_errormessage($this->connection);
 797      }
 798  
 799      // }}}
 800      // {{{ errorCode()
 801  
 802      /**
 803       * Determines PEAR::DB error code from the database's text error message.
 804       *
 805       * @param  string  $errormsg  error message returned from the database
 806       * @return integer  an error number from a DB error constant
 807       */
 808      function errorCode($errormsg)
 809      {
 810          static $error_regexps;
 811          if (!isset($error_regexps)) {
 812              $error_regexps = array(
 813                  '/column .* (of relation .*)?does not exist/i'
 814                      => DB_ERROR_NOSUCHFIELD,
 815                  '/(relation|sequence|table).*does not exist|class .* not found/i'
 816                      => DB_ERROR_NOSUCHTABLE,
 817                  '/index .* does not exist/'
 818                      => DB_ERROR_NOT_FOUND,
 819                  '/relation .* already exists/i'
 820                      => DB_ERROR_ALREADY_EXISTS,
 821                  '/(divide|division) by zero$/i'
 822                      => DB_ERROR_DIVZERO,
 823                  '/pg_atoi: error in .*: can\'t parse /i'
 824                      => DB_ERROR_INVALID_NUMBER,
 825                  '/invalid input syntax for( type)? (integer|numeric)/i'
 826                      => DB_ERROR_INVALID_NUMBER,
 827                  '/value .* is out of range for type \w*int/i'
 828                      => DB_ERROR_INVALID_NUMBER,
 829                  '/integer out of range/i'
 830                      => DB_ERROR_INVALID_NUMBER,
 831                  '/value too long for type character/i'
 832                      => DB_ERROR_INVALID,
 833                  '/attribute .* not found|relation .* does not have attribute/i'
 834                      => DB_ERROR_NOSUCHFIELD,
 835                  '/column .* specified in USING clause does not exist in (left|right) table/i'
 836                      => DB_ERROR_NOSUCHFIELD,
 837                  '/parser: parse error at or near/i'
 838                      => DB_ERROR_SYNTAX,
 839                  '/syntax error at/'
 840                      => DB_ERROR_SYNTAX,
 841                  '/column reference .* is ambiguous/i'
 842                      => DB_ERROR_SYNTAX,
 843                  '/permission denied/'
 844                      => DB_ERROR_ACCESS_VIOLATION,
 845                  '/violates not-null constraint/'
 846                      => DB_ERROR_CONSTRAINT_NOT_NULL,
 847                  '/violates [\w ]+ constraint/'
 848                      => DB_ERROR_CONSTRAINT,
 849                  '/referential integrity violation/'
 850                      => DB_ERROR_CONSTRAINT,
 851                  '/more expressions than target columns/i'
 852                      => DB_ERROR_VALUE_COUNT_ON_ROW,
 853              );
 854          }
 855          foreach ($error_regexps as $regexp => $code) {
 856              if (preg_match($regexp, $errormsg)) {
 857                  return $code;
 858              }
 859          }
 860          // Fall back to DB_ERROR if there was no mapping.
 861          return DB_ERROR;
 862      }
 863  
 864      // }}}
 865      // {{{ tableInfo()
 866  
 867      /**
 868       * Returns information about a table or a result set
 869       *
 870       * NOTE: only supports 'table' and 'flags' if <var>$result</var>
 871       * is a table name.
 872       *
 873       * @param object|string  $result  DB_result object from a query or a
 874       *                                 string containing the name of a table.
 875       *                                 While this also accepts a query result
 876       *                                 resource identifier, this behavior is
 877       *                                 deprecated.
 878       * @param int            $mode    a valid tableInfo mode
 879       *
 880       * @return array  an associative array with the information requested.
 881       *                 A DB_Error object on failure.
 882       *
 883       * @see DB_common::tableInfo()
 884       */
 885      function tableInfo($result, $mode = null)
 886      {
 887          if (is_string($result)) {
 888              /*
 889               * Probably received a table name.
 890               * Create a result resource identifier.
 891               */
 892              $id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0");
 893              $got_string = true;
 894          } elseif (isset($result->result)) {
 895              /*
 896               * Probably received a result object.
 897               * Extract the result resource identifier.
 898               */
 899              $id = $result->result;
 900              $got_string = false;
 901          } else {
 902              /*
 903               * Probably received a result resource identifier.
 904               * Copy it.
 905               * Deprecated.  Here for compatibility only.
 906               */
 907              $id = $result;
 908              $got_string = false;
 909          }
 910  
 911          if (!is_resource($id)) {
 912              return $this->pgsqlRaiseError(DB_ERROR_NEED_MORE_DATA);
 913          }
 914  
 915          if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
 916              $case_func = 'strtolower';
 917          } else {
 918              $case_func = 'strval';
 919          }
 920  
 921          $count = @pg_numfields($id);
 922          $res   = array();
 923  
 924          if ($mode) {
 925              $res['num_fields'] = $count;
 926          }
 927  
 928          for ($i = 0; $i < $count; $i++) {
 929              $res[$i] = array(
 930                  'table' => $got_string ? $case_func($result) : '',
 931                  'name'  => $case_func(@pg_fieldname($id, $i)),
 932                  'type'  => @pg_fieldtype($id, $i),
 933                  'len'   => @pg_fieldsize($id, $i),
 934                  'flags' => $got_string
 935                             ? $this->_pgFieldFlags($id, $i, $result)
 936                             : '',
 937              );
 938              if ($mode & DB_TABLEINFO_ORDER) {
 939                  $res['order'][$res[$i]['name']] = $i;
 940              }
 941              if ($mode & DB_TABLEINFO_ORDERTABLE) {
 942                  $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
 943              }
 944          }
 945  
 946          // free the result only if we were called on a table
 947          if ($got_string) {
 948              @pg_freeresult($id);
 949          }
 950          return $res;
 951      }
 952  
 953      // }}}
 954      // {{{ _pgFieldFlags()
 955  
 956      /**
 957       * Get a column's flags
 958       *
 959       * Supports "not_null", "default_value", "primary_key", "unique_key"
 960       * and "multiple_key".  The default value is passed through
 961       * rawurlencode() in case there are spaces in it.
 962       *
 963       * @param int $resource   the PostgreSQL result identifier
 964       * @param int $num_field  the field number
 965       *
 966       * @return string  the flags
 967       *
 968       * @access private
 969       */
 970      function _pgFieldFlags($resource, $num_field, $table_name)
 971      {
 972          $field_name = @pg_fieldname($resource, $num_field);
 973  
 974          // Check if there's a schema in $table_name and update things
 975          // accordingly.
 976          $from = 'pg_attribute f, pg_class tab, pg_type typ';
 977          if (strpos($table_name, '.') !== false) {
 978              $from .= ', pg_namespace nsp';
 979              list($schema, $table) = explode('.', $table_name);
 980              $tableWhere = "tab.relname = '$table' AND tab.relnamespace = nsp.oid AND nsp.nspname = '$schema'";
 981          } else {
 982              $tableWhere = "tab.relname = '$table_name'";
 983          }
 984  
 985          $result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef
 986                                  FROM $from
 987                                  WHERE tab.relname = typ.typname
 988                                  AND typ.typrelid = f.attrelid
 989                                  AND f.attname = '$field_name'
 990                                  AND $tableWhere");
 991          if (@pg_numrows($result) > 0) {
 992              $row = @pg_fetch_row($result, 0);
 993              $flags  = ($row[0] == 't') ? 'not_null ' : '';
 994  
 995              if ($row[1] == 't') {
 996                  $result = @pg_exec($this->connection, "SELECT a.adsrc
 997                                      FROM $from, pg_attrdef a
 998                                      WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid
 999                                      AND f.attrelid = a.adrelid AND f.attname = '$field_name'
1000                                      AND $tableWhere AND f.attnum = a.adnum");
1001                  $row = @pg_fetch_row($result, 0);
1002                  $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]);
1003                  $flags .= 'default_' . rawurlencode($num) . ' ';
1004              }
1005          } else {
1006              $flags = '';
1007          }
1008          $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey
1009                                  FROM $from, pg_index i
1010                                  WHERE tab.relname = typ.typname
1011                                  AND typ.typrelid = f.attrelid
1012                                  AND f.attrelid = i.indrelid
1013                                  AND f.attname = '$field_name'
1014                                  AND $tableWhere");
1015          $count = @pg_numrows($result);
1016  
1017          for ($i = 0; $i < $count ; $i++) {
1018              $row = @pg_fetch_row($result, $i);
1019              $keys = explode(' ', $row[2]);
1020  
1021              if (in_array($num_field + 1, $keys)) {
1022                  $flags .= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : '';
1023                  $flags .= ($row[1] == 't') ? 'primary_key ' : '';
1024                  if (count($keys) > 1)
1025                      $flags .= 'multiple_key ';
1026              }
1027          }
1028  
1029          return trim($flags);
1030      }
1031  
1032      // }}}
1033      // {{{ getSpecialQuery()
1034  
1035      /**
1036       * Obtains the query string needed for listing a given type of objects
1037       *
1038       * @param string $type  the kind of objects you want to retrieve
1039       *
1040       * @return string  the SQL query string or null if the driver doesn't
1041       *                  support the object type requested
1042       *
1043       * @access protected
1044       * @see DB_common::getListOf()
1045       */
1046      function getSpecialQuery($type)
1047      {
1048          switch ($type) {
1049              case 'tables':
1050                  return 'SELECT c.relname AS "Name"'
1051                          . ' FROM pg_class c, pg_user u'
1052                          . ' WHERE c.relowner = u.usesysid'
1053                          . " AND c.relkind = 'r'"
1054                          . ' AND NOT EXISTS'
1055                          . ' (SELECT 1 FROM pg_views'
1056                          . '  WHERE viewname = c.relname)'
1057                          . " AND c.relname !~ '^(pg_|sql_)'"
1058                          . ' UNION'
1059                          . ' SELECT c.relname AS "Name"'
1060                          . ' FROM pg_class c'
1061                          . " WHERE c.relkind = 'r'"
1062                          . ' AND NOT EXISTS'
1063                          . ' (SELECT 1 FROM pg_views'
1064                          . '  WHERE viewname = c.relname)'
1065                          . ' AND NOT EXISTS'
1066                          . ' (SELECT 1 FROM pg_user'
1067                          . '  WHERE usesysid = c.relowner)'
1068                          . " AND c.relname !~ '^pg_'";
1069              case 'schema.tables':
1070                  return "SELECT schemaname || '.' || tablename"
1071                          . ' AS "Name"'
1072                          . ' FROM pg_catalog.pg_tables'
1073                          . ' WHERE schemaname NOT IN'
1074                          . " ('pg_catalog', 'information_schema', 'pg_toast')";
1075              case 'views':
1076                  // Table cols: viewname | viewowner | definition
1077                  return 'SELECT viewname from pg_views WHERE schemaname'
1078                          . " NOT IN ('information_schema', 'pg_catalog')";
1079              case 'users':
1080                  // cols: usename |usesysid|usecreatedb|usetrace|usesuper|usecatupd|passwd  |valuntil
1081                  return 'SELECT usename FROM pg_user';
1082              case 'databases':
1083                  return 'SELECT datname FROM pg_database';
1084              case 'functions':
1085              case 'procedures':
1086                  return 'SELECT proname FROM pg_proc WHERE proowner <> 1';
1087              default:
1088                  return null;
1089          }
1090      }
1091  
1092      // }}}
1093  
1094  }
1095  
1096  /*
1097   * Local variables:
1098   * tab-width: 4
1099   * c-basic-offset: 4
1100   * End:
1101   */
1102  
1103  ?>


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