Source for file ibase.php

Documentation is available at ibase.php

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * The PEAR DB driver for PHP's interbase extension
  7.  * for interacting with Interbase and Firebird databases
  8.  *
  9.  * While this class works with PHP 4, PHP's InterBase extension is
  10.  * unstable in PHP 4.  Use PHP 5.
  11.  *
  12.  * PHP versions 4 and 5
  13.  *
  14.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  15.  * that is available through the world-wide-web at the following URI:
  16.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  17.  * the PHP License and are unable to obtain it through the web, please
  18.  * send a note to license@php.net so we can mail you a copy immediately.
  19.  *
  20.  * @category   Database
  21.  * @package    DB
  22.  * @author     Sterling Hughes <sterling@php.net>
  23.  * @author     Daniel Convissor <danielc@php.net>
  24.  * @copyright  1997-2007 The PHP Group
  25.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  26.  * @version    CVS: $Id: ibase.php,v 1.116 2007/09/21 13:40:41 aharvey Exp $
  27.  * @link       http://pear.php.net/package/DB
  28.  */
  29.  
  30. /**
  31.  * Obtain the DB_common class so it can be extended from
  32.  */
  33. require_once DB_PEAR_PATH.'DB/common.php';
  34.  
  35. /**
  36.  * The methods PEAR DB uses to interact with PHP's interbase extension
  37.  * for interacting with Interbase and Firebird databases
  38.  *
  39.  * These methods overload the ones declared in DB_common.
  40.  *
  41.  * While this class works with PHP 4, PHP's InterBase extension is
  42.  * unstable in PHP 4.  Use PHP 5.
  43.  *
  44.  * NOTICE:  limitQuery() only works for Firebird.
  45.  *
  46.  * @category   Database
  47.  * @package    DB
  48.  * @author     Sterling Hughes <sterling@php.net>
  49.  * @author     Daniel Convissor <danielc@php.net>
  50.  * @copyright  1997-2007 The PHP Group
  51.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  52.  * @version    Release: 1.7.13
  53.  * @link       http://pear.php.net/package/DB
  54.  * @since      Class became stable in Release 1.7.0
  55.  */
  56. class DB_ibase extends DB_common
  57. {
  58.     // {{{ properties
  59.  
  60.     /**
  61.      * The DB driver type (mysql, oci8, odbc, etc.)
  62.      * @var string 
  63.      */
  64.     var $phptype = 'ibase';
  65.  
  66.     /**
  67.      * The database syntax variant to be used (db2, access, etc.), if any
  68.      * @var string 
  69.      */
  70.     var $dbsyntax = 'ibase';
  71.  
  72.     /**
  73.      * The capabilities of this DB implementation
  74.      *
  75.      * The 'new_link' element contains the PHP version that first provided
  76.      * new_link support for this DBMS.  Contains false if it's unsupported.
  77.      *
  78.      * Meaning of the 'limit' element:
  79.      *   + 'emulate' = emulate with fetch row by number
  80.      *   + 'alter'   = alter the query
  81.      *   + false     = skip rows
  82.      *
  83.      * NOTE: only firebird supports limit.
  84.      *
  85.      * @var array 
  86.      */
  87.     var $features = array(
  88.         'limit'         => false,
  89.         'new_link'      => false,
  90.         'numrows'       => 'emulate',
  91.         'pconnect'      => true,
  92.         'prepare'       => true,
  93.         'ssl'           => false,
  94.         'transactions'  => true,
  95.     );
  96.  
  97.     /**
  98.      * A mapping of native error codes to DB error codes
  99.      * @var array 
  100.      */
  101.     var $errorcode_map = array(
  102.         -104 => DB_ERROR_SYNTAX,
  103.         -150 => DB_ERROR_ACCESS_VIOLATION,
  104.         -151 => DB_ERROR_ACCESS_VIOLATION,
  105.         -155 => DB_ERROR_NOSUCHTABLE,
  106.         -157 => DB_ERROR_NOSUCHFIELD,
  107.         -158 => DB_ERROR_VALUE_COUNT_ON_ROW,
  108.         -170 => DB_ERROR_MISMATCH,
  109.         -171 => DB_ERROR_MISMATCH,
  110.         -172 => DB_ERROR_INVALID,
  111.         // -204 =>  // Covers too many errors, need to use regex on msg
  112.         -205 => DB_ERROR_NOSUCHFIELD,
  113.         -206 => DB_ERROR_NOSUCHFIELD,
  114.         -208 => DB_ERROR_INVALID,
  115.         -219 => DB_ERROR_NOSUCHTABLE,
  116.         -297 => DB_ERROR_CONSTRAINT,
  117.         -303 => DB_ERROR_INVALID,
  118.         -413 => DB_ERROR_INVALID_NUMBER,
  119.         -530 => DB_ERROR_CONSTRAINT,
  120.         -551 => DB_ERROR_ACCESS_VIOLATION,
  121.         -552 => DB_ERROR_ACCESS_VIOLATION,
  122.         // -607 =>  // Covers too many errors, need to use regex on msg
  123.         -625 => DB_ERROR_CONSTRAINT_NOT_NULL,
  124.         -803 => DB_ERROR_CONSTRAINT,
  125.         -804 => DB_ERROR_VALUE_COUNT_ON_ROW,
  126.         // -902 =>  // Covers too many errors, need to use regex on msg
  127.         -904 => DB_ERROR_CONNECT_FAILED,
  128.         -922 => DB_ERROR_NOSUCHDB,
  129.         -923 => DB_ERROR_CONNECT_FAILED,
  130.         -924 => DB_ERROR_CONNECT_FAILED
  131.     );
  132.  
  133.     /**
  134.      * The raw database connection created by PHP
  135.      * @var resource 
  136.      */
  137.     var $connection;
  138.  
  139.     /**
  140.      * The DSN information for connecting to a database
  141.      * @var array 
  142.      */
  143.     var $dsn = array();
  144.  
  145.  
  146.     /**
  147.      * The number of rows affected by a data manipulation query
  148.      * @var integer 
  149.      * @access private
  150.      */
  151.     var $affected 0;
  152.  
  153.     /**
  154.      * Should data manipulation queries be committed automatically?
  155.      * @var bool 
  156.      * @access private
  157.      */
  158.     var $autocommit true;
  159.  
  160.     /**
  161.      * The prepared statement handle from the most recently executed statement
  162.      *
  163.      * {@internal  Mainly here because the InterBase/Firebird API is only
  164.      * able to retrieve data from result sets if the statemnt handle is
  165.      * still in scope.}}}
  166.      *
  167.      * @var resource 
  168.      */
  169.     var $last_stmt;
  170.  
  171.     /**
  172.      * Is the given prepared statement a data manipulation query?
  173.      * @var array 
  174.      * @access private
  175.      */
  176.     var $manip_query array();
  177.  
  178.  
  179.     // }}}
  180.     // {{{ constructor
  181.  
  182.     /**
  183.      * This constructor calls <kbd>$this->DB_common()</kbd>
  184.      *
  185.      * @return void 
  186.      */
  187.     function DB_ibase()
  188.     {
  189.         $this->DB_common();
  190.     }
  191.  
  192.     // }}}
  193.     // {{{ connect()
  194.  
  195.     /**
  196.      * Connect to the database server, log in and open the database
  197.      *
  198.      * Don't call this method directly.  Use DB::connect() instead.
  199.      *
  200.      * PEAR DB's ibase driver supports the following extra DSN options:
  201.      *   + buffers    The number of database buffers to allocate for the
  202.      *                 server-side cache.
  203.      *   + charset    The default character set for a database.
  204.      *   + dialect    The default SQL dialect for any statement
  205.      *                 executed within a connection.  Defaults to the
  206.      *                 highest one supported by client libraries.
  207.      *                 Functional only with InterBase 6 and up.
  208.      *   + role       Functional only with InterBase 5 and up.
  209.      *
  210.      * @param array $dsn         the data source name
  211.      * @param bool  $persistent  should the connection be persistent?
  212.      *
  213.      * @return int  DB_OK on success. A DB_Error object on failure.
  214.      */
  215.     function connect($dsn$persistent false)
  216.     {
  217.         if (!PEAR::loadExtension('interbase')) {
  218.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  219.         }
  220.  
  221.         $this->dsn = $dsn;
  222.         if ($dsn['dbsyntax']{
  223.             $this->dbsyntax = $dsn['dbsyntax'];
  224.         }
  225.         if ($this->dbsyntax == 'firebird'{
  226.             $this->features['limit''alter';
  227.         }
  228.  
  229.         $params array(
  230.             $dsn['hostspec']
  231.                     ? ($dsn['hostspec'':' $dsn['database'])
  232.                     : $dsn['database'],
  233.             $dsn['username'$dsn['username'null,
  234.             $dsn['password'$dsn['password'null,
  235.             isset($dsn['charset']$dsn['charset'null,
  236.             isset($dsn['buffers']$dsn['buffers'null,
  237.             isset($dsn['dialect']$dsn['dialect'null,
  238.             isset($dsn['role'])    $dsn['role'null,
  239.         );
  240.  
  241.         $connect_function $persistent 'ibase_pconnect' 'ibase_connect';
  242.  
  243.         $this->connection = @call_user_func_array($connect_function$params);
  244.         if (!$this->connection{
  245.             return $this->ibaseRaiseError(DB_ERROR_CONNECT_FAILED);
  246.         }
  247.         return DB_OK;
  248.     }
  249.  
  250.     // }}}
  251.     // {{{ disconnect()
  252.  
  253.     /**
  254.      * Disconnects from the database server
  255.      *
  256.      * @return bool  TRUE on success, FALSE on failure
  257.      */
  258.     function disconnect()
  259.     {
  260.         $ret @ibase_close($this->connection);
  261.         $this->connection = null;
  262.         return $ret;
  263.     }
  264.  
  265.     // }}}
  266.     // {{{ simpleQuery()
  267.  
  268.     /**
  269.      * Sends a query to the database server
  270.      *
  271.      * @param string  the SQL query string
  272.      *
  273.      * @return mixed  + a PHP result resrouce for successful SELECT queries
  274.      *                 + the DB_OK constant for other successful queries
  275.      *                 + a DB_Error object on failure
  276.      */
  277.     function simpleQuery($query)
  278.     {
  279.         $ismanip $this->_checkManip($query);
  280.         $this->last_query = $query;
  281.         $query $this->modifyQuery($query);
  282.         $result @ibase_query($this->connection$query);
  283.  
  284.         if (!$result{
  285.             return $this->ibaseRaiseError();
  286.         }
  287.         if ($this->autocommit && $ismanip{
  288.             @ibase_commit($this->connection);
  289.         }
  290.         if ($ismanip{
  291.             $this->affected $result;
  292.             return DB_OK;
  293.         else {
  294.             $this->affected 0;
  295.             return $result;
  296.         }
  297.     }
  298.  
  299.     // }}}
  300.     // {{{ modifyLimitQuery()
  301.  
  302.     /**
  303.      * Adds LIMIT clauses to a query string according to current DBMS standards
  304.      *
  305.      * Only works with Firebird.
  306.      *
  307.      * @param string $query   the query to modify
  308.      * @param int    $from    the row to start to fetching (0 = the first row)
  309.      * @param int    $count   the numbers of rows to fetch
  310.      * @param mixed  $params  array, string or numeric data to be used in
  311.      *                          execution of the statement.  Quantity of items
  312.      *                          passed must match quantity of placeholders in
  313.      *                          query:  meaning 1 placeholder for non-array
  314.      *                          parameters or 1 placeholder per array element.
  315.      *
  316.      * @return string  the query string with LIMIT clauses added
  317.      *
  318.      * @access protected
  319.      */
  320.     function modifyLimitQuery($query$from$count$params array())
  321.     {
  322.         if ($this->dsn['dbsyntax'== 'firebird'{
  323.             $query preg_replace('/^([\s(])*SELECT/i',
  324.                                   "SELECT FIRST $count SKIP $from"$query);
  325.         }
  326.         return $query;
  327.     }
  328.  
  329.     // }}}
  330.     // {{{ nextResult()
  331.  
  332.     /**
  333.      * Move the internal ibase result pointer to the next available result
  334.      *
  335.      * @param valid fbsql result resource
  336.      *
  337.      * @access public
  338.      *
  339.      * @return true if a result is available otherwise return false
  340.      */
  341.     function nextResult($result)
  342.     {
  343.         return false;
  344.     }
  345.  
  346.     // }}}
  347.     // {{{ fetchInto()
  348.  
  349.     /**
  350.      * Places a row from the result set into the given array
  351.      *
  352.      * Formating of the array and the data therein are configurable.
  353.      * See DB_result::fetchInto() for more information.
  354.      *
  355.      * This method is not meant to be called directly.  Use
  356.      * DB_result::fetchInto() instead.  It can't be declared "protected"
  357.      * because DB_result is a separate object.
  358.      *
  359.      * @param resource $result    the query result resource
  360.      * @param array    $arr       the referenced array to put the data in
  361.      * @param int      $fetchmode how the resulting array should be indexed
  362.      * @param int      $rownum    the row number to fetch (0 = first row)
  363.      *
  364.      * @return mixed  DB_OK on success, NULL when the end of a result set is
  365.      *                  reached or on failure
  366.      *
  367.      * @see DB_result::fetchInto()
  368.      */
  369.     function fetchInto($result&$arr$fetchmode$rownum null)
  370.     {
  371.         if ($rownum !== null{
  372.             return $this->ibaseRaiseError(DB_ERROR_NOT_CAPABLE);
  373.         }
  374.         if ($fetchmode DB_FETCHMODE_ASSOC{
  375.             if (function_exists('ibase_fetch_assoc')) {
  376.                 $arr @ibase_fetch_assoc($result);
  377.             else {
  378.                 $arr get_object_vars(ibase_fetch_object($result));
  379.             }
  380.             if ($this->options['portability'DB_PORTABILITY_LOWERCASE && $arr{
  381.                 $arr array_change_key_case($arrCASE_LOWER);
  382.             }
  383.         else {
  384.             $arr @ibase_fetch_row($result);
  385.         }
  386.         if (!$arr{
  387.             return null;
  388.         }
  389.         if ($this->options['portability'DB_PORTABILITY_RTRIM{
  390.             $this->_rtrimArrayValues($arr);
  391.         }
  392.         if ($this->options['portability'DB_PORTABILITY_NULL_TO_EMPTY{
  393.             $this->_convertNullArrayValuesToEmpty($arr);
  394.         }
  395.         return DB_OK;
  396.     }
  397.  
  398.     // }}}
  399.     // {{{ freeResult()
  400.  
  401.     /**
  402.      * Deletes the result set and frees the memory occupied by the result set
  403.      *
  404.      * This method is not meant to be called directly.  Use
  405.      * DB_result::free() instead.  It can't be declared "protected"
  406.      * because DB_result is a separate object.
  407.      *
  408.      * @param resource $result  PHP's query result resource
  409.      *
  410.      * @return bool  TRUE on success, FALSE if $result is invalid
  411.      *
  412.      * @see DB_result::free()
  413.      */
  414.     function freeResult($result)
  415.     {
  416.         return is_resource($resultibase_free_result($resultfalse;
  417.     }
  418.  
  419.     // }}}
  420.     // {{{ freeQuery()
  421.  
  422.     function freeQuery($query)
  423.     {
  424.         return is_resource($queryibase_free_query($queryfalse;
  425.     }
  426.  
  427.     // }}}
  428.     // {{{ affectedRows()
  429.  
  430.     /**
  431.      * Determines the number of rows affected by a data maniuplation query
  432.      *
  433.      * 0 is returned for queries that don't manipulate data.
  434.      *
  435.      * @return int  the number of rows.  A DB_Error object on failure.
  436.      */
  437.     function affectedRows()
  438.     {
  439.         if (is_integer($this->affected)) {
  440.             return $this->affected;
  441.         }
  442.         return $this->ibaseRaiseError(DB_ERROR_NOT_CAPABLE);
  443.     }
  444.  
  445.     // }}}
  446.     // {{{ numCols()
  447.  
  448.     /**
  449.      * Gets the number of columns in a result set
  450.      *
  451.      * This method is not meant to be called directly.  Use
  452.      * DB_result::numCols() instead.  It can't be declared "protected"
  453.      * because DB_result is a separate object.
  454.      *
  455.      * @param resource $result  PHP's query result resource
  456.      *
  457.      * @return int  the number of columns.  A DB_Error object on failure.
  458.      *
  459.      * @see DB_result::numCols()
  460.      */
  461.     function numCols($result)
  462.     {
  463.         $cols @ibase_num_fields($result);
  464.         if (!$cols{
  465.             return $this->ibaseRaiseError();
  466.         }
  467.         return $cols;
  468.     }
  469.  
  470.     // }}}
  471.     // {{{ prepare()
  472.  
  473.     /**
  474.      * Prepares a query for multiple execution with execute().
  475.      *
  476.      * prepare() requires a generic query as string like <code>
  477.      *    INSERT INTO numbers VALUES (?, ?, ?)
  478.      * </code>.  The <kbd>?</kbd> characters are placeholders.
  479.      *
  480.      * Three types of placeholders can be used:
  481.      *   + <kbd>?</kbd>  a quoted scalar value, i.e. strings, integers
  482.      *   + <kbd>!</kbd>  value is inserted 'as is'
  483.      *   + <kbd>&</kbd>  requires a file name.  The file's contents get
  484.      *                     inserted into the query (i.e. saving binary
  485.      *                     data in a db)
  486.      *
  487.      * Use backslashes to escape placeholder characters if you don't want
  488.      * them to be interpreted as placeholders.  Example: <code>
  489.      *    "UPDATE foo SET col=? WHERE col='over \& under'"
  490.      * </code>
  491.      *
  492.      * @param string $query query to be prepared
  493.      * @return mixed DB statement resource on success. DB_Error on failure.
  494.      */
  495.     function prepare($query)
  496.     {
  497.         $tokens   preg_split('/((?<!\\\)[&?!])/'$query-1,
  498.                                PREG_SPLIT_DELIM_CAPTURE);
  499.         $token    0;
  500.         $types    array();
  501.         $newquery '';
  502.  
  503.         foreach ($tokens as $key => $val{
  504.             switch ($val{
  505.                 case '?':
  506.                     $types[$token++DB_PARAM_SCALAR;
  507.                     break;
  508.                 case '&':
  509.                     $types[$token++DB_PARAM_OPAQUE;
  510.                     break;
  511.                 case '!':
  512.                     $types[$token++DB_PARAM_MISC;
  513.                     break;
  514.                 default:
  515.                     $tokens[$keypreg_replace('/\\\([&?!])/'"\\1"$val);
  516.                     $newquery .= $tokens[$key'?';
  517.             }
  518.         }
  519.  
  520.         $newquery substr($newquery0-1);
  521.         $this->last_query = $query;
  522.         $newquery $this->modifyQuery($newquery);
  523.         $stmt @ibase_prepare($this->connection$newquery);
  524.  
  525.         if ($stmt === false{
  526.             $stmt $this->ibaseRaiseError();
  527.         else {
  528.             $this->prepare_types[(int)$stmt$types;
  529.             $this->manip_query[(int)$stmt]   DB::isManip($query);
  530.         }
  531.  
  532.         return $stmt;
  533.     }
  534.  
  535.     // }}}
  536.     // {{{ execute()
  537.  
  538.     /**
  539.      * Executes a DB statement prepared with prepare().
  540.      *
  541.      * @param resource  $stmt  a DB statement resource returned from prepare()
  542.      * @param mixed  $data  array, string or numeric data to be used in
  543.      *                       execution of the statement.  Quantity of items
  544.      *                       passed must match quantity of placeholders in
  545.      *                       query:  meaning 1 for non-array items or the
  546.      *                       quantity of elements in the array.
  547.      * @return object  new DB_Result or a DB_Error when fail
  548.      * @see DB_ibase::prepare()
  549.      * @access public
  550.      */
  551.     function &execute($stmt$data array())
  552.     {
  553.         $data = (array)$data;
  554.         $this->last_parameters = $data;
  555.  
  556.         $types $this->prepare_types[(int)$stmt];
  557.         if (count($types!= count($data)) {
  558.             $tmp $this->raiseError(DB_ERROR_MISMATCH);
  559.             return $tmp;
  560.         }
  561.  
  562.         $i 0;
  563.         foreach ($data as $key => $value{
  564.             if ($types[$i== DB_PARAM_MISC{
  565.                 /*
  566.                  * ibase doesn't seem to have the ability to pass a
  567.                  * parameter along unchanged, so strip off quotes from start
  568.                  * and end, plus turn two single quotes to one single quote,
  569.                  * in order to avoid the quotes getting escaped by
  570.                  * ibase and ending up in the database.
  571.                  */
  572.                 $data[$keypreg_replace("/^'(.*)'$/""\\1"$data[$key]);
  573.                 $data[$keystr_replace("''""'"$data[$key]);
  574.             elseif ($types[$i== DB_PARAM_OPAQUE{
  575.                 $fp @fopen($data[$key]'rb');
  576.                 if (!$fp{
  577.                     $tmp $this->raiseError(DB_ERROR_ACCESS_VIOLATION);
  578.                     return $tmp;
  579.                 }
  580.                 $data[$keyfread($fpfilesize($data[$key]));
  581.                 fclose($fp);
  582.             }
  583.             $i++;
  584.         }
  585.  
  586.         array_unshift($data$stmt);
  587.  
  588.         $res call_user_func_array('ibase_execute'$data);
  589.         if (!$res{
  590.             $tmp $this->ibaseRaiseError();
  591.             return $tmp;
  592.         }
  593.         /* XXX need this?
  594.         if ($this->autocommit && $this->manip_query[(int)$stmt]) {
  595.             @ibase_commit($this->connection);
  596.         }*/
  597.         $this->last_stmt = $stmt;
  598.         if ($this->manip_query[(int)$stmt|| $this->_next_query_manip{
  599.             $this->_last_query_manip = true;
  600.             $this->_next_query_manip = false;
  601.             $tmp DB_OK;
  602.         else {
  603.             $this->_last_query_manip = false;
  604.             $tmp new DB_result($this$res);
  605.         }
  606.         return $tmp;
  607.     }
  608.  
  609.     /**
  610.      * Frees the internal resources associated with a prepared query
  611.      *
  612.      * @param resource $stmt           the prepared statement's PHP resource
  613.      * @param bool     $free_resource  should the PHP resource be freed too?
  614.      *                                   Use false if you need to get data
  615.      *                                   from the result set later.
  616.      *
  617.      * @return bool  TRUE on success, FALSE if $result is invalid
  618.      *
  619.      * @see DB_ibase::prepare()
  620.      */
  621.     function freePrepared($stmt$free_resource true)
  622.     {
  623.         if (!is_resource($stmt)) {
  624.             return false;
  625.         }
  626.         if ($free_resource{
  627.             @ibase_free_query($stmt);
  628.         }
  629.         unset($this->prepare_tokens[(int)$stmt]);
  630.         unset($this->prepare_types[(int)$stmt]);
  631.         unset($this->manip_query[(int)$stmt]);
  632.         return true;
  633.     }
  634.  
  635.     // }}}
  636.     // {{{ autoCommit()
  637.  
  638.     /**
  639.      * Enables or disables automatic commits
  640.      *
  641.      * @param bool $onoff  true turns it on, false turns it off
  642.      *
  643.      * @return int  DB_OK on success.  A DB_Error object if the driver
  644.      *                doesn't support auto-committing transactions.
  645.      */
  646.     function autoCommit($onoff false)
  647.     {
  648.         $this->autocommit $onoff 0;
  649.         return DB_OK;
  650.     }
  651.  
  652.     // }}}
  653.     // {{{ commit()
  654.  
  655.     /**
  656.      * Commits the current transaction
  657.      *
  658.      * @return int  DB_OK on success.  A DB_Error object on failure.
  659.      */
  660.     function commit()
  661.     {
  662.         return @ibase_commit($this->connection);
  663.     }
  664.  
  665.     // }}}
  666.     // {{{ rollback()
  667.  
  668.     /**
  669.      * Reverts the current transaction
  670.      *
  671.      * @return int  DB_OK on success.  A DB_Error object on failure.
  672.      */
  673.     function rollback()
  674.     {
  675.         return @ibase_rollback($this->connection);
  676.     }
  677.  
  678.     // }}}
  679.     // {{{ transactionInit()
  680.  
  681.     function transactionInit($trans_args 0)
  682.     {
  683.         return $trans_args
  684.                 ? @ibase_trans($trans_args$this->connection)
  685.                 : @ibase_trans();
  686.     }
  687.  
  688.     // }}}
  689.     // {{{ nextId()
  690.  
  691.     /**
  692.      * Returns the next free id in a sequence
  693.      *
  694.      * @param string  $seq_name  name of the sequence
  695.      * @param boolean $ondemand  when true, the seqence is automatically
  696.      *                             created if it does not exist
  697.      *
  698.      * @return int  the next id number in the sequence.
  699.      *                A DB_Error object on failure.
  700.      *
  701.      * @see DB_common::nextID(), DB_common::getSequenceName(),
  702.      *       DB_ibase::createSequence(), DB_ibase::dropSequence()
  703.      */
  704.     function nextId($seq_name$ondemand true)
  705.     {
  706.         $sqn strtoupper($this->getSequenceName($seq_name));
  707.         $repeat 0;
  708.         do {
  709.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  710.             $result $this->query("SELECT GEN_ID(${sqn}, 1) "
  711.                                    . 'FROM RDB$GENERATORS '
  712.                                    . "WHERE RDB\$GENERATOR_NAME='${sqn}'");
  713.             $this->popErrorHandling();
  714.             if ($ondemand && DB::isError($result)) {
  715.                 $repeat 1;
  716.                 $result $this->createSequence($seq_name);
  717.                 if (DB::isError($result)) {
  718.                     return $result;
  719.                 }
  720.             else {
  721.                 $repeat 0;
  722.             }
  723.         while ($repeat);
  724.         if (DB::isError($result)) {
  725.             return $this->raiseError($result);
  726.         }
  727.         $arr $result->fetchRow(DB_FETCHMODE_ORDERED);
  728.         $result->free();
  729.         return $arr[0];
  730.     }
  731.  
  732.     // }}}
  733.     // {{{ createSequence()
  734.  
  735.     /**
  736.      * Creates a new sequence
  737.      *
  738.      * @param string $seq_name  name of the new sequence
  739.      *
  740.      * @return int  DB_OK on success.  A DB_Error object on failure.
  741.      *
  742.      * @see DB_common::createSequence(), DB_common::getSequenceName(),
  743.      *       DB_ibase::nextID(), DB_ibase::dropSequence()
  744.      */
  745.     function createSequence($seq_name)
  746.     {
  747.         $sqn strtoupper($this->getSequenceName($seq_name));
  748.         $this->pushErrorHandling(PEAR_ERROR_RETURN);
  749.         $result $this->query("CREATE GENERATOR ${sqn}");
  750.         $this->popErrorHandling();
  751.  
  752.         return $result;
  753.     }
  754.  
  755.     // }}}
  756.     // {{{ dropSequence()
  757.  
  758.     /**
  759.      * Deletes a sequence
  760.      *
  761.      * @param string $seq_name  name of the sequence to be deleted
  762.      *
  763.      * @return int  DB_OK on success.  A DB_Error object on failure.
  764.      *
  765.      * @see DB_common::dropSequence(), DB_common::getSequenceName(),
  766.      *       DB_ibase::nextID(), DB_ibase::createSequence()
  767.      */
  768.     function dropSequence($seq_name)
  769.     {
  770.         return $this->query('DELETE FROM RDB$GENERATORS '
  771.                             . "WHERE RDB\$GENERATOR_NAME='"
  772.                             . strtoupper($this->getSequenceName($seq_name))
  773.                             . "'");
  774.     }
  775.  
  776.     // }}}
  777.     // {{{ _ibaseFieldFlags()
  778.  
  779.     /**
  780.      * Get the column's flags
  781.      *
  782.      * Supports "primary_key", "unique_key", "not_null", "default",
  783.      * "computed" and "blob".
  784.      *
  785.      * @param string $field_name  the name of the field
  786.      * @param string $table_name  the name of the table
  787.      *
  788.      * @return string  the flags
  789.      *
  790.      * @access private
  791.      */
  792.     function _ibaseFieldFlags($field_name$table_name)
  793.     {
  794.         $sql 'SELECT R.RDB$CONSTRAINT_TYPE CTYPE'
  795.                .' FROM RDB$INDEX_SEGMENTS I'
  796.                .'  JOIN RDB$RELATION_CONSTRAINTS R ON I.RDB$INDEX_NAME=R.RDB$INDEX_NAME'
  797.                .' WHERE I.RDB$FIELD_NAME=\'' $field_name '\''
  798.                .'  AND UPPER(R.RDB$RELATION_NAME)=\'' strtoupper($table_name'\'';
  799.  
  800.         $result @ibase_query($this->connection$sql);
  801.         if (!$result{
  802.             return $this->ibaseRaiseError();
  803.         }
  804.  
  805.         $flags '';
  806.         if ($obj @ibase_fetch_object($result)) {
  807.             @ibase_free_result($result);
  808.             if (isset($obj->CTYPE)  && trim($obj->CTYPE== 'PRIMARY KEY'{
  809.                 $flags .= 'primary_key ';
  810.             }
  811.             if (isset($obj->CTYPE)  && trim($obj->CTYPE== 'UNIQUE'{
  812.                 $flags .= 'unique_key ';
  813.             }
  814.         }
  815.  
  816.         $sql 'SELECT R.RDB$NULL_FLAG AS NFLAG,'
  817.                .'  R.RDB$DEFAULT_SOURCE AS DSOURCE,'
  818.                .'  F.RDB$FIELD_TYPE AS FTYPE,'
  819.                .'  F.RDB$COMPUTED_SOURCE AS CSOURCE'
  820.                .' FROM RDB$RELATION_FIELDS R '
  821.                .'  JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME'
  822.                .' WHERE UPPER(R.RDB$RELATION_NAME)=\'' strtoupper($table_name'\''
  823.                .'  AND R.RDB$FIELD_NAME=\'' $field_name '\'';
  824.  
  825.         $result @ibase_query($this->connection$sql);
  826.         if (!$result{
  827.             return $this->ibaseRaiseError();
  828.         }
  829.         if ($obj @ibase_fetch_object($result)) {
  830.             @ibase_free_result($result);
  831.             if (isset($obj->NFLAG)) {
  832.                 $flags .= 'not_null ';
  833.             }
  834.             if (isset($obj->DSOURCE)) {
  835.                 $flags .= 'default ';
  836.             }
  837.             if (isset($obj->CSOURCE)) {
  838.                 $flags .= 'computed ';
  839.             }
  840.             if (isset($obj->FTYPE)  && $obj->FTYPE == 261{
  841.                 $flags .= 'blob ';
  842.             }
  843.         }
  844.  
  845.         return trim($flags);
  846.     }
  847.  
  848.     // }}}
  849.     // {{{ ibaseRaiseError()
  850.  
  851.     /**
  852.      * Produces a DB_Error object regarding the current problem
  853.      *
  854.      * @param int $errno  if the error is being manually raised pass a
  855.      *                      DB_ERROR* constant here.  If this isn't passed
  856.      *                      the error information gathered from the DBMS.
  857.      *
  858.      * @return object  the DB_Error object
  859.      *
  860.      * @see DB_common::raiseError(),
  861.      *       DB_ibase::errorNative(), DB_ibase::errorCode()
  862.      */
  863.     function &ibaseRaiseError($errno null)
  864.     {
  865.         if ($errno === null{
  866.             $errno $this->errorCode($this->errorNative());
  867.         }
  868.         $tmp $this->raiseError($errnonullnullnull@ibase_errmsg());
  869.         return $tmp;
  870.     }
  871.  
  872.     // }}}
  873.     // {{{ errorNative()
  874.  
  875.     /**
  876.      * Gets the DBMS' native error code produced by the last query
  877.      *
  878.      * @return int  the DBMS' error code.  NULL if there is no error code.
  879.      *
  880.      * @since Method available since Release 1.7.0
  881.      */
  882.     function errorNative()
  883.     {
  884.         if (function_exists('ibase_errcode')) {
  885.             return @ibase_errcode();
  886.         }
  887.         if (preg_match('/^Dynamic SQL Error SQL error code = ([0-9-]+)/i',
  888.                        @ibase_errmsg()$m)) {
  889.             return (int)$m[1];
  890.         }
  891.         return null;
  892.     }
  893.  
  894.     // }}}
  895.     // {{{ errorCode()
  896.  
  897.     /**
  898.      * Maps native error codes to DB's portable ones
  899.      *
  900.      * @param int $nativecode  the error code returned by the DBMS
  901.      *
  902.      * @return int  the portable DB error code.  Return DB_ERROR if the
  903.      *                current driver doesn't have a mapping for the
  904.      *                $nativecode submitted.
  905.      *
  906.      * @since Method available since Release 1.7.0
  907.      */
  908.     function errorCode($nativecode null)
  909.     {
  910.         if (isset($this->errorcode_map[$nativecode])) {
  911.             return $this->errorcode_map[$nativecode];
  912.         }
  913.  
  914.         static $error_regexps;
  915.         if (!isset($error_regexps)) {
  916.             $error_regexps array(
  917.                 '/generator .* is not defined/'
  918.                     => DB_ERROR_SYNTAX,  // for compat. w ibase_errcode()
  919.                 '/table.*(not exist|not found|unknown)/i'
  920.                     => DB_ERROR_NOSUCHTABLE,
  921.                 '/table .* already exists/i'
  922.                     => DB_ERROR_ALREADY_EXISTS,
  923.                 '/unsuccessful metadata update .* failed attempt to store duplicate value/i'
  924.                     => DB_ERROR_ALREADY_EXISTS,
  925.                 '/unsuccessful metadata update .* not found/i'
  926.                     => DB_ERROR_NOT_FOUND,
  927.                 '/validation error for column .* value "\*\*\* null/i'
  928.                     => DB_ERROR_CONSTRAINT_NOT_NULL,
  929.                 '/violation of [\w ]+ constraint/i'
  930.                     => DB_ERROR_CONSTRAINT,
  931.                 '/conversion error from string/i'
  932.                     => DB_ERROR_INVALID_NUMBER,
  933.                 '/no permission for/i'
  934.                     => DB_ERROR_ACCESS_VIOLATION,
  935.                 '/arithmetic exception, numeric overflow, or string truncation/i'
  936.                     => DB_ERROR_INVALID,
  937.                 '/feature is not supported/i'
  938.                     => DB_ERROR_NOT_CAPABLE,
  939.             );
  940.         }
  941.  
  942.         $errormsg @ibase_errmsg();
  943.         foreach ($error_regexps as $regexp => $code{
  944.             if (preg_match($regexp$errormsg)) {
  945.                 return $code;
  946.             }
  947.         }
  948.         return DB_ERROR;
  949.     }
  950.  
  951.     // }}}
  952.     // {{{ tableInfo()
  953.  
  954.     /**
  955.      * Returns information about a table or a result set
  956.      *
  957.      * NOTE: only supports 'table' and 'flags' if <var>$result</var>
  958.      * is a table name.
  959.      *
  960.      * @param object|string $result  DB_result object from a query or a
  961.      *                                  string containing the name of a table.
  962.      *                                  While this also accepts a query result
  963.      *                                  resource identifier, this behavior is
  964.      *                                  deprecated.
  965.      * @param int            $mode    a valid tableInfo mode
  966.      *
  967.      * @return array  an associative array with the information requested.
  968.      *                  A DB_Error object on failure.
  969.      *
  970.      * @see DB_common::tableInfo()
  971.      */
  972.     function tableInfo($result$mode null)
  973.     {
  974.         if (is_string($result)) {
  975.             /*
  976.              * Probably received a table name.
  977.              * Create a result resource identifier.
  978.              */
  979.             $id @ibase_query($this->connection,
  980.                                "SELECT * FROM $result WHERE 1=0");
  981.             $got_string true;
  982.         elseif (isset($result->result)) {
  983.             /*
  984.              * Probably received a result object.
  985.              * Extract the result resource identifier.
  986.              */
  987.             $id $result->result;
  988.             $got_string false;
  989.         else {
  990.             /*
  991.              * Probably received a result resource identifier.
  992.              * Copy it.
  993.              * Deprecated.  Here for compatibility only.
  994.              */
  995.             $id $result;
  996.             $got_string false;
  997.         }
  998.  
  999.         if (!is_resource($id)) {
  1000.             return $this->ibaseRaiseError(DB_ERROR_NEED_MORE_DATA);
  1001.         }
  1002.  
  1003.         if ($this->options['portability'DB_PORTABILITY_LOWERCASE{
  1004.             $case_func 'strtolower';
  1005.         else {
  1006.             $case_func 'strval';
  1007.         }
  1008.  
  1009.         $count @ibase_num_fields($id);
  1010.         $res   array();
  1011.  
  1012.         if ($mode{
  1013.             $res['num_fields'$count;
  1014.         }
  1015.  
  1016.         for ($i 0$i $count$i++{
  1017.             $info @ibase_field_info($id$i);
  1018.             $res[$iarray(
  1019.                 'table' => $got_string $case_func($result'',
  1020.                 'name'  => $case_func($info['name']),
  1021.                 'type'  => $info['type'],
  1022.                 'len'   => $info['length'],
  1023.                 'flags' => ($got_string)
  1024.                             ? $this->_ibaseFieldFlags($info['name']$result)
  1025.                             : '',
  1026.             );
  1027.             if ($mode DB_TABLEINFO_ORDER{
  1028.                 $res['order'][$res[$i]['name']] $i;
  1029.             }
  1030.             if ($mode DB_TABLEINFO_ORDERTABLE{
  1031.                 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] $i;
  1032.             }
  1033.         }
  1034.  
  1035.         // free the result only if we were called on a table
  1036.         if ($got_string{
  1037.             @ibase_free_result($id);
  1038.         }
  1039.         return $res;
  1040.     }
  1041.  
  1042.     // }}}
  1043.     // {{{ getSpecialQuery()
  1044.  
  1045.     /**
  1046.      * Obtains the query string needed for listing a given type of objects
  1047.      *
  1048.      * @param string $type  the kind of objects you want to retrieve
  1049.      *
  1050.      * @return string  the SQL query string or null if the driver doesn't
  1051.      *                   support the object type requested
  1052.      *
  1053.      * @access protected
  1054.      * @see DB_common::getListOf()
  1055.      */
  1056.     function getSpecialQuery($type)
  1057.     {
  1058.         switch ($type{
  1059.             case 'tables':
  1060.                 return 'SELECT DISTINCT R.RDB$RELATION_NAME FROM '
  1061.                        . 'RDB$RELATION_FIELDS R WHERE R.RDB$SYSTEM_FLAG=0';
  1062.             case 'views':
  1063.                 return 'SELECT DISTINCT RDB$VIEW_NAME from RDB$VIEW_RELATIONS';
  1064.             case 'users':
  1065.                 return 'SELECT DISTINCT RDB$USER FROM RDB$USER_PRIVILEGES';
  1066.             default:
  1067.                 return null;
  1068.         }
  1069.     }
  1070.  
  1071.     // }}}
  1072.  
  1073. }
  1074.  
  1075. /*
  1076.  * Local variables:
  1077.  * tab-width: 4
  1078.  * c-basic-offset: 4
  1079.  * End:
  1080.  */
  1081.  
  1082. ?>

Documentation generated on Wed, 09 Feb 2011 09:01:30 +0700 by phpDocumentor 1.4.2