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 Version 4                                                        |
  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.23 2004/04/23 17:06:46 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. {
  56.     // {{{ properties
  57.     var $escape_quotes = "'";
  58.  
  59.     var $transaction_id = 0;
  60.  
  61.     var $database_path = '';
  62.     var $database_extension = '';
  63.  
  64.     var $query_parameters = array();
  65.     var $query_parameter_values = array();
  66.  
  67.     // }}}
  68.     // {{{ constructor
  69.  
  70.     /**
  71.      * Constructor
  72.      */
  73.     function MDB2_Driver_ibase()
  74.     {
  75.         $this->MDB2_Driver_Common();
  76.         $this->phptype  'ibase';
  77.         $this->dbsyntax 'ibase';
  78.  
  79.         $this->supported['sequences'= true;
  80.         $this->supported['indexes'= true;
  81.         $this->supported['affected_rows'= true;
  82.         $this->supported['summary_functions'= true;
  83.         $this->supported['order_by_text'= true;
  84.         $this->supported['transactions'= true;
  85.         $this->supported['current_id'= true;
  86.         // maybe this needs different handling for ibase and firebird?
  87.         $this->supported['limit_queries'= true;
  88.         $this->supported['LOBs'= true;
  89.         $this->supported['replace'= false;
  90.         $this->supported['sub_selects'= true;
  91.  
  92.         $this->options['database_path''';
  93.         $this->options['database_extension''.gdb';
  94.         $this->options['default_text_field_length'= 4000;
  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_errno{
  128.                     case -204:
  129.                         if (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.                                   88 => MDB2_ERROR_NOSUCHTABLE,
  142.                                 -157 => MDB2_ERROR_NOSUCHFIELD,
  143.                                 -158 => MDB2_ERROR_VALUE_COUNT_ON_ROW,
  144.                                 -170 => MDB2_ERROR_MISMATCH,
  145.                                 -171 => MDB2_ERROR_MISMATCH,
  146.                                 -172 => MDB2_ERROR_INVALID,
  147.                                 -204 => MDB2_ERROR_INVALID,
  148.                                 -205 => MDB2_ERROR_NOSUCHFIELD,
  149.                                 -206 => MDB2_ERROR_NOSUCHFIELD,
  150.                                 -208 => MDB2_ERROR_INVALID,
  151.                                 -219 => MDB2_ERROR_NOSUCHTABLE,
  152.                                 -297 => MDB2_ERROR_CONSTRAINT,
  153.                                 -530 => MDB2_ERROR_CONSTRAINT,
  154.                                 -551 => MDB2_ERROR_ACCESS_VIOLATION,
  155.                                 -552 => MDB2_ERROR_ACCESS_VIOLATION,
  156.                                 -607 => MDB2_ERROR_NOSUCHTABLE,
  157.                                 -803 => MDB2_ERROR_CONSTRAINT,
  158.                                 -913 => MDB2_ERROR_DEADLOCK,
  159.                                 -922 => MDB2_ERROR_NOSUCHDB,
  160.                                 -923 => MDB2_ERROR_CONNECT_FAILED,
  161.                                 -924 => MDB2_ERROR_CONNECT_FAILED,
  162.                             );
  163.                         }
  164.                         if (isset($ecode_map[$native_code])) {
  165.                             $error $ecode_map[$native_code];
  166.                         }
  167.                         break;
  168.                 }
  169.             else {
  170.                 static $error_regexps;
  171.                 if (!isset($error_regexps)) {
  172.                     $error_regexps = array(
  173.                         '/[tT]able not found/' => MDB2_ERROR_NOSUCHTABLE,
  174.                         '/[tT]able .* already exists/' => MDB2_ERROR_ALREADY_EXISTS,
  175.                         '/validation error for column .* value "\*\*\* null/' => MDB2_ERROR_CONSTRAINT_NOT_NULL,
  176.                         '/violation of [\w ]+ constraint/' => MDB2_ERROR_CONSTRAINT,
  177.                         '/conversion error from string/' => MDB2_ERROR_INVALID_NUMBER,
  178.                         '/no permission for/' => MDB2_ERROR_ACCESS_VIOLATION,
  179.                         '/arithmetic exception, numeric overflow, or string truncation/' => MDB2_ERROR_DIVZERO,
  180.                         '/deadlock/' => MDB2_ERROR_DEADLOCK,
  181.                         '/attempt to store duplicate value/' => MDB2_ERROR_CONSTRAINT,
  182.                     );
  183.                 }
  184.                 foreach ($error_regexps as $regexp => $code{
  185.                     if (preg_match($regexp$native_msg$m)) {
  186.                         $error $code;
  187.                         break;
  188.                     }
  189.                 }
  190.             }
  191.         }
  192.         return array($error$native_code$native_msg);
  193.     }
  194.  
  195.     // }}}
  196.     // {{{ autoCommit()
  197.  
  198.     /**
  199.      * Define whether database changes done on the database be automatically
  200.      * committed. This function may also implicitly start or end a transaction.
  201.      *
  202.      * @param boolean $auto_commit flag that indicates whether the database
  203.      *      changes should be committed right after executing every query
  204.      *      statement. If this argument is 0 a transaction implicitly started.
  205.      *      Otherwise, if a transaction is in progress it is ended by committing
  206.      *      any database changes that were pending.
  207.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  208.      * @access public
  209.      */
  210.     function autoCommit($auto_commit)
  211.     {
  212.         $this->debug(($auto_commit 'On' 'Off')'autoCommit');
  213.         if ($this->auto_commit == $auto_commit{
  214.             return MDB2_OK;
  215.         }
  216.         if ($this->connection && $auto_commit
  217.             && MDB2::isError($commit $this->commit())
  218.         {
  219.             return $commit;
  220.         }
  221.         $this->auto_commit = $auto_commit;
  222.         $this->in_transaction !$auto_commit;
  223.         return MDB2_OK;
  224.     }
  225.  
  226.     // }}}
  227.     // {{{ commit()
  228.  
  229.     /**
  230.      * Commit the database changes done during a transaction that is in
  231.      * progress. This function may only be called when auto-committing is
  232.      * disabled, otherwise it will fail. Therefore, a new transaction is
  233.      * implicitly started after committing the pending changes.
  234.      *
  235.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  236.      * @access public
  237.      */
  238.     function commit()
  239.     {
  240.         $this->debug('commit transaction''commit');
  241.         if ($this->auto_commit{
  242.             return $this->raiseError(MDB2_ERRORnullnull,
  243.                 'commit: transaction changes are being auto commited');
  244.         }
  245.         if (!@ibase_commit($this->connection)) {
  246.             return $this->raiseError(MDB2_ERRORnullnull,
  247.                 'commit: could not commit');
  248.         }
  249.         return MDB2_OK;
  250.     }
  251.  
  252.     // }}}
  253.     // {{{ rollback()
  254.  
  255.     /**
  256.      * Cancel any database changes done during a transaction that is in
  257.      * progress. This function may only be called when auto-committing is
  258.      * disabled, otherwise it will fail. Therefore, a new transaction is
  259.      * implicitly started after canceling the pending changes.
  260.      *
  261.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  262.      * @access public
  263.      */
  264.     function rollback()
  265.     {
  266.         $this->debug('rolling back transaction''rollback');
  267.         if ($this->auto_commit{
  268.             return $this->raiseError(MDB2_ERRORnullnull,
  269.                 'rollback: transactions can not be rolled back when changes are auto commited');
  270.         }
  271.  
  272.         if ($this->transaction_id && !@ibase_rollback($this->connection)) {
  273.             return $this->raiseError(MDB2_ERRORnullnull,
  274.                 'rollback: Could not rollback a pending transaction: '.ibase_errmsg());
  275.         }
  276.         if (!$this->transaction_id = @ibase_trans(IBASE_COMMITTED$this->connection)) {
  277.             return $this->raiseError(MDB2_ERRORnullnull,
  278.                 'rollback: Could not start a new transaction: '.ibase_errmsg());
  279.         }
  280.         return MDB2_OK;
  281.     }
  282.  
  283.     // }}}
  284.     // {{{ getDatabaseFile()
  285.  
  286.     /**
  287.      * Builds the string with path+dbname+extension
  288.      *
  289.      * @return string full database path+file
  290.      * @access private
  291.      */
  292.     function _getDatabaseFile($database_name)
  293.     {
  294.         $this->database_path = $this->options['database_path'];
  295.         $this->database_extension = $this->options['database_extension'];
  296.  
  297.         return $this->database_path.$database_name.$this->database_extension;
  298.     }
  299.  
  300.     // }}}
  301.     // {{{ _doConnect()
  302.  
  303.     /**
  304.      * Does the grunt work of connecting to the database
  305.      *
  306.      * @return mixed connection resource on success, MDB2 Error Object on failure
  307.      * @access private
  308.      ***/
  309.     function _doConnect($database_name$persistent = false)
  310.     {
  311.         $dsninfo $this->dsn;
  312.         $user $dsninfo['username'];
  313.         $pw   $dsninfo['password'];
  314.         $dbhost $dsninfo['hostspec'?
  315.             ($dsninfo['hostspec'].':'.$database_name$database_name;
  316.  
  317.         $params = array();
  318.         $params[$dbhost;
  319.         $params[!empty($user$user : null;
  320.         $params[!empty($pw$pw : null;
  321.         $params[= isset($dsninfo['charset']$dsninfo['charset': null;
  322.         $params[= isset($dsninfo['buffers']$dsninfo['buffers': null;
  323.         $params[= isset($dsninfo['dialect']$dsninfo['dialect': null;
  324.         $params[= isset($dsninfo['role'])    $dsninfo['role': null;
  325.  
  326.         $function ($persistent 'ibase_pconnect' 'ibase_connect');
  327.         $connection @call_user_func_array($function$params);
  328.         if ($connection > 0{
  329.             @ibase_timefmt("%Y-%m-%d %H:%M:%S"IBASE_TIMESTAMP);
  330.             @ibase_timefmt("%Y-%m-%d"IBASE_DATE);
  331.             return $connection;
  332.         }
  333.         if (isset($php_errormsg)) {
  334.             $error_msg $php_errormsg;
  335.         else {
  336.             $error_msg 'Could not connect to FireBird/InterBase server';
  337.         }
  338.         return $this->raiseError(MDB2_ERROR_CONNECT_FAILEDnullnull$error_msg);
  339.     }
  340.  
  341.     // }}}
  342.     // {{{ connect()
  343.  
  344.     /**
  345.      * Connect to the database
  346.      *
  347.      * @return true on success, MDB2 Error Object on failure
  348.      * @access public
  349.      ***/
  350.     function connect()
  351.     {
  352.         $database_file $this->_getDatabaseFile($this->database_name);
  353.  
  354.         if ($this->connection != 0{
  355.             if (count(array_diff($this->connected_dsn$this->dsn)) == 0
  356.                 && $this->connected_database_name == $database_file
  357.                 && $this->opened_persistent == $this->options['persistent']
  358.             {
  359.                 return MDB2_OK;
  360.             }
  361.             @ibase_close($this->connection);
  362.             $this->connection = 0;
  363.         }
  364.  
  365.         if (!PEAR::loadExtension('interbase')) {
  366.             return $this->raiseError(MDB2_ERROR_NOT_FOUNDnullnull,
  367.                 'connect: extension '.$this->phptype.' is not compiled into PHP');
  368.         }
  369.  
  370.         if (!empty($this->database_name)) {
  371.             $connection $this->_doConnect($database_file$this->options['persistent']);
  372.             if (MDB2::isError($connection)) {
  373.                 return $connection;
  374.             }
  375.             $this->connection $connection;
  376.             $this->connected_dsn $this->dsn;
  377.             $this->connected_database_name $database_file;
  378.             $this->opened_persistent $this->options['persistent'];
  379.  
  380.             if (!$this->auto_commit && MDB2::isError($trans_result $this->_doQuery('BEGIN'))) {
  381.                 @ibase_close($this->connection);
  382.                 $this->connection = 0;
  383.                 return $trans_result;
  384.             }
  385.         }
  386.         return MDB2_OK;
  387.     }
  388.  
  389.     // }}}
  390.     // {{{ _close()
  391.     /**
  392.      * Close the database connection
  393.      *
  394.      * @return boolean 
  395.      * @access private
  396.      ***/
  397.     function _close()
  398.     {
  399.         if ($this->connection != 0{
  400.             if (!$this->auto_commit{
  401.                 $result $this->_doQuery('END');
  402.             }
  403.             @ibase_close($this->connection);
  404.             $this->connection = 0;
  405.             unset($GLOBALS['_MDB2_databases'][$this->db_index]);
  406.  
  407.             if (isset($result&& MDB2::isError($result)) {
  408.                 return $result;
  409.             }
  410.         }
  411.         return MDB2_OK;
  412.     }
  413.  
  414.     // }}}
  415.     // {{{ _doQuery()
  416.  
  417.     /**
  418.      * Execute a query
  419.      * @param string $query the SQL query
  420.      * @return mixed result identifier if query executed, else MDB2_error
  421.      * @access private
  422.      ***/
  423.     function _doQuery($query$prepared_query = false)
  424.     {
  425.         $connection ($this->auto_commit ? $this->connection $this->transaction_id);
  426.         if ($prepared_query
  427.             && isset($this->query_parameters[$prepared_query])
  428.             && count($this->query_parameters[$prepared_query]> 2)
  429.         {
  430.             $this->query_parameters[$prepared_query][0$connection;
  431.             $this->query_parameters[$prepared_query][1$query;
  432.             $result @call_user_func_array('ibase_query'$this->query_parameters[$prepared_query]);
  433.         else {
  434.             //Not Prepared Query
  435.             $result @ibase_query($connection$query);
  436.             if (ibase_errmsg(== 'Query argument missed'//ibase_errcode() only available in PHP5
  437.                 //connection lost, try again...
  438.                 $this->connect();
  439.                 //rollback the failed transaction to prevent deadlock and execute the query again
  440.                 if ($this->transaction_id{
  441.                     $this->rollback();
  442.                 }
  443.                 $result @ibase_query($this->connection$query);
  444.             }
  445.         }
  446.         if (!$result{
  447.             return $this->raiseError($result);
  448.         }
  449.         return $result;
  450.     }
  451.  
  452.     // }}}
  453.     // {{{ _executePrepared()
  454.  
  455.     /**
  456.      * Execute a prepared query statement.
  457.      *
  458.      * @param int $prepared_query argument is a handle that was returned by
  459.      *        the function prepare()
  460.      * @param string $query query to be executed
  461.      * @param array $types array that contains the types of the columns in the result set
  462.      * @param mixed $result_class string which specifies which result class to use
  463.      * @param mixed $result_wrap_class string which specifies which class to wrap results in
  464.      * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure
  465.      *
  466.      * @access private
  467.      */
  468.     function &_executePrepared($prepared_query$query$types = null,
  469.         $result_class = false$result_wrap_class = false)
  470.     {
  471.         $ismanip MDB2::isManip($query);
  472.         $offset $this->row_offset;
  473.         $limit $this->row_limit;
  474.         $this->row_offset $this->row_limit = 0;
  475.         $this->debug($query'query');
  476.         $this->last_query = $query;
  477.  
  478.         $connect $this->connect();
  479.         if (MDB2::isError($connect)) {
  480.             return $connect;
  481.         }
  482.  
  483.         $result $this->_doQuery($query$prepared_query);
  484.         if (!MDB2::isError($result)) {
  485.             if ($ismanip{
  486.                 return MDB2_OK;
  487.             else {
  488.                 if (!$result_class{
  489.                     $result_class $this->options['result_buffering']
  490.                         ? $this->options['buffered_result_class'$this->options['result_class'];
  491.                 }
  492.                 $class_name sprintf($result_class$this->phptype);
  493.                 $result =new $class_name($this$result$offset$limit);
  494.                 if ($types{
  495.                     $err $result->setResultTypes($types);
  496.                     if (MDB2::isError($err)) {
  497.                         $result->free();
  498.                         return $err;
  499.                     }
  500.                 }
  501.                 if (!$result_wrap_class{
  502.                     $result_wrap_class $this->options['result_wrap_class'];
  503.                 }
  504.                 if ($result_wrap_class{
  505.                     $result =new $result_wrap_class($result);
  506.                 }
  507.                 return $result;
  508.             }
  509.         }
  510.         return $result;
  511.     }
  512.  
  513.     // }}}
  514.     // {{{ query()
  515.  
  516.     /**
  517.      * Send a query to the database and return any results
  518.      *
  519.      * @param string $query the SQL query
  520.      * @param array $types array that contains the types of the columns in the result set
  521.      * @param mixed $result_class string which specifies which result class to use
  522.      * @param mixed $result_wrap_class string which specifies which class to wrap results in
  523.      * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure
  524.      *
  525.      * @access public
  526.      */
  527.     function &query($query$types = null$result_class = false$result_wrap_class = false)
  528.     {
  529.         $result =$this->_executePrepared(false$query$types$result_class$result_wrap_class);
  530.         return $result;
  531.     }
  532.  
  533.     // }}}
  534.     // {{{ affectedRows()
  535.  
  536.     /**
  537.      * returns the affected rows of a query
  538.      *
  539.      * @return mixed MDB2 Error Object or number of rows
  540.      * @access public
  541.      */
  542.     function affectedRows()
  543.     {
  544.         if (function_exists('ibase_affected_rows')) //PHP5 only
  545.             $affected_rows @ibase_affected_rows($this->connection);
  546.             if ($affected_rows === false{
  547.                 return $this->raiseError(MDB2_ERROR_NEED_MORE_DATA);
  548.             }
  549.             return $affected_rows;
  550.         }
  551.         return parent::affectedRows();
  552.     }
  553.  
  554.     // }}}
  555.     // {{{ nextID()
  556.  
  557.     /**
  558.      * returns the next free id of a sequence
  559.      *
  560.      * @param string  $seq_name name of the sequence
  561.      * @param boolean $ondemand when true the seqence is
  562.      *                           automatic created, if it
  563.      *                           not exists
  564.      * @return mixed MDB2 Error Object or id
  565.      * @access public
  566.      */
  567.     function nextID($seq_name$ondemand = true)
  568.     {
  569.         $sequence_name $this->getSequenceName($seq_name);
  570.         $this->pushErrorHandling(PEAR_ERROR_RETURN);
  571.         $query = "SELECT GEN_ID($sequence_name, 1) as the_value FROM RDB\$DATABASE";
  572.         $result $this->queryOne($query);
  573.         $this->popErrorHandling();
  574.         if (MDB2::isError($result)) {
  575.             if ($ondemand{
  576.                 $this->loadModule('manager');
  577.                 // Since we are creating the sequence on demand
  578.                 // we know the first id = 1 so initialize the
  579.                 // sequence at 2
  580.                 $result $this->manager->createSequence($seq_name2);
  581.                 if (MDB2::isError($result)) {
  582.                     return $this->raiseError(MDB2_ERRORnullnull,
  583.                         'nextID: on demand sequence could not be created');
  584.                 else {
  585.                     // First ID of a newly created sequence is 1
  586.                     return 1;
  587.                 }
  588.             }
  589.         }
  590.         return $result;
  591.     }
  592.  
  593.     // }}}
  594.     // {{{ currID()
  595.  
  596.     /**
  597.      * returns the current id of a sequence
  598.      *
  599.      * @param string  $seq_name name of the sequence
  600.      * @return mixed MDB2 Error Object or id
  601.      * @access public
  602.      */
  603.     function currID($seq_name)
  604.     {
  605.         //$sequence_name = $this->getSequenceName($seq_name);
  606.         $sequence_name strtoupper($this->getSequenceName($seq_name));
  607.         $query = "SELECT RDB\$GENERATOR_ID FROM RDB\$GENERATORS WHERE RDB\$GENERATOR_NAME='$sequence_name'";
  608.         $value $this->queryOne($query);
  609.         if (MDB2::isError($value)) {
  610.             return $this->raiseError(MDB2_ERRORnullnull,
  611.                 'currID: Unable to select from ' $seqname;
  612.         }
  613.         if (!is_numeric($value)) {
  614.             return $this->raiseError(MDB2_ERRORnullnull,
  615.                 'currID: could not find value in sequence table');
  616.         }
  617.         return $value;
  618.     }
  619. }
  620.  
  621. class MDB2_Result_ibase extends MDB2_Result_Common
  622. {
  623.     var $limits;
  624.  
  625.     // }}}
  626.     // {{{ constructor
  627.  
  628.     /**
  629.      * Constructor
  630.      */
  631.     function MDB2_Result_ibase(&$mdb&$result$offset$limit)
  632.     {
  633.         parent::MDB2_Result_Common($mdb$result);
  634.         if ($offset || $limit{
  635.             $this->limits = array(
  636.                 'offset' => $offset,
  637.                 'count' => 0,
  638.                 'limit' => ($limit - 1),
  639.             );
  640.         }
  641.     }
  642.  
  643.     // }}}
  644.     // {{{ _skipLimitOffset()
  645.  
  646.     /**
  647.      * Skip the first row of a result set.
  648.      *
  649.      * @param resource $result 
  650.      * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure
  651.      * @access private
  652.      */
  653.     function _skipLimitOffset()
  654.     {
  655.         if (isset($this->limits&& is_array($this->limits)) {
  656.             if ($this->rownum $this->limits['limit']{
  657.                 return false;
  658.             }
  659.             while ($this->limits['count'$this->limits['offset']{
  660.                 ++$this->limits['count'];
  661.                 if (!is_array(@ibase_fetch_row($this->result))) {
  662.                     $this->limits['count'$this->limits['offset'];
  663.                     return false;
  664.                 }
  665.             }
  666.         }
  667.         return true;
  668.     }
  669.  
  670.     // }}}
  671.     // {{{ fetch()
  672.  
  673.     /**
  674.     * fetch value from a result set
  675.     *
  676.     * @param int    $rownum    number of the row where the data can be found
  677.     * @param int    $colnum    field number where the data can be found
  678.     * @return mixed string on success, a MDB2 error on failure
  679.     * @access public
  680.     */
  681.     function fetch($rownum = 0$colnum = 0)
  682.     {
  683.         $seek $this->seek($rownum);
  684.         if (MDB2::isError($seek)) {
  685.             return $seek;
  686.         }
  687.         $fetchmode is_numeric($colnumMDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC;
  688.         $row $this->fetchRow($fetchmode);
  689.         if (!$row || MDB2::isError($row)) {
  690.             return $row;
  691.         }
  692.         if (!array_key_exists($colnum$row)) {
  693.             return null;
  694.         }
  695.         return $row[$colnum];
  696.     }
  697.  
  698.     // }}}
  699.     // {{{ fetchRow()
  700.  
  701.     /**
  702.      * Fetch a row and insert the data into an existing array.
  703.      *
  704.      * @param int       $fetchmode  how the array data should be indexed
  705.      * @return int data array on success, a MDB2 error on failure
  706.      * @access public
  707.      */
  708.     function fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT)
  709.     {
  710.         /*
  711.         if ($this->result === true) {
  712.             //query successfully executed, but without results...
  713.             return null;
  714.         }
  715.         */
  716.  
  717.         if ($fetchmode == MDB2_FETCHMODE_DEFAULT{
  718.             $fetchmode $this->mdb->fetchmode;
  719.         }
  720.         if (!$this->_skipLimitOffset()) {
  721.             return null;
  722.         }
  723.         if ($fetchmode MDB2_FETCHMODE_ASSOC{
  724.             $row @ibase_fetch_assoc($this->result);
  725.             if (is_array($row)
  726.                 && $this->mdb->options['portability'MDB2_PORTABILITY_LOWERCASE
  727.             {
  728.                 $row array_change_key_case($rowCASE_LOWER);
  729.             }
  730.         else {
  731.             $row @ibase_fetch_row($this->result);
  732.         }
  733.         if (!$row{
  734.             if (is_null($this->result)) {
  735.                 return $this->mdb->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  736.                     'fetchRow: resultset has already been freed');
  737.             }
  738.             return null;
  739.         }
  740.         if (isset($this->types)) {
  741.             $row $this->mdb->datatype->convertResultRow($this->types$row);
  742.         }
  743.         if ($this->mdb->options['portability'MDB2_PORTABILITY_RTRIM{
  744.             $this->mdb->_rtrimArrayValues($row);
  745.         }
  746.         if ($this->mdb->options['portability'MDB2_PORTABILITY_EMPTY_TO_NULL{
  747.             $this->mdb->_convertEmptyArrayValuesToNull($row);
  748.         }
  749.         ++$this->rownum;
  750.         return $row;
  751.     }
  752.  
  753.     // }}}
  754.     // {{{ getColumnNames()
  755.  
  756.     /**
  757.      * Retrieve the names of columns returned by the DBMS in a query result.
  758.      *
  759.      * @return mixed associative array variable
  760.      *       that holds the names of columns. The indexes of the array are
  761.      *       the column names mapped to lower case and the values are the
  762.      *       respective numbers of the columns starting from 0. Some DBMS may
  763.      *       not return any columns when the result set does not contain any
  764.      *       rows.
  765.      * @access public
  766.      */
  767.     function getColumnNames()
  768.     {
  769.         $columns = array();
  770.         $numcols $this->numCols();
  771.         if (MDB2::isError($numcols)) {
  772.             return $numcols;
  773.         }
  774.         for ($column = 0; $column $numcols$column++{
  775.             $column_info @ibase_field_info($this->result$column);
  776.             $columns[$column_info['name']] $column;
  777.         }
  778.         if ($this->mdb->options['portability'MDB2_PORTABILITY_LOWERCASE{
  779.             $columns array_change_key_case($columnsCASE_LOWER);
  780.         }
  781.         return $columns;
  782.     }
  783.  
  784.     // }}}
  785.     // {{{ numCols()
  786.  
  787.     /**
  788.      * Count the number of columns returned by the DBMS in a query result.
  789.      *
  790.      * @return mixed integer value with the number of columns, a MDB2 error
  791.      *       on failure
  792.      * @access public
  793.      */
  794.     function numCols()
  795.     {
  796.         /*
  797.         if ($this->result === true) {
  798.             //query successfully executed, but without results...
  799.             return 0;
  800.         }
  801.         */
  802.         if (!is_resource($this->result)) {
  803.             return $this->mdb->raiseError('numCols(): not a valid ibase resource');
  804.         }
  805.         $cols @ibase_num_fields($this->result);
  806.         if (is_null($cols)) {
  807.             if (is_null($this->result)) {
  808.                 return $this->mdb->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  809.                     'numCols: resultset has already been freed');
  810.             }
  811.             return $this->mdb->raiseError();
  812.         }
  813.         return $cols;
  814.     }
  815.  
  816.     // }}}
  817.     // {{{ free()
  818.  
  819.     /**
  820.      * Free the internal resources associated with $result.
  821.      *
  822.      * @return boolean true on success, false if $result is invalid
  823.      * @access public
  824.      */
  825.     function free()
  826.     {
  827.         if (is_resource($this->result)) {
  828.             $free @ibase_free_result($this->result);
  829.             if (!$free{
  830.                 if (is_null($this->result)) {
  831.                     return MDB2_OK;
  832.                 }
  833.                 return $this->mdb->raiseError();
  834.             }
  835.         }
  836.         $this->result = null;
  837.         return MDB2_OK;
  838.     }
  839. }
  840.  
  841. class MDB2_BufferedResult_ibase extends MDB2_Result_ibase
  842. {
  843.     var $buffer;
  844.     var $buffer_rownum = - 1;
  845.  
  846.     // }}}
  847.     // {{{ constructor
  848.  
  849.     /**
  850.      * Constructor
  851.      */
  852.     function MDB2_BufferedResult_ibase(&$mdb&$result$offset$limit)
  853.     {
  854.         parent::MDB2_Result_ibase($mdb$result$offset$limit);
  855.     }
  856.  
  857.     // }}}
  858.     // {{{ _fillBuffer()
  859.  
  860.     /**
  861.      * Fill the row buffer
  862.      *
  863.      * @param int $rownum   row number upto which the buffer should be filled
  864.                             if the row number is null all rows are ready into the buffer
  865.      * @return boolean true on success, false on failure
  866.      * @access private
  867.      */
  868.     function _fillBuffer($rownum = null)
  869.     {
  870.         if (isset($this->buffer&& is_array($this->buffer)) {
  871.             if (is_null($rownum)) {
  872.                 if (!end($this->buffer)) {
  873.                     return false;
  874.                 }
  875.             else if (isset($this->buffer[$rownum])) {
  876.                 return (bool) $this->buffer[$rownum];
  877.             }
  878.         }
  879.  
  880.         if (!$this->_skipLimitOffset()) {
  881.             return false;
  882.         }
  883.  
  884.         $buffer = true;
  885.         while ((is_null($rownum|| $this->buffer_rownum $rownum)
  886.             && (!isset($this->limits|| $this->buffer_rownum $this->limits['limit'])
  887.             && ($buffer @ibase_fetch_row($this->result))
  888.         {
  889.             ++$this->buffer_rownum;
  890.             $this->buffer[$this->buffer_rownum$buffer;
  891.         }
  892.  
  893.         if (!$buffer{
  894.             ++$this->buffer_rownum;
  895.             $this->buffer[$this->buffer_rownum= false;
  896.             return false;
  897.         elseif (isset($this->limits&& $this->buffer_rownum >= $this->limits['limit']{
  898.             ++$this->buffer_rownum;
  899.             $this->buffer[$this->buffer_rownum= false;
  900.         }
  901.         return true;
  902.     }
  903.  
  904.     // }}}
  905.     // {{{ fetchRow()
  906.  
  907.     /**
  908.      * Fetch a row and insert the data into an existing array.
  909.      *
  910.      * @param int       $fetchmode  how the array data should be indexed
  911.      * @return int data array on success, a MDB2 error on failure
  912.      * @access public
  913.      */
  914.     function fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT)
  915.     {
  916.         if (is_null($this->result)) {
  917.             return $this->mdb->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  918.                 'fetchRow: resultset has already been freed');
  919.         }
  920.         $target_rownum $this->rownum + 1;
  921.         if ($fetchmode == MDB2_FETCHMODE_DEFAULT{
  922.             $fetchmode $this->mdb->fetchmode;
  923.         }
  924.         if (!$this->_fillBuffer($target_rownum)) {
  925.             return null;
  926.         }
  927.         $row $this->buffer[$target_rownum];
  928.         if ($fetchmode MDB2_FETCHMODE_ASSOC{
  929.             $column_names $this->getColumnNames();
  930.             foreach ($column_names as $name => $i{
  931.                 $column_names[$name$row[$i];
  932.             }
  933.             $row $column_names;
  934.         }
  935.         if (isset($this->types)) {
  936.             $row $this->mdb->datatype->convertResultRow($this->types$row);
  937.         }
  938.         if ($this->mdb->options['portability'MDB2_PORTABILITY_RTRIM{
  939.             $this->mdb->_rtrimArrayValues($row);
  940.         }
  941.         if ($this->mdb->options['portability'MDB2_PORTABILITY_EMPTY_TO_NULL{
  942.             $this->mdb->_convertEmptyArrayValuesToNull($row);
  943.         }
  944.         ++$this->rownum;
  945.         return $row;
  946.     }
  947.  
  948.     // }}}
  949.     // {{{ seek()
  950.  
  951.     /**
  952.     * seek to a specific row in a result set
  953.     *
  954.     * @param int    $rownum    number of the row where the data can be found
  955.     * @return mixed MDB2_OK on success, a MDB2 error on failure
  956.     * @access public
  957.     */
  958.     function seek($rownum = 0)
  959.     {
  960.         if (is_null($this->result)) {
  961.             return $this->mdb->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  962.                 'seek: resultset has already been freed');
  963.         }
  964.         $this->rownum $rownum - 1;
  965.         return MDB2_OK;
  966.     }
  967.  
  968.     // }}}
  969.     // {{{ valid()
  970.  
  971.     /**
  972.      * check if the end of the result set has been reached
  973.      *
  974.      * @return mixed true or false on sucess, a MDB2 error on failure
  975.      * @access public
  976.      */
  977.     function valid()
  978.     {
  979.         if (is_null($this->result)) {
  980.             return $this->mdb->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  981.                 'valid: resultset has already been freed');
  982.         }
  983.         if ($this->_fillBuffer($this->rownum + 1)) {
  984.             return true;
  985.         }
  986.         return false;
  987.     }
  988.  
  989.     // }}}
  990.     // {{{ numRows()
  991.  
  992.     /**
  993.      * returns the number of rows in a result object
  994.      *
  995.      * @return mixed MDB2 Error Object or the number of rows
  996.      * @access public
  997.      */
  998.     function numRows()
  999.     {
  1000.         if (is_null($this->result)) {
  1001.             return $this->mdb->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  1002.                 'seek: resultset has already been freed');
  1003.         }
  1004.         $this->_fillBuffer();
  1005.         return $this->buffer_rownum;
  1006.     }
  1007.  
  1008.     // }}}
  1009.     // {{{ free()
  1010.  
  1011.     /**
  1012.      * Free the internal resources associated with $result.
  1013.      *
  1014.      * @return boolean true on success, false if $result is invalid
  1015.      * @access public
  1016.      */
  1017.     function free()
  1018.     {
  1019.         $this->buffer = null;
  1020.         $this->buffer_rownum = null;
  1021.         $free = parent::free();
  1022.     }
  1023. }
  1024.  
  1025. ?>

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