home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 February (DVD) / PCWorld_2008-02_DVD.iso / v cisle / PHP / PHP.exe / xampp-win32-1.6.5-installer.exe / php / PEAR / DB / pgsql.php < prev    next >
Encoding:
PHP Script  |  2007-12-20  |  34.9 KB  |  1,104 lines

  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. ?>
  1104.