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

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 293241 2010-01-08 05:00:28Z danielc $
  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/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.14
  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($result? OCIFreeStatement($result: false;
  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.             unset($this->_prepared_queries[(int)$stmt]);
  456.         else {
  457.             return false;
  458.         }
  459.         return true;
  460.     }
  461.  
  462.     // }}}
  463.     // {{{ numRows()
  464.  
  465.     /**
  466.      * Gets the number of rows in a result set
  467.      *
  468.      * Only works if the DB_PORTABILITY_NUMROWS portability option
  469.      * is turned on.
  470.      *
  471.      * This method is not meant to be called directly.  Use
  472.      * DB_result::numRows() instead.  It can't be declared "protected"
  473.      * because DB_result is a separate object.
  474.      *
  475.      * @param resource $result  PHP's query result resource
  476.      *
  477.      * @return int  the number of rows.  A DB_Error object on failure.
  478.      *
  479.      * @see DB_result::numRows(), DB_common::setOption()
  480.      */
  481.     function numRows($result)
  482.     {
  483.         // emulate numRows for Oracle.  yuck.
  484.         if ($this->options['portability'DB_PORTABILITY_NUMROWS &&
  485.             $result === $this->last_stmt)
  486.         {
  487.             $countquery 'SELECT COUNT(*) FROM ('.$this->last_query.')';
  488.             $save_query $this->last_query;
  489.             $save_stmt $this->last_stmt;
  490.  
  491.             $count $this->query($countquery);
  492.  
  493.             // Restore the last query and statement.
  494.             $this->last_query = $save_query;
  495.             $this->last_stmt = $save_stmt;
  496.             
  497.             if (DB::isError($count||
  498.                 DB::isError($row $count->fetchRow(DB_FETCHMODE_ORDERED)))
  499.             {
  500.                 return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  501.             }
  502.  
  503.             return $row[0];
  504.         }
  505.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  506.     }
  507.  
  508.     // }}}
  509.     // {{{ numCols()
  510.  
  511.     /**
  512.      * Gets the number of columns in a result set
  513.      *
  514.      * This method is not meant to be called directly.  Use
  515.      * DB_result::numCols() instead.  It can't be declared "protected"
  516.      * because DB_result is a separate object.
  517.      *
  518.      * @param resource $result  PHP's query result resource
  519.      *
  520.      * @return int  the number of columns.  A DB_Error object on failure.
  521.      *
  522.      * @see DB_result::numCols()
  523.      */
  524.     function numCols($result)
  525.     {
  526.         $cols @OCINumCols($result);
  527.         if (!$cols{
  528.             return $this->oci8RaiseError($result);
  529.         }
  530.         return $cols;
  531.     }
  532.  
  533.     // }}}
  534.     // {{{ prepare()
  535.  
  536.     /**
  537.      * Prepares a query for multiple execution with execute().
  538.      *
  539.      * With oci8, this is emulated.
  540.      *
  541.      * prepare() requires a generic query as string like <code>
  542.      *    INSERT INTO numbers VALUES (?, ?, ?)
  543.      * </code>.  The <kbd>?</kbd> characters are placeholders.
  544.      *
  545.      * Three types of placeholders can be used:
  546.      *   + <kbd>?</kbd>  a quoted scalar value, i.e. strings, integers
  547.      *   + <kbd>!</kbd>  value is inserted 'as is'
  548.      *   + <kbd>&</kbd>  requires a file name.  The file's contents get
  549.      *                     inserted into the query (i.e. saving binary
  550.      *                     data in a db)
  551.      *
  552.      * Use backslashes to escape placeholder characters if you don't want
  553.      * them to be interpreted as placeholders.  Example: <code>
  554.      *    "UPDATE foo SET col=? WHERE col='over \& under'"
  555.      * </code>
  556.      *
  557.      * @param string $query  the query to be prepared
  558.      *
  559.      * @return mixed  DB statement resource on success. DB_Error on failure.
  560.      *
  561.      * @see DB_oci8::execute()
  562.      */
  563.     function prepare($query)
  564.     {
  565.         $tokens   preg_split('/((?<!\\\)[&?!])/'$query-1,
  566.                                PREG_SPLIT_DELIM_CAPTURE);
  567.         $binds    count($tokens- 1;
  568.         $token    = 0;
  569.         $types    = array();
  570.         $newquery '';
  571.  
  572.         foreach ($tokens as $key => $val{
  573.             switch ($val{
  574.                 case '?':
  575.                     $types[$token++DB_PARAM_SCALAR;
  576.                     unset($tokens[$key]);
  577.                     break;
  578.                 case '&':
  579.                     $types[$token++DB_PARAM_OPAQUE;
  580.                     unset($tokens[$key]);
  581.                     break;
  582.                 case '!':
  583.                     $types[$token++DB_PARAM_MISC;
  584.                     unset($tokens[$key]);
  585.                     break;
  586.                 default:
  587.                     $tokens[$keypreg_replace('/\\\([&?!])/'"\\1"$val);
  588.                     if ($key != $binds{
  589.                         $newquery .= $tokens[$key':bind' $token;
  590.                     else {
  591.                         $newquery .= $tokens[$key];
  592.                     }
  593.             }
  594.         }
  595.  
  596.         $this->last_query = $query;
  597.         $newquery $this->modifyQuery($newquery);
  598.         if (!$stmt @OCIParse($this->connection$newquery)) {
  599.             return $this->oci8RaiseError();
  600.         }
  601.         $this->prepare_types[(int)$stmt$types;
  602.         $this->manip_query[(int)$stmtDB::isManip($query);
  603.         $this->_prepared_queries[(int)$stmt$newquery;
  604.         return $stmt;
  605.     }
  606.  
  607.     // }}}
  608.     // {{{ execute()
  609.  
  610.     /**
  611.      * Executes a DB statement prepared with prepare().
  612.      *
  613.      * To determine how many rows of a result set get buffered using
  614.      * ocisetprefetch(), see the "result_buffering" option in setOptions().
  615.      * This option was added in Release 1.7.0.
  616.      *
  617.      * @param resource  $stmt  a DB statement resource returned from prepare()
  618.      * @param mixed  $data  array, string or numeric data to be used in
  619.      *                       execution of the statement.  Quantity of items
  620.      *                       passed must match quantity of placeholders in
  621.      *                       query:  meaning 1 for non-array items or the
  622.      *                       quantity of elements in the array.
  623.      *
  624.      * @return mixed  returns an oic8 result resource for successful SELECT
  625.      *                 queries, DB_OK for other successful queries.
  626.      *                 A DB error object is returned on failure.
  627.      *
  628.      * @see DB_oci8::prepare()
  629.      */
  630.     function &execute($stmt$data = array())
  631.     {
  632.         $data = (array)$data;
  633.         $this->last_parameters = $data;
  634.         $this->last_query = $this->_prepared_queries[(int)$stmt];
  635.         $this->_data $data;
  636.  
  637.         $types $this->prepare_types[(int)$stmt];
  638.         if (count($types!= count($data)) {
  639.             $tmp $this->raiseError(DB_ERROR_MISMATCH);
  640.             return $tmp;
  641.         }
  642.  
  643.         $i = 0;
  644.         foreach ($data as $key => $value{
  645.             if ($types[$i== DB_PARAM_MISC{
  646.                 /*
  647.                  * Oracle doesn't seem to have the ability to pass a
  648.                  * parameter along unchanged, so strip off quotes from start
  649.                  * and end, plus turn two single quotes to one single quote,
  650.                  * in order to avoid the quotes getting escaped by
  651.                  * Oracle and ending up in the database.
  652.                  */
  653.                 $data[$keypreg_replace("/^'(.*)'$/""\\1"$data[$key]);
  654.                 $data[$keystr_replace("''""'"$data[$key]);
  655.             elseif ($types[$i== DB_PARAM_OPAQUE{
  656.                 $fp @fopen($data[$key]'rb');
  657.                 if (!$fp{
  658.                     $tmp $this->raiseError(DB_ERROR_ACCESS_VIOLATION);
  659.                     return $tmp;
  660.                 }
  661.                 $data[$keyfread($fpfilesize($data[$key]));
  662.                 fclose($fp);
  663.             elseif ($types[$i== DB_PARAM_SCALAR{
  664.                 // Floats have to be converted to a locale-neutral
  665.                 // representation.
  666.                 if (is_float($data[$key])) {
  667.                     $data[$key$this->quoteFloat($data[$key]);
  668.                 }
  669.             }
  670.             if (!@OCIBindByName($stmt':bind' $i$data[$key]-1)) {
  671.                 $tmp $this->oci8RaiseError($stmt);
  672.                 return $tmp;
  673.             }
  674.             $this->last_query = preg_replace("/:bind$i(?!\d)/",
  675.                     $this->quoteSmart($data[$key])$this->last_query1);
  676.             $i++;
  677.         }
  678.         if ($this->autocommit{
  679.             $success @OCIExecute($stmtOCI_COMMIT_ON_SUCCESS);
  680.         else {
  681.             $success @OCIExecute($stmtOCI_DEFAULT);
  682.         }
  683.         if (!$success{
  684.             $tmp $this->oci8RaiseError($stmt);
  685.             return $tmp;
  686.         }
  687.         $this->last_stmt = $stmt;
  688.         if ($this->manip_query[(int)$stmt|| $this->_next_query_manip{
  689.             $this->_last_query_manip = true;
  690.             $this->_next_query_manip = false;
  691.             $tmp DB_OK;
  692.         else {
  693.             $this->_last_query_manip = false;
  694.             @ocisetprefetch($stmt$this->options['result_buffering']);
  695.             $tmp = new DB_result($this$stmt);
  696.         }
  697.         return $tmp;
  698.     }
  699.  
  700.     // }}}
  701.     // {{{ autoCommit()
  702.  
  703.     /**
  704.      * Enables or disables automatic commits
  705.      *
  706.      * @param bool $onoff  true turns it on, false turns it off
  707.      *
  708.      * @return int  DB_OK on success.  A DB_Error object if the driver
  709.      *                doesn't support auto-committing transactions.
  710.      */
  711.     function autoCommit($onoff = false)
  712.     {
  713.         $this->autocommit = (bool)$onoff;;
  714.         return DB_OK;
  715.     }
  716.  
  717.     // }}}
  718.     // {{{ commit()
  719.  
  720.     /**
  721.      * Commits the current transaction
  722.      *
  723.      * @return int  DB_OK on success.  A DB_Error object on failure.
  724.      */
  725.     function commit()
  726.     {
  727.         $result @OCICommit($this->connection);
  728.         if (!$result{
  729.             return $this->oci8RaiseError();
  730.         }
  731.         return DB_OK;
  732.     }
  733.  
  734.     // }}}
  735.     // {{{ rollback()
  736.  
  737.     /**
  738.      * Reverts the current transaction
  739.      *
  740.      * @return int  DB_OK on success.  A DB_Error object on failure.
  741.      */
  742.     function rollback()
  743.     {
  744.         $result @OCIRollback($this->connection);
  745.         if (!$result{
  746.             return $this->oci8RaiseError();
  747.         }
  748.         return DB_OK;
  749.     }
  750.  
  751.     // }}}
  752.     // {{{ affectedRows()
  753.  
  754.     /**
  755.      * Determines the number of rows affected by a data maniuplation query
  756.      *
  757.      * 0 is returned for queries that don't manipulate data.
  758.      *
  759.      * @return int  the number of rows.  A DB_Error object on failure.
  760.      */
  761.     function affectedRows()
  762.     {
  763.         if ($this->last_stmt === false{
  764.             return $this->oci8RaiseError();
  765.         }
  766.         $result @OCIRowCount($this->last_stmt);
  767.         if ($result === false{
  768.             return $this->oci8RaiseError($this->last_stmt);
  769.         }
  770.         return $result;
  771.     }
  772.  
  773.     // }}}
  774.     // {{{ modifyQuery()
  775.  
  776.     /**
  777.      * Changes a query string for various DBMS specific reasons
  778.      *
  779.      * "SELECT 2+2" must be "SELECT 2+2 FROM dual" in Oracle.
  780.      *
  781.      * @param string $query  the query string to modify
  782.      *
  783.      * @return string  the modified query string
  784.      *
  785.      * @access protected
  786.      */
  787.     function modifyQuery($query)
  788.     {
  789.         if (preg_match('/^\s*SELECT/i'$query&&
  790.             !preg_match('/\sFROM\s/i'$query)) {
  791.             $query .= ' FROM dual';
  792.         }
  793.         return $query;
  794.     }
  795.  
  796.     // }}}
  797.     // {{{ modifyLimitQuery()
  798.  
  799.     /**
  800.      * Adds LIMIT clauses to a query string according to current DBMS standards
  801.      *
  802.      * @param string $query   the query to modify
  803.      * @param int    $from    the row to start to fetching (0 = the first row)
  804.      * @param int    $count   the numbers of rows to fetch
  805.      * @param mixed  $params  array, string or numeric data to be used in
  806.      *                          execution of the statement.  Quantity of items
  807.      *                          passed must match quantity of placeholders in
  808.      *                          query:  meaning 1 placeholder for non-array
  809.      *                          parameters or 1 placeholder per array element.
  810.      *
  811.      * @return string  the query string with LIMIT clauses added
  812.      *
  813.      * @access protected
  814.      */
  815.     function modifyLimitQuery($query$from$count$params = array())
  816.     {
  817.         // Let Oracle return the name of the columns instead of
  818.         // coding a "home" SQL parser
  819.  
  820.         if (count($params)) {
  821.             $result $this->prepare("SELECT * FROM ($query"
  822.                                      . 'WHERE NULL = NULL');
  823.             $tmp $this->execute($result$params);
  824.         else {
  825.             $q_fields = "SELECT * FROM ($query) WHERE NULL = NULL";
  826.  
  827.             if (!$result @OCIParse($this->connection$q_fields)) {
  828.                 $this->last_query = $q_fields;
  829.                 return $this->oci8RaiseError();
  830.             }
  831.             if (!@OCIExecute($resultOCI_DEFAULT)) {
  832.                 $this->last_query = $q_fields;
  833.                 return $this->oci8RaiseError($result);
  834.             }
  835.         }
  836.  
  837.         $ncols = OCINumCols($result);
  838.         $cols  = array();
  839.         for $i = 1; $i <= $ncols$i++ {
  840.             $cols['"' . OCIColumnName($result$i'"';
  841.         }
  842.         $fields implode(', '$cols);
  843.         // XXX Test that (tip by John Lim)
  844.         //if (preg_match('/^\s*SELECT\s+/is', $query, $match)) {
  845.         //    // Introduce the FIRST_ROWS Oracle query optimizer
  846.         //    $query = substr($query, strlen($match[0]), strlen($query));
  847.         //    $query = "SELECT /* +FIRST_ROWS */ " . $query;
  848.         //}
  849.  
  850.         // Construct the query
  851.         // more at: http://marc.theaimsgroup.com/?l=php-db&m=99831958101212&w=2
  852.         // Perhaps this could be optimized with the use of Unions
  853.         $query = "SELECT $fields FROM".
  854.                  "  (SELECT rownum as linenum, $fields FROM".
  855.                  "      ($query)".
  856.                  '  WHERE rownum <= '($from $count.
  857.                  ') WHERE linenum >= ' . ++$from;
  858.         return $query;
  859.     }
  860.  
  861.     // }}}
  862.     // {{{ nextId()
  863.  
  864.     /**
  865.      * Returns the next free id in a sequence
  866.      *
  867.      * @param string  $seq_name  name of the sequence
  868.      * @param boolean $ondemand  when true, the seqence is automatically
  869.      *                             created if it does not exist
  870.      *
  871.      * @return int  the next id number in the sequence.
  872.      *                A DB_Error object on failure.
  873.      *
  874.      * @see DB_common::nextID(), DB_common::getSequenceName(),
  875.      *       DB_oci8::createSequence(), DB_oci8::dropSequence()
  876.      */
  877.     function nextId($seq_name$ondemand = true)
  878.     {
  879.         $seqname $this->getSequenceName($seq_name);
  880.         $repeat = 0;
  881.         do {
  882.             $this->expectError(DB_ERROR_NOSUCHTABLE);
  883.             $result $this->query("SELECT ${seqname}.nextval FROM dual");
  884.             $this->popExpect();
  885.             if ($ondemand && DB::isError($result&&
  886.                 $result->getCode(== DB_ERROR_NOSUCHTABLE{
  887.                 $repeat = 1;
  888.                 $result $this->createSequence($seq_name);
  889.                 if (DB::isError($result)) {
  890.                     return $this->raiseError($result);
  891.                 }
  892.             else {
  893.                 $repeat = 0;
  894.             }
  895.         while ($repeat);
  896.         if (DB::isError($result)) {
  897.             return $this->raiseError($result);
  898.         }
  899.         $arr $result->fetchRow(DB_FETCHMODE_ORDERED);
  900.         return $arr[0];
  901.     }
  902.  
  903.     /**
  904.      * Creates a new sequence
  905.      *
  906.      * @param string $seq_name  name of the new sequence
  907.      *
  908.      * @return int  DB_OK on success.  A DB_Error object on failure.
  909.      *
  910.      * @see DB_common::createSequence(), DB_common::getSequenceName(),
  911.      *       DB_oci8::nextID(), DB_oci8::dropSequence()
  912.      */
  913.     function createSequence($seq_name)
  914.     {
  915.         return $this->query('CREATE SEQUENCE '
  916.                             . $this->getSequenceName($seq_name));
  917.     }
  918.  
  919.     // }}}
  920.     // {{{ dropSequence()
  921.  
  922.     /**
  923.      * Deletes a sequence
  924.      *
  925.      * @param string $seq_name  name of the sequence to be deleted
  926.      *
  927.      * @return int  DB_OK on success.  A DB_Error object on failure.
  928.      *
  929.      * @see DB_common::dropSequence(), DB_common::getSequenceName(),
  930.      *       DB_oci8::nextID(), DB_oci8::createSequence()
  931.      */
  932.     function dropSequence($seq_name)
  933.     {
  934.         return $this->query('DROP SEQUENCE '
  935.                             . $this->getSequenceName($seq_name));
  936.     }
  937.  
  938.     // }}}
  939.     // {{{ oci8RaiseError()
  940.  
  941.     /**
  942.      * Produces a DB_Error object regarding the current problem
  943.      *
  944.      * @param int $errno  if the error is being manually raised pass a
  945.      *                      DB_ERROR* constant here.  If this isn't passed
  946.      *                      the error information gathered from the DBMS.
  947.      *
  948.      * @return object  the DB_Error object
  949.      *
  950.      * @see DB_common::raiseError(),
  951.      *       DB_oci8::errorNative(), DB_oci8::errorCode()
  952.      */
  953.     function oci8RaiseError($errno = null)
  954.     {
  955.         if ($errno === null{
  956.             $error @OCIError($this->connection);
  957.             return $this->raiseError($this->errorCode($error['code']),
  958.                                      nullnullnull$error['message']);
  959.         elseif (is_resource($errno)) {
  960.             $error @OCIError($errno);
  961.             return $this->raiseError($this->errorCode($error['code']),
  962.                                      nullnullnull$error['message']);
  963.         }
  964.         return $this->raiseError($this->errorCode($errno));
  965.     }
  966.  
  967.     // }}}
  968.     // {{{ errorNative()
  969.  
  970.     /**
  971.      * Gets the DBMS' native error code produced by the last query
  972.      *
  973.      * @return int  the DBMS' error code.  FALSE if the code could not be
  974.      *                determined
  975.      */
  976.     function errorNative()
  977.     {
  978.         if (is_resource($this->last_stmt)) {
  979.             $error @OCIError($this->last_stmt);
  980.         else {
  981.             $error @OCIError($this->connection);
  982.         }
  983.         if (is_array($error)) {
  984.             return $error['code'];
  985.         }
  986.         return false;
  987.     }
  988.  
  989.     // }}}
  990.     // {{{ tableInfo()
  991.  
  992.     /**
  993.      * Returns information about a table or a result set
  994.      *
  995.      * NOTE: only supports 'table' and 'flags' if <var>$result</var>
  996.      * is a table name.
  997.      *
  998.      * NOTE: flags won't contain index information.
  999.      *
  1000.      * @param object|string $result  DB_result object from a query or a
  1001.      *                                  string containing the name of a table.
  1002.      *                                  While this also accepts a query result
  1003.      *                                  resource identifier, this behavior is
  1004.      *                                  deprecated.
  1005.      * @param int            $mode    a valid tableInfo mode
  1006.      *
  1007.      * @return array  an associative array with the information requested.
  1008.      *                  A DB_Error object on failure.
  1009.      *
  1010.      * @see DB_common::tableInfo()
  1011.      */
  1012.     function tableInfo($result$mode = null)
  1013.     {
  1014.         if ($this->options['portability'DB_PORTABILITY_LOWERCASE{
  1015.             $case_func 'strtolower';
  1016.         else {
  1017.             $case_func 'strval';
  1018.         }
  1019.  
  1020.         $res = array();
  1021.  
  1022.         if (is_string($result)) {
  1023.             /*
  1024.              * Probably received a table name.
  1025.              * Create a result resource identifier.
  1026.              */
  1027.             $result strtoupper($result);
  1028.             $q_fields 'SELECT column_name, data_type, data_length, '
  1029.                         . 'nullable '
  1030.                         . 'FROM user_tab_columns '
  1031.                         . "WHERE table_name='$result' ORDER BY column_id";
  1032.  
  1033.             $this->last_query = $q_fields;
  1034.  
  1035.             if (!$stmt @OCIParse($this->connection$q_fields)) {
  1036.                 return $this->oci8RaiseError(DB_ERROR_NEED_MORE_DATA);
  1037.             }
  1038.             if (!@OCIExecute($stmtOCI_DEFAULT)) {
  1039.                 return $this->oci8RaiseError($stmt);
  1040.             }
  1041.             
  1042.             $i = 0;
  1043.             while (@OCIFetch($stmt)) {
  1044.                 $res[$i= array(
  1045.                     'table' => $case_func($result),
  1046.                     'name'  => $case_func(@OCIResult($stmt1)),
  1047.                     'type'  => @OCIResult($stmt2),
  1048.                     'len'   => @OCIResult($stmt3),
  1049.                     'flags' => (@OCIResult($stmt4== 'N''not_null' '',
  1050.                 );
  1051.                 if ($mode DB_TABLEINFO_ORDER{
  1052.                     $res['order'][$res[$i]['name']] $i;
  1053.                 }
  1054.                 if ($mode DB_TABLEINFO_ORDERTABLE{
  1055.                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] $i;
  1056.                 }
  1057.                 $i++;
  1058.             }
  1059.  
  1060.             if ($mode{
  1061.                 $res['num_fields'$i;
  1062.             }
  1063.             @OCIFreeStatement($stmt);
  1064.  
  1065.         else {
  1066.             if (isset($result->result)) {
  1067.                 /*
  1068.                  * Probably received a result object.
  1069.                  * Extract the result resource identifier.
  1070.                  */
  1071.                 $result $result->result;
  1072.             }
  1073.  
  1074.             $res = array();
  1075.  
  1076.             if ($result === $this->last_stmt{
  1077.                 $count @OCINumCols($result);
  1078.                 if ($mode{
  1079.                     $res['num_fields'$count;
  1080.                 }
  1081.                 for ($i = 0; $i $count$i++{
  1082.                     $res[$i= array(
  1083.                         'table' => '',
  1084.                         'name'  => $case_func(@OCIColumnName($result$i+1)),
  1085.                         'type'  => @OCIColumnType($result$i+1),
  1086.                         'len'   => @OCIColumnSize($result$i+1),
  1087.                         'flags' => '',
  1088.                     );
  1089.                     if ($mode DB_TABLEINFO_ORDER{
  1090.                         $res['order'][$res[$i]['name']] $i;
  1091.                     }
  1092.                     if ($mode DB_TABLEINFO_ORDERTABLE{
  1093.                         $res['ordertable'][$res[$i]['table']][$res[$i]['name']] $i;
  1094.                     }
  1095.                 }
  1096.             else {
  1097.                 return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  1098.             }
  1099.         }
  1100.         return $res;
  1101.     }
  1102.  
  1103.     // }}}
  1104.     // {{{ getSpecialQuery()
  1105.  
  1106.     /**
  1107.      * Obtains the query string needed for listing a given type of objects
  1108.      *
  1109.      * @param string $type  the kind of objects you want to retrieve
  1110.      *
  1111.      * @return string  the SQL query string or null if the driver doesn't
  1112.      *                   support the object type requested
  1113.      *
  1114.      * @access protected
  1115.      * @see DB_common::getListOf()
  1116.      */
  1117.     function getSpecialQuery($type)
  1118.     {
  1119.         switch ($type{
  1120.             case 'tables':
  1121.                 return 'SELECT table_name FROM user_tables';
  1122.             case 'synonyms':
  1123.                 return 'SELECT synonym_name FROM user_synonyms';
  1124.             case 'views':
  1125.                 return 'SELECT view_name FROM user_views';
  1126.             default:
  1127.                 return null;
  1128.         }
  1129.     }
  1130.  
  1131.     // }}}
  1132.     // {{{ quoteFloat()
  1133.  
  1134.     /**
  1135.      * Formats a float value for use within a query in a locale-independent
  1136.      * manner.
  1137.      *
  1138.      * @param float the float value to be quoted.
  1139.      * @return string the quoted string.
  1140.      * @see DB_common::quoteSmart()
  1141.      * @since Method available since release 1.7.8.
  1142.      */
  1143.     function quoteFloat($float{
  1144.         return $this->escapeSimple(str_replace(',''.'strval(floatval($float))));
  1145.     }
  1146.      
  1147.     // }}}
  1148.  
  1149. }
  1150.  
  1151. /*
  1152.  * Local variables:
  1153.  * tab-width: 4
  1154.  * c-basic-offset: 4
  1155.  * End:
  1156.  */
  1157.  
  1158. ?>

Documentation generated on Sat, 27 Aug 2011 14:00:16 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.