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,v 1.116 2007/11/28 02:22:39 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/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.14RC1
  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.         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($tokens- 1;
  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