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

Source for file oci8.php

Documentation is available at oci8.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-2006 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: Lukas Smith <smith@pooteeweet.org>                           |
  44. // +----------------------------------------------------------------------+
  45.  
  46. // $Id: oci8.php,v 1.186 2006/10/25 14:25:17 quipo Exp $
  47.  
  48. /**
  49.  * MDB2 OCI8 driver
  50.  *
  51.  * @package MDB2
  52.  * @category Database
  53.  * @author Lukas Smith <smith@pooteeweet.org>
  54.  */
  55. class MDB2_Driver_oci8 extends MDB2_Driver_Common
  56. {
  57.     // {{{ properties
  58.     var $string_quoting = array('start' => "'"'end' => "'"'escape' => "'"'escape_pattern' => '@');
  59.  
  60.     var $identifier_quoting = array('start' => '"''end' => '"''escape' => '"');
  61.  
  62.     var $uncommitedqueries = 0;
  63.     // }}}
  64.     // {{{ constructor
  65.  
  66.     /**
  67.      * Constructor
  68.      */
  69.     function __construct()
  70.     {
  71.         parent::__construct();
  72.  
  73.         $this->phptype 'oci8';
  74.         $this->dbsyntax 'oci8';
  75.  
  76.         $this->supported['sequences'= true;
  77.         $this->supported['indexes'= true;
  78.         $this->supported['summary_functions'= true;
  79.         $this->supported['order_by_text'= true;
  80.         $this->supported['current_id'= true;
  81.         $this->supported['affected_rows'= true;
  82.         $this->supported['transactions'= true;
  83.         $this->supported['savepoints'= true;
  84.         $this->supported['limit_queries'= true;
  85.         $this->supported['LOBs'= true;
  86.         $this->supported['replace''emulated';
  87.         $this->supported['sub_selects'= true;
  88.         $this->supported['auto_increment'= false; // implementation is broken
  89.         $this->supported['primary_key'= true;
  90.         $this->supported['result_introspection'= true;
  91.         $this->supported['prepared_statements'= true;
  92.         $this->supported['identifier_quoting'= true;
  93.         $this->supported['pattern_escaping'= true;
  94.         $this->supported['new_link'= true;
  95.  
  96.         $this->options['DBA_username'= false;
  97.         $this->options['DBA_password'= false;
  98.         $this->options['database_name_prefix'= false;
  99.         $this->options['emulate_database'= true;
  100.         $this->options['default_tablespace'= false;
  101.         $this->options['default_text_field_length'= 2000;
  102.         $this->options['result_prefetching'= false;
  103.     }
  104.  
  105.     // }}}
  106.     // {{{ errorInfo()
  107.  
  108.     /**
  109.      * This method is used to collect information about an error
  110.      *
  111.      * @param integer $error 
  112.      * @return array 
  113.      * @access public
  114.      */
  115.     function errorInfo($error = null)
  116.     {
  117.         if (is_resource($error)) {
  118.             $error_data @OCIError($error);
  119.             $error = null;
  120.         elseif ($this->connection{
  121.             $error_data @OCIError($this->connection);
  122.         else {
  123.             $error_data @OCIError();
  124.         }
  125.         $native_code $error_data['code'];
  126.         $native_msg  $error_data['message'];
  127.         if (is_null($error)) {
  128.             static $ecode_map;
  129.             if (empty($ecode_map)) {
  130.                 $ecode_map = array(
  131.                     1    => MDB2_ERROR_CONSTRAINT,
  132.                     900  => MDB2_ERROR_SYNTAX,
  133.                     904  => MDB2_ERROR_NOSUCHFIELD,
  134.                     913  => MDB2_ERROR_VALUE_COUNT_ON_ROW,
  135.                     921  => MDB2_ERROR_SYNTAX,
  136.                     923  => MDB2_ERROR_SYNTAX,
  137.                     942  => MDB2_ERROR_NOSUCHTABLE,
  138.                     955  => MDB2_ERROR_ALREADY_EXISTS,
  139.                     1400 => MDB2_ERROR_CONSTRAINT_NOT_NULL,
  140.                     1401 => MDB2_ERROR_INVALID,
  141.                     1407 => MDB2_ERROR_CONSTRAINT_NOT_NULL,
  142.                     1418 => MDB2_ERROR_NOT_FOUND,
  143.                     1476 => MDB2_ERROR_DIVZERO,
  144.                     1722 => MDB2_ERROR_INVALID_NUMBER,
  145.                     2289 => MDB2_ERROR_NOSUCHTABLE,
  146.                     2291 => MDB2_ERROR_CONSTRAINT,
  147.                     2292 => MDB2_ERROR_CONSTRAINT,
  148.                     2449 => MDB2_ERROR_CONSTRAINT,
  149.                 );
  150.             }
  151.             if (isset($ecode_map[$native_code])) {
  152.                 $error $ecode_map[$native_code];
  153.             }
  154.         }
  155.         return array($error$native_code$native_msg);
  156.     }
  157.  
  158.     // }}}
  159.     // {{{ beginTransaction()
  160.  
  161.     /**
  162.      * Start a transaction or set a savepoint.
  163.      *
  164.      * @param   string  name of a savepoint to set
  165.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  166.      *
  167.      * @access  public
  168.      */
  169.     function beginTransaction($savepoint = null)
  170.     {
  171.         $this->debug('Starting transaction/savepoint'__FUNCTION__array('is_manip' => true'savepoint' => $savepoint));
  172.         if (!is_null($savepoint)) {
  173.             if (!$this->in_transaction{
  174.                 return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  175.                     'savepoint cannot be released when changes are auto committed'__FUNCTION__);
  176.             }
  177.             $query 'SAVEPOINT '.$savepoint;
  178.             return $this->_doQuery($querytrue);
  179.         elseif ($this->in_transaction{
  180.             return MDB2_OK;  //nothing to do
  181.         }
  182.         if (!$this->destructor_registered && $this->opened_persistent{
  183.             $this->destructor_registered = true;
  184.             register_shutdown_function('MDB2_closeOpenTransactions');
  185.         }
  186.         $this->in_transaction = true;
  187.         ++$this->uncommitedqueries;
  188.         return MDB2_OK;
  189.     }
  190.  
  191.     // }}}
  192.     // {{{ commit()
  193.  
  194.     /**
  195.      * Commit the database changes done during a transaction that is in
  196.      * progress or release a savepoint. This function may only be called when
  197.      * auto-committing is disabled, otherwise it will fail. Therefore, a new
  198.      * transaction is implicitly started after committing the pending changes.
  199.      *
  200.      * @param   string  name of a savepoint to release
  201.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  202.      *
  203.      * @access  public
  204.      */
  205.     function commit($savepoint = null)
  206.     {
  207.         $this->debug('Committing transaction/savepoint'__FUNCTION__array('is_manip' => true'savepoint' => $savepoint));
  208.         if (!$this->in_transaction{
  209.             return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  210.                 'commit/release savepoint cannot be done changes are auto committed'__FUNCTION__);
  211.         }
  212.         if (!is_null($savepoint)) {
  213.             return MDB2_OK;
  214.         }
  215.  
  216.         if ($this->uncommitedqueries{
  217.             $connection $this->getConnection();
  218.             if (PEAR::isError($connection)) {
  219.                 return $connection;
  220.             }
  221.             if (!@OCICommit($connection)) {
  222.                 return $this->raiseError(nullnullnull,
  223.                 'Unable to commit transaction'__FUNCTION__);
  224.             }
  225.             $this->uncommitedqueries = 0;
  226.         }
  227.         $this->in_transaction = false;
  228.         return MDB2_OK;
  229.     }
  230.  
  231.     // }}}
  232.     // {{{ rollback()
  233.  
  234.     /**
  235.      * Cancel any database changes done during a transaction or since a specific
  236.      * savepoint that is in progress. This function may only be called when
  237.      * auto-committing is disabled, otherwise it will fail. Therefore, a new
  238.      * transaction is implicitly started after canceling the pending changes.
  239.      *
  240.      * @param   string  name of a savepoint to rollback to
  241.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  242.      *
  243.      * @access  public
  244.      */
  245.     function rollback($savepoint = null)
  246.     {
  247.         $this->debug('Rolling back transaction/savepoint'__FUNCTION__array('is_manip' => true'savepoint' => $savepoint));
  248.         if (!$this->in_transaction{
  249.             return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  250.                 'rollback cannot be done changes are auto committed'__FUNCTION__);
  251.         }
  252.         if (!is_null($savepoint)) {
  253.             $query 'ROLLBACK TO SAVEPOINT '.$savepoint;
  254.             return $this->_doQuery($querytrue);
  255.         }
  256.  
  257.         if ($this->uncommitedqueries{
  258.             $connection $this->getConnection();
  259.             if (PEAR::isError($connection)) {
  260.                 return $connection;
  261.             }
  262.             if (!@OCIRollback($connection)) {
  263.                 return $this->raiseError(nullnullnull,
  264.                 'Unable to rollback transaction'__FUNCTION__);
  265.             }
  266.             $this->uncommitedqueries = 0;
  267.         }
  268.         $this->in_transaction = false;
  269.         return MDB2_OK;
  270.     }
  271.  
  272.     // }}}
  273.     // {{{ function setTransactionIsolation()
  274.  
  275.     /**
  276.      * Set the transacton isolation level.
  277.      *
  278.      * @param   string  standard isolation level
  279.      *                   READ UNCOMMITTED (allows dirty reads)
  280.      *                   READ COMMITTED (prevents dirty reads)
  281.      *                   REPEATABLE READ (prevents nonrepeatable reads)
  282.      *                   SERIALIZABLE (prevents phantom reads)
  283.      * @return  mixed   MDB2_OK on success, a MDB2 error on failure
  284.      *
  285.      * @access  public
  286.      * @since   2.1.1
  287.      */
  288.     function setTransactionIsolation($isolation)
  289.     {
  290.         $this->debug('Setting transaction isolation level'__FUNCTION__array('is_manip' => true));
  291.         switch ($isolation{
  292.         case 'READ UNCOMMITTED':
  293.             $isolation 'READ COMMITTED';
  294.         case 'READ COMMITTED':
  295.         case 'REPEATABLE READ':
  296.             $isolation 'SERIALIZABLE';
  297.         case 'SERIALIZABLE':
  298.             break;
  299.         default:
  300.             return $this->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  301.                 'isolation level is not supported: '.$isolation__FUNCTION__);
  302.         }
  303.  
  304.         $query = "ALTER SESSION ISOLATION LEVEL $isolation";
  305.         return $this->_doQuery($querytrue);
  306.     }
  307.  
  308.     // }}}
  309.     // {{{ _doConnect()
  310.  
  311.     /**
  312.      * do the grunt work of the connect
  313.      *
  314.      * @return connection on success or MDB2 Error Object on failure
  315.      * @access protected
  316.      */
  317.     function _doConnect($username$password$persistent = false)
  318.     {
  319.         if (!PEAR::loadExtension($this->phptype)) {
  320.             return $this->raiseError(MDB2_ERROR_NOT_FOUNDnullnull,
  321.                 'extension '.$this->phptype.' is not compiled into PHP'__FUNCTION__);
  322.         }
  323.  
  324.         $sid '';
  325.         if ($this->dsn['hostspec']{
  326.             $sid $this->dsn['hostspec'];
  327.             if (!$this->options['emulate_database'&& $this->database_name{
  328.                 $port $service '';
  329.                 if ($this->dsn['port']{
  330.                     $port ':'.$this->dsn['port'];
  331.                 }
  332.                 $service $this->database_name;
  333.                 if (substr($service01!== '/'{
  334.                     $service '/'.$service;
  335.                 }
  336.                 $sid '//'.$sid.$port.$service;
  337.             }
  338.         elseif (!$this->options['emulate_database'&& $this->database_name{
  339.             $sid $this->database_name;
  340.         else {
  341.             $sid getenv('ORACLE_SID');
  342.         }
  343.  
  344.         if (empty($sid)) {
  345.             return $this->raiseError(MDB2_ERROR_NOT_FOUNDnullnull,
  346.                 'it was not specified a valid Oracle Service Identifier (SID)'__FUNCTION__);
  347.         }
  348.  
  349.         if (function_exists('oci_connect')) {
  350.             if (isset($this->dsn['new_link'])
  351.                 && ($this->dsn['new_link'== 'true' || $this->dsn['new_link'=== true)
  352.             {
  353.                 $connect_function 'oci_new_connect';
  354.             else {
  355.                 $connect_function $persistent 'oci_pconnect' 'oci_connect';
  356.             }
  357.  
  358.             $charset = empty($this->dsn['charset']? null : $this->dsn['charset'];
  359.             $connection @$connect_function($username$password$sid$charset);
  360.             $error @OCIError();
  361.             if (isset($error['code']&& $error['code'== 12541{
  362.                 // Couldn't find TNS listener.  Try direct connection.
  363.                 $connection @$connect_function($username$passwordnull$charset);
  364.             }
  365.         else {
  366.             $connect_function $persistent 'OCIPLogon' 'OCILogon';
  367.             $connection @$connect_function($username$password$sid);
  368.  
  369.             if (!empty($this->dsn['charset'])) {
  370.                 $result $this->setCharset($this->dsn['charset']$connection);
  371.                 if (PEAR::isError($result)) {
  372.                     return $result;
  373.                 }
  374.             }
  375.         }
  376.  
  377.         if (!$connection{
  378.             return $this->raiseError(MDB2_ERROR_CONNECT_FAILEDnullnull,
  379.                 'unable to establish a connection'__FUNCTION__);
  380.         }
  381.  
  382.        if (empty($this->dsn['disable_iso_date'])) {
  383.             $query "ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'";
  384.             $err =$this->_doQuery($querytrue$connection);
  385.             if (PEAR::isError($err)) {
  386.                 $this->disconnect(false);
  387.                 return $err;
  388.             }
  389.        }
  390.  
  391.         $query "ALTER SESSION SET NLS_NUMERIC_CHARACTERS='. '";
  392.         $err =$this->_doQuery($querytrue$connection);
  393.         if (PEAR::isError($err)) {
  394.             $this->disconnect(false);
  395.             return $err;
  396.         }
  397.  
  398.         return $connection;
  399.     }
  400.  
  401.     // }}}
  402.     // {{{ connect()
  403.  
  404.     /**
  405.      * Connect to the database
  406.      *
  407.      * @return MDB2_OK on success, MDB2 Error Object on failure
  408.      * @access public
  409.      */
  410.     function connect()
  411.     {
  412.         if ($this->database_name && $this->options['emulate_database']{
  413.              $this->dsn['username'$this->options['database_name_prefix'].$this->database_name;
  414.         }
  415.         if (is_resource($this->connection)) {
  416.             if (count(array_diff($this->connected_dsn$this->dsn)) == 0
  417.                 && $this->connected_database_name == $this->database_name
  418.                 && $this->opened_persistent == $this->options['persistent']
  419.             {
  420.                 return MDB2_OK;
  421.             }
  422.             $this->disconnect(false);
  423.         }
  424.  
  425.         $connection $this->_doConnect(
  426.             $this->dsn['username'],
  427.             $this->dsn['password'],
  428.             $this->options['persistent']
  429.         );
  430.         if (PEAR::isError($connection)) {
  431.             return $connection;
  432.         }
  433.         $this->connection $connection;
  434.         $this->connected_dsn $this->dsn;
  435.         $this->connected_database_name $this->database_name;
  436.         $this->opened_persistent $this->options['persistent'];
  437.         $this->dbsyntax $this->dsn['dbsyntax'$this->dsn['dbsyntax'$this->phptype;
  438.  
  439.         $this->as_keyword ' ';
  440.         $server_info $this->getServerVersion();
  441.         if (is_array($server_info)) {
  442.             if ($server_info['major'>= '10'{
  443.                 $this->as_keyword ' AS ';
  444.             }
  445.         }
  446.         return MDB2_OK;
  447.     }
  448.  
  449.     // }}}
  450.     // {{{ disconnect()
  451.  
  452.     /**
  453.      * Log out and disconnect from the database.
  454.      *
  455.      * @param  boolean $force if the disconnect should be forced even if the
  456.      *                         connection is opened persistently
  457.      * @return mixed true on success, false if not connected and error
  458.      *                 object on error
  459.      * @access public
  460.      */
  461.     function disconnect($force = true)
  462.     {
  463.         if (is_resource($this->connection)) {
  464.             if ($this->in_transaction{
  465.                 $dsn $this->dsn;
  466.                 $database_name $this->database_name;
  467.                 $persistent $this->options['persistent'];
  468.                 $this->dsn $this->connected_dsn;
  469.                 $this->database_name $this->connected_database_name;
  470.                 $this->options['persistent'$this->opened_persistent;
  471.                 $this->rollback();
  472.                 $this->dsn $dsn;
  473.                 $this->database_name $database_name;
  474.                 $this->options['persistent'$persistent;
  475.             }
  476.  
  477.             if (!$this->opened_persistent || $force{
  478.                 if (function_exists('oci_close')) {
  479.                     @oci_close($this->connection);
  480.                 else {
  481.                     @OCILogOff($this->connection);
  482.                 }
  483.             }
  484.             $this->uncommitedqueries = 0;
  485.         }
  486.         return parent::disconnect($force);
  487.     }
  488.  
  489.     // }}}
  490.     // {{{ standaloneExec()
  491.  
  492.    /**
  493.      * execute a query as database administrator
  494.      *
  495.      * @param string $query the SQL query
  496.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  497.      * @access public
  498.      */
  499.     function &standaloneExec($query)
  500.     {
  501.         $connection $this->_doConnect(
  502.             $this->options['DBA_username'],
  503.             $this->options['DBA_password'],
  504.             $this->options['persistent']
  505.         );
  506.         if (PEAR::isError($connection)) {
  507.             return $connection;
  508.         }
  509.  
  510.         $offset $this->offset;
  511.         $limit $this->limit;
  512.         $this->offset $this->limit = 0;
  513.         $query $this->_modifyQuery($queryfalse$limit$offset);
  514.  
  515.         $result =$this->_doQuery($queryfalse$connectionfalse);
  516.         @OCILogOff($connection);
  517.         if (PEAR::isError($result)) {
  518.             return $result;
  519.         }
  520.  
  521.         return $this->_affectedRows($connection$result);
  522.     }
  523.  
  524.     // }}}
  525.     // {{{ standaloneQuery()
  526.  
  527.    /**
  528.      * execute a query as DBA
  529.      *
  530.      * @param string $query the SQL query
  531.      * @param mixed   $types  array that contains the types of the columns in
  532.      *                         the result set
  533.      * @param boolean $is_manip  if the query is a manipulation query
  534.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  535.      * @access public
  536.      */
  537.     function &standaloneQuery($query$types = null$is_manip = false)
  538.     {
  539.         $connection $this->_doConnect(
  540.             $this->options['DBA_username'],
  541.             $this->options['DBA_password'],
  542.             $this->options['persistent']
  543.         );
  544.         if (PEAR::isError($connection)) {
  545.             return $connection;
  546.         }
  547.  
  548.         $offset $this->offset;
  549.         $limit $this->limit;
  550.         $this->offset $this->limit = 0;
  551.         $query $this->_modifyQuery($query$is_manip$limit$offset);
  552.  
  553.         $result =$this->_doQuery($query$is_manip$connectionfalse);
  554.         @OCILogOff($connection);
  555.         if (PEAR::isError($result)) {
  556.             return $result;
  557.         }
  558.  
  559.         if ($is_manip{
  560.             $affected_rows =  $this->_affectedRows($connection$result);
  561.             return $affected_rows;
  562.         }
  563.         $return =$this->_wrapResult($result$typestruefalse$limit$offset);
  564.         return $return;
  565.     }
  566.  
  567.     // }}}
  568.     // {{{ _modifyQuery()
  569.  
  570.     /**
  571.      * Changes a query string for various DBMS specific reasons
  572.      *
  573.      * @param string $query  query to modify
  574.      * @param boolean $is_manip  if it is a DML query
  575.      * @param integer $limit  limit the number of rows
  576.      * @param integer $offset  start reading from given offset
  577.      * @return string modified query
  578.      * @access protected
  579.      */
  580.     function _modifyQuery($query$is_manip$limit$offset)
  581.     {
  582.         if (preg_match('/^\s*SELECT/i'$query)) {
  583.             if (!preg_match('/\sFROM\s/i'$query)) {
  584.                 $query.= " FROM dual";
  585.             }
  586.             if ($limit > 0{
  587.                 // taken from http://svn.ez.no/svn/ezcomponents/packages/Database
  588.                 $max $offset $limit;
  589.                 if ($offset > 0{
  590.                     $min $offset + 1;
  591.                     $query = "SELECT * FROM (SELECT a.*, ROWNUM mdb2rn FROM ($query) a WHERE ROWNUM <= $max) WHERE mdb2rn >= $min";
  592.                 else {
  593.                     $query = "SELECT a.* FROM ($query) a WHERE ROWNUM <= $max";
  594.                 }
  595.             }
  596.         }
  597.         return $query;
  598.     }
  599.  
  600.     // }}}
  601.     // {{{ _doQuery()
  602.  
  603.     /**
  604.      * Execute a query
  605.      * @param string $query  query
  606.      * @param boolean $is_manip  if the query is a manipulation query
  607.      * @param resource $connection 
  608.      * @param string $database_name 
  609.      * @return result or error object
  610.      * @access protected
  611.      */
  612.     function &_doQuery($query$is_manip = false$connection = null$database_name = null)
  613.     {
  614.         $this->last_query $query;
  615.         $result $this->debug($query'query'array('is_manip' => $is_manip'when' => 'pre'));
  616.         if ($result{
  617.             if (PEAR::isError($result)) {
  618.                 return $result;
  619.             }
  620.             $query $result;
  621.         }
  622.         if ($this->getOption('disable_query')) {
  623.             if ($is_manip{
  624.                 return 0;
  625.             }
  626.             return null;
  627.         }
  628.  
  629.         if (is_null($connection)) {
  630.             $connection $this->getConnection();
  631.             if (PEAR::isError($connection)) {
  632.                 return $connection;
  633.             }
  634.         }
  635.  
  636.         $result @OCIParse($connection$query);
  637.         if (!$result{
  638.             $err $this->raiseError(nullnullnull,
  639.                 'Could not create statement'__FUNCTION__);
  640.             return $err;
  641.         }
  642.  
  643.         $mode $this->in_transaction ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS;
  644.         if (!@OCIExecute($result$mode)) {
  645.             $err =$this->raiseError($resultnullnull,
  646.                 'Could not execute statement'__FUNCTION__);
  647.             return $err;
  648.         }
  649.  
  650.         if (is_numeric($this->options['result_prefetching'])) {
  651.             @ocisetprefetch($result$this->options['result_prefetching']);
  652.         }
  653.  
  654.         $this->debug($query'query'array('is_manip' => $is_manip'when' => 'post''result' => $result));
  655.         return $result;
  656.     }
  657.  
  658.     // }}}
  659.     // {{{ _affectedRows()
  660.  
  661.     /**
  662.      * Returns the number of rows affected
  663.      *
  664.      * @param resource $result 
  665.      * @param resource $connection 
  666.      * @return mixed MDB2 Error Object or the number of rows affected
  667.      * @access private
  668.      */
  669.     function _affectedRows($connection$result = null)
  670.     {
  671.         if (is_null($connection)) {
  672.             $connection $this->getConnection();
  673.             if (PEAR::isError($connection)) {
  674.                 return $connection;
  675.             }
  676.         }
  677.         return @OCIRowCount($result);
  678.     }
  679.  
  680.     // }}}
  681.     // {{{ getServerVersion()
  682.  
  683.     /**
  684.      * return version information about the server
  685.      *
  686.      * @param string     $native  determines if the raw version string should be returned
  687.      * @return mixed array/string with version information or MDB2 error object
  688.      * @access public
  689.      */
  690.     function getServerVersion($native = false)
  691.     {
  692.         $connection $this->getConnection();
  693.         if (PEAR::isError($connection)) {
  694.             return $connection;
  695.         }
  696.         if ($this->connected_server_info{
  697.             $server_info $this->connected_server_info;
  698.         else {
  699.             $server_info @ociserverversion($connection);
  700.         }
  701.         if (!$server_info{
  702.             return $this->raiseError(nullnullnull,
  703.                 'Could not get server information'__FUNCTION__);
  704.         }
  705.         // cache server_info
  706.         $this->connected_server_info $server_info;
  707.         if (!$native{
  708.             if (!preg_match('/ (\d+)\.(\d+)\.(\d+)\.([\d\.]+) /'$server_info$tmp)) {
  709.                 return $this->raiseError(MDB2_ERROR_INVALIDnullnull,
  710.                     'Could not parse version information:'.$server_info__FUNCTION__);
  711.             }
  712.             $server_info = array(
  713.                 'major' => $tmp[1],
  714.                 'minor' => $tmp[2],
  715.                 'patch' => $tmp[3],
  716.                 'extra' => $tmp[4],
  717.                 'native' => $server_info,
  718.             );
  719.         }
  720.         return $server_info;
  721.     }
  722.  
  723.     // }}}
  724.     // {{{ prepare()
  725.  
  726.     /**
  727.      * Prepares a query for multiple execution with execute().
  728.      * With some database backends, this is emulated.
  729.      * prepare() requires a generic query as string like
  730.      * 'INSERT INTO numbers VALUES(?,?)' or
  731.      * 'INSERT INTO numbers VALUES(:foo,:bar)'.
  732.      * The ? and :[a-zA-Z] and  are placeholders which can be set using
  733.      * bindParam() and the query can be send off using the execute() method.
  734.      *
  735.      * @param string $query the query to prepare
  736.      * @param mixed   $types  array that contains the types of the placeholders
  737.      * @param mixed   $result_types  array that contains the types of the columns in
  738.      *                         the result set or MDB2_PREPARE_RESULT, if set to
  739.      *                         MDB2_PREPARE_MANIP the query is handled as a manipulation query
  740.      * @param mixed   $lobs   key (field) value (parameter) pair for all lob placeholders
  741.      * @return mixed resource handle for the prepared query on success, a MDB2
  742.      *         error on failure
  743.      * @access public
  744.      * @see bindParam, execute
  745.      */
  746.     function &prepare($query$types = null$result_types = null$lobs = array())
  747.     {
  748.         if ($this->options['emulate_prepared']{
  749.             $obj =parent::prepare($query$types$result_types$lobs);
  750.             return $obj;
  751.         }
  752.         $is_manip ($result_types === MDB2_PREPARE_MANIP);
  753.         $offset $this->offset;
  754.         $limit $this->limit;
  755.         $this->offset $this->limit = 0;
  756.         $result $this->debug($query__FUNCTION__array('is_manip' => $is_manip'when' => 'pre'));
  757.         if ($result{
  758.             if (PEAR::isError($result)) {
  759.                 return $result;
  760.             }
  761.             $query $result;
  762.         }
  763.         $query $this->_modifyQuery($query$is_manip$limit$offset);
  764.         $placeholder_type_guess $placeholder_type = null;
  765.         $question '?';
  766.         $colon ':';
  767.         $positions = array();
  768.         $position = 0;
  769.         $parameter = -1;
  770.         while ($position strlen($query)) {
  771.             $q_position strpos($query$question$position);
  772.             $c_position strpos($query$colon$position);
  773.             if ($q_position && $c_position{
  774.                 $p_position min($q_position$c_position);
  775.             elseif ($q_position{
  776.                 $p_position $q_position;
  777.             elseif ($c_position{
  778.                 $p_position $c_position;
  779.             else {
  780.                 break;
  781.             }
  782.             if (is_null($placeholder_type)) {
  783.                 $placeholder_type_guess $query[$p_position];
  784.             }
  785.             
  786.             $new_pos $this->_skipDelimitedStrings($query$position$p_position);
  787.             if (PEAR::isError($new_pos)) {
  788.                 return $new_pos;
  789.             }
  790.             if ($new_pos != $position{
  791.                 $position $new_pos;
  792.                 continue; //evaluate again starting from the new position
  793.             }
  794.  
  795.             if ($query[$position== $placeholder_type_guess{
  796.                 if (is_null($placeholder_type)) {
  797.                     $placeholder_type $query[$p_position];
  798.                     $question $colon $placeholder_type;
  799.                     if (!empty($types&& is_array($types)) {
  800.                         if ($placeholder_type == ':'{
  801.                             if (is_int(key($types))) {
  802.                                 $types_tmp $types;
  803.                                 $types = array();
  804.                                 $count = -1;
  805.                             }
  806.                         else {
  807.                             $types array_values($types);
  808.                         }
  809.                     }
  810.                 }
  811.                 if ($placeholder_type == ':'{
  812.                     $parameter preg_replace('/^.{'.($position+1).'}([a-z0-9_]+).*$/si''\\1'$query);
  813.                     if ($parameter === ''{
  814.                         $err =$this->raiseError(MDB2_ERROR_SYNTAXnullnull,
  815.                             'named parameter with an empty name'__FUNCTION__);
  816.                         return $err;
  817.                     }
  818.                     // use parameter name in type array
  819.                     if (isset($count&& isset($types_tmp[++$count])) {
  820.                         $types[$parameter$types_tmp[$count];
  821.                     }
  822.                     $length strlen($parameter+ 1;
  823.                 else {
  824.                     ++$parameter;
  825.                     $length strlen($parameter);
  826.                 }
  827.                 if (!in_array($parameter$positions)) {
  828.                     $positions[$parameter;
  829.                 }
  830.                 if (isset($types[$parameter])
  831.                     && ($types[$parameter== 'clob' || $types[$parameter== 'blob')
  832.                 {
  833.                     if (!isset($lobs[$parameter])) {
  834.                         $lobs[$parameter$parameter;
  835.                     }
  836.                     $value $this->quote(true$types[$parameter]);
  837.                     $query substr_replace($query$value$p_position$length);
  838.                     $position $p_position strlen($value- 1;
  839.                 elseif ($placeholder_type == '?'{
  840.                     $query substr_replace($query':'.$parameter$p_position1);
  841.                     $position $p_position $length;
  842.                 else {
  843.                     $position $p_position + 1;
  844.                 }
  845.             else {
  846.                 $position $p_position;
  847.             }
  848.         }
  849.         if (is_array($lobs)) {
  850.             $columns $variables '';
  851.             foreach ($lobs as $parameter => $field{
  852.                 $columns.= ($columns ', ' ' RETURNING ').$field;
  853.                 $variables.= ($variables ', ' ' INTO ').':'.$parameter;
  854.             }
  855.             $query.= $columns.$variables;
  856.         }
  857.         $connection $this->getConnection();
  858.         if (PEAR::isError($connection)) {
  859.             return $connection;
  860.         }
  861.         $statement @OCIParse($connection$query);
  862.         if (!$statement{
  863.             $err =$this->raiseError(nullnullnull,
  864.                 'Could not create statement'__FUNCTION__);
  865.             return $err;
  866.         }
  867.  
  868.         $class_name 'MDB2_Statement_'.$this->phptype;
  869.         $obj =new $class_name($this$statement$positions$query$types$result_types$is_manip$limit$offset);
  870.         $this->debug($query__FUNCTION__array('is_manip' => $is_manip'when' => 'post''result' => $obj));
  871.         return $obj;
  872.     }
  873.  
  874.     // }}}
  875.     // {{{ nextID()
  876.  
  877.     /**
  878.      * Returns the next free id of a sequence
  879.      *
  880.      * @param string $seq_name name of the sequence
  881.      * @param boolean $ondemand when true the sequence is
  882.      *                            automatic created, if it
  883.      *                            not exists
  884.      * @return mixed MDB2 Error Object or id
  885.      * @access public
  886.      */
  887.     function nextID($seq_name$ondemand = true)
  888.     {
  889.         $sequence_name $this->quoteIdentifier($this->getSequenceName($seq_name)true);
  890.         $query = "SELECT $sequence_name.nextval FROM DUAL";
  891.         $this->expectError(MDB2_ERROR_NOSUCHTABLE);
  892.         $result $this->queryOne($query'integer');
  893.         $this->popExpect();
  894.         if (PEAR::isError($result)) {
  895.             if ($ondemand && $result->getCode(== MDB2_ERROR_NOSUCHTABLE{
  896.                 $this->loadModule('Manager'nulltrue);
  897.                 $result $this->manager->createSequence($seq_name);
  898.                 if (PEAR::isError($result)) {
  899.                     return $result;
  900.                 }
  901.                 return $this->nextId($seq_namefalse);
  902.             }
  903.         }
  904.         return $result;
  905.     }
  906.  
  907.     // }}}
  908.     // {{{ lastInsertID()
  909.  
  910.     /**
  911.      * Returns the autoincrement ID if supported or $id or fetches the current
  912.      * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field)
  913.      *
  914.      * @param string $table name of the table into which a new row was inserted
  915.      * @param string $field name of the field into which a new row was inserted
  916.      * @return mixed MDB2 Error Object or id
  917.      * @access public
  918.      */
  919.     function lastInsertID($table = null$field = null)
  920.     {
  921.         $seq $table.(empty($field'' '_'.$field);
  922.         $sequence_name $this->quoteIdentifier($this->getSequenceName($seq)true);
  923.         return $this->queryOne("SELECT $sequence_name.currval"'integer');
  924.     }
  925.  
  926.     // }}}
  927.     // {{{ currId()
  928.  
  929.     /**
  930.      * Returns the current id of a sequence
  931.      *
  932.      * @param string $seq_name name of the sequence
  933.      * @return mixed MDB2_Error or id
  934.      * @access public
  935.      */
  936.     function currId($seq_name)
  937.     {
  938.         $sequence_name $this->getSequenceName($seq_name);
  939.         $query 'SELECT (last_number-1) FROM user_sequences';
  940.         $query.= ' WHERE sequence_name='.$this->quote($sequence_name'text');
  941.         $query.= ' OR sequence_name='.$this->quote(strtoupper($sequence_name)'text');
  942.         return $this->queryOne($query'integer');
  943.     }
  944. }
  945.  
  946. /**
  947.  * MDB2 OCI8 result driver
  948.  *
  949.  * @package MDB2
  950.  * @category Database
  951.  * @author Lukas Smith <smith@pooteeweet.org>
  952.  */
  953. class MDB2_Result_oci8 extends MDB2_Result_Common
  954. {
  955.     // }}}
  956.     // {{{ fetchRow()
  957.  
  958.     /**
  959.      * Fetch a row and insert the data into an existing array.
  960.      *
  961.      * @param int       $fetchmode  how the array data should be indexed
  962.      * @param int    $rownum    number of the row where the data can be found
  963.      * @return int data array on success, a MDB2 error on failure
  964.      * @access public
  965.      */
  966.     function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT$rownum = null)
  967.     {
  968.         if (!is_null($rownum)) {
  969.             $seek $this->seek($rownum);
  970.             if (PEAR::isError($seek)) {
  971.                 return $seek;
  972.             }
  973.         }
  974.         if ($fetchmode == MDB2_FETCHMODE_DEFAULT{
  975.             $fetchmode $this->db->fetchmode;
  976.         }
  977.         if ($fetchmode MDB2_FETCHMODE_ASSOC{
  978.             @OCIFetchInto($this->result$rowOCI_ASSOC+OCI_RETURN_NULLS);
  979.             if (is_array($row)
  980.                 && $this->db->options['portability'MDB2_PORTABILITY_FIX_CASE
  981.             {
  982.                 $row array_change_key_case($row$this->db->options['field_case']);
  983.             }
  984.         else {
  985.             @OCIFetchInto($this->result$rowOCI_RETURN_NULLS);
  986.         }
  987.         if (!$row{
  988.             if ($this->result === false{
  989.                 $err =$this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  990.                     'resultset has already been freed'__FUNCTION__);
  991.                 return $err;
  992.             }
  993.             $null = null;
  994.             return $null;
  995.         }
  996.         // remove additional column at the end
  997.         if ($this->offset > 0{
  998.             array_pop($row);
  999.         }
  1000.         $mode = 0;
  1001.         $rtrim = false;
  1002.         if ($this->db->options['portability'MDB2_PORTABILITY_RTRIM{
  1003.             if (empty($this->types)) {
  1004.                 $mode += MDB2_PORTABILITY_RTRIM;
  1005.             else {
  1006.                 $rtrim = true;
  1007.             }
  1008.         }
  1009.         if ($mode{
  1010.             $this->db->_fixResultArrayValues($row$mode);
  1011.         }
  1012.         if (!empty($this->types)) {
  1013.             $row $this->db->datatype->convertResultRow($this->types$row$rtrim);
  1014.         }
  1015.         if (!empty($this->values)) {
  1016.             $this->_assignBindColumns($row);
  1017.         }
  1018.         if ($fetchmode === MDB2_FETCHMODE_OBJECT{
  1019.             $object_class $this->db->options['fetch_class'];
  1020.             if ($object_class == 'stdClass'{
  1021.                 $row = (object) $row;
  1022.             else {
  1023.                 $row &new $object_class($row);
  1024.             }
  1025.         }
  1026.         ++$this->rownum;
  1027.         return $row;
  1028.     }
  1029.  
  1030.     // }}}
  1031.     // {{{ _getColumnNames()
  1032.  
  1033.     /**
  1034.      * Retrieve the names of columns returned by the DBMS in a query result.
  1035.      *
  1036.      * @return  mixed   Array variable that holds the names of columns as keys
  1037.      *                   or an MDB2 error on failure.
  1038.      *                   Some DBMS may not return any columns when the result set
  1039.      *                   does not contain any rows.
  1040.      * @access private
  1041.      */
  1042.     function _getColumnNames()
  1043.     {
  1044.         $columns = array();
  1045.         $numcols $this->numCols();
  1046.         if (PEAR::isError($numcols)) {
  1047.             return $numcols;
  1048.         }
  1049.         for ($column = 0; $column $numcols$column++{
  1050.             $column_name @OCIColumnName($this->result$column + 1);
  1051.             $columns[$column_name$column;
  1052.         }
  1053.         if ($this->db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  1054.             $columns array_change_key_case($columns$this->db->options['field_case']);
  1055.         }
  1056.         return $columns;
  1057.     }
  1058.  
  1059.     // }}}
  1060.     // {{{ numCols()
  1061.  
  1062.     /**
  1063.      * Count the number of columns returned by the DBMS in a query result.
  1064.      *
  1065.      * @return mixed integer value with the number of columns, a MDB2 error
  1066.      *       on failure
  1067.      * @access public
  1068.      */
  1069.     function numCols()
  1070.     {
  1071.         $cols @OCINumCols($this->result);
  1072.         if (is_null($cols)) {
  1073.             if ($this->result === false{
  1074.                 return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  1075.                     'resultset has already been freed'__FUNCTION__);
  1076.             elseif (is_null($this->result)) {
  1077.                 return count($this->types);
  1078.             }
  1079.             return $this->db->raiseError(nullnullnull,
  1080.                 'Could not get column count'__FUNCTION__);
  1081.         }
  1082.         if ($this->offset > 0{
  1083.             --$cols;
  1084.         }
  1085.         return $cols;
  1086.     }
  1087.  
  1088.     // }}}
  1089.     // {{{ free()
  1090.  
  1091.     /**
  1092.      * Free the internal resources associated with $result.
  1093.      *
  1094.      * @return boolean true on success, false if $result is invalid
  1095.      * @access public
  1096.      */
  1097.     function free()
  1098.     {
  1099.         if (is_resource($this->result&& $this->db->connection{
  1100.             $free @OCIFreeCursor($this->result);
  1101.             if ($free === false{
  1102.                 return $this->db->raiseError(nullnullnull,
  1103.                     'Could not free result'__FUNCTION__);
  1104.             }
  1105.         }
  1106.         $this->result = false;
  1107.         return MDB2_OK;
  1108.  
  1109.     }
  1110. }
  1111.  
  1112. /**
  1113.  * MDB2 OCI8 buffered result driver
  1114.  *
  1115.  * @package MDB2
  1116.  * @category Database
  1117.  * @author Lukas Smith <smith@pooteeweet.org>
  1118.  */
  1119. {
  1120.     var $buffer;
  1121.     var $buffer_rownum = - 1;
  1122.  
  1123.     // {{{ _fillBuffer()
  1124.  
  1125.     /**
  1126.      * Fill the row buffer
  1127.      *
  1128.      * @param int $rownum   row number upto which the buffer should be filled
  1129.                             if the row number is null all rows are ready into the buffer
  1130.      * @return boolean true on success, false on failure
  1131.      * @access protected
  1132.      */
  1133.     function _fillBuffer($rownum = null)
  1134.     {
  1135.         if (isset($this->buffer&& is_array($this->buffer)) {
  1136.             if (is_null($rownum)) {
  1137.                 if (!end($this->buffer)) {
  1138.                     return false;
  1139.                 }
  1140.             elseif (isset($this->buffer[$rownum])) {
  1141.                 return (bool)$this->buffer[$rownum];
  1142.             }
  1143.         }
  1144.  
  1145.         $row = true;
  1146.         while ((is_null($rownum|| $this->buffer_rownum < $rownum)
  1147.             && ($row @OCIFetchInto($this->result$bufferOCI_RETURN_NULLS))
  1148.         {
  1149.             ++$this->buffer_rownum;
  1150.             // remove additional column at the end
  1151.             if ($this->offset > 0{
  1152.                 array_pop($buffer);
  1153.             }
  1154.             if (empty($this->types)) {
  1155.                 foreach (array_keys($bufferas $key{
  1156.                     if (is_a($buffer[$key]'oci-lob')) {
  1157.                         $buffer[$key$buffer[$key]->load();
  1158.                     }
  1159.                 }
  1160.             }
  1161.             $this->buffer[$this->buffer_rownum$buffer;
  1162.         }
  1163.  
  1164.         if (!$row{
  1165.             ++$this->buffer_rownum;
  1166.             $this->buffer[$this->buffer_rownum= false;
  1167.             return false;
  1168.         }
  1169.         return true;
  1170.     }
  1171.  
  1172.     // }}}
  1173.     // {{{ fetchRow()
  1174.  
  1175.     /**
  1176.      * Fetch a row and insert the data into an existing array.
  1177.      *
  1178.      * @param int       $fetchmode  how the array data should be indexed
  1179.      * @param int    $rownum    number of the row where the data can be found
  1180.      * @return int data array on success, a MDB2 error on failure
  1181.      * @access public
  1182.      */
  1183.     function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT$rownum = null)
  1184.     {
  1185.         if ($this->result === false{
  1186.             $err =$this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  1187.                 'resultset has already been freed'__FUNCTION__);
  1188.             return $err;
  1189.         elseif (is_null($this->result)) {
  1190.             return null;
  1191.         }
  1192.         if (!is_null($rownum)) {
  1193.             $seek $this->seek($rownum);
  1194.             if (PEAR::isError($seek)) {
  1195.                 return $seek;
  1196.             }
  1197.         }
  1198.         $target_rownum $this->rownum + 1;
  1199.         if ($fetchmode == MDB2_FETCHMODE_DEFAULT{
  1200.             $fetchmode $this->db->fetchmode;
  1201.         }
  1202.         if (!$this->_fillBuffer($target_rownum)) {
  1203.             $null = null;
  1204.             return $null;
  1205.         }
  1206.         $row $this->buffer[$target_rownum];
  1207.         if ($fetchmode MDB2_FETCHMODE_ASSOC{
  1208.             $column_names $this->getColumnNames();
  1209.             foreach ($column_names as $name => $i{
  1210.                 $column_names[$name$row[$i];
  1211.             }
  1212.             $row $column_names;
  1213.         }
  1214.         $mode = 0;
  1215.         $rtrim = false;
  1216.         if ($this->db->options['portability'MDB2_PORTABILITY_RTRIM{
  1217.             if (empty($this->types)) {
  1218.                 $mode += MDB2_PORTABILITY_RTRIM;
  1219.             else {
  1220.                 $rtrim = true;
  1221.             }
  1222.         }
  1223.         if ($mode{
  1224.             $this->db->_fixResultArrayValues($row$mode);
  1225.         }
  1226.         if (!empty($this->types)) {
  1227.             $row $this->db->datatype->convertResultRow($this->types$row$rtrim);
  1228.         }
  1229.         if (!empty($this->values)) {
  1230.             $this->_assignBindColumns($row);
  1231.         }
  1232.         if ($fetchmode === MDB2_FETCHMODE_OBJECT{
  1233.             $object_class $this->db->options['fetch_class'];
  1234.             if ($object_class == 'stdClass'{
  1235.                 $row = (object) $row;
  1236.             else {
  1237.                 $row &new $object_class($row);
  1238.             }
  1239.         }
  1240.         ++$this->rownum;
  1241.         return $row;
  1242.     }
  1243.  
  1244.     // }}}
  1245.     // {{{ seek()
  1246.  
  1247.     /**
  1248.      * Seek to a specific row in a result set
  1249.      *
  1250.      * @param int    $rownum    number of the row where the data can be found
  1251.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  1252.      * @access public
  1253.      */
  1254.     function seek($rownum = 0)
  1255.     {
  1256.         if ($this->result === false{
  1257.             return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  1258.                 'resultset has already been freed'__FUNCTION__);
  1259.         }
  1260.         $this->rownum $rownum - 1;
  1261.         return MDB2_OK;
  1262.     }
  1263.  
  1264.     // }}}
  1265.     // {{{ valid()
  1266.  
  1267.     /**
  1268.      * Check if the end of the result set has been reached
  1269.      *
  1270.      * @return mixed true or false on sucess, a MDB2 error on failure
  1271.      * @access public
  1272.      */
  1273.     function valid()
  1274.     {
  1275.         if ($this->result === false{
  1276.             return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  1277.                 'resultset has already been freed'__FUNCTION__);
  1278.         elseif (is_null($this->result)) {
  1279.             return true;
  1280.         }
  1281.         if ($this->_fillBuffer($this->rownum + 1)) {
  1282.             return true;
  1283.         }
  1284.         return false;
  1285.     }
  1286.  
  1287.     // }}}
  1288.     // {{{ numRows()
  1289.  
  1290.     /**
  1291.      * Returns the number of rows in a result object
  1292.      *
  1293.      * @return mixed MDB2 Error Object or the number of rows
  1294.      * @access public
  1295.      */
  1296.     function numRows()
  1297.     {
  1298.         if ($this->result === false{
  1299.             return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATAnullnull,
  1300.                 'resultset has already been freed'__FUNCTION__);
  1301.         elseif (is_null($this->result)) {
  1302.             return 0;
  1303.         }
  1304.         $this->_fillBuffer();
  1305.         return $this->buffer_rownum;
  1306.     }
  1307.  
  1308.     // }}}
  1309.     // {{{ free()
  1310.  
  1311.     /**
  1312.      * Free the internal resources associated with $result.
  1313.      *
  1314.      * @return boolean true on success, false if $result is invalid
  1315.      * @access public
  1316.      */
  1317.     function free()
  1318.     {
  1319.         $this->buffer = null;
  1320.         $this->buffer_rownum = null;
  1321.         return parent::free();
  1322.     }
  1323. }
  1324.  
  1325. /**
  1326.  * MDB2 OCI8 statement driver
  1327.  *
  1328.  * @package MDB2
  1329.  * @category Database
  1330.  * @author Lukas Smith <smith@pooteeweet.org>
  1331.  */
  1332. class MDB2_Statement_oci8 extends MDB2_Statement_Common
  1333. {
  1334.     // }}}
  1335.     // {{{ _execute()
  1336.  
  1337.     /**
  1338.      * Execute a prepared query statement helper method.
  1339.      *
  1340.      * @param mixed $result_class string which specifies which result class to use
  1341.      * @param mixed $result_wrap_class string which specifies which class to wrap results in
  1342.      * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure
  1343.      * @access private
  1344.      */
  1345.     function &_execute($result_class = true$result_wrap_class = false)
  1346.     {
  1347.         if (is_null($this->statement)) {
  1348.             $result =parent::_execute($result_class$result_wrap_class);
  1349.             return $result;
  1350.         }
  1351.         $this->db->last_query = $this->query;
  1352.         $this->db->debug($this->query'execute'array('is_manip' => $this->is_manip'when' => 'pre''parameters' => $this->values));
  1353.         if ($this->db->getOption('disable_query')) {
  1354.             $result $this->is_manip ? 0 : null;
  1355.             return $result;
  1356.         }
  1357.  
  1358.         $connection $this->db->getConnection();
  1359.         if (PEAR::isError($connection)) {
  1360.             return $connection;
  1361.         }
  1362.  
  1363.         $result = MDB2_OK;
  1364.         $lobs $quoted_values = array();
  1365.         $i = 0;
  1366.         foreach ($this->positions as $parameter{
  1367.             if (!array_key_exists($parameter$this->values)) {
  1368.                 return $this->db->raiseError(MDB2_ERROR_NOT_FOUNDnullnull,
  1369.                     'Unable to bind to missing placeholder: '.$parameter__FUNCTION__);
  1370.             }
  1371.             $value $this->values[$parameter];
  1372.             $type array_key_exists($parameter$this->types$this->types[$parameter: null;
  1373.             if ($type == 'clob' || $type == 'blob'{
  1374.                 $lobs[$i]['file'= false;
  1375.                 if (is_resource($value)) {
  1376.                     $fp $value;
  1377.                     $value '';
  1378.                     while (!feof($fp)) {
  1379.                         $value.= fread($fp8192);
  1380.                     }
  1381.                 elseif (preg_match('/^(\w+:\/\/)(.*)$/'$value$match)) {
  1382.                     $lobs[$i]['file'= true;
  1383.                     if ($match[1== 'file://'{
  1384.                         $value $match[2];
  1385.                     }
  1386.                 }
  1387.                 $lobs[$i]['value'$value;
  1388.                 $lobs[$i]['descriptor'@OCINewDescriptor($connectionOCI_D_LOB);
  1389.                 if (!is_object($lobs[$i]['descriptor'])) {
  1390.                     $result $this->db->raiseError(nullnullnull,
  1391.                         'Unable to create descriptor for LOB in parameter: '.$parameter__FUNCTION__);
  1392.                     break;
  1393.                 }
  1394.                 $lob_type ($type == 'blob' ? OCI_B_BLOB : OCI_B_CLOB);
  1395.                 if (!@OCIBindByName($this->statement':'.$parameter$lobs[$i]['descriptor']-1$lob_type)) {
  1396.                     $result $this->db->raiseError($this->statementnullnull,
  1397.                         'could not bind LOB parameter'__FUNCTION__);
  1398.                     break;
  1399.                 }
  1400.             else {
  1401.                 $quoted_values[$i$this->db->quote($value$typefalse);
  1402.                 if (PEAR::isError($quoted_values[$i])) {
  1403.                     return $quoted_values[$i];
  1404.                 }
  1405.                 if (!@OCIBindByName($this->statement':'.$parameter$quoted_values[$i])) {
  1406.                     $result $this->db->raiseError($this->statementnullnull,
  1407.                         'could not bind non LOB parameter'__FUNCTION__);
  1408.                     break;
  1409.                 }
  1410.             }
  1411.             ++$i;
  1412.         }
  1413.  
  1414.         $lob_keys array_keys($lobs);
  1415.         if (!PEAR::isError($result)) {
  1416.             $mode (!empty($lobs|| $this->db->in_transaction? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS;
  1417.             if (!@OCIExecute($this->statement$mode)) {
  1418.                 $err =$this->db->raiseError($this->statementnullnull,
  1419.                     'could not execute statement'__FUNCTION__);
  1420.                 return $err;
  1421.             }
  1422.  
  1423.             if (!empty($lobs)) {
  1424.                 foreach ($lob_keys as $i{
  1425.                     if (!is_null($lobs[$i]['value']&& $lobs[$i]['value'!== ''{
  1426.                         if ($lobs[$i]['file']{
  1427.                             $result $lobs[$i]['descriptor']->savefile($lobs[$i]['value']);
  1428.                         else {
  1429.                             $result $lobs[$i]['descriptor']->save($lobs[$i]['value']);
  1430.                         }
  1431.                         if (!$result{
  1432.                             $result $this->db->raiseError(nullnullnull,
  1433.                                 'Unable to save descriptor contents'__FUNCTION__);
  1434.                             break;
  1435.                         }
  1436.                     }
  1437.                 }
  1438.  
  1439.                 if (!PEAR::isError($result)) {
  1440.                     if (!$this->db->in_transaction{
  1441.                         if (!@OCICommit($connection)) {
  1442.                             $result $this->db->raiseError(nullnullnull,
  1443.                                 'Unable to commit transaction'__FUNCTION__);
  1444.                         }
  1445.                     else {
  1446.                         ++$this->db->uncommitedqueries;
  1447.                     }
  1448.                 }
  1449.             }
  1450.         }
  1451.  
  1452.         $lob_keys array_keys($lobs);
  1453.         foreach ($lob_keys as $i{
  1454.             $lobs[$i]['descriptor']->free();
  1455.         }
  1456.  
  1457.         if (PEAR::isError($result)) {
  1458.             return $result;
  1459.         }
  1460.  
  1461.         if ($this->is_manip{
  1462.             $affected_rows $this->db->_affectedRows($connection$this->statement);
  1463.             return $affected_rows;
  1464.         }
  1465.  
  1466.         $result =$this->db->_wrapResult($this->statement$this->result_types,
  1467.             $result_class$result_wrap_class$this->limit$this->offset);
  1468.         $this->db->debug($this->query'execute'array('is_manip' => $this->is_manip'when' => 'post''result' => $result));
  1469.         return $result;
  1470.     }
  1471.  
  1472.     // }}}
  1473.     // {{{ free()
  1474.  
  1475.     /**
  1476.      * Release resources allocated for the specified prepared query.
  1477.      *
  1478.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  1479.      * @access public
  1480.      */
  1481.     function free()
  1482.     {
  1483.         if (is_null($this->positions)) {
  1484.             return $this->db->raiseError(MDB2_ERRORnullnull,
  1485.                 'Prepared statement has already been freed'__FUNCTION__);
  1486.         }
  1487.         $result = MDB2_OK;
  1488.  
  1489.         if (!is_null($this->statement&& !@OCIFreeStatement($this->statement)) {
  1490.             $result $this->db->raiseError(nullnullnull,
  1491.                 'Could not free statement'__FUNCTION__);
  1492.         }
  1493.  
  1494.         parent::free();
  1495.         return $result;
  1496.     }
  1497. }
  1498. ?>

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