DB
[ class tree: DB ] [ index: DB ] [ all elements ]

Source for file pgsql.php

Documentation is available at pgsql.php

  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-2007 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.139 2007/11/28 02:19:44 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-2007 The PHP Group
  45.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  46.  * @version    Release: 1.7.14RC1
  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.                                      nullnullnull,
  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 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$rownumPGSQL_ASSOC);
  422.             if ($this->options['portability'DB_PORTABILITY_LOWERCASE && $arr{
  423.                 $arr array_change_key_case($arrCASE_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.             /* This fixes an undocumented BC break in PHP 5.2.0 which changed
  516.              * the prototype of pg_escape_string. I'm not thrilled about having
  517.              * to sniff the PHP version, quite frankly, but it's the only way
  518.              * to deal with the problem. Revision 1.331.2.13.2.10 on
  519.              * php-src/ext/pgsql/pgsql.c (PHP_5_2 branch) is to blame, for the
  520.              * record. */
  521.             if (version_compare(PHP_VERSION'5.2.0''>=')) {
  522.                 return pg_escape_string($this->connection$str);
  523.             else {
  524.                 return pg_escape_string($str);
  525.             }
  526.         else {
  527.             return str_replace("'""''"str_replace('\\''\\\\'$str));
  528.         }
  529.     }
  530.  
  531.     // }}}
  532.     // {{{ numCols()
  533.  
  534.     /**
  535.      * Gets the number of columns in a result set
  536.      *
  537.      * This method is not meant to be called directly.  Use
  538.      * DB_result::numCols() instead.  It can't be declared "protected"
  539.      * because DB_result is a separate object.
  540.      *
  541.      * @param resource $result  PHP's query result resource
  542.      *
  543.      * @return int  the number of columns.  A DB_Error object on failure.
  544.      *
  545.      * @see DB_result::numCols()
  546.      */
  547.     function numCols($result)
  548.     {
  549.         $cols @pg_numfields($result);
  550.         if (!$cols{
  551.             return $this->pgsqlRaiseError();
  552.         }
  553.         return $cols;
  554.     }
  555.  
  556.     // }}}
  557.     // {{{ numRows()
  558.  
  559.     /**
  560.      * Gets the number of rows in a result set
  561.      *
  562.      * This method is not meant to be called directly.  Use
  563.      * DB_result::numRows() instead.  It can't be declared "protected"
  564.      * because DB_result is a separate object.
  565.      *
  566.      * @param resource $result  PHP's query result resource
  567.      *
  568.      * @return int  the number of rows.  A DB_Error object on failure.
  569.      *
  570.      * @see DB_result::numRows()
  571.      */
  572.     function numRows($result)
  573.     {
  574.         $rows @pg_numrows($result);
  575.         if ($rows === null{
  576.             return $this->pgsqlRaiseError();
  577.         }
  578.         return $rows;
  579.     }
  580.  
  581.     // }}}
  582.     // {{{ autoCommit()
  583.  
  584.     /**
  585.      * Enables or disables automatic commits
  586.      *
  587.      * @param bool $onoff  true turns it on, false turns it off
  588.      *
  589.      * @return int  DB_OK on success.  A DB_Error object if the driver
  590.      *                doesn't support auto-committing transactions.
  591.      */
  592.     function autoCommit($onoff = false)
  593.     {
  594.         // XXX if $this->transaction_opcount > 0, we should probably
  595.         // issue a warning here.
  596.         $this->autocommit $onoff ? true : false;
  597.         return DB_OK;
  598.     }
  599.  
  600.     // }}}
  601.     // {{{ commit()
  602.  
  603.     /**
  604.      * Commits the current transaction
  605.      *
  606.      * @return int  DB_OK on success.  A DB_Error object on failure.
  607.      */
  608.     function commit()
  609.     {
  610.         if ($this->transaction_opcount > 0{
  611.             // (disabled) hack to shut up error messages from libpq.a
  612.             //@fclose(@fopen("php://stderr", "w"));
  613.             $result @pg_exec($this->connection'end;');
  614.             $this->transaction_opcount = 0;
  615.             if (!$result{
  616.                 return $this->pgsqlRaiseError();
  617.             }
  618.         }
  619.         return DB_OK;
  620.     }
  621.  
  622.     // }}}
  623.     // {{{ rollback()
  624.  
  625.     /**
  626.      * Reverts the current transaction
  627.      *
  628.      * @return int  DB_OK on success.  A DB_Error object on failure.
  629.      */
  630.     function rollback()
  631.     {
  632.         if ($this->transaction_opcount > 0{
  633.             $result @pg_exec($this->connection'abort;');
  634.             $this->transaction_opcount = 0;
  635.             if (!$result{
  636.                 return $this->pgsqlRaiseError();
  637.             }
  638.         }
  639.         return DB_OK;
  640.     }
  641.  
  642.     // }}}
  643.     // {{{ affectedRows()
  644.  
  645.     /**
  646.      * Determines the number of rows affected by a data maniuplation query
  647.      *
  648.      * 0 is returned for queries that don't manipulate data.
  649.      *
  650.      * @return int  the number of rows.  A DB_Error object on failure.
  651.      */
  652.     function affectedRows()
  653.     {
  654.         return $this->affected;
  655.     }
  656.  
  657.     // }}}
  658.     // {{{ nextId()
  659.  
  660.     /**
  661.      * Returns the next free id in a sequence
  662.      *
  663.      * @param string