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

Source for file pgsql.php

Documentation is available at pgsql.php

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

Documentation generated on Mon, 11 Mar 2019 10:15:31 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.