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

Source for file ibase.php

Documentation is available at ibase.php

  1. <?php
  2. // vim: set et ts=4 sw=4 fdm=marker:
  3. // +----------------------------------------------------------------------+
  4. // | PHP versions 4 and 5                                                 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
  7. // | Stig. S. Bakken, Lukas Smith                                         |
  8. // | All rights reserved.                                                 |
  9. // +----------------------------------------------------------------------+
  10. // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB  |
  11. // | API as well as database abstraction for PHP applications.            |
  12. // | This LICENSE is in the BSD license style.                            |
  13. // |                                                                      |
  14. // | Redistribution and use in source and binary forms, with or without   |
  15. // | modification, are permitted provided that the following conditions   |
  16. // | are met:                                                             |
  17. // |                                                                      |
  18. // | Redistributions of source code must retain the above copyright       |
  19. // | notice, this list of conditions and the following disclaimer.        |
  20. // |                                                                      |
  21. // | Redistributions in binary form must reproduce the above copyright    |
  22. // | notice, this list of conditions and the following disclaimer in the  |
  23. // | documentation and/or other materials provided with the distribution. |
  24. // |                                                                      |
  25. // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
  26. // | Lukas Smith nor the names of his contributors may be used to endorse |
  27. // | or promote products derived from this software without specific prior|
  28. // | written permission.                                                  |
  29. // |                                                                      |
  30. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
  31. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
  32. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
  33. // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
  34. // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
  35. // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  36. // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
  37. // |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
  38. // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
  39. // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
  40. // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
  41. // | POSSIBILITY OF SUCH DAMAGE.                                          |
  42. // +----------------------------------------------------------------------+
  43. // | Author: Lorenzo Alberton <l.alberton@quipo.it>                       |
  44. // +----------------------------------------------------------------------+
  45. //
  46. // $Id: ibase.php,v 1.95 2005/06/06 09:29:29 lsmith Exp $
  47.  
  48. /**
  49.  * MDB2 FireBird/InterBase driver
  50.  *
  51.  * @package MDB2
  52.  * @category Database
  53.  * @author  Lorenzo Alberton <l.alberton@quipo.it>
  54.  */
  55. class MDB2_Driver_ibase extends MDB2_Driver_Common
  56. {
  57.     // {{{ properties
  58.     var $escape_quotes = "'";
  59.  
  60.     var $transaction_id = 0;
  61.  
  62.     var $query_parameters = array();
  63.     var $query_parameter_values = array();
  64.  
  65.     // }}}
  66.     // {{{ constructor
  67.  
  68.     /**
  69.      * Constructor
  70.      */
  71.     function __construct()
  72.     {
  73.         parent::__construct();
  74.  
  75.         $this->phptype  'ibase';
  76.         $this->dbsyntax 'ibase';
  77.  
  78.         $this->supported['sequences'= true;
  79.         $this->supported['indexes'= true;
  80.         $this->supported['affected_rows'function_exists('ibase_affected_rows');
  81.         $this->supported['summary_functions'= true;
  82.         $this->supported['order_by_text'= true;
  83.         $this->supported['transactions'= true;
  84.         $this->supported['current_id'= true;
  85.         // maybe this needs different handling for ibase and firebird?
  86.         $this->supported['limit_queries'= true;
  87.         $this->supported['LOBs'= true;
  88.         $this->supported['replace'= false;
  89.         $this->supported['sub_selects'= true;
  90.         $this->supported['auto_increment'= false;
  91.  
  92.         $this->options['database_path''';
  93.         $this->options['database_extension''.gdb';
  94.         $this->options['default_text_field_length'= 4096;
  95.     }
  96.  
  97.     // }}}
  98.     // {{{ errorInfo()
  99.  
  100.     /**
  101.      * This method is used to collect information about an error
  102.      *
  103.      * @param integer $error 
  104.      * @return array 
  105.      * @access public
  106.      */
  107.     function errorInfo($error = null)
  108.     {
  109.         $native_msg @ibase_errmsg();
  110.  
  111.         if (function_exists('ibase_errcode')) {
  112.             $native_code @ibase_errcode();
  113.         else {
  114.             // memo for the interbase php module hackers: we need something similar
  115.             // to mysql_errno() to retrieve error codes instead of this ugly hack
  116.             if (preg_match('/^([^0-9\-]+)([0-9\-]+)\s+(.*)$/'$native_msg$m)) {
  117.                 $native_code = (int)$m[2];
  118.             else {
  119.                 $native_code = null;
  120.             }
  121.         }
  122.         if (is_null($error)) {
  123.             $error = MDB2_ERROR;
  124.             if ($native_code{
  125.                 // try to interpret Interbase error code (that's why we need ibase_errno()
  126.                 // in the interbase module to return the real error code)
  127.                 switch ($native_code{
  128.                 case -204:
  129.                     if (isset($m[3]&& is_int(strpos($m[3]'Table unknown'))) {
  130.                         $errno = MDB2_ERROR_NOSUCHTABLE;
  131.                     }
  132.                 break;
  133.                 default:
  134.                     static $ecode_map;
  135.                     if (empty($ecode_map)) {
  136.                         $ecode_map = array(
  137.                             -104 => MDB2_ERROR_SYNTAX,
  138.                             -150 => MDB2_ERROR_ACCESS_VIOLATION,
  139.                             -151 => MDB2_ERROR_ACCESS_VIOLATION,
  140.                             -155 => MDB2_ERROR_NOSUCHTABLE,
  141.                             -157 => MDB2_ERROR_NOSUCHFIELD,
  142.                             -158 => MDB2_ERROR_VALUE_COUNT_ON_ROW,
  143.                             -170 => MDB2_ERROR_MISMATCH,
  144.                             -171 => MDB2_ERROR_MISMATCH,
  145.                             -172 => MDB2_ERROR_INVALID,
  146.                             // -204 =>  // Covers too many errors, need to use regex on msg
  147.                             -205 => MDB2_ERROR_NOSUCHFIELD,
  148.                             -206 => MDB2_ERROR_NOSUCHFIELD,
  149.                             -208 => MDB2_ERROR_INVALID,
  150.                             -219 => MDB2_ERROR_NOSUCHTABLE,
  151.                             -297 => MDB2_ERROR_CONSTRAINT,
  152.                             -303 => MDB2_ERROR_INVALID,
  153.                             -413 => MDB2_ERROR_INVALID_NUMBER,
  154.                             -530 => MDB2_ERROR_CONSTRAINT,
  155.                             -551 => MDB2_ERROR_ACCESS_VIOLATION,
  156.                             -552 => MDB2_ERROR_ACCESS_VIOLATION,
  157.                             // -607 =>  // Covers too many errors, need to use regex on msg
  158.                             -625 => MDB2_ERROR_CONSTRAINT_NOT_NULL,
  159.                             -803 => MDB2_ERROR_CONSTRAINT,
  160.                             -804 => MDB2_ERROR_VALUE_COUNT_ON_ROW,
  161.                             -904 => MDB2_ERROR_CONNECT_FAILED,
  162.                             -922 => MDB2_ERROR_NOSUCHDB,
  163.                             -923 => MDB2_ERROR_CONNECT_FAILED,
  164.                             -924 => MDB2_ERROR_CONNECT_FAILED
  165.                         );
  166.                     }
  167.                     if (isset($ecode_map[$native_code])) {
  168.                         $error $ecode_map[$native_code];
  169.                     }
  170.                     break;
  171.                 }
  172.             else {
  173.                 static $error_regexps;
  174.                 if (!isset($error_regexps)) {
  175.                     $error_regexps = array(
  176.                         '/generator .* is not defined/'
  177.                             => MDB2_ERROR_SYNTAX,  // for compat. w ibase_errcode()
  178.                         '/table.*(not exist|not found|unknown)/i'
  179.                             => MDB2_ERROR_NOSUCHTABLE,
  180.                         '/table .* already exists/i'
  181.                             => MDB2_ERROR_ALREADY_EXISTS,
  182.                         '/unsuccessful metadata update .* failed attempt to store duplicate value/i'
  183.                             => MDB2_ERROR_ALREADY_EXISTS,
  184.                         '/unsuccessful metadata update .* not found/i'
  185.                             => MDB2_ERROR_NOT_FOUND,
  186.                         '/validation error for column .* value "\*\*\* null/i'
  187.                             => MDB2_ERROR_CONSTRAINT_NOT_NULL,
  188.                         '/violation of [\w ]+ constraint/i'
  189.                             => MDB2_ERROR_CONSTRAINT,
  190.                         '/conversion error from string/i'
  191.                             => MDB2_ERROR_INVALID_NUMBER,
  192.                         '/no permission for/i'
  193.                             => MDB2_ERROR_ACCESS_VIOLATION,
  194.                         '/arithmetic exception, numeric overflow, or string truncation/i'
  195.                             => MDB2_ERROR_INVALID,
  196.                     );
  197.                 }
  198.                 foreach ($error_regexps as $regexp => $code{
  199.                     if (preg_match($regexp$native_msg$m)) {
  200.                         $error $code;
  201.                         break;
  202.                     }
  203.                 }
  204.             }
  205.         }
  206.         return array($error$native_code$native_msg);
  207.     }
  208.  
  209.     // }}}
  210.     // {{{ beginTransaction()
  211.  
  212.     /**
  213.      * Start a transaction.
  214.      *
  215.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  216.      * @access public
  217.      */
  218.     function beginTransaction()
  219.     {
  220.         $this->debug('starting transaction''beginTransaction');
  221.         if ($this->in_transaction{
  222.             return MDB2_OK;  //nothing to do
  223.         }
  224.         if (!$this->destructor_registered && $this->opened_persistent{
  225.             $this->destructor_registered = true;
  226.             register_shutdown_function('MDB2_closeOpenTransactions');
  227.         }
  228.         $result = ibase_trans();
  229.         if (!$result{
  230.             return $this->raiseError(MDB2_ERRORnullnull,
  231.                 'beginTransaction: could not start a transaction');
  232.         }
  233.         $this->transaction_id = $result;
  234.         $this->in_transaction = true;
  235.         return MDB2_OK;
  236.     }
  237.  
  238.     // }}}
  239.     // {{{ commit()
  240.  
  241.     /**
  242.      * Commit the database changes done during a transaction that is in
  243.      * progress.
  244.      *
  245.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  246.      * @access public
  247.      */
  248.     function commit()
  249.     {
  250.         $this->debug('commit transaction''commit');
  251.         if (!$this->in_transaction{
  252.             return $this->raiseError(MDB2_ERRORnullnull,
  253.                 'commit: transaction changes are being auto committed');
  254.         }
  255.         if (!ibase_commit($this->transaction_id)) {
  256.             return $this->raiseError(MDB2_ERRORnullnull,
  257.                 'commit: could not commit a transaction');
  258.         }
  259.         $this->in_transaction = false;
  260.         //$this->transaction_id = 0;
  261.         return MDB2_OK;
  262.     }
  263.  
  264.     // }}}
  265.     // {{{ rollback()
  266.  
  267.     /**
  268.      * Cancel any database changes done during a transaction that is in
  269.      * progress.
  270.      *
  271.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  272.      * @access public
  273.      */
  274.     function rollback()
  275.     {
  276.         $this->debug('rolling back transaction''rollback');
  277.         if (!$this->in_transaction{
  278.             return $this->raiseError(MDB2_ERRORnullnull,
  279.                 'rollback: transactions can not be rolled back when changes are auto committed');
  280.         }
  281.         if ($this->transaction_id && !ibase_rollback($this->transaction_id)) {
  282.             return $this->raiseError(MDB2_ERRORnullnull,
  283.                 'rollback: Could not rollback a pending transaction: '.ibase_errmsg());
  284.         }
  285.         $this->in_transaction = false;
  286.         $this->transaction_id = 0;
  287.         return MDB2_OK;
  288.     }
  289.  
  290.     // }}}
  291.     // {{{ getDatabaseFile()
  292.  
  293.     /**
  294.      * Builds the string with path+dbname+extension
  295.      *
  296.      * @return string full database path+file
  297.      * @access protected
  298.      */
  299.     function _getDatabaseFile($database_name)
  300.     {
  301.         if ($database_name == ''{
  302.             return $database_name;
  303.         }
  304.         return $this->options['database_path'].$database_name.$this->options['database_extension'];
  305.     }
  306.  
  307.     // }}}
  308.     // {{{ _doConnect()
  309.  
  310.     /**
  311.      * Does the grunt work of connecting to the database
  312.      *
  313.      * @return mixed connection resource on success, MDB2 Error Object on failure
  314.      * @access protected
  315.      */
  316.     function _doConnect($database_name$persistent = false)
  317.     {
  318.         $user    $this->dsn['username'];
  319.         $pw      $this->dsn['password'];
  320.         $dbhost  $this->dsn['hostspec'?
  321.             ($this->dsn['hostspec'].':'.$database_name$database_name;
  322.  
  323.         $params = array();
  324.         $params[$dbhost;
  325.         $params[!empty($user$user : null;
  326.         $params[!empty($pw$pw : null;
  327.         $params[= isset($this->dsn['charset']$this->dsn['charset': null;
  328.         $params[= isset($this->dsn['buffers']$this->dsn['buffers': null;
  329.         $params[= isset($this->dsn['dialect']$this->dsn['dialect': null;
  330.         $params[= isset($this->dsn['role'])    $this->dsn['role': null;
  331.  
  332.         $connect_function $persistent 'ibase_pconnect' 'ibase_connect';
  333.  
  334.         $connection @call_user_func_array($connect_function$params);
  335.         if ($connection <= 0{
  336.             return $this->raiseError(MDB2_ERROR_CONNECT_FAILED);
  337.         }
  338.         if (function_exists('ibase_timefmt')) {
  339.             @ibase_timefmt("%Y-%m-%d %H:%M:%S"IBASE_TIMESTAMP);
  340.             @ibase_timefmt("%Y-%m-%d"IBASE_DATE);
  341.         else {
  342.             @ini_set("ibase.timestampformat""%Y-%m-%d %H:%M:%S");
  343.             //@ini_set("ibase.timeformat", "%H:%M:%S");
  344.             @ini_set("ibase.dateformat""%Y-%m-%d");
  345.         }
  346.  
  347.         return $connection;
  348.     }
  349.  
  350.     // }}}
  351.     // {{{ connect()
  352.  
  353.     /**
  354.      * Connect to the database
  355.      *
  356.      * @return true on success, MDB2 Error Object on failure
  357.      * @access public
  358.      */
  359.     function connect()
  360.     {
  361.         $database_file $this->_getDatabaseFile($this->database_name);
  362.         if (is_resource($this->connection)) {
  363.             if (count(array_diff($this->connected_dsn$this->dsn)) == 0
  364.                 && $this->connected_database_name == $database_file
  365.                 && $this->opened_persistent == $this->options['persistent']
  366.             {
  367.                 return MDB2_OK;
  368.             }
  369.             $this->disconnect(false);
  370.         }
  371.  
  372.         if (!PEAR::loadExtension('interbase')) {
  373.             return $this->raiseError(MDB2_ERROR_NOT_FOUNDnullnull,
  374.                 'connect: extension '.$this->phptype.' is not compiled into PHP');
  375.         }
  376.  
  377.         if (!empty($this->database_name)) {
  378.             $connection $this->_doConnect($database_file$this->options['persistent']);
  379.             if (PEAR::isError($connection)) {
  380.                 return $connection;
  381.             }
  382.             $this->connection =$connection;
  383.             $this->connected_dsn $this->dsn;
  384.             $this->connected_database_name $database_file;
  385.             $this->opened_persistent $this->options['persistent'];
  386.             $this->dbsyntax $this->dsn['dbsyntax'$this->dsn['dbsyntax'$this->phptype;
  387.         }
  388.         return MDB2_OK;
  389.     }
  390.  
  391.     // }}}
  392.     // {{{ disconnect()
  393.  
  394.     /**
  395.      * Log out and disconnect from the database.
  396.      *
  397.      * @return mixed true on success, false if not connected and error
  398.      *                 object on error
  399.      * @access public
  400.      */
  401.     function disconnect($force = true)
  402.     {
  403.         if (is_resource($this->connection)) {
  404.             if (!$this->opened_persistent || $force{
  405.                 @ibase_close($this->connection);
  406.             }
  407.             $this->connection = 0;
  408.         }
  409.         return MDB2_OK;
  410.     }
  411.  
  412.     // }}}
  413.     // {{{ _doQuery()
  414.  
  415.     /**
  416.      * Execute a query
  417.      * @param string $query  query
  418.      * @param boolean $isManip  if the query is a manipulation query
  419.      * @param resource $connection 
  420.      * @param string $database_name 
  421.      * @return result or error object
  422.      * @access protected
  423.      */
  424.     function _doQuery($query$isManip = false$connection = null$database_name = null)
  425.     {
  426.         $this->last_query $query;
  427.         $this->debug($query'query');
  428.         if ($this->options['disable_query']{
  429.             if ($isManip{
  430.                 return MDB2_OK;
  431.             }
  432.             return null;
  433.         }
  434.  
  435.         if (is_null($connection)) {
  436.             if ($this->in_transaction{
  437.                 $connection $this->transaction_id;
  438.             else {
  439.                 $error $this->connect();
  440.                 if (PEAR::isError($error)) {
  441.                     return $error;
  442.                 }
  443.                 $connection $this->connection;
  444.             }
  445.         }
  446.         $result = ibase_query($connection$query);
  447.  
  448.         if ($result === false{
  449.             return $this->raiseError();
  450.         }
  451.  
  452.         if ($isManip{
  453.             //return $result;
  454.             return (function_exists('ibase_affected_rows'? ibase_affected_rows($connection: 0);
  455.         }
  456.         return $result;
  457.     }
  458.  
  459.     // }}}
  460.     // {{{ _modifyQuery()
  461.  
  462.     /**
  463.      * Changes a query string for various DBMS specific reasons
  464.      *
  465.      * @param string $query  query to modify
  466.      * @return the new (modified) query
  467.      * @access protected
  468.      */
  469.     function _modifyQuery($query$isManip$limit$offset)
  470.     {
  471.         if ($limit > 0 && $this->dsn['dbsyntax'== 'firebird'{
  472.             $query preg_replace('/^([\s(])*SELECT(?!\s*FIRST\s*\d+)/i',
  473.                 "SELECT FIRST $limit SKIP $offset"$query);
  474.         }
  475.         return $query;
  476.     }
  477.  
  478.     // }}}
  479.     // {{{ prepare()
  480.  
  481.     /**
  482.      * Prepares a query for multiple execution with execute().
  483.      * With some database backends, this is emulated.
  484.      * prepare() requires a generic query as string like
  485.      * 'INSERT INTO numbers VALUES(?,?)' or
  486.      * 'INSERT INTO numbers VALUES(:foo,:bar)'.
  487.      * The ? and :[a-zA-Z] and  are placeholders which can be set using
  488.      * bindParam() and the query can be send off using the execute() method.
  489.      *
  490.      * @param string $query the query to prepare
  491.      * @param mixed   $types  array that contains the types of the placeholders
  492.      * @param mixed   $result_types  array that contains the types of the columns in
  493.      *                         the result set
  494.      * @return mixed resource handle for the prepared query on success, a MDB2
  495.      *         error on failure
  496.      * @access public
  497.      * @see bindParam, execute
  498.      */
  499.     function &prepare($query$types = null$result_types = null)
  500.     {
  501.         $this->debug($query'prepare');
  502.         $placeholder_type_guess $placeholder_type = null;
  503.         $question '?';
  504.         $colon ':';
  505.         $position = 0;
  506.         while ($position strlen($query)) {
  507.             $q_position strpos($query$question$position);
  508.             $c_position strpos($query$colon$position);
  509.             if ($q_position && $c_position{
  510.                 $p_position min($q_position$c_position);
  511.             elseif ($q_position{
  512.                 $p_position $q_position;
  513.             elseif ($c_position{
  514.                 $p_position $c_position;
  515.             else {
  516.                 break;
  517.             }
  518.             if (is_null($placeholder_type)) {
  519.                 $placeholder_type_guess $query[$p_position];
  520.             }
  521.             if (is_int($quote strpos($query"'"$position)) && $quote $p_position{
  522.                 if (!is_int($end_quote strpos($query"'"$quote + 1))) {
  523.                     return $this->raiseError(MDB2_ERROR_SYNTAXnullnull,
  524.                         'prepare: query with an unterminated text string specified');
  525.                 }
  526.                 switch ($this->escape_quotes{
  527.                 case '':
  528.                 case "'":
  529.                     $position $end_quote + 1;
  530.                     break;
  531.                 default:
  532.                     if ($end_quote == $quote + 1{
  533.                         $position $end_quote + 1;
  534.                     else {
  535.                         if ($query[$end_quote-1== $this->escape_quotes{
  536.                             $position $end_quote;
  537.                         else {
  538.                             $position $end_quote + 1;
  539.                         }
  540.                     }
  541.                     break;
  542.                 }
  543.             elseif ($query[$position== $placeholder_type_guess{
  544.                 if ($placeholder_type_guess == '?'{
  545.                     break;
  546.                 }
  547.                 if (is_null($placeholder_type)) {
  548.                     $placeholder_type $query[$p_position];
  549.                     $question $colon $placeholder_type;
  550.                 }
  551.                 $name preg_replace('/^.{'.($position+1).'}([a-z0-9_]+).*$/i''\\1'$query);
  552.                 if ($name === ''{
  553.                     return $this->raiseError(MDB2_ERROR_SYNTAXnullnull,
  554.                         'prepare: named parameter with an empty name');
  555.                 }
  556.                 $query substr_replace($query'?'$positionstrlen($name)+1);
  557.                 $position $p_position + 1;
  558.             else {
  559.                 $position $p_position;
  560.             }
  561.         }
  562.         $connection ($this->in_transaction $this->transaction_id : $this->connection);
  563.         $statement = ibase_prepare($connection$query);
  564.  
  565.         $class_name 'MDB2_Statement_'.$this->phptype;
  566.         $obj =new $class_name($this$statement$query$types$result_types$this->row_limit$this->row_offset);
  567.         return $obj;
  568.     }
  569.  
  570.     // }}}
  571.     // {{{ nextID()
  572.  
  573.     /**
  574.      * returns the next free id of a sequence
  575.      *
  576.      * @param string  $seq_name name of the sequence
  577.      * @param boolean $ondemand when true the seqence is
  578.      *                           automatic created, if it
  579.      *                           not exists
  580.      * @return mixed MDB2 Error Object or id
  581.      * @access public
  582.      */
  583.     function nextID($seq_name$ondemand = true)
  584.     {
  585.         $sequence_name $this->getSequenceName($seq_name);
  586.         $query 'SELECT GEN_ID('.strtoupper($sequence_name).', 1) as the_value FROM RDB$DATABASE';
  587.         $this->expectError('*');
  588.         $result $this->queryOne($query'integer');
  589.         $this->popExpect();
  590.         if (PEAR::isError($result)) {
  591.             if ($ondemand{
  592.                 $this->loadModule('Manager');
  593.                 // Since we are creating the sequence on demand
  594.                 // we know the first id = 1 so initialize the
  595.                 // sequence at 2
  596.                 $result $this->manager->createSequence($seq_name2);
  597.                 if (PEAR::isError($result)) {
  598.                     return $this->raiseError(MDB2_ERRORnullnull,
  599.                         'nextID: on demand sequence could not be created');
  600.                 else {
  601.                     // First ID of a newly created sequence is 1
  602.                     // return 1;
  603.                     // BUT generators are not always reset, so return the actual value
  604.                     return $this->currID($seq_name);
  605.                 }
  606.             }
  607.         }
  608.         return $result;
  609.     }
  610.  
  611.     // }}}
  612.     // {{{ currID()
  613.  
  614.     /**
  615.      * returns the current id of a sequence
  616.      *
  617.      * @param string  $seq_name name of the sequence
  618.      * @return mixed MDB2 Error Object or id
  619.      * @access public
  620.      */
  621.     function currID($seq_name)
  622.     {
  623.         $sequence_name $this->getSequenceName($seq_name);
  624.         $query 'SELECT GEN_ID('.strtoupper($sequence_name).', 0) as the_value FROM RDB$DATABASE';
  625.         $value @$this->queryOne($query);
  626.         if (PEAR::isError($value)) {
  627.             return $this->raiseError(MDB2_ERRORnullnull,
  628.                 'currID: Unable to select from ' $seq_name;
  629.         }
  630.         if (!is_numeric($value)) {
  631.             return $this->raiseError(MDB2_ERRORnullnull,
  632.                 'currID: could not find value in sequence table');
  633.         }
  634.         return $value;
  635.     }
  636.  
  637.     // }}}
  638. }
  639.  
  640. class MDB2_Result_ibase extends MDB2_Result_Common
  641. {
  642.     // {{{ _skipLimitOffset()
  643.  
  644.     /**
  645.      * Skip the first row of a result set.
  646.      *
  647.      * @param resource $result 
  648.      * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure
  649.      * @access protected
  650.      */
  651.     function _skipLimitOffset()
  652.     {
  653.         if ($this->db->dsn['dbsyntax'== 'firebird'{
  654.             return true;
  655.         }
  656.         if ($this->limit{
  657.             if ($this->rownum $this->limit{
  658.                 return false;
  659.             }
  660.         }
  661.         if ($this->offset{
  662.             while ($this->offset_count $this->offset{
  663.                 ++$this->offset_count;
  664.                 if (!is_array(@ibase_fetch_row($this->result))) {
  665.                     $this->offset_count $this->offset;
  666.                     return false;
  667.                 }
  668.             }
  669.         }
  670.         return true;
  671.     }
  672.  
  673.     // }}}
  674.     // {{{ fetchRow()
  675.  
  676.     /**
  677.      * Fetch a row and insert the data into an existing array.
  678.      *
  679.      * @param int  $fetchmode how the array data should be indexed
  680.      * @param int  $rownum    number of the row where the data can be found
  681.      * @return int data array on success, a MDB2 error on failure
  682.      * @access public
  683.      */
  684.     function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT$rownum = null)
  685.     {
  686.         if ($this->result === true{
  687.             //query successfully executed, but without results...
  688.             return null;
  689.         }
  690.         if (!$this->_skipLimitOffset()) {
  691.             return null;
  692.         }
  693.         if (!is_null($rownum)) {
  694.             $seek $this->seek($rownum);
  695.             if (PEAR::isError($seek)) {
  696.                 return $seek;
  697.             }
  698.         }
  699.         if ($fetchmode == MDB2_FETCHMODE_DEFAULT{
  700.             $fetchmode $this->db->fetchmode;
  701.         }
  702.         if ($fetchmode MDB2_FETCHMODE_ASSOC{
  703.             $row @ibase_fetch_assoc($this->result);
  704.             if (is_array($row)
  705.                 && $this->db->options['portability'MDB2_PORTABILITY_LOWERCASE
  706.             {
  707.                 $row array_change_key_case($rowCASE_LOWER);
  708.             }
  709.         else {
  710.             $row @ibase_fetch_row($this->result);
  711.         }
  712.         if (!$row{
  713.             if (is_null($this->result)) {
  714.                 return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  715.                     'fetchRow: resultset has already been freed');
  716.             }
  717.             return null;
  718.         }
  719.         if ($this->db->options['portability'MDB2_PORTABILITY_RTRIM{
  720.             $this->db->_rtrimArrayValues($row);
  721.         }
  722.         if ($this->db->options['portability'MDB2_PORTABILITY_EMPTY_TO_NULL{
  723.             $this->db->_convertEmptyArrayValuesToNull($row);
  724.         }
  725.         if (isset($this->values)) {
  726.             $this->_assignBindColumns($row);
  727.         }
  728.         if (isset($this->types)) {
  729.             $row $this->db->datatype->convertResultRow($this->types$row);
  730.         }
  731.         if ($fetchmode === MDB2_FETCHMODE_OBJECT{
  732.             $object_class $this->db->options['fetch_class'];
  733.             if ($object_class == 'stdClass'{
  734.                 $row = (object) $row;
  735.             else {
  736.                 $row &new $object_class($row);
  737.             }
  738.         }
  739.         ++$this->rownum;
  740.         return $row;
  741.     }
  742.  
  743.     // }}}
  744.     // {{{ _getColumnNames()
  745.  
  746.     /**
  747.      * Retrieve the names of columns returned by the DBMS in a query result.
  748.      *
  749.      * @return mixed associative array variable
  750.      *       that holds the names of columns. The indexes of the array are
  751.      *       the column names mapped to lower case and the values are the
  752.      *       respective numbers of the columns starting from 0. Some DBMS may
  753.      *       not return any columns when the result set does not contain any
  754.      *       rows.
  755.      * @access private
  756.      */
  757.     function _getColumnNames()
  758.     {
  759.         $columns = array();
  760.         $numcols $this->numCols();
  761.         if (PEAR::isError($numcols)) {
  762.             return $numcols;
  763.         }
  764.         for ($column = 0; $column $numcols$column++{
  765.             $column_info @ibase_field_info($this->result$column);
  766.             $columns[$column_info['alias']] $column;
  767.         }
  768.         if ($this->db->options['portability'MDB2_PORTABILITY_LOWERCASE{
  769.             $columns array_change_key_case($columnsCASE_LOWER);
  770.         }
  771.         return $columns;
  772.     }
  773.  
  774.     // }}}
  775.     // {{{ numCols()
  776.  
  777.     /**
  778.      * Count the number of columns returned by the DBMS in a query result.
  779.      *
  780.      * @return mixed integer value with the number of columns, a MDB2 error
  781.      *       on failure
  782.      * @access public
  783.      */
  784.     function numCols()
  785.     {
  786.         if ($this->result === true{
  787.             //query successfully executed, but without results...
  788.             return 0;
  789.         }
  790.  
  791.         if (!is_resource($this->result)) {
  792.             return $this->db->raiseError('numCols(): not a valid ibase resource');
  793.         }
  794.         $cols @ibase_num_fields($this->result);
  795.         if (is_null($cols)) {
  796.             if (is_null($this->result)) {
  797.                 return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  798.                     'numCols: resultset has already been freed');
  799.             }
  800.             return $this->db->raiseError();
  801.         }
  802.         return $cols;
  803.     }
  804.  
  805.     // }}}
  806.     // {{{ free()
  807.  
  808.     /**
  809.      * Free the internal resources associated with $result.
  810.      *
  811.      * @return boolean true on success, false if $result is invalid
  812.      * @access public
  813.      */
  814.     function free()
  815.     {
  816.         if (is_resource($this->result)) {
  817.             $free @ibase_free_result($this->result);
  818.             if (!$free{
  819.                 if (is_null($this->result)) {
  820.                     return MDB2_OK;
  821.                 }
  822.                 return $this->db->raiseError();
  823.             }
  824.         }
  825.         $this->result = null;
  826.         return MDB2_OK;
  827.     }
  828.  
  829.     // }}}
  830. }
  831.  
  832. {
  833.     // {{{ class vars
  834.  
  835.     var $buffer;
  836.     var $buffer_rownum = - 1;
  837.  
  838.     // }}}
  839.     // {{{ _fillBuffer()
  840.  
  841.     /**
  842.      * Fill the row buffer
  843.      *
  844.      * @param int $rownum   row number upto which the buffer should be filled
  845.      *                       if the row number is null all rows are ready into the buffer
  846.      * @return boolean true on success, false on failure
  847.      * @access protected
  848.      */
  849.     function _fillBuffer($rownum = null)
  850.     {
  851.         if (isset($this->buffer&& is_array($this->buffer)) {
  852.             if (is_null($rownum)) {
  853.                 if (!end($this->buffer)) {
  854.                     return false;
  855.                 }
  856.             elseif (isset($this->buffer[$rownum])) {
  857.                 return (bool) $this->buffer[$rownum];
  858.             }
  859.         }
  860.  
  861.         if (!$this->_skipLimitOffset()) {
  862.             return false;
  863.         }
  864.  
  865.         $buffer = true;
  866.         while ((is_null($rownum|| $this->buffer_rownum < $rownum)
  867.             && (!$this->limit || $this->buffer_rownum < $this->limit)
  868.             && ($buffer @ibase_fetch_row($this->result))
  869.         {
  870.             ++$this->buffer_rownum;
  871.             $this->buffer[$this->buffer_rownum$buffer;
  872.         }
  873.  
  874.         if (!$buffer{
  875.             ++$this->buffer_rownum;
  876.             $this->buffer[$this->buffer_rownum= false;
  877.             return false;
  878.         elseif ($this->limit && $this->buffer_rownum >= $this->limit{
  879.             ++$this->buffer_rownum;
  880.             $this->buffer[$this->buffer_rownum= false;
  881.         }
  882.         return true;
  883.     }
  884.  
  885.     // }}}
  886.     // {{{ fetchRow()
  887.  
  888.     /**
  889.      * Fetch a row and insert the data into an existing array.
  890.      *
  891.      * @param int       $fetchmode  how the array data should be indexed
  892.      * @param int    $rownum    number of the row where the data can be found
  893.      * @return int data array on success, a MDB2 error on failure
  894.      * @access public
  895.      */
  896.     function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT$rownum = null)
  897.     {
  898.         if ($this->result === true{
  899.             //query successfully executed, but without results...
  900.             return null;
  901.         }
  902.         if (is_null($this->result)) {
  903.             return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  904.                 'fetchRow: resultset has already been freed');
  905.         }
  906.         if (!is_null($rownum)) {
  907.             $seek $this->seek($rownum);
  908.             if (PEAR::isError($seek)) {
  909.                 return $seek;
  910.             }
  911.         }
  912.         $target_rownum $this->rownum + 1;
  913.         if ($fetchmode == MDB2_FETCHMODE_DEFAULT{
  914.             $fetchmode $this->db->fetchmode;
  915.         }
  916.         if (!$this->_fillBuffer($target_rownum)) {
  917.             return null;
  918.         }
  919.         $row $this->buffer[$target_rownum];
  920.         if ($fetchmode MDB2_FETCHMODE_ASSOC{
  921.             $column_names $this->getColumnNames();
  922.             foreach ($column_names as $name => $i{
  923.                 $column_names[$name$row[$i];
  924.             }
  925.             $row $column_names;
  926.         }
  927.         if ($this->db->options['portability'MDB2_PORTABILITY_EMPTY_TO_NULL{
  928.             $this->db->_convertEmptyArrayValuesToNull($row);
  929.         }
  930.         if (isset($this->values)) {
  931.             $this->_assignBindColumns($row);
  932.         }
  933.         if (isset($this->types)) {
  934.             $row $this->db->datatype->convertResultRow($this->types$row);
  935.         }
  936.         if ($this->db->options['portability'MDB2_PORTABILITY_RTRIM{
  937.             $this->db->_rtrimArrayValues($row);
  938.         }
  939.         if ($this->db->options['portability'MDB2_PORTABILITY_EMPTY_TO_NULL{
  940.             $this->db->_convertEmptyArrayValuesToNull($row);
  941.         }
  942.         if ($fetchmode === MDB2_FETCHMODE_OBJECT{
  943.             $object_class $this->db->options['fetch_class'];
  944.             if ($object_class == 'stdClass'{
  945.                 $row = (object) $row;
  946.             else {
  947.                 $row &new $object_class($row);
  948.             }
  949.         }
  950.         ++$this->rownum;
  951.         return $row;
  952.     }
  953.  
  954.     // }}}
  955.     // {{{ seek()
  956.  
  957.     /**
  958.      * seek to a specific row in a result set
  959.      *
  960.      * @param int    $rownum    number of the row where the data can be found
  961.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  962.      * @access public
  963.      */
  964.     function seek($rownum = 0)
  965.     {
  966.         if (is_null($this->result)) {
  967.             return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  968.                 'seek: resultset has already been freed');
  969.         }
  970.         $this->rownum $rownum - 1;
  971.         return MDB2_OK;
  972.     }
  973.  
  974.     // }}}
  975.     // {{{ valid()
  976.  
  977.     /**
  978.      * check if the end of the result set has been reached
  979.      *
  980.      * @return mixed true or false on sucess, a MDB2 error on failure
  981.      * @access public
  982.      */
  983.     function valid()
  984.     {
  985.         if (is_null($this->result)) {
  986.             return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  987.                 'valid: resultset has already been freed');
  988.         }
  989.         if ($this->_fillBuffer($this->rownum + 1)) {
  990.             return true;
  991.         }
  992.         return false;
  993.     }
  994.  
  995.     // }}}
  996.     // {{{ numRows()
  997.  
  998.     /**
  999.      * returns the number of rows in a result object
  1000.      *
  1001.      * @return mixed MDB2 Error Object or the number of rows
  1002.      * @access public
  1003.      */
  1004.     function numRows()
  1005.     {
  1006.         if (is_null($this->result)) {
  1007.             return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  1008.                 'seek: resultset has already been freed');
  1009.         }
  1010.         $this->_fillBuffer();
  1011.         return $this->buffer_rownum;
  1012.     }
  1013.  
  1014.     // }}}
  1015.     // {{{ free()
  1016.  
  1017.     /**
  1018.      * Free the internal resources associated with $result.
  1019.      *
  1020.      * @return boolean true on success, false if $result is invalid
  1021.      * @access public
  1022.      */
  1023.     function free()
  1024.     {
  1025.         $this->buffer = null;
  1026.         $this->buffer_rownum = null;
  1027.         $free = parent::free();
  1028.     }
  1029.  
  1030.     // }}}
  1031. }
  1032.  
  1033. class MDB2_Statement_ibase extends MDB2_Statement_Common
  1034. {
  1035.     // {{{ _execute()
  1036.  
  1037.     /**
  1038.      * Execute a prepared query statement helper method.
  1039.      *
  1040.      * @param mixed $result_class string which specifies which result class to use
  1041.      * @param mixed $result_wrap_class string which specifies which class to wrap results in
  1042.      * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure
  1043.      * @access private
  1044.      */
  1045.     function &_execute($result_class = true$result_wrap_class = false)
  1046.     {
  1047.         $isManip = MDB2::isManip($this->query);
  1048.         $this->db->last_query = $this->query;
  1049.         $this->db->debug($this->query'execute');
  1050.         if ($this->db->getOption('disable_query')) {
  1051.             return $isManip ? MDB2_OK : null;
  1052.         }
  1053.  
  1054.         $connected $this->db->connect();
  1055.         if (PEAR::isError($connected)) {
  1056.             return $connected;
  1057.         }
  1058.         $connection $this->db->in_transaction
  1059.             ? $this->db->transaction_id : $this->db->connection;
  1060.  
  1061.         $parameters = array(0 => $this->statement);
  1062.         $i = 0;
  1063.         $types_numeric is_numeric(key($this->types));
  1064.         foreach ($this->values as $parameter => $value{
  1065.             $type_key $types_numeric $i $parameter;
  1066.             $type = isset($this->types[$type_key]$this->types[$type_key: null;
  1067.             $parameters[$this->db->quote($value$typefalse);
  1068.             ++$i;
  1069.         }
  1070.  
  1071.         $result call_user_func_array('ibase_execute'$parameters);
  1072.         if ($result === false{
  1073.             return $this->db->raiseError();
  1074.         }
  1075.  
  1076.         if ($isManip{
  1077.             return (function_exists('ibase_affected_rows'? ibase_affected_rows($connection: 0);
  1078.         }
  1079.  
  1080.         return $this->db->_wrapResult($result$this->types,
  1081.             $result_class$result_wrap_class$this->row_limit$this->row_offset);
  1082.     }
  1083.  
  1084.     // }}}
  1085.  
  1086.     // }}}
  1087.     // {{{ free()
  1088.  
  1089.     /**
  1090.      * Release resources allocated for the specified prepared query.
  1091.      *
  1092.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  1093.      * @access public
  1094.      */
  1095.     function free()
  1096.     {
  1097.         if (!@ibase_free_query($this->statement)) {
  1098.             return $this->db->raiseError();
  1099.         }
  1100.         return MDB2_OK;
  1101.     }
  1102. }
  1103. ?>

Documentation generated on Mon, 11 Mar 2019 14:19:34 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.