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-2005 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.111 2007/01/12 03:11:17 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-2005 The PHP Group
  49.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  50.  * @version    Release: 1.7.10
  51.  * @link       http://pear.php.net/package/DB
  52.  */
  53. class DB_oci8 extends DB_common
  54. {
  55.     // {{{ properties
  56.  
  57.     
  58.     /**
  59.      * The DB driver type (mysql, oci8, odbc, etc.)
  60.      * @var string 
  61.      */
  62.     var $phptype = 'oci8';
  63.  
  64.     /**
  65.      * The database syntax variant to be used (db2, access, etc.), if any
  66.      * @var string 
  67.      */
  68.     var $dbsyntax = 'oci8';
  69.  
  70.     /**
  71.      * The capabilities of this DB implementation
  72.      *
  73.      * The 'new_link' element contains the PHP version that first provided
  74.      * new_link support for this DBMS.  Contains false if it's unsupported.
  75.      *
  76.      * Meaning of the 'limit' element:
  77.      *   + 'emulate' = emulate with fetch row by number
  78.      *   + 'alter'   = alter the query
  79.      *   + false     = skip rows
  80.      *
  81.      * @var array 
  82.      */
  83.     var $features = array(
  84.         'limit'         => 'alter',
  85.         'new_link'      => '5.0.0',
  86.         'numrows'       => 'subquery',
  87.         'pconnect'      => true,
  88.         'prepare'       => true,
  89.         'ssl'           => false,
  90.         'transactions'  => true,
  91.     );
  92.  
  93.     /**
  94.      * A mapping of native error codes to DB error codes
  95.      * @var array 
  96.      */
  97.     var $errorcode_map = array(
  98.         1     => DB_ERROR_CONSTRAINT,
  99.         900   => DB_ERROR_SYNTAX,
  100.         904   => DB_ERROR_NOSUCHFIELD,
  101.         913   => DB_ERROR_VALUE_COUNT_ON_ROW,
  102.         921   => DB_ERROR_SYNTAX,
  103.         923   => DB_ERROR_SYNTAX,
  104.         942   => DB_ERROR_NOSUCHTABLE,
  105.         955   => DB_ERROR_ALREADY_EXISTS,
  106.         1400  => DB_ERROR_CONSTRAINT_NOT_NULL,
  107.         1401  => DB_ERROR_INVALID,
  108.         1407  => DB_ERROR_CONSTRAINT_NOT_NULL,
  109.         1418  => DB_ERROR_NOT_FOUND,
  110.         1476  => DB_ERROR_DIVZERO,
  111.         1722  => DB_ERROR_INVALID_NUMBER,
  112.         2289  => DB_ERROR_NOSUCHTABLE,
  113.         2291  => DB_ERROR_CONSTRAINT,
  114.         2292  => DB_ERROR_CONSTRAINT,
  115.         2449  => DB_ERROR_CONSTRAINT,
  116.         12899 => DB_ERROR_INVALID,
  117.     );
  118.  
  119.     /**
  120.      * The raw database connection created by PHP
  121.      * @var resource 
  122.      */
  123.     var $connection;
  124.  
  125.     /**
  126.      * The DSN information for connecting to a database
  127.      * @var array 
  128.      */
  129.     var $dsn = array();
  130.  
  131.  
  132.     /**
  133.      * Should data manipulation queries be committed automatically?
  134.      * @var bool 
  135.      * @access private
  136.      */
  137.     var $autocommit = true;
  138.  
  139.     /**
  140.      * Stores the $data passed to execute() in the oci8 driver
  141.      *
  142.      * Gets reset to array() when simpleQuery() is run.
  143.      *
  144.      * Needed in case user wants to call numRows() after prepare/execute
  145.      * was used.
  146.      *
  147.      * @var array 
  148.      * @access private
  149.      */
  150.     var $_data = array();
  151.  
  152.     /**
  153.      * The result or statement handle from the most recently executed query
  154.      * @var resource 
  155.      */
  156.     var $last_stmt;
  157.  
  158.     /**
  159.      * Is the given prepared statement a data manipulation query?
  160.      * @var array 
  161.      * @access private
  162.      */
  163.     var $manip_query = array();
  164.  
  165.     /**
  166.      * Store of prepared SQL queries.
  167.      * @var array 
  168.      * @access private
  169.      */
  170.     var $_prepared_queries = array();
  171.  
  172.  
  173.     // }}}
  174.     // {{{ constructor
  175.  
  176.     
  177.     /**
  178.      * This constructor calls <kbd>$this->DB_common()</kbd>
  179.      *
  180.      * @return void 
  181.      */
  182.     function DB_oci8()
  183.     {
  184.         $this->DB_common();
  185.     }
  186.  
  187.     // }}}
  188.     // {{{ connect()
  189.  
  190.     
  191.     /**
  192.      * Connect to the database server, log in and open the database
  193.      *
  194.      * Don't call this method directly.  Use DB::connect() instead.
  195.      *
  196.      * If PHP is at version 5.0.0 or greater:
  197.      *   + Generally, oci_connect() or oci_pconnect() are used.
  198.      *   + But if the new_link DSN option is set to true, oci_new_connect()
  199.      *     is used.
  200.      *
  201.      * When using PHP version 4.x, OCILogon() or OCIPLogon() are used.
  202.      *
  203.      * PEAR DB's oci8 driver supports the following extra DSN options:
  204.      *   + charset       The character set to be used on the connection.
  205.      *                    Only used if PHP is at version 5.0.0 or greater
  206.      *                    and the Oracle server is at 9.2 or greater.
  207.      *                    Available since PEAR DB 1.7.0.
  208.      *   + new_link      If set to true, causes subsequent calls to
  209.      *                    connect() to return a new connection link
  210.      *                    instead of the existing one.  WARNING: this is
  211.      *                    not portable to other DBMS's.
  212.      *                    Available since PEAR DB 1.7.0.
  213.      *
  214.      * @param array $dsn         the data source name
  215.      * @param bool  $persistent  should the connection be persistent?
  216.      *
  217.      * @return int  DB_OK on success. A DB_Error object on failure.
  218.      */
  219.     function connect($dsn$persistent = false)
  220.     {
  221.         if (!PEAR::loadExtension('oci8')) {
  222.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  223.         }
  224.  
  225.         $this->dsn = $dsn;
  226.         if ($dsn['dbsyntax']{
  227.             $this->dbsyntax = $dsn['dbsyntax'];
  228.         }
  229.  
  230.         // Backwards compatibility with DB < 1.7.0
  231.         if (empty($dsn['database']&& !empty($dsn['hostspec'])) {
  232.             $db $dsn['hostspec'];
  233.         else {
  234.             $db $dsn['database'];
  235.         }
  236.  
  237.         if (function_exists('oci_connect')) {
  238.             if (isset($dsn['new_link'])
  239.                 && ($dsn['new_link'== 'true' || $dsn['new_link'=== true))
  240.             {
  241.                 $connect_function 'oci_new_connect';
  242.             else {
  243.                 $connect_function $persistent 'oci_pconnect'
  244.                                     : 'oci_connect';
  245.             }
  246.             if (isset($this->dsn['port']&& $this->dsn['port']{
  247.                 $db '//'.$db.':'.$this->dsn['port'];
  248.             }
  249.  
  250.             $char = empty($dsn['charset']? null : $dsn['charset'];
  251.             $this->connection = @$connect_function($dsn['username'],
  252.                                                    $dsn['password'],
  253.                                                    $db,
  254.                                                    $char);
  255.             $error = OCIError();
  256.             if (!empty($error&& $error['code'== 12541{
  257.                 // Couldn't find TNS listener.  Try direct connection.
  258.                 $this->connection = @$connect_function($dsn['username'],
  259.                                                        $dsn['password'],
  260.                                                        null,
  261.                                                        $char);
  262.             }
  263.         else {
  264.             $connect_function $persistent 'OCIPLogon' 'OCILogon';
  265.             if ($db{
  266.                 $this->connection = @$connect_function($dsn['username'],
  267.                                                        $dsn['password'],
  268.                                                        $db);
  269.             elseif ($dsn['username'|| $dsn['password']{
  270.                 $this->connection = @$connect_function($dsn['username'],
  271.                                                        $dsn['password']);
  272.             }
  273.         }
  274.  
  275.         if (!$this->connection{
  276.             $error = OCIError();
  277.             $error (is_array($error)) $error['message': null;
  278.             return $this->raiseError(DB_ERROR_CONNECT_FAILED,
  279.                                      nullnullnull,
  280.                                      $error);
  281.         }
  282.         return DB_OK;
  283.     }
  284.  
  285.     // }}}
  286.     // {{{ disconnect()
  287.  
  288.     
  289.     /**
  290.      * Disconnects from the database server
  291.      *
  292.      * @return bool  TRUE on success, FALSE on failure
  293.      */
  294.     function disconnect()
  295.     {
  296.         if (function_exists('oci_close')) {
  297.             $ret @oci_close($this->connection);
  298.         else {
  299.             $ret @OCILogOff($this->connection);
  300.         }
  301.         $this->connection = null;
  302.         return $ret;
  303.     }
  304.  
  305.     // }}}
  306.     // {{{ simpleQuery()
  307.  
  308.     
  309.     /**
  310.      * Sends a query to the database server
  311.      *
  312.      * To determine how many rows of a result set get buffered using
  313.      * ocisetprefetch(), see the "result_buffering" option in setOptions().
  314.      * This option was added in Release 1.7.0.
  315.      *
  316.      * @param string  the SQL query string
  317.      *
  318.      * @return mixed  + a PHP result resrouce for successful SELECT queries
  319.      *                 + the DB_OK constant for other successful queries
  320.      *                 + a DB_Error object on failure
  321.      */
  322.     function simpleQuery($query)
  323.     {
  324.         $this->_data = array();
  325.         $this->last_parameters = array();
  326.         $this->last_query = $query;
  327.         $query $this->modifyQuery($query);
  328.         $result @OCIParse($this->connection$query);
  329.         if (!$result{
  330.             return $this->oci8RaiseError();
  331.         }
  332.         if ($this->autocommit{
  333.             $success @OCIExecute($result,OCI_COMMIT_ON_SUCCESS);
  334.         else {
  335.             $success @OCIExecute($result,OCI_DEFAULT);
  336.         }
  337.         if (!$success{
  338.             return $this->oci8RaiseError($result);
  339.         }
  340.         $this->last_stmt = $result;
  341.         if ($this->_checkManip($query)) {
  342.             return DB_OK;
  343.         else {
  344.             @ocisetprefetch($result$this->options['result_buffering']);
  345.             return $result;
  346.         }
  347.     }
  348.  
  349.     // }}}
  350.     // {{{ nextResult()
  351.  
  352.     
  353.     /**
  354.      * Move the internal oracle result pointer to the next available result
  355.      *
  356.      * @param valid oci8 result resource
  357.      *
  358.      * @access public
  359.      *
  360.      * @return true if a result is available otherwise return false
  361.      */
  362.     function nextResult($result)
  363.     {
  364.         return false;
  365.     }
  366.  
  367.     // }}}
  368.     // {{{ fetchInto()
  369.  
  370.     
  371.     /**
  372.      * Places a row from the result set into the given array
  373.      *
  374.      * Formating of the array and the data therein are configurable.
  375.      * See DB_result::fetchInto() for more information.
  376.      *
  377.      * This method is not meant to be called directly.  Use
  378.      * DB_result::fetchInto() instead.  It can't be declared "protected"
  379.      * because DB_result is a separate object.
  380.      *
  381.      * @param resource $result    the query result resource
  382.      * @param array    $arr       the referenced array to put the data in
  383.      * @param int      $fetchmode how the resulting array should be indexed
  384.      * @param int      $rownum    the row number to fetch (0 = first row)
  385.      *
  386.      * @return mixed  DB_OK on success, NULL when the end of a result set is
  387.      *                  reached or on failure
  388.      *
  389.      * @see DB_result::fetchInto()
  390.      */
  391.     function fetchInto($result&$arr$fetchmode$rownum = null)
  392.     {
  393.         if ($rownum !== null{
  394.             return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  395.         }
  396.         if ($fetchmode DB_FETCHMODE_ASSOC{
  397.             $moredata @OCIFetchInto($result,$arr,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
  398.             if ($this->options['portability'DB_PORTABILITY_LOWERCASE &&
  399.                 $moredata)
  400.             {
  401.                 $arr array_change_key_case($arrCASE_LOWER);
  402.             }
  403.         else {
  404.             $moredata = OCIFetchInto($result,$arr,OCI_RETURN_NULLS+OCI_RETURN_LOBS);
  405.         }
  406.         if (!$moredata{
  407.             return null;
  408.         }
  409.         if ($this->options['portability'DB_PORTABILITY_RTRIM{
  410.             $this->_rtrimArrayValues($arr);
  411.         }
  412.         if ($this->options['portability'DB_PORTABILITY_NULL_TO_EMPTY{
  413.             $this->_convertNullArrayValuesToEmpty($arr);
  414.         }
  415.         return DB_OK;
  416.     }
  417.  
  418.     // }}}
  419.     // {{{ freeResult()
  420.  
  421.     
  422.     /**
  423.      * Deletes the result set and frees the memory occupied by the result set
  424.      *
  425.      * This method is not meant to be called directly.  Use
  426.      * DB_result::free() instead.  It can't be declared "protected"
  427.      * because DB_result is a separate object.
  428.      *
  429.      * @param resource $result  PHP's query result resource
  430.      *
  431.      * @return bool  TRUE on success, FALSE if $result is invalid
  432.      *
  433.      * @see DB_result::free()
  434.      */
  435.     function freeResult($result)
  436.     {
  437.         return is_resource($result? OCIFreeStatement($result: false;
  438.     }
  439.  
  440.     /**
  441.      * Frees the internal resources associated with a prepared query
  442.      *
  443.      * @param resource $stmt           the prepared statement's resource
  444.      * @param bool     $free_resource  should the PHP resource be freed too?
  445.      *                                   Use false if you need to get data
  446.      *                                   from the result set later.
  447.      *
  448.      * @return bool  TRUE on success, FALSE if $result is invalid
  449.      *
  450.      * @see DB_oci8::prepare()
  451.      */
  452.     function freePrepared($stmt$free_resource = true)
  453.     {
  454.         if (!is_resource($stmt)) {
  455.             return false;
  456.         }
  457.         if ($free_resource{
  458.             @ocifreestatement($stmt);
  459.         }
  460.         if (isset($this->prepare_types[(int)$stmt])) {
  461.             unset($this->prepare_types[(int)$stmt]);
  462.             unset($this->manip_query[(int)$stmt]);
  463.         else {
  464.             return false;
  465.         }
  466.         return true;
  467.     }
  468.  
  469.     // }}}
  470.     // {{{ numRows()
  471.  
  472.     
  473.     /**
  474.      * Gets the number of rows in a result set
  475.      *
  476.      * Only works if the DB_PORTABILITY_NUMROWS portability option
  477.      * is turned on.
  478.      *
  479.      * This method is not meant to be called directly.  Use
  480.      * DB_result::numRows() instead.  It can't be declared "protected"
  481.      * because DB_result is a separate object.
  482.      *
  483.      * @param resource $result  PHP's query result resource
  484.      *
  485.      * @return int  the number of rows.  A DB_Error object on failure.
  486.      *
  487.      * @see DB_result::numRows(), DB_common::setOption()
  488.      */
  489.     function numRows($result)
  490.     {
  491.         // emulate numRows for Oracle.  yuck.
  492.         if ($this->options['portability'DB_PORTABILITY_NUMROWS &&
  493.             $result === $this->last_stmt)
  494.         {
  495.             $countquery 'SELECT COUNT(*) FROM ('.$this->last_query.')';
  496.             $save_query $this->last_query;
  497.             $save_stmt $this->last_stmt;
  498.  
  499.             $count =$this->query($countquery);
  500.  
  501.             // Restore the last query and statement.
  502.             $this->last_query = $save_query;
  503.             $this->last_stmt = $save_stmt;
  504.             
  505.             if (DB::isError($count||
  506.                 DB::isError($row $count->fetchRow(DB_FETCHMODE_ORDERED)))
  507.             {
  508.                 return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  509.             }
  510.  
  511.             return $row[0];
  512.         }
  513.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  514.     }
  515.  
  516.     // }}}
  517.     // {{{ numCols()
  518.  
  519.     
  520.     /**
  521.      * Gets the number of columns in a result set
  522.      *
  523.      * This method is not meant to be called directly.  Use
  524.      * DB_result::numCols() instead.  It can't be declared "protected"
  525.      * because DB_result is a separate object.
  526.      *
  527.      * @param resource $result  PHP's query result resource
  528.      *
  529.      * @return int  the number of columns.  A DB_Error object on failure.
  530.      *
  531.      * @see DB_result::numCols()
  532.      */
  533.     function numCols($result)
  534.     {
  535.         $cols @OCINumCols($result);
  536.         if (!$cols{
  537.             return $this->oci8RaiseError($result);
  538.         }
  539.         return $cols;
  540.     }
  541.  
  542.     // }}}
  543.     // {{{ prepare()
  544.  
  545.     
  546.     /**
  547.      * Prepares a query for multiple execution with execute().
  548.      *
  549.      * With oci8, this is emulated.
  550.      *
  551.      * prepare() requires a generic query as string like <code>
  552.      *    INSERT INTO numbers VALUES (?, ?, ?)
  553.      * </code>.  The <kbd>?</kbd> characters are placeholders.
  554.      *
  555.      * Three types of placeholders can be used:
  556.      *   + <kbd>?</kbd>  a quoted scalar value, i.e. strings, integers
  557.      *   + <kbd>!</kbd>  value is inserted 'as is'
  558.      *   + <kbd>&</kbd>  requires a file name.  The file's contents get
  559.      *                     inserted into the query (i.e. saving binary
  560.      *                     data in a db)
  561.      *
  562.      * Use backslashes to escape placeholder characters if you don't want
  563.      * them to be interpreted as placeholders.  Example: <code>
  564.      *    "UPDATE foo SET col=? WHERE col='over \& under'"
  565.      * </code>
  566.      *
  567.      * @param string $query  the query to be prepared
  568.      *
  569.      * @return mixed  DB statement resource on success. DB_Error on failure.
  570.      *
  571.      * @see DB_oci8::execute()
  572.      */
  573.     function prepare($query)
  574.     {
  575.         $tokens   preg_split('/((?<!\\\)[&?!])/'$query-1,
  576.                                PREG_SPLIT_DELIM_CAPTURE);
  577.         $binds    count($tokens- 1;
  578.         $token    = 0;
  579.         $types    = array();
  580.         $newquery '';
  581.  
  582.         foreach ($tokens as $key => $val{
  583.             switch ($val{
  584.                 case '?':
  585.                     $types[$token++DB_PARAM_SCALAR;
  586.                     unset($tokens[$key]);
  587.                     break;
  588.                 case '&':
  589.                     $types[$token++DB_PARAM_OPAQUE;
  590.                     unset($tokens[$key]);
  591.                     break;
  592.                 case '!':
  593.                     $types[$token++DB_PARAM_MISC;
  594.                     unset($tokens[$key]);
  595.                     break;
  596.                 default:
  597.                     $tokens[$keypreg_replace('/\\\([&?!])/'"\\1"$val);
  598.                     if ($key != $binds{
  599.                         $newquery .= $tokens[$key':bind' $token;
  600.                     else {
  601.                         $newquery .= $tokens[$key];
  602.                     }
  603.             }
  604.         }
  605.  
  606.         $this->last_query = $query;
  607.         $newquery $this->modifyQuery($newquery);
  608.         if (!$stmt @OCIParse($this->connection$newquery)) {
  609.             return $this->oci8RaiseError();
  610.         }
  611.         $this->prepare_types[(int)$stmt$types;
  612.         $this->manip_query[(int)$stmtDB::isManip($query);
  613.         $this->_prepared_queries[(int)$stmt$newquery;
  614.         return $stmt;
  615.     }
  616.  
  617.     // }}}
  618.     // {{{ execute()
  619.  
  620.     
  621.     /**
  622.      * Executes a DB statement prepared with prepare().
  623.      *
  624.      * To determine how many rows of a result set get buffered using
  625.      * ocisetprefetch(), see the "result_buffering" option in setOptions().
  626.      * This option was added in Release 1.7.0.
  627.      *
  628.      * @param resource  $stmt  a DB statement resource returned from prepare()
  629.      * @param mixed  $data  array, string or numeric data to be used in
  630.      *                       execution of the statement.  Quantity of items
  631.      *                       passed must match quantity of placeholders in
  632.      *                       query:  meaning 1 for non-array items or the
  633.      *                       quantity of elements in the array.
  634.      *
  635.      * @return mixed  returns an oic8 result resource for successful SELECT
  636.      *                 queries, DB_OK for other successful queries.
  637.      *                 A DB error object is returned on failure.
  638.      *
  639.      * @see DB_oci8::prepare()
  640.      */
  641.     function &execute($stmt$data = array())
  642.     {
  643.         $data = (array)$data;
  644.         $this->last_parameters = $data;
  645.         $this->