Source for file oci8.php

Documentation is available at oci8.php

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * The PEAR DB driver for PHP's oci8 extension
  7.  * for interacting with Oracle databases
  8.  *
  9.  * PHP versions 4 and 5
  10.  *
  11.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  12.  * that is available through the world-wide-web at the following URI:
  13.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  14.  * the PHP License and are unable to obtain it through the web, please
  15.  * send a note to license@php.net so we can mail you a copy immediately.
  16.  *
  17.  * @category   Database
  18.  * @package    DB
  19.  * @author     James L. Pine <jlp@valinux.com>
  20.  * @author     Daniel Convissor <danielc@php.net>
  21.  * @copyright  1997-2007 The PHP Group
  22.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23.  * @version    CVS: $Id: oci8.php,v 1.115 2007/09/21 13:40:41 aharvey Exp $
  24.  * @link       http://pear.php.net/package/DB
  25.  */
  26.  
  27. /**
  28.  * Obtain the DB_common class so it can be extended from
  29.  */
  30. require_once DB_PEAR_PATH.'DB/common.php';
  31.  
  32. /**
  33.  * The methods PEAR DB uses to interact with PHP's oci8 extension
  34.  * for interacting with Oracle databases
  35.  *
  36.  * Definitely works with versions 8 and 9 of Oracle.
  37.  *
  38.  * These methods overload the ones declared in DB_common.
  39.  *
  40.  * Be aware...  OCIError() only appears to return anything when given a
  41.  * statement, so functions return the generic DB_ERROR instead of more
  42.  * useful errors that have to do with feedback from the database.
  43.  *
  44.  * @category   Database
  45.  * @package    DB
  46.  * @author     James L. Pine <jlp@valinux.com>
  47.  * @author     Daniel Convissor <danielc@php.net>
  48.  * @copyright  1997-2007 The PHP Group
  49.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  50.  * @version    Release: 1.7.13
  51.  * @link       http://pear.php.net/package/DB
  52.  */
  53. class DB_oci8 extends DB_common
  54. {
  55.     // {{{ properties
  56.  
  57.     /**
  58.      * The DB driver type (mysql, oci8, odbc, etc.)
  59.      * @var string 
  60.      */
  61.     var $phptype = 'oci8';
  62.  
  63.     /**
  64.      * The database syntax variant to be used (db2, access, etc.), if any
  65.      * @var string 
  66.      */
  67.     var $dbsyntax = 'oci8';
  68.  
  69.     /**
  70.      * The capabilities of this DB implementation
  71.      *
  72.      * The 'new_link' element contains the PHP version that first provided
  73.      * new_link support for this DBMS.  Contains false if it's unsupported.
  74.      *
  75.      * Meaning of the 'limit' element:
  76.      *   + 'emulate' = emulate with fetch row by number
  77.      *   + 'alter'   = alter the query
  78.      *   + false     = skip rows
  79.      *
  80.      * @var array 
  81.      */
  82.     var $features = array(
  83.         'limit'         => 'alter',
  84.         'new_link'      => '5.0.0',
  85.         'numrows'       => 'subquery',
  86.         'pconnect'      => true,
  87.         'prepare'       => true,
  88.         'ssl'           => false,
  89.         'transactions'  => true,
  90.     );
  91.  
  92.     /**
  93.      * A mapping of native error codes to DB error codes
  94.      * @var array 
  95.      */
  96.     var $errorcode_map = array(
  97.         1     => DB_ERROR_CONSTRAINT,
  98.         900   => DB_ERROR_SYNTAX,
  99.         904   => DB_ERROR_NOSUCHFIELD,
  100.         913   => DB_ERROR_VALUE_COUNT_ON_ROW,
  101.         921   => DB_ERROR_SYNTAX,
  102.         923   => DB_ERROR_SYNTAX,
  103.         942   => DB_ERROR_NOSUCHTABLE,
  104.         955   => DB_ERROR_ALREADY_EXISTS,
  105.         1400  => DB_ERROR_CONSTRAINT_NOT_NULL,
  106.         1401  => DB_ERROR_INVALID,
  107.         1407  => DB_ERROR_CONSTRAINT_NOT_NULL,
  108.         1418  => DB_ERROR_NOT_FOUND,
  109.         1476  => DB_ERROR_DIVZERO,
  110.         1722  => DB_ERROR_INVALID_NUMBER,
  111.         2289  => DB_ERROR_NOSUCHTABLE,
  112.         2291  => DB_ERROR_CONSTRAINT,
  113.         2292  => DB_ERROR_CONSTRAINT,
  114.         2449  => DB_ERROR_CONSTRAINT,
  115.         12899 => DB_ERROR_INVALID,
  116.     );
  117.  
  118.     /**
  119.      * The raw database connection created by PHP
  120.      * @var resource 
  121.      */
  122.     var $connection;
  123.  
  124.     /**
  125.      * The DSN information for connecting to a database
  126.      * @var array 
  127.      */
  128.     var $dsn = array();
  129.  
  130.  
  131.     /**
  132.      * Should data manipulation queries be committed automatically?
  133.      * @var bool 
  134.      * @access private
  135.      */
  136.     var $autocommit true;
  137.  
  138.     /**
  139.      * Stores the $data passed to execute() in the oci8 driver
  140.      *
  141.      * Gets reset to array() when simpleQuery() is run.
  142.      *
  143.      * Needed in case user wants to call numRows() after prepare/execute
  144.      * was used.
  145.      *
  146.      * @var array 
  147.      * @access private
  148.      */
  149.     var $_data array();
  150.  
  151.     /**
  152.      * The result or statement handle from the most recently executed query
  153.      * @var resource 
  154.      */
  155.     var $last_stmt;
  156.  
  157.     /**
  158.      * Is the given prepared statement a data manipulation query?
  159.      * @var array 
  160.      * @access private
  161.      */
  162.     var $manip_query array();
  163.  
  164.     /**
  165.      * Store of prepared SQL queries.
  166.      * @var array 
  167.      * @access private
  168.      */
  169.     var $_prepared_queries array();
  170.  
  171.  
  172.     // }}}
  173.     // {{{ constructor
  174.  
  175.     /**
  176.      * This constructor calls <kbd>$this->DB_common()</kbd>
  177.      *
  178.      * @return void 
  179.      */
  180.     function DB_oci8()
  181.     {
  182.         $this->DB_common();
  183.     }
  184.  
  185.     // }}}
  186.     // {{{ connect()
  187.  
  188.     /**
  189.      * Connect to the database server, log in and open the database
  190.      *
  191.      * Don't call this method directly.  Use DB::connect() instead.
  192.      *
  193.      * If PHP is at version 5.0.0 or greater:
  194.      *   + Generally, oci_connect() or oci_pconnect() are used.
  195.      *   + But if the new_link DSN option is set to true, oci_new_connect()
  196.      *     is used.
  197.      *
  198.      * When using PHP version 4.x, OCILogon() or OCIPLogon() are used.
  199.      *
  200.      * PEAR DB's oci8 driver supports the following extra DSN options:
  201.      *   + charset       The character set to be used on the connection.
  202.      *                    Only used if PHP is at version 5.0.0 or greater
  203.      *                    and the Oracle server is at 9.2 or greater.
  204.      *                    Available since PEAR DB 1.7.0.
  205.      *   + new_link      If set to true, causes subsequent calls to
  206.      *                    connect() to return a new connection link
  207.      *                    instead of the existing one.  WARNING: this is
  208.      *                    not portable to other DBMS's.
  209.      *                    Available since PEAR DB 1.7.0.
  210.      *
  211.      * @param array $dsn         the data source name
  212.      * @param bool  $persistent  should the connection be persistent?
  213.      *
  214.      * @return int  DB_OK on success. A DB_Error object on failure.
  215.      */
  216.     function connect($dsn$persistent false)
  217.     {
  218.         if (!PEAR::loadExtension('oci8')) {
  219.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  220.         }
  221.  
  222.         $this->dsn = $dsn;
  223.         if ($dsn['dbsyntax']{
  224.             $this->dbsyntax = $dsn['dbsyntax'];
  225.         }
  226.  
  227.         // Backwards compatibility with DB < 1.7.0
  228.         if (empty($dsn['database']&& !empty($dsn['hostspec'])) {
  229.             $db $dsn['hostspec'];
  230.         else {
  231.             $db $dsn['database'];
  232.         }
  233.  
  234.         if (function_exists('oci_connect')) {
  235.             if (isset($dsn['new_link'])
  236.                 && ($dsn['new_link'== 'true' || $dsn['new_link'=== true))
  237.             {
  238.                 $connect_function 'oci_new_connect';
  239.             else {
  240.                 $connect_function $persistent 'oci_pconnect'
  241.                                     : 'oci_connect';
  242.             }
  243.             if (isset($this->dsn['port']&& $this->dsn['port']{
  244.                 $db '//'.$db.':'.$this->dsn['port'];
  245.             }
  246.  
  247.             $char empty($dsn['charset']null $dsn['charset'];
  248.             $this->connection = @$connect_function($dsn['username'],
  249.                                                    $dsn['password'],
  250.                                                    $db,
  251.                                                    $char);
  252.             $error OCIError();
  253.             if (!empty($error&& $error['code'== 12541{
  254.                 // Couldn't find TNS listener.  Try direct connection.
  255.                 $this->connection = @$connect_function($dsn['username'],
  256.                                                        $dsn['password'],
  257.                                                        null,
  258.                                                        $char);
  259.             }
  260.         else {
  261.             $connect_function $persistent 'OCIPLogon' 'OCILogon';
  262.             if ($db{
  263.                 $this->connection = @$connect_function($dsn['username'],
  264.                                                        $dsn['password'],
  265.                                                        $db);
  266.             elseif ($dsn['username'|| $dsn['password']{
  267.                 $this->connection = @$connect_function($dsn['username'],
  268.                                                        $dsn['password']);
  269.             }
  270.         }
  271.  
  272.         if (!$this->connection{
  273.             $error OCIError();
  274.             $error (is_array($error)) $error['message'null;
  275.             return $this->raiseError(DB_ERROR_CONNECT_FAILED,
  276.                                      nullnullnull,
  277.                                      $error);
  278.         }
  279.         return DB_OK;
  280.     }
  281.  
  282.     // }}}
  283.     // {{{ disconnect()
  284.  
  285.     /**
  286.      * Disconnects from the database server
  287.      *
  288.      * @return bool  TRUE on success, FALSE on failure
  289.      */
  290.     function disconnect()
  291.     {
  292.         if (function_exists('oci_close')) {
  293.             $ret @oci_close($this->connection);
  294.         else {
  295.             $ret @OCILogOff($this->connection);
  296.         }
  297.         $this->connection = null;
  298.         return $ret;
  299.     }
  300.  
  301.     // }}}
  302.     // {{{ simpleQuery()
  303.  
  304.     /**
  305.      * Sends a query to the database server
  306.      *
  307.      * To determine how many rows of a result set get buffered using
  308.      * ocisetprefetch(), see the "result_buffering" option in setOptions().
  309.      * This option was added in Release 1.7.0.
  310.      *
  311.      * @param string  the SQL query string
  312.      *
  313.      * @return mixed  + a PHP result resrouce for successful SELECT queries
  314.      *                 + the DB_OK constant for other successful queries
  315.      *                 + a DB_Error object on failure
  316.      */
  317.     function simpleQuery($query)
  318.     {
  319.         $this->_data array();
  320.         $this->last_parameters = array();
  321.         $this->last_query = $query;
  322.         $query $this->modifyQuery($query);
  323.         $result @OCIParse($this->connection$query);
  324.         if (!$result{
  325.             return $this->oci8RaiseError();
  326.         }
  327.         if ($this->autocommit{
  328.             $success @OCIExecute($result,OCI_COMMIT_ON_SUCCESS);
  329.         else {
  330.             $success @OCIExecute($result,OCI_DEFAULT);
  331.         }
  332.         if (!$success{
  333.             return $this->oci8RaiseError($result);
  334.         }
  335.         $this->last_stmt = $result;
  336.         if ($this->_checkManip($query)) {
  337.             return DB_OK;
  338.         else {
  339.             @ocisetprefetch($result$this->options['result_buffering']);
  340.             return $result;
  341.         }
  342.     }
  343.  
  344.     // }}}
  345.     // {{{ nextResult()
  346.  
  347.     /**
  348.      * Move the internal oracle result pointer to the next available result
  349.      *
  350.      * @param valid oci8 result resource
  351.      *
  352.      * @access public
  353.      *
  354.      * @return true if a result is available otherwise return false
  355.      */
  356.     function nextResult($result)
  357.     {
  358.         return false;
  359.     }
  360.  
  361.     // }}}
  362.     // {{{ fetchInto()
  363.  
  364.     /**
  365.      * Places a row from the result set into the given array
  366.      *
  367.      * Formating of the array and the data therein are configurable.
  368.      * See DB_result::fetchInto() for more information.
  369.      *
  370.      * This method is not meant to be called directly.  Use
  371.      * DB_result::fetchInto() instead.  It can't be declared "protected"
  372.      * because DB_result is a separate object.
  373.      *
  374.      * @param resource $result    the query result resource
  375.      * @param array    $arr       the referenced array to put the data in
  376.      * @param int      $fetchmode how the resulting array should be indexed
  377.      * @param int      $rownum    the row number to fetch (0 = first row)
  378.      *
  379.      * @return mixed  DB_OK on success, NULL when the end of a result set is
  380.      *                  reached or on failure
  381.      *
  382.      * @see DB_result::fetchInto()
  383.      */
  384.     function fetchInto($result&$arr$fetchmode$rownum null)
  385.     {
  386.         if ($rownum !== null{
  387.             return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  388.         }
  389.         if ($fetchmode DB_FETCHMODE_ASSOC{
  390.             $moredata @OCIFetchInto($result,$arr,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
  391.             if ($this->options['portability'DB_PORTABILITY_LOWERCASE &&
  392.                 $moredata)
  393.             {
  394.                 $arr array_change_key_case($arrCASE_LOWER);
  395.             }
  396.         else {
  397.             $moredata OCIFetchInto($result,$arr,OCI_RETURN_NULLS+OCI_RETURN_LOBS);
  398.         }
  399.         if (!$moredata{
  400.             return null;
  401.         }
  402.         if ($this->options['portability'DB_PORTABILITY_RTRIM{
  403.             $this->_rtrimArrayValues($arr);
  404.         }
  405.         if ($this->options['portability'DB_PORTABILITY_NULL_TO_EMPTY{
  406.             $this->_convertNullArrayValuesToEmpty($arr);
  407.         }
  408.         return DB_OK;
  409.     }
  410.  
  411.     // }}}
  412.     // {{{ freeResult()
  413.  
  414.     /**
  415.      * Deletes the result set and frees the memory occupied by the result set
  416.      *
  417.      * This method is not meant to be called directly.  Use
  418.      * DB_result::free() instead.  It can't be declared "protected"
  419.      * because DB_result is a separate object.
  420.      *
  421.      * @param resource $result  PHP's query result resource
  422.      *
  423.      * @return bool  TRUE on success, FALSE if $result is invalid
  424.      *
  425.      * @see DB_result::free()
  426.      */
  427.     function freeResult($result)
  428.     {
  429.         return is_resource($resultOCIFreeStatement($resultfalse;
  430.     }
  431.  
  432.     /**
  433.      * Frees the internal resources associated with a prepared query
  434.      *
  435.      * @param resource $stmt           the prepared statement's resource
  436.      * @param bool     $free_resource  should the PHP resource be freed too?
  437.      *                                   Use false if you need to get data
  438.      *                                   from the result set later.
  439.      *
  440.      * @return bool  TRUE on success, FALSE if $result is invalid
  441.      *
  442.      * @see DB_oci8::prepare()
  443.      */
  444.     function freePrepared($stmt$free_resource true)
  445.     {
  446.         if (!is_resource($stmt)) {
  447.             return false;
  448.         }
  449.         if ($free_resource{
  450.             @ocifreestatement($stmt);
  451.         }
  452.         if (isset($this->prepare_types[(int)$stmt])) {
  453.             unset($this->prepare_types[(int)$stmt]);
  454.             unset($this->manip_query[(int)$stmt]);
  455.         else {
  456.             return false;
  457.         }
  458.         return true;
  459.     }
  460.  
  461.     // }}}
  462.     // {{{ numRows()
  463.  
  464.     /**
  465.      * Gets the number of rows in a result set
  466.      *
  467.      * Only works if the DB_PORTABILITY_NUMROWS portability option
  468.      * is turned on.
  469.      *
  470.      * This method is not meant to be called directly.  Use
  471.      * DB_result::numRows() instead.  It can't be declared "protected"
  472.      * because DB_result is a separate object.
  473.      *
  474.      * @param resource $result  PHP's query result resource
  475.      *
  476.      * @return int  the number of rows.  A DB_Error object on failure.
  477.      *
  478.      * @see DB_result::numRows(), DB_common::setOption()
  479.      */
  480.     function numRows($result)
  481.     {
  482.         // emulate numRows for Oracle.  yuck.
  483.         if ($this->options['portability'DB_PORTABILITY_NUMROWS &&
  484.             $result === $this->last_stmt)
  485.         {
  486.             $countquery 'SELECT COUNT(*) FROM ('.$this->last_query.')';
  487.             $save_query $this->last_query;
  488.             $save_stmt $this->last_stmt;
  489.  
  490.             $count $this->query($countquery);
  491.  
  492.             // Restore the last query and statement.
  493.             $this->last_query = $save_query;
  494.             $this->last_stmt = $save_stmt;
  495.             
  496.             if (DB::isError($count||
  497.                 DB::isError($row $count->fetchRow(DB_FETCHMODE_ORDERED)))
  498.             {
  499.                 return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  500.             }
  501.  
  502.             return $row[0];
  503.         }
  504.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  505.     }
  506.  
  507.     // }}}
  508.     // {{{ numCols()
  509.  
  510.     /**
  511.      * Gets the number of columns in a result set
  512.      *
  513.      * This method is not meant to be called directly.  Use
  514.      * DB_result::numCols() instead.  It can't be declared "protected"
  515.      * because DB_result is a separate object.
  516.      *
  517.      * @param resource $result  PHP's query result resource
  518.      *
  519.      * @return int  the number of columns.  A DB_Error object on failure.
  520.      *
  521.      * @see DB_result::numCols()
  522.      */
  523.     function numCols($result)
  524.     {
  525.         $cols @OCINumCols($result);
  526.         if (!$cols{
  527.             return $this->oci8RaiseError($result);
  528.         }
  529.         return $cols;
  530.     }
  531.  
  532.     // }}}
  533.     // {{{ prepare()
  534.  
  535.     /**
  536.      * Prepares a query for multiple execution with execute().
  537.      *
  538.      * With oci8, this is emulated.
  539.      *
  540.      * prepare() requires a generic query as string like <code>
  541.      *    INSERT INTO numbers VALUES (?, ?, ?)
  542.      * </code>.  The <kbd>?</kbd> characters are placeholders.
  543.      *
  544.      * Three types of placeholders can be used:
  545.      *   + <kbd>?</kbd>  a quoted scalar value, i.e. strings, integers
  546.      *   + <kbd>!</kbd>  value is inserted 'as is'
  547.      *   + <kbd>&</kbd>  requires a file name.  The file's contents get
  548.      *                     inserted into the query (i.e. saving binary
  549.      *                     data in a db)
  550.      *
  551.      * Use backslashes to escape placeholder characters if you don't want
  552.      * them to be interpreted as placeholders.  Example: <code>
  553.      *    "UPDATE foo SET col=? WHERE col='over \& under'"
  554.      * </code>
  555.      *
  556.      * @param string $query  the query to be prepared
  557.      *
  558.      * @return mixed  DB statement resource on success. DB_Error on failure.
  559.      *
  560.      * @see DB_oci8::execute()
  561.      */
  562.     function prepare($query)
  563.     {
  564.         $tokens   preg_split('/((?<!\\\)[&?!])/'$query-1,
  565.                                PREG_SPLIT_DELIM_CAPTURE);
  566.         $binds    count($tokens1;
  567.         $token    0;
  568.         $types    array();
  569.         $newquery '';
  570.  
  571.         foreach ($tokens as $key => $val{
  572.             switch ($val{
  573.                 case '?':
  574.                     $types[$token++DB_PARAM_SCALAR;
  575.                     unset($tokens[$key]);
  576.                     break;
  577.                 case '&':
  578.                     $types[$token++DB_PARAM_OPAQUE;
  579.                     unset($tokens[$key]);
  580.                     break;
  581.                 case '!':
  582.                     $types[$token++DB_PARAM_MISC;
  583.                     unset($tokens[$key]);
  584.                     break;
  585.                 default:
  586.                     $tokens[$keypreg_replace('/\\\([&?!])/'"\\1"$val);
  587.                     if ($key != $binds{
  588.                         $newquery .= $tokens[$key':bind' $token;
  589.                     else {
  590.                         $newquery .= $tokens[$key];
  591.                     }
  592.             }
  593.         }
  594.  
  595.         $this->last_query = $query;
  596.         $newquery $this->modifyQuery($newquery);
  597.         if (!$stmt @OCIParse($this->connection$newquery)) {
  598.             return $this->oci8RaiseError();
  599.         }
  600.         $this->prepare_types[(int)$stmt$types;
  601.         $this->manip_query[(int)$stmtDB::isManip($query);
  602.         $this->_prepared_queries[(int)$stmt$newquery;
  603.         return $stmt;
  604.     }
  605.  
  606.     // }}}
  607.     // {{{ execute()
  608.  
  609.     /**
  610.      * Executes a DB statement prepared with prepare().
  611.      *
  612.      * To determine how many rows of a result set get buffered using
  613.      * ocisetprefetch(), see the "result_buffering" option in setOptions().
  614.      * This option was added in Release 1.7.0.
  615.      *
  616.      * @param resource  $stmt  a DB statement resource returned from prepare()
  617.      * @param mixed  $data  array, string or numeric data to be used in
  618.      *                       execution of the statement.  Quantity of items
  619.      *                       passed must match quantity of placeholders in
  620.      *                       query:  meaning 1 for non-array items or the
  621.      *                       quantity of elements in the array.
  622.      *
  623.      * @return mixed  returns an oic8 result resource for successful SELECT
  624.      *                 queries, DB_OK for other successful queries.
  625.      *                 A DB error object is returned on failure.
  626.      *
  627.      * @see DB_oci8::prepare()
  628.      */
  629.     function &execute($stmt$data array())
  630.     {
  631.         $data = (array)$data;
  632.         $this->last_parameters = $data;
  633.         $this->last_query = $this->_prepared_queries[(int)$stmt];
  634.         $this->_data $data;
  635.  
  636.         $types $this->prepare_types[(int)$stmt];
  637.         if (count($types!= count($data)) {
  638.             $tmp $this->raiseError(DB_ERROR_MISMATCH);
  639.             return $tmp;
  640.         }
  641.  
  642.         $i 0;
  643.         foreach ($data as $key => $value{
  644.             if ($types[$i== DB_PARAM_MISC{
  645.                 /*
  646.                  * Oracle doesn't seem to have the ability to pass a
  647.                  * parameter along unchanged, so strip off quotes from start
  648.                  * and end, plus turn two single quotes to one single quote,
  649.                  * in order to avoid the quotes getting escaped by
  650.                  * Oracle and ending up in the database.
  651.                  */
  652.                 $data[$keypreg_replace("/^'(.*)'$/""\\1"$data[$key]);
  653.                 $data[$keystr_replace("''""'"$data[$key]);
  654.             elseif ($types[$i== DB_PARAM_OPAQUE{
  655.                 $fp @fopen($data[$key]'rb');
  656.                 if (!$fp{
  657.                     $tmp $this->raiseError(DB_ERROR_ACCESS_VIOLATION);
  658.                     return $tmp;
  659.                 }
  660.                 $data[$keyfread($fpfilesize($data[$key]));
  661.                 fclose($fp);
  662.             elseif ($types[$i== DB_PARAM_SCALAR{
  663.                 // Floats have to be converted to a locale-neutral
  664.                 // representation.
  665.                 if (is_float($data[$key])) {
  666.                     $data[$key$this->quoteFloat($data[$key]);
  667.                 }
  668.             }
  669.             if (!@OCIBindByName($stmt':bind' $i$data[$key]-1)) {
  670.                 $tmp $this->oci8RaiseError($stmt);
  671.                 return $tmp;
  672.             }
  673.             $this->last_query = str_replace(':bind'.$i$this->quoteSmart($data[$key])$this->last_query);
  674.             $i++;
  675.         }
  676.         if ($this->autocommit{
  677.             $success @OCIExecute($stmtOCI_COMMIT_ON_SUCCESS);
  678.         else {
  679.             $success @OCIExecute($stmtOCI_DEFAULT);
  680.         }
  681.         if (!$success{
  682.             $tmp $this->oci8RaiseError($stmt);
  683.             return $tmp;
  684.         }
  685.         $this->last_stmt = $stmt;
  686.         if ($this->manip_query[(int)$stmt|| $this->_next_query_manip{
  687.             $this->_last_query_manip = true;
  688.             $this->_next_query_manip = false;
  689.             $tmp DB_OK;
  690.         else {
  691.             $this->_last_query_manip = false;
  692.             @ocisetprefetch($stmt$this->options['result_buffering']);
  693.             $tmp new DB_result($this$stmt);
  694.         }
  695.         return $tmp;
  696.     }
  697.  
  698.     // }}}
  699.     // {{{ autoCommit()
  700.  
  701.     /**
  702.      * Enables or disables automatic commits
  703.      *
  704.      * @param bool $onoff  true turns it on, false turns it off
  705.      *
  706.      * @return int  DB_OK on success.  A DB_Error object if the driver
  707.      *                doesn't support auto-committing transactions.
  708.      */
  709.     function autoCommit($onoff false)
  710.     {
  711.         $this->autocommit = (bool)$onoff;;
  712.         return DB_OK;
  713.     }
  714.  
  715.     // }}}
  716.     // {{{ commit()
  717.  
  718.     /**
  719.      * Commits the current transaction
  720.      *
  721.      * @return int  DB_OK on success.  A DB_Error object on failure.
  722.      */
  723.     function commit()
  724.     {
  725.         $result @OCICommit($this->connection);
  726.         if (!$result{
  727.             return $this->oci8RaiseError();
  728.         }
  729.         return DB_OK;
  730.     }
  731.  
  732.     // }}}
  733.     // {{{ rollback()
  734.  
  735.     /**
  736.      * Reverts the current transaction
  737.      *
  738.      * @return int  DB_OK on success.  A DB_Error object on failure.
  739.      */
  740.     function rollback()
  741.     {
  742.         $result @OCIRollback($this->connection);
  743.         if (!$result{
  744.             return $this->oci8RaiseError();
  745.         }
  746.         return DB_OK;
  747.     }
  748.  
  749.     // }}}
  750.     // {{{ affectedRows()
  751.  
  752.     /**
  753.      * Determines the number of rows affected by a data maniuplation query
  754.      *
  755.      * 0 is returned for queries that don't manipulate data.
  756.      *
  757.      * @return int  the number of rows.  A DB_Error object on failure.
  758.      */
  759.     function affectedRows()
  760.     {
  761.         if ($this->last_stmt === false{
  762.             return $this->oci8RaiseError();
  763.         }
  764.         $result @OCIRowCount($this->last_stmt);
  765.         if ($result === false{
  766.             return $this->oci8RaiseError($this->last_stmt);
  767.         }
  768.         return $result;
  769.     }
  770.  
  771.     // }}}
  772.     // {{{ modifyQuery()
  773.  
  774.     /**
  775.      * Changes a query string for various DBMS specific reasons
  776.      *
  777.      * "SELECT 2+2" must be "SELECT 2+2 FROM dual" in Oracle.
  778.      *
  779.      * @param string $query  the query string to modify
  780.      *
  781.      * @return string  the modified query string
  782.      *
  783.      * @access protected
  784.      */
  785.     function modifyQuery($query)
  786.     {
  787.         if (preg_match('/^\s*SELECT/i'$query&&
  788.             !preg_match('/\sFROM\s/i'$query)) {
  789.             $query .= ' FROM dual';
  790.         }
  791.         return $query;
  792.     }
  793.  
  794.     // }}}
  795.     // {{{ modifyLimitQuery()
  796.  
  797.     /**
  798.      * Adds LIMIT clauses to a query string according to current DBMS standards
  799.      *
  800.      * @param string $query   the query to modify
  801.      * @param int    $from    the row to start to fetching (0 = the first row)
  802.      * @param int    $count   the numbers of rows to fetch
  803.      * @param mixed  $params  array, string or numeric data to be used in
  804.      *                          execution of the statement.  Quantity of items
  805.      *                          passed must match quantity of placeholders in
  806.      *                          query:  meaning 1 placeholder for non-array
  807.      *                          parameters or 1 placeholder per array element.
  808.      *
  809.      * @return string  the query string with LIMIT clauses added
  810.      *
  811.      * @access protected
  812.      */
  813.     function modifyLimitQuery($query$from$count$params array())
  814.     {
  815.         // Let Oracle return the name of the columns instead of
  816.         // coding a "home" SQL parser
  817.  
  818.         if (count($params)) {
  819.             $result $this->prepare("SELECT * FROM ($query"
  820.                                      . 'WHERE NULL = NULL');
  821.             $tmp $this->execute($result$params);
  822.         else {
  823.             $q_fields "SELECT * FROM ($query) WHERE NULL = NULL";
  824.  
  825.             if (!$result @OCIParse($this->connection$q_fields)) {
  826.                 $this->last_query = $q_fields;
  827.                 return $this->oci8RaiseError();
  828.             }
  829.             if (!@OCIExecute($resultOCI_DEFAULT)) {
  830.                 $this->last_query = $q_fields;
  831.                 return $this->oci8RaiseError($result);
  832.             }
  833.         }
  834.  
  835.         $ncols OCINumCols($result);
  836.         $cols  array();
  837.         for $i 1$i <= $ncols$i++ {
  838.             $cols['"' OCIColumnName($result$i'"';
  839.         }
  840.         $fields implode(', '$cols);
  841.         // XXX Test that (tip by John Lim)
  842.         //if (preg_match('/^\s*SELECT\s+/is', $query, $match)) {
  843.         //    // Introduce the FIRST_ROWS Oracle query optimizer
  844.         //    $query = substr($query, strlen($match[0]), strlen($query));
  845.         //    $query = "SELECT /* +FIRST_ROWS */ " . $query;
  846.         //}
  847.  
  848.         // Construct the query
  849.         // more at: http://marc.theaimsgroup.com/?l=php-db&m=99831958101212&w=2
  850.         // Perhaps this could be optimized with the use of Unions
  851.         $query "SELECT $fields FROM".
  852.                  "  (SELECT rownum as linenum, $fields FROM".
  853.                  "      ($query)".
  854.                  '  WHERE rownum <= '($from $count.
  855.                  ') WHERE linenum >= ' . ++$from;
  856.         return $query;
  857.     }
  858.  
  859.     // }}}
  860.     // {{{ nextId()
  861.  
  862.     /**
  863.      * Returns the next free id in a sequence
  864.      *
  865.      * @param string  $seq_name  name of the sequence
  866.      * @param boolean $ondemand  when true, the seqence is automatically
  867.      *                             created if it does not exist
  868.      *
  869.      * @return int  the next id number in the sequence.
  870.      *                A DB_Error object on failure.
  871.      *
  872.      * @see DB_common::nextID(), DB_common::getSequenceName(),
  873.      *       DB_oci8::createSequence(), DB_oci8::dropSequence()
  874.      */
  875.     function nextId($seq_name$ondemand true)
  876.     {
  877.         $seqname $this->getSequenceName($seq_name);
  878.         $repeat 0;
  879.         do {
  880.             $this->expectError(DB_ERROR_NOSUCHTABLE);
  881.             $result $this->query("SELECT ${seqname}.nextval FROM dual");
  882.             $this->popExpect();
  883.             if ($ondemand && DB::isError($result&&
  884.                 $result->getCode(== DB_ERROR_NOSUCHTABLE{
  885.                 $repeat 1;
  886.                 $result $this->createSequence($seq_name);
  887.                 if (DB::isError($result)) {
  888.                     return $this->raiseError($result);
  889.                 }
  890.             else {
  891.                 $repeat 0;
  892.             }
  893.         while ($repeat);
  894.         if (DB::isError($result)) {
  895.             return $this->raiseError($result);
  896.         }
  897.         $arr $result->fetchRow(DB_FETCHMODE_ORDERED);
  898.         return $arr[0];
  899.     }
  900.  
  901.     /**
  902.      * Creates a new sequence
  903.      *
  904.      * @param string $seq_name  name of the new sequence
  905.      *
  906.      * @return int  DB_OK on success.  A DB_Error object on failure.
  907.      *
  908.      * @see DB_common::createSequence(), DB_common::getSequenceName(),
  909.      *       DB_oci8::nextID(), DB_oci8::dropSequence()
  910.      */
  911.     function createSequence($seq_name)
  912.     {
  913.         return $this->query('CREATE SEQUENCE '
  914.                             . $this->getSequenceName($seq_name));
  915.     }
  916.  
  917.     // }}}
  918.     // {{{ dropSequence()
  919.  
  920.     /**
  921.      * Deletes a sequence
  922.      *
  923.      * @param string $seq_name  name of the sequence to be deleted
  924.      *
  925.      * @return int  DB_OK on success.  A DB_Error object on failure.
  926.      *
  927.      * @see DB_common::dropSequence(), DB_common::getSequenceName(),
  928.      *       DB_oci8::nextID(), DB_oci8::createSequence()
  929.      */
  930.     function dropSequence($seq_name)
  931.     {
  932.         return $this->query('DROP SEQUENCE '
  933.                             . $this->getSequenceName($seq_name));
  934.     }
  935.  
  936.     // }}}
  937.     // {{{ oci8RaiseError()
  938.  
  939.     /**
  940.      * Produces a DB_Error object regarding the current problem
  941.      *
  942.      * @param int $errno  if the error is being manually raised pass a
  943.      *                      DB_ERROR* constant here.  If this isn't passed
  944.      *                      the error information gathered from the DBMS.
  945.      *
  946.      * @return object  the DB_Error object
  947.      *
  948.      * @see DB_common::raiseError(),
  949.      *       DB_oci8::errorNative(), DB_oci8::errorCode()
  950.      */
  951.     function oci8RaiseError($errno null)
  952.     {
  953.         if ($errno === null{
  954.             $error @OCIError($this->connection);
  955.             return $this->raiseError($this->errorCode($error['code']),
  956.                                      nullnullnull$error['message']);
  957.         elseif (is_resource($errno)) {
  958.             $error @OCIError($errno);
  959.             return $this->raiseError($this->errorCode($error['code']),
  960.                                      nullnullnull$error['message']);
  961.         }
  962.         return $this->raiseError($this->errorCode($errno));
  963.     }
  964.  
  965.     // }}}
  966.     // {{{ errorNative()
  967.  
  968.     /**
  969.      * Gets the DBMS' native error code produced by the last query
  970.      *
  971.      * @return int  the DBMS' error code.  FALSE if the code could not be
  972.      *                determined
  973.      */
  974.     function errorNative()
  975.     {
  976.         if (is_resource($this->last_stmt)) {
  977.             $error @OCIError($this->last_stmt);
  978.         else {
  979.             $error @OCIError($this->connection);
  980.         }
  981.         if (is_array($error)) {
  982.             return $error['code'];
  983.         }
  984.         return false;
  985.     }
  986.  
  987.     // }}}
  988.     // {{{ tableInfo()
  989.  
  990.     /**
  991.      * Returns information about a table or a result set
  992.      *
  993.      * NOTE: only supports 'table' and 'flags' if <var>$result</var>
  994.      * is a table name.
  995.      *
  996.      * NOTE: flags won't contain index information.
  997.      *
  998.      * @param object|string $result  DB_result object from a query or a
  999.      *                                  string containing the name of a table.
  1000.      *                                  While this also accepts a query result
  1001.      *                                  resource identifier, this behavior is
  1002.      *                                  deprecated.
  1003.      * @param int            $mode    a valid tableInfo mode
  1004.      *
  1005.      * @return array  an associative array with the information requested.
  1006.      *                  A DB_Error object on failure.
  1007.      *
  1008.      * @see DB_common::tableInfo()
  1009.      */
  1010.     function tableInfo($result$mode null)
  1011.     {
  1012.         if ($this->options['portability'DB_PORTABILITY_LOWERCASE{
  1013.             $case_func 'strtolower';
  1014.         else {
  1015.             $case_func 'strval';
  1016.         }
  1017.  
  1018.         $res array();
  1019.  
  1020.         if (is_string($result)) {
  1021.             /*
  1022.              * Probably received a table name.
  1023.              * Create a result resource identifier.
  1024.              */
  1025.             $result strtoupper($result);
  1026.             $q_fields 'SELECT column_name, data_type, data_length, '
  1027.                         . 'nullable '
  1028.                         . 'FROM user_tab_columns '
  1029.                         . "WHERE table_name='$result' ORDER BY column_id";
  1030.  
  1031.             $this->last_query = $q_fields;
  1032.  
  1033.             if (!$stmt @OCIParse($this->connection$q_fields)) {
  1034.                 return $this->oci8RaiseError(DB_ERROR_NEED_MORE_DATA);
  1035.             }
  1036.             if (!@OCIExecute($stmtOCI_DEFAULT)) {
  1037.                 return $this->oci8RaiseError($stmt);
  1038.             }
  1039.             
  1040.             $i 0;
  1041.             while (@OCIFetch($stmt)) {
  1042.                 $res[$iarray(
  1043.                     'table' => $case_func($result),
  1044.                     'name'  => $case_func(@OCIResult($stmt1)),
  1045.                     'type'  => @OCIResult($stmt2),
  1046.                     'len'   => @OCIResult($stmt3),
  1047.                     'flags' => (@OCIResult($stmt4== 'N''not_null' '',
  1048.                 );
  1049.                 if ($mode DB_TABLEINFO_ORDER{
  1050.                     $res['order'][$res[$i]['name']] $i;
  1051.                 }
  1052.                 if ($mode DB_TABLEINFO_ORDERTABLE{
  1053.                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] $i;
  1054.                 }
  1055.                 $i++;
  1056.             }
  1057.  
  1058.             if ($mode{
  1059.                 $res['num_fields'$i;
  1060.             }
  1061.             @OCIFreeStatement($stmt);
  1062.  
  1063.         else {
  1064.             if (isset($result->result)) {
  1065.                 /*
  1066.                  * Probably received a result object.
  1067.                  * Extract the result resource identifier.
  1068.                  */
  1069.                 $result $result->result;
  1070.             }
  1071.  
  1072.             $res array();
  1073.  
  1074.             if ($result === $this->last_stmt{
  1075.                 $count @OCINumCols($result);
  1076.                 if ($mode{
  1077.                     $res['num_fields'$count;
  1078.                 }
  1079.                 for ($i 0$i $count$i++{
  1080.                     $res[$iarray(
  1081.                         'table' => '',
  1082.                         'name'  => $case_func(@OCIColumnName($result$i+1)),
  1083.                         'type'  => @OCIColumnType($result$i+1),
  1084.                         'len'   => @OCIColumnSize($result$i+1),
  1085.                         'flags' => '',
  1086.                     );
  1087.                     if ($mode DB_TABLEINFO_ORDER{
  1088.                         $res['order'][$res[$i]['name']] $i;
  1089.                     }
  1090.                     if ($mode DB_TABLEINFO_ORDERTABLE{
  1091.                         $res['ordertable'][$res[$i]['table']][$res[$i]['name']] $i;
  1092.                     }
  1093.                 }
  1094.             else {
  1095.                 return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1096.             }
  1097.         }
  1098.         return $res;
  1099.     }
  1100.  
  1101.     // }}}
  1102.     // {{{ getSpecialQuery()
  1103.  
  1104.     /**
  1105.      * Obtains the query string needed for listing a given type of objects
  1106.      *
  1107.      * @param string $type  the kind of objects you want to retrieve
  1108.      *
  1109.      * @return string  the SQL query string or null if the driver doesn't
  1110.      *                   support the object type requested
  1111.      *
  1112.      * @access protected
  1113.      * @see DB_common::getListOf()
  1114.      */
  1115.     function getSpecialQuery($type)
  1116.     {
  1117.         switch ($type{
  1118.             case 'tables':
  1119.                 return 'SELECT table_name FROM user_tables';
  1120.             case 'synonyms':
  1121.                 return 'SELECT synonym_name FROM user_synonyms';
  1122.             case 'views':
  1123.                 return 'SELECT view_name FROM user_views';
  1124.             default:
  1125.                 return null;
  1126.         }
  1127.     }
  1128.  
  1129.     // }}}
  1130.     // {{{ quoteFloat()
  1131.  
  1132.     /**
  1133.      * Formats a float value for use within a query in a locale-independent
  1134.      * manner.
  1135.      *
  1136.      * @param float the float value to be quoted.
  1137.      * @return string the quoted string.
  1138.      * @see DB_common::quoteSmart()
  1139.      * @since Method available since release 1.7.8.
  1140.      */
  1141.     function quoteFloat($float{
  1142.         return $this->escapeSimple(str_replace(',''.'strval(floatval($float))));
  1143.     }
  1144.      
  1145.     // }}}
  1146.  
  1147. }
  1148.  
  1149. /*
  1150.  * Local variables:
  1151.  * tab-width: 4
  1152.  * c-basic-offset: 4
  1153.  * End:
  1154.  */
  1155.  
  1156. ?>

Documentation generated on Wed, 09 Feb 2011 09:02:29 +0700 by phpDocumentor 1.4.2