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-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.10
  47.  * @link       http://pear.php.net/package/DB
  48.  */
  49. class DB_pgsql extends DB_common
  50. {
  51.     // {{{ properties
  52.  
  53.     
  54.     /**
  55.      * The DB driver type (mysql, oci8, odbc, etc.)
  56.      * @var string 
  57.      */
  58.     var $phptype = 'pgsql';
  59.  
  60.     /**
  61.      * The database syntax variant to be used (db2, access, etc.), if any
  62.      * @var string 
  63.      */
  64.     var $dbsyntax = 'pgsql';
  65.  
  66.     /**
  67.      * The capabilities of this DB implementation
  68.      *
  69.      * The 'new_link' element contains the PHP version that first provided
  70.      * new_link support for this DBMS.  Contains false if it's unsupported.
  71.      *
  72.      * Meaning of the 'limit' element:
  73.      *   + 'emulate' = emulate with fetch row by number
  74.      *   + 'alter'   = alter the query
  75.      *   + false     = skip rows
  76.      *
  77.      * @var array 
  78.      */
  79.     var $features = array(
  80.         'limit'         => 'alter',
  81.         'new_link'      => '4.3.0',
  82.         'numrows'       => true,
  83.         'pconnect'      => true,
  84.         'prepare'       => false,
  85.         'ssl'           => true,
  86.         'transactions'  => true,
  87.     );
  88.  
  89.     /**
  90.      * A mapping of native error codes to DB error codes
  91.      * @var array 
  92.      */
  93.     var $errorcode_map = array(
  94.     );
  95.  
  96.     /**
  97.      * The raw database connection created by PHP
  98.      * @var resource 
  99.      */
  100.     var $connection;
  101.  
  102.     /**
  103.      * The DSN information for connecting to a database
  104.      * @var array 
  105.      */
  106.     var $dsn = array();
  107.  
  108.  
  109.     /**
  110.      * Should data manipulation queries be committed automatically?
  111.      * @var bool 
  112.      * @access private
  113.      */
  114.     var $autocommit = true;
  115.  
  116.     /**
  117.      * The quantity of transactions begun
  118.      *
  119.      * {@internal  While this is private, it can't actually be designated
  120.      * private in PHP 5 because it is directly accessed in the test suite.}}
  121.      *
  122.      * @var integer 
  123.      * @access private
  124.      */
  125.     var $transaction_opcount = 0;
  126.  
  127.     /**
  128.      * The number of rows affected by a data manipulation query
  129.      * @var integer 
  130.      */
  131.     var $affected = 0;
  132.  
  133.     /**
  134.      * The current row being looked at in fetchInto()
  135.      * @var array 
  136.      * @access private
  137.      */
  138.     var $row = array();
  139.  
  140.     /**
  141.      * The number of rows in a given result set
  142.      * @var array 
  143.      * @access private
  144.      */
  145.     var $_num_rows = array();
  146.  
  147.  
  148.     // }}}
  149.     // {{{ constructor
  150.  
  151.     
  152.     /**
  153.      * This constructor calls <kbd>$this->DB_common()</kbd>
  154.      *
  155.      * @return void 
  156.      */
  157.     function DB_pgsql()
  158.     {
  159.         $this->DB_common();
  160.     }
  161.  
  162.     // }}}
  163.     // {{{ connect()
  164.  
  165.     
  166.     /**
  167.      * Connect to the database server, log in and open the database
  168.      *
  169.      * Don't call this method directly.  Use DB::connect() instead.
  170.      *
  171.      * PEAR DB's pgsql driver supports the following extra DSN options:
  172.      *   + connect_timeout  How many seconds to wait for a connection to
  173.      *                       be established.  Available since PEAR DB 1.7.0.
  174.      *   + new_link         If set to true, causes subsequent calls to
  175.      *                       connect() to return a new connection link
  176.      *                       instead of the existing one.  WARNING: this is
  177.      *                       not portable to other DBMS's.  Available only
  178.      *                       if PHP is >= 4.3.0 and PEAR DB is >= 1.7.0.
  179.      *   + options          Command line options to be sent to the server.
  180.      *                       Available since PEAR DB 1.6.4.
  181.      *   + service          Specifies a service name in pg_service.conf that
  182.      *                       holds additional connection parameters.
  183.      *                       Available since PEAR DB 1.7.0.
  184.      *   + sslmode          How should SSL be used when connecting?  Values:
  185.      *                       disable, allow, prefer or require.
  186.      *                       Available since PEAR DB 1.7.0.
  187.      *   + tty              This was used to specify where to send server
  188.      *                       debug output.  Available since PEAR DB 1.6.4.
  189.      *
  190.      * Example of connecting to a new link via a socket:
  191.      * <code>
  192.      * require_once 'DB.php';
  193.      * 
  194.      * $dsn = 'pgsql://user:pass@unix(/tmp)/dbname?new_link=true';
  195.      * $options = array(
  196.      *     'portability' => DB_PORTABILITY_ALL,
  197.      * );
  198.      * 
  199.      * $db =& DB::connect($dsn, $options);
  200.      * if (PEAR::isError($db)) {
  201.      *     die($db->getMessage());
  202.      * }
  203.      * </code>
  204.      *
  205.      * @param array $dsn         the data source name
  206.      * @param bool  $persistent  should the connection be persistent?
  207.      *
  208.      * @return int  DB_OK on success. A DB_Error object on failure.
  209.      *
  210.      * @link http://www.postgresql.org/docs/current/static/libpq.html#LIBPQ-CONNECT
  211.      */
  212.     function connect($dsn$persistent = false)
  213.     {
  214.         if (!PEAR::loadExtension('pgsql')) {
  215.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  216.         }
  217.  
  218.         $this->dsn = $dsn;
  219.         if ($dsn['dbsyntax']{
  220.             $this->dbsyntax = $dsn['dbsyntax'];
  221.         }
  222.  
  223.         $protocol $dsn['protocol'$dsn['protocol''tcp';
  224.  
  225.         $params = array('');
  226.         if ($protocol == 'tcp'{
  227.             if ($dsn['hostspec']{
  228.                 $params[0.= 'host=' $dsn['hostspec'];
  229.             }
  230.             if ($dsn['port']{
  231.                 $params[0.= ' port=' $dsn['port'];
  232.             }
  233.         elseif ($protocol == 'unix'{
  234.             // Allow for pg socket in non-standard locations.
  235.             if ($dsn['socket']{
  236.                 $params[0.= 'host=' $dsn['socket'];
  237.             }
  238.             if ($dsn['port']{
  239.                 $params[0.= ' port=' $dsn['port'];
  240.             }
  241.         }
  242.         if ($dsn['database']{
  243.             $params[0.= ' dbname=\'' addslashes($dsn['database']'\'';
  244.         }
  245.         if ($dsn['username']{
  246.             $params[0.= ' user=\'' addslashes($dsn['username']'\'';
  247.         }
  248.         if ($dsn['password']{
  249.             $params[0.= ' password=\'' addslashes($dsn['password']'\'';
  250.         }
  251.         if (!empty($dsn['options'])) {
  252.             $params[0.= ' options=' $dsn['options'];
  253.         }
  254.         if (!empty($dsn['tty'])) {
  255.             $params[0.= ' tty=' $dsn['tty'];
  256.         }
  257.         if (!empty($dsn['connect_timeout'])) {
  258.             $params[0.= ' connect_timeout=' $dsn['connect_timeout'];
  259.         }
  260.         if (!empty($dsn['sslmode'])) {
  261.             $params[0.= ' sslmode=' $dsn['sslmode'];
  262.         }
  263.         if (!empty($dsn['service'])) {
  264.             $params[0.= ' service=' $dsn['service'];
  265.         }
  266.  
  267.         if (isset($dsn['new_link'])
  268.             && ($dsn['new_link'== 'true' || $dsn['new_link'=== true))
  269.         {
  270.             if (version_compare(phpversion()'4.3.0''>=')) {
  271.                 $params[= PGSQL_CONNECT_FORCE_NEW;
  272.             }
  273.         }
  274.  
  275.         $connect_function $persistent 'pg_pconnect' 'pg_connect';
  276.  
  277.         $ini ini_get('track_errors');
  278.         $php_errormsg '';
  279.         if ($ini{
  280.             $this->connection = @call_user_func_array($connect_function,
  281.                                                       $params);
  282.         else {
  283.             @ini_set('track_errors'1);
  284.             $this->connection = @call_user_func_array($connect_function,
  285.                                                       $params);
  286.             @ini_set('track_errors'$ini);
  287.         }
  288.  
  289.         if (!$this->connection{
  290.             return $this->raiseError(DB_ERROR_CONNECT_FAILED,
  291.                                      nullnullnull,
  292.                                      $php_errormsg);
  293.         }
  294.         return DB_OK;
  295.     }
  296.  
  297.     // }}}
  298.     // {{{ disconnect()
  299.  
  300.     
  301.     /**
  302.      * Disconnects from the database server
  303.      *
  304.      * @return bool  TRUE on success, FALSE on failure
  305.      */
  306.     function disconnect()
  307.     {
  308.         $ret @pg_close($this->connection);
  309.         $this->connection = null;
  310.         return $ret;
  311.     }
  312.  
  313.     // }}}
  314.     // {{{ simpleQuery()
  315.  
  316.     
  317.     /**
  318.      * Sends a query to the database server
  319.      *
  320.      * @param string  the SQL query string
  321.      *
  322.      * @return mixed  + a PHP result resrouce for successful SELECT queries
  323.      *                 + the DB_OK constant for other successful queries
  324.      *                 + a DB_Error object on failure
  325.      */
  326.     function simpleQuery($query)
  327.     {
  328.         $ismanip $this->_checkManip($query);
  329.         $this->last_query = $query;
  330.         $query $this->modifyQuery($query);
  331.         if (!$this->autocommit && $ismanip{
  332.             if ($this->transaction_opcount == 0{
  333.                 $result @pg_exec($this->connection'begin;');
  334.                 if (!$result{
  335.                     return $this->pgsqlRaiseError();
  336.                 }
  337.             }
  338.             $this->transaction_opcount++;
  339.         }
  340.         $result @pg_exec($this->connection$query);
  341.         if (!$result{
  342.             return $this->pgsqlRaiseError();
  343.         }
  344.  
  345.         /*
  346.          * Determine whether queries produce affected rows, result or nothing.
  347.          *
  348.          * This logic was introduced in version 1.1 of the file by ssb,
  349.          * though the regex has been modified slightly since then.
  350.          *
  351.          * PostgreSQL commands:
  352.          * ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY,
  353.          * CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH,
  354.          * GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET,
  355.          * REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW,
  356.          * UNLISTEN, UPDATE, VACUUM
  357.          */
  358.         if ($ismanip{
  359.             $this->affected = @pg_affected_rows($result);
  360.             return DB_OK;
  361.         elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|FETCH|SHOW)\s/si',
  362.                              $query))
  363.         {
  364.             $this->row[(int)$result= 0; // reset the row counter.
  365.             $numrows $this->numRows($result);
  366.             if (is_object($numrows)) {
  367.                 return $numrows;
  368.             }
  369.             $this->_num_rows[(int)$result$numrows;
  370.             $this->affected = 0;
  371.             return $result;
  372.         else {
  373.             $this->affected = 0;
  374.             return DB_OK;
  375.         }
  376.     }
  377.  
  378.     // }}}
  379.     // {{{ nextResult()
  380.  
  381.     
  382.     /**
  383.      * Move the internal pgsql result pointer to the next available result
  384.      *
  385.      * @param valid fbsql result resource
  386.      *
  387.      * @access public
  388.      *
  389.      * @return true if a result is available otherwise return false
  390.      */
  391.     function nextResult($result)
  392.     {
  393.         return false;
  394.     }
  395.  
  396.     // }}}
  397.     // {{{ fetchInto()
  398.  
  399.     
  400.     /**
  401.      * Places a row from the result set into the given array
  402.      *
  403.      * Formating of the array and the data therein are configurable.
  404.      * See DB_result::fetchInto() for more information.
  405.      *
  406.      * This method is not meant to be called directly.  Use
  407.      * DB_result::fetchInto() instead.  It can't be declared "protected"
  408.      * because DB_result is a separate object.
  409.      *
  410.      * @param resource $result    the query result resource
  411.      * @param array    $arr       the referenced array to put the data in
  412.      * @param int      $fetchmode how the resulting array should be indexed
  413.      * @param int      $rownum    the row number to fetch (0 = first row)
  414.      *
  415.      * @return mixed  DB_OK on success, NULL when the end of a result set is
  416.      *                  reached or on failure
  417.      *
  418.      * @see DB_result::fetchInto()
  419.      */
  420.     function fetchInto($result&$arr$fetchmode$rownum = null)
  421.     {
  422.         $result_int = (int)$result;
  423.         $rownum ($rownum !== null$rownum $this->row[$result_int];
  424.         if ($rownum >= $this->_num_rows[$result_int]{
  425.             return null;
  426.         }
  427.         if ($fetchmode DB_FETCHMODE_ASSOC{
  428.             $arr @pg_fetch_array($result$rownumPGSQL_ASSOC);
  429.             if ($this->options['portability'DB_PORTABILITY_LOWERCASE && $arr{
  430.                 $arr array_change_key_case($arrCASE_LOWER);
  431.             }
  432.         else {
  433.             $arr @pg_fetch_row($result$rownum);
  434.         }
  435.         if (!$arr{
  436.             return null;
  437.         }
  438.         if ($this->options['portability'DB_PORTABILITY_RTRIM{
  439.             $this->_rtrimArrayValues($arr);
  440.         }
  441.         if ($this->options['portability'DB_PORTABILITY_NULL_TO_EMPTY{
  442.             $this->_convertNullArrayValuesToEmpty($arr);
  443.         }
  444.         $this->row[$result_int= ++$rownum;
  445.         return DB_OK;
  446.     }
  447.  
  448.     // }}}
  449.     // {{{ freeResult()
  450.  
  451.     
  452.     /**
  453.      * Deletes the result set and frees the memory occupied by the result set
  454.      *
  455.      * This method is not meant to be called directly.  Use
  456.      * DB_result::free() instead.  It can't be declared "protected"
  457.      * because DB_result is a separate object.
  458.      *
  459.      * @param resource $result  PHP's query result resource
  460.      *
  461.      * @return bool  TRUE on success, FALSE if $result is invalid
  462.      *
  463.      * @see DB_result::free()
  464.      */
  465.     function freeResult($result)
  466.     {
  467.         if (is_resource($result)) {
  468.             unset($this->row[(int)$result]);
  469.             unset($this->_num_rows[(int)$result]);
  470.             $this->affected = 0;
  471.             return @pg_freeresult($result);
  472.         }
  473.         return false;
  474.     }
  475.  
  476.     // }}}
  477.     // {{{ quote()
  478.  
  479.     
  480.     /**
  481.      * @deprecated  Deprecated in release 1.6.0
  482.      * @internal
  483.      */
  484.     function quote($str)
  485.     {
  486.         return $this->quoteSmart($str);
  487.     }
  488.  
  489.     // }}}
  490.     // {{{ quoteBoolean()
  491.  
  492.     
  493.     /**
  494.      * Formats a boolean value for use within a query in a locale-independent
  495.      * manner.
  496.      *
  497.      * @param boolean the boolean value to be quoted.
  498.      * @return string the quoted string.
  499.      * @see DB_common::quoteSmart()
  500.      * @since Method available since release 1.7.8.
  501.      */
  502.     function quoteBoolean($boolean{
  503.         return $boolean 'TRUE' 'FALSE';
  504.     }
  505.      
  506.     // }}}
  507.     // {{{ escapeSimple()
  508.  
  509.     
  510.     /**
  511.      * Escapes a string according to the current DBMS's standards
  512.      *
  513.      * {@internal PostgreSQL treats a backslash as an escape character,
  514.      * so they are escaped as well.
  515.      *
  516.      * @param string $str  the string to be escaped
  517.      *
  518.      * @return string  the escaped string
  519.      *
  520.      * @see DB_common::quoteSmart()
  521.      * @since Method available since Release 1.6.0
  522.      */
  523.     function escapeSimple($str)
  524.     {
  525.         if (function_exists('pg_escape_string')) {
  526.             return pg_escape_string($str);
  527.         else {
  528.             return str_replace("'""''"str_replace('\\''\\\\'$str));
  529.         }
  530.     }
  531.  
  532.     // }}}
  533.     // {{{ numCols()
  534.  
  535.     
  536.     /**
  537.      * Gets the number of columns in a result set
  538.      *
  539.      * This method is not meant to be called directly.  Use
  540.      * DB_result::numCols() instead.  It can't be declared "protected"
  541.      * because DB_result is a separate object.
  542.      *
  543.      * @param resource $result  PHP's query result resource
  544.      *
  545.      * @return int  the number of columns.  A DB_Error object on failure.
  546.      *
  547.      * @see DB_result::numCols()
  548.      */
  549.     function numCols($result)
  550.     {
  551.         $cols @pg_numfields($result);
  552.         if (!$cols{
  553.             return $this->pgsqlRaiseError();
  554.         }
  555.         return $cols;
  556.     }
  557.  
  558.     // }}}
  559.     // {{{ numRows()
  560.  
  561.     
  562.     /**
  563.      * Gets the number of rows in a result set
  564.      *
  565.      * This method is not meant to be called directly.  Use
  566.      * DB_result::numRows() instead.  It can't be declared "protected"
  567.      * because DB_result is a separate object.
  568.      *
  569.      * @param resource $result  PHP's query result resource
  570.      *
  571.      * @return int  the number of rows.  A DB_Error object on failure.
  572.      *
  573.      * @see DB_result::numRows()
  574.      */
  575.     function numRows($result)
  576.     {
  577.         $rows @pg_numrows($result);
  578.         if ($rows === null{
  579.             return $this->pgsqlRaiseError();
  580.         }
  581.         return $rows;
  582.     }
  583.  
  584.     // }}}
  585.     // {{{ autoCommit()
  586.  
  587.     
  588.     /**
  589.      * Enables or disables automatic commits
  590.      *
  591.      * @param bool $onoff  true turns it on, false turns it off
  592.      *
  593.      * @return int  DB_OK on success.  A DB_Error object if the driver
  594.      *                doesn't support auto-committing transactions.
  595.      */
  596.     function autoCommit($onoff = false)
  597.     {
  598.         // XXX if $this->transaction_opcount > 0, we should probably
  599.         // issue a warning here.
  600.         $this->autocommit $onoff ? true : false;
  601.         return DB_OK;
  602.     }
  603.  
  604.     // }}}
  605.     // {{{ commit()
  606.  
  607.     
  608.     /**
  609.      * Commits the current transaction
  610.      *
  611.      * @return int  DB_OK on success.  A DB_Error object on failure.
  612.      */
  613.     function commit()
  614.     {
  615.         if ($this->transaction_opcount > 0{
  616.             // (disabled) hack to shut up error messages from libpq.a
  617.             //@fclose(@fopen("php://stderr", "w"));
  618.             $result @pg_exec($this->connection'end;');
  619.             $this->transaction_opcount = 0;
  620.             if (!$result{
  621.                 return $this->pgsqlRaiseError();
  622.             }
  623.         }
  624.         return DB_OK;
  625.     }
  626.  
  627.     // }}}
  628.     // {{{ rollback()
  629.  
  630.     
  631.     /**
  632.      * Reverts the current transaction
  633.      *
  634.      * @return int  DB_OK on success.  A DB_Error object on failure.
  635.      */
  636.     function rollback()
  637.     {
  638.         if ($this->transaction_opcount > 0{
  639.             $result @pg_exec($this->connection'abort;');
  640.             $this->transaction_opcount = 0;
  641.             if (!$result{
  642.                 return $this->pgsqlRaiseError();
  643.             }
  644.         }
  645.         return DB_OK;
  646.     }
  647.  
  648.     // }}}
  649.     // {{{ affectedRows()
  650.  
  651.     
  652.     /**
  653.      * Determines the number of rows affected by a data maniuplation query
  654.      *
  655.      * 0 is returned for queries that don't manipulate data.
  656.      *
  657.      * @return int  the number of rows.  A DB_Error object on failure.
  658.      */
  659.     function affectedRows()
  660.     {
  661.         return $this->affected;
  662.     }
  663.  
  664.     // }}}
  665.     // {{{ nextId()
  666.  
  667.     
  668.     /**
  669.      * Returns the next free id in a sequence
  670.      *
  671.      * @param string  $seq_name  name of the sequence
  672.      * @param boolean $ondemand  when true, the seqence is automatically
  673.      *                             created if it does not exist
  674.      *
  675.      * @return int  the next id number in the sequence.
  676.      *  &nb