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

Source for file oci8.php

Documentation is available at oci8.php

  1. <?php 
  2. // +----------------------------------------------------------------------+
  3. // | PHP Version 4                                                        |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
  6. // | Stig. S. Bakken, Lukas Smith                                         |
  7. // | All rights reserved.                                                 |
  8. // +----------------------------------------------------------------------+
  9. // | MDB is a merge of PEAR DB and Metabases that provides a unified DB   |
  10. // | API as well as database abstraction for PHP applications.            |
  11. // | This LICENSE is in the BSD license style.                            |
  12. // |                                                                      |
  13. // | Redistribution and use in source and binary forms, with or without   |
  14. // | modification, are permitted provided that the following conditions   |
  15. // | are met:                                                             |
  16. // |                                                                      |
  17. // | Redistributions of source code must retain the above copyright       |
  18. // | notice, this list of conditions and the following disclaimer.        |
  19. // |                                                                      |
  20. // | Redistributions in binary form must reproduce the above copyright    |
  21. // | notice, this list of conditions and the following disclaimer in the  |
  22. // | documentation and/or other materials provided with the distribution. |
  23. // |                                                                      |
  24. // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
  25. // | Lukas Smith nor the names of his contributors may be used to endorse |
  26. // | or promote products derived from this software without specific prior|
  27. // | written permission.                                                  |
  28. // |                                                                      |
  29. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
  30. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
  31. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
  32. // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
  33. // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
  34. // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  35. // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
  36. // |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
  37. // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
  38. // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
  39. // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
  40. // | POSSIBILITY OF SUCH DAMAGE.                                          |
  41. // +----------------------------------------------------------------------+
  42. // | Author: Lukas Smith <smith@backendmedia.com>                         |
  43. // +----------------------------------------------------------------------+
  44.  
  45. // $Id: oci8.php,v 1.21.4.24 2004/03/31 16:02:40 lsmith Exp $
  46.  
  47. require_once('MDB/Common.php');
  48.  
  49. /**
  50.  * MDB OCI8 driver
  51.  *
  52.  * Notes:
  53.  * - when fetching in associative mode all keys are uppercased which is not the
  54.  *   intenteded behavior. Due to BC issues this will not be changed in MDB 1.x
  55.  *   however.
  56.  *
  57.  * - createDatabase and dropDatabase are not supported
  58.  *
  59.  * - Text fields with unspecified length limit are created as VARCHAR with an
  60.  *   optional limit that may not exceed 4000 characters.
  61.  *
  62.  * - date fields are emulated with date fields with time set to 00:00:00.
  63.      time fields are emulated with date fields with the day set to 0001-01-01.
  64.  *
  65.  * - The numRows method is emulated by fetching all the rows into memory.
  66.  *   Avoid using it if for queries with large result sets.
  67.  *
  68.  * - Oracle does not provide direct support for returning result sets restricted
  69.      to a given range. Such support is emulated in the MDB oci8 driver.
  70.  *
  71.  * - Storing data in large object fields has to be done in two phases: first the
  72.      fields are initialized using a INSERT or UPDATE query that sets the fields
  73.      to an empty value, then the data values are uploaded to the large objects
  74.      returned by reference from the executed queries.
  75.  *   Besides the fact that only INSERT and UPDATE queries are supported to
  76.      upload large object data values, only UPDATE queries that affect only one
  77.      row will set the large object fields correctly.
  78.  *
  79.  * - The driver alterTable method does not implement table or column renaming.
  80.  *
  81.  * @package MDB
  82.  * @category Database
  83.  * @author Lukas Smith <smith@backendmedia.com>
  84.  */
  85. class MDB_oci8 extends MDB_Common {
  86.     var $connection = 0;
  87.     var $connected_user;
  88.     var $connected_password;
  89.  
  90.     var $escape_quotes = "'";
  91.  
  92.     var $uncommitedqueries = 0;
  93.  
  94.     var $results = array();
  95.     var $current_row = array();
  96.     var $columns = array();
  97.     var $rows = array();
  98.     var $limits = array();
  99.     var $row_buffer = array();
  100.     var $highest_fetched_row = array();
  101.  
  102.     // {{{ constructor
  103.  
  104.     /**
  105.      * Constructor
  106.      */
  107.     function MDB_oci8()
  108.     {
  109.         $this->MDB_Common();
  110.         $this->phptype 'oci8';
  111.         $this->dbsyntax 'oci8';
  112.         
  113.         $this->supported['Sequences'= 1;
  114.         $this->supported['Indexes'= 1;
  115.         $this->supported['SummaryFunctions'= 1;
  116.         $this->supported['OrderByText'= 1;
  117.         $this->supported['CurrId'= 1;
  118.         $this->supported["AffectedRows"]= 1;
  119.         $this->supported['Transactions'= 1;
  120.         $this->supported['SelectRowRanges'= 1;
  121.         $this->supported['LOBs'= 1;
  122.         $this->supported['Replace'= 1;
  123.         $this->supported['SubSelects'= 1;
  124.         
  125.         $this->options['DBAUser'= FALSE;
  126.         $this->options['DBAPassword'= FALSE;
  127.         
  128.         $this->errorcode_map = array(
  129.             1 => MDB_ERROR_CONSTRAINT,
  130.             900 => MDB_ERROR_SYNTAX,
  131.             904 => MDB_ERROR_NOSUCHFIELD,
  132.             921 => MDB_ERROR_SYNTAX,
  133.             923 => MDB_ERROR_SYNTAX,
  134.             942 => MDB_ERROR_NOSUCHTABLE,
  135.             955 => MDB_ERROR_ALREADY_EXISTS,
  136.             1400 => MDB_ERROR_CONSTRAINT_NOT_NULL,
  137.             1407 => MDB_ERROR_CONSTRAINT_NOT_NULL,
  138.             1476 => MDB_ERROR_DIVZERO,
  139.             1722 => MDB_ERROR_INVALID_NUMBER,
  140.             2289 => MDB_ERROR_NOSUCHTABLE,
  141.             2291 => MDB_ERROR_CONSTRAINT,
  142.             2449 => MDB_ERROR_CONSTRAINT,
  143.         );
  144.     }
  145.  
  146.     // }}}
  147.     // {{{ errorNative()
  148.  
  149.     /**
  150.      * Get the native error code of the last error (if any) that
  151.      * occured on the current connection.
  152.      * 
  153.      * @access public
  154.      * @return int native oci8 error code
  155.      */
  156.     function errorNative($statement = NULL)
  157.     {
  158.         if (is_resource($statement)) {
  159.             $error @OCIError($statement);
  160.         else {
  161.             $error @OCIError($this->connection);
  162.         }
  163.         if (is_array($error)) {
  164.             return($error['code']);
  165.         }
  166.         return(FALSE);
  167.     }
  168.  
  169.     // }}}
  170.     // {{{ oci8RaiseError()
  171.  
  172.     /**
  173.      * This method is used to communicate an error and invoke error
  174.      * callbacks etc.  Basically a wrapper for MDB::raiseError
  175.      * that checks for native error msgs.
  176.      * 
  177.      * @param integer $errno error code
  178.      * @param string  $message userinfo message
  179.      * @return object PEAR error object
  180.      * @access public
  181.      * @see PEAR_Error
  182.      */
  183.     function oci8RaiseError($errno = NULL$message = NULL)
  184.     {
  185.         if ($errno === NULL{
  186.             if ($this->connection{
  187.                 $error @OCIError($this->connection);
  188.             else {
  189.                 $error @OCIError();
  190.             }
  191.             return($this->raiseError($this->errorCode($error['code']),
  192.                 NULLNULL$message$error['message']));
  193.         elseif (is_resource($errno)) {
  194.             $error @OCIError($errno);
  195.             return($this->raiseError($this->errorCode($error['code']),
  196.                 NULLNULL$message$error['message']));
  197.         }
  198.         return($this->raiseError($this->errorCode($errno)NULLNULL$message));
  199.     }
  200.  
  201.     // }}}
  202.     // {{{ autoCommit()
  203.  
  204.     /**
  205.      * Define whether database changes done on the database be automatically
  206.      * committed. This function may also implicitly start or end a transaction.
  207.      * 
  208.      * @param boolean $auto_commit flag that indicates whether the database
  209.      *                                  changes should be committed right after
  210.      *                                  executing every query statement. If this
  211.      *                                  argument is 0 a transaction implicitly
  212.      *                                  started. Otherwise, if a transaction is
  213.      *                                  in progress it is ended by committing any
  214.      *                                  database changes that were pending.
  215.      * @access public
  216.      * @return mixed MDB_OK on success, a MDB error on failure
  217.      */
  218.     function autoCommit($auto_commit)
  219.     {
  220.         $this->debug('AutoCommit: '.($auto_commit 'On' 'Off'));
  221.         if ($this->auto_commit == $auto_commit{
  222.             return(MDB_OK);
  223.         }
  224.         if ($this->connection && $auto_commit && MDB::isError($commit $this->commit())) {
  225.             return($commit);
  226.         }
  227.         $this->auto_commit $auto_commit;
  228.         $this->in_transaction !$auto_commit;
  229.         return(MDB_OK);
  230.     }
  231.  
  232.     // }}}
  233.     // {{{ commit()
  234.  
  235.     /**
  236.      * Commit the database changes done during a transaction that is in
  237.      * progress. This function may only be called when auto-committing is
  238.      * disabled, otherwise it will fail. Therefore, a new transaction is
  239.      * implicitly started after committing the pending changes.
  240.      * 
  241.      * @access public
  242.      * @return mixed MDB_OK on success, a MDB error on failure
  243.      */
  244.     function commit()
  245.     {
  246.         $this->debug('Commit Transaction');
  247.         if (!isset($this->supported['Transactions'])) {
  248.             return($this->raiseError(MDB_ERROR_UNSUPPORTEDNULLNULL,
  249.                 'Commit transactions: transactions are not in use'));
  250.         }
  251.         if ($this->auto_commit{
  252.             return($this->raiseError(MDB_ERRORNULLNULL,
  253.             'Commit transactions: transaction changes are being auto commited'));
  254.         }
  255.         if ($this->uncommitedqueries{
  256.             if (!@OCICommit($this->connection)) {
  257.                 return($this->oci8RaiseError(NULL,
  258.                     'Commit transactions: Could not commit pending transaction: '."$message. Error: ".$error['code'].' ('.$error['message'].')'));
  259.             }
  260.             $this->uncommitedqueries = 0;
  261.         }
  262.         return(MDB_OK);
  263.     }
  264.  
  265.     // }}}
  266.     // {{{ rollback()
  267.  
  268.     /**
  269.      * Cancel any database changes done during a transaction that is in
  270.      * progress. This function may only be called when auto-committing is
  271.      * disabled, otherwise it will fail. Therefore, a new transaction is
  272.      * implicitly started after canceling the pending changes.
  273.      * 
  274.      * @access public
  275.      * @return mixed MDB_OK on success, a MDB error on failure
  276.      */
  277.     function rollback()
  278.     {
  279.         $this->debug('Rollback Transaction');
  280.         if ($this->auto_commit{
  281.             return($this->raiseError(MDB_ERRORNULLNULL,
  282.                 'Rollback transactions: transactions can not be rolled back when changes are auto commited'));
  283.         }
  284.         if ($this->uncommitedqueries{
  285.             if (!@OCIRollback($this->connection)) {
  286.                 return($this->oci8RaiseError(NULL,
  287.                     'Rollback transaction: Could not rollback pending transaction'));
  288.             }
  289.             $this->uncommitedqueries = 0;
  290.         }
  291.         return(MDB_OK);
  292.     }
  293.  
  294.     // }}}
  295.     // {{{ connect()
  296.  
  297.     /**
  298.      * Connect to the database
  299.      * 
  300.      * @return TRUE on success, MDB_Error on failure
  301.      */
  302.     function connect($user = NULL $password = NULL$persistent = NULL)
  303.     {
  304.         if($user === NULL{
  305.             $user $this->user;
  306.         }
  307.         if($password === NULL{
  308.             $password $this->password;
  309.         }
  310.         if($persistent === NULL{
  311.             $persistent $this->getOption('persistent');
  312.         }
  313.         if (isset($this->host)) {
  314.             $sid $this->host;
  315.         else {
  316.             $sid getenv('ORACLE_SID');
  317.         }
  318.         if(!strcmp($sid'')) {
  319.             return($this->raiseError(MDB_ERRORNULLNULL,
  320.                 'Connect: it was not specified a valid Oracle Service IDentifier (SID)'));
  321.         }
  322.         if($this->connection != 0{
  323.             if (!strcmp($this->connected_user$user)
  324.                 && !strcmp($this->connected_password$password)
  325.                 && $this->opened_persistent == $persistent)
  326.             {
  327.                 return(MDB_OK);
  328.             }
  329.             $this->_close();
  330.         }
  331.  
  332.         if(!PEAR::loadExtension($this->phptype)) {
  333.             return(PEAR::raiseError(NULLMDB_ERROR_NOT_FOUND,
  334.                 NULLNULL'extension '.$this->phptype.' is not compiled into PHP',
  335.                 'MDB_Error'TRUE));
  336.         }
  337.  
  338.         if (isset($this->options['HOME'])) {
  339.             putenv('ORACLE_HOME='.$this->options['HOME']);
  340.         }
  341.         putenv('ORACLE_SID='.$sid);
  342.         $function ($persistent 'OCIPLogon' 'OCINLogon');
  343.         if (!function_exists($function)) {
  344.             return($this->raiseError(MDB_ERRORNULLNULL,
  345.                 'Connect: Oracle OCI API support is not available in this PHP configuration'));
  346.         }
  347.         if (!($this->connection = @$function($user$password$sid))) {
  348.             return($this->oci8RaiseError(NULL,
  349.                 'Connect: Could not connect to Oracle server'));
  350.         }
  351.         if (MDB::isError($doquery $this->_doQuery("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'"))) {
  352.             $this->_close();
  353.             return($doquery);
  354.         }
  355.         if (MDB::isError($doquery $this->_doQuery("ALTER SESSION SET NLS_NUMERIC_CHARACTERS='. '"))) {
  356.             $this->_close();
  357.             return($doquery);
  358.         }
  359.  
  360.         $this->connected_user = $user;
  361.         $this->connected_password = $password;
  362.         $this->opened_persistent $persistent;
  363.         return(MDB_OK);
  364.     }
  365.  
  366.     // }}}
  367.     // {{{ _close()
  368.  
  369.     /**
  370.      * all the RDBMS specific things needed close a DB connection
  371.      * 
  372.      * @access private
  373.      */
  374.     function _close()
  375.     {
  376.         if ($this->connection != 0{
  377.             @OCILogOff($this->connection);
  378.             $this->connection = 0;
  379.             $this->affected_rows = -1;
  380.             $this->uncommitedqueries = 0;
  381.         }
  382.     }
  383.  
  384.     // }}}
  385.     // {{{ _doQuery()
  386.  
  387.     /**
  388.      * all the RDBMS specific things needed close a DB connection
  389.      * 
  390.      * @access private
  391.      */
  392.     function _doQuery($query$first = 0$limit = 0$prepared_query = 0)
  393.     {
  394.         $lobs = 0;
  395.         $success MDB_OK;
  396.         $result = 0;
  397.         $descriptors = array();
  398.         if ($prepared_query{
  399.             $columns '';
  400.             $variables '';
  401.             for(reset($this->clobs[$prepared_query])$clob = 0;
  402.                 $clob count($this->clobs[$prepared_query]);
  403.                 $clob++next($this->clobs[$prepared_query]))
  404.             {
  405.                 $position key($this->clobs[$prepared_query]);
  406.                 if (gettype($descriptors[$position@OCINewDescriptor($this->connectionOCI_D_LOB)) != 'object'{
  407.                     $success $this->raiseError(MDB_ERRORNULLNULL,
  408.                         'Do query: Could not create descriptor for clob parameter');
  409.                     break;
  410.                 }
  411.                 $columns.= ($lobs == 0 ? ' RETURNING ' ',').$this->prepared_queries[$prepared_query-1]['Fields'][$position-1];
  412.                 $variables.= ($lobs == 0 ? ' INTO ' ',').':clob'.$position;
  413.                 $lobs++;
  414.             }
  415.             if (!MDB::isError($success)) {
  416.                 for(reset($this->blobs[$prepared_query])$blob = 0;$blob count($this->blobs[$prepared_query]);$blob++next($this->blobs[$prepared_query])) {
  417.                     $position key($this->blobs[$prepared_query]);
  418.                     if (gettype($descriptors[$position@OCINewDescriptor($this->connectionOCI_D_LOB)) != 'object'{
  419.                         $success $this->raiseError(MDB_ERRORNULLNULL,
  420.                             'Do query: Could not create descriptor for blob parameter');
  421.                         break;
  422.                     }
  423.                     $columns.= ($lobs == 0 ? ' RETURNING ' ',').$this->prepared_queries[$prepared_query-1]['Fields'][$position-1];
  424.                     $variables.= ($lobs == 0 ? ' INTO ' ',').':blob'.$position;
  425.                     $lobs++;
  426.                 }
  427.                 $query.= $columns.$variables;
  428.             }
  429.         }
  430.         if (!MDB::isError($success)) {
  431.             if (($statement @OCIParse($this->connection$query))) {
  432.                 if ($lobs{
  433.                     for(reset($this->clobs[$prepared_query])$clob = 0;$clob count($this->clobs[$prepared_query]);$clob++next($this->clobs[$prepared_query])) {
  434.                         $position key($this->clobs[$prepared_query]);
  435.                         if (!@OCIBindByName($statement':clob'.$position$descriptors[$position]-1OCI_B_CLOB)) {
  436.                             $success $this->oci8RaiseError(NULL,
  437.                                 'Do query: Could not bind clob upload descriptor');
  438.                             break;
  439.                         }
  440.                     }
  441.                     if (!MDB::isError($success)) {
  442.                         for(reset($this->blobs[$prepared_query])$blob = 0;
  443.                             $blob count($this->blobs[$prepared_query]);
  444.                             $blob++next($this->blobs[$prepared_query]))
  445.                         {
  446.                             $position key($this->blobs[$prepared_query]);
  447.                             if (!@OCIBindByName($statement':blob'.$position$descriptors[$position]-1OCI_B_BLOB)) {
  448.                                 $success $this->oci8RaiseError(NULL,
  449.                                     'Do query: Could not bind blob upload descriptor');
  450.                                 break;
  451.                             }
  452.                         }
  453.                     }
  454.                 }
  455.                 if (!MDB::isError($success)) {
  456.                     if (($result @OCIExecute($statement($lobs == 0 && $this->auto_commit? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT))) {
  457.                         if ($lobs{
  458.                             for(reset($this->clobs[$prepared_query])$clob = 0;
  459.                                 $clob count($this->clobs[$prepared_query]);
  460.                                 $clob++next($this->clobs[$prepared_query]))
  461.                             {
  462.                                 $position key($this->clobs[$prepared_query]);
  463.                                 $clob_stream $this->prepared_queries[$prepared_query-1]['Values'][$position-1];
  464.                                 for($value '';!$this->endOfLOB($clob_stream);{
  465.                                     if ($this->readLOB($clob_stream$data$this->getOption('lob_buffer_length')) < 0{
  466.                                         $success $this->raiseError();
  467.                                         break;
  468.                                     }
  469.                                     $value.= $data;
  470.                                 }
  471.                                 if (!MDB::isError($success&& !$descriptors[$position]->save($value)) {
  472.                                     $success $this->oci8RaiseError(NULL,
  473.                                         'Do query: Could not upload clob data');
  474.                                 }
  475.                             }
  476.                             if (!MDB::isError($success)) {
  477.                                 for(reset($this->blobs[$prepared_query])$blob = 0;$blob count($this->blobs[$prepared_query]);$blob++next($this->blobs[$prepared_query])) {
  478.                                     $position key($this->blobs[$prepared_query]);
  479.                                     $blob_stream $this->prepared_queries[$prepared_query-1]['Values'][$position-1];
  480.                                     for($value '';!$this->endOfLOB($blob_stream);{
  481.                                         if ($this->readLOB($blob_stream$data$this->getOption('lob_buffer_length')) < 0{
  482.                                             $success $this->raiseError();
  483.                                             break;
  484.                                         }
  485.                                         $value.= $data;
  486.                                     }
  487.                                     if (!MDB::isError($success&& !$descriptors[$position]->save($value)) {
  488.                                         $success $this->oci8RaiseError(NULL,
  489.                                                 'Do query: Could not upload blob data');
  490.                                     }
  491.                                 }
  492.                             }
  493.                         }
  494.                         if ($this->auto_commit{
  495.                             if ($lobs{
  496.                                 if (MDB::isError($success)) {
  497.                                     if (!@OCIRollback($this->connection)) {
  498.                                         $success $this->oci8RaiseError(NULL,
  499.                                             'Do query: '.$success->getUserinfo().' and then could not rollback LOB updating transaction');
  500.                                     }
  501.                                 else {
  502.                                     if (!@OCICommit($this->connection)) {
  503.                                         $success $this->oci8RaiseError(NULL,
  504.                                             'Do query: Could not commit pending LOB updating transaction');
  505.                                     }
  506.                                 }
  507.                             }
  508.                         else {
  509.                             $this->uncommitedqueries++;
  510.                         }
  511.                         if (!MDB::isError($success)) {
  512.                             switch (@OCIStatementType($statement)) {
  513.                                 case 'SELECT':
  514.                                     $result_value intval($statement);
  515.                                     $this->current_row[$result_value= -1;
  516.                                     if ($limit > 0{
  517.                                         $this->limits[$result_value= array($first$limit0);
  518.                                     }
  519.                                     $this->highest_fetched_row[$result_value= -1;
  520.                                     break;
  521.                                 default:
  522.                                     $this->affected_rows @OCIRowCount($statement);
  523.                                     @OCIFreeCursor($statement);
  524.                                     break;
  525.                             }
  526.                             $result $statement;
  527.                         }
  528.                     else {
  529.                         return($this->oci8RaiseError($statement'Do query: Could not execute query'));
  530.                     }
  531.                 }
  532.             else {
  533.                 return($this->oci8RaiseError(NULL'Do query: Could not parse query'));
  534.             }
  535.         }
  536.         for(reset($descriptors)$descriptor = 0;
  537.             $descriptor count($descriptors);
  538.             $descriptor++next($descriptors))
  539.         {
  540.             @OCIFreeDesc($descriptors[key($descriptors)]);
  541.         }
  542.         return($result);
  543.     }
  544.  
  545.     // }}}
  546.     // {{{ query()
  547.  
  548.    /**
  549.      * Send a query to the database and return any results
  550.      * 
  551.      * @access public
  552.      * @param string $query the SQL query
  553.      * @param array $types array that contains the types of the columns in
  554.      *                          the result set
  555.      * @return mixed a result handle or MDB_OK on success, a MDB error on failure
  556.      */
  557.     function query($query$types = NULL)
  558.     {
  559.         $this->debug("Query: $query");
  560.         $this->last_query $query;
  561.         $first $this->first_selected_row;
  562.         $limit $this->selected_row_limit;
  563.         $this->first_selected_row $this->selected_row_limit = 0;
  564.         if (MDB::isError($connect $this->connect())) {
  565.             return($connect);
  566.         }
  567.         if(!MDB::isError($result $this->_doQuery($query$first$limit))) {
  568.             if ($types != NULL{
  569.                 if (!is_array($types)) {
  570.                     $types = array($types);
  571.                 }
  572.                 if (MDB::isError($err $this->setResultTypes($result$types))) {
  573.                     $this->freeResult($result);
  574.                     return($err);
  575.                 }
  576.             }
  577.             return($result);
  578.         }
  579.         return($this->oci8RaiseError());
  580.     }
  581.  
  582.     // }}}
  583.     // {{{ _executePreparedQuery()
  584.  
  585.     /**
  586.      * Execute a prepared query statement.
  587.      *
  588.      * @param int $prepared_query argument is a handle that was returned by
  589.      *        the function prepareQuery()
  590.      * @param string $query query to be executed
  591.      * @param array $types array that contains the types of the columns in
  592.      *        the result set
  593.      * @return mixed a result handle or MDB_OK on success, a MDB error on failure
  594.      * @access private
  595.      */
  596.     function _executePreparedQuery($prepared_query$query)
  597.     {
  598.         $first $this->first_selected_row;
  599.         $limit $this->selected_row_limit;
  600.         $this->first_selected_row $this->selected_row_limit = 0;
  601.         if (MDB::isError($connect $this->connect())) {
  602.             return($connect);
  603.         }
  604.         return($this->_doQuery($query$first$limit$prepared_query));
  605.     }
  606.  
  607.     // }}}
  608.     // {{{ _skipLimitOffset()
  609.  
  610.     /**
  611.      * Skip the first row of a result set.
  612.      *
  613.      * @param resource $result 
  614.      * @return mixed a result handle or MDB_OK on success, a MDB error on failure
  615.      * @access private
  616.      */
  617.     function _skipLimitOffset($result)
  618.     {
  619.         $result_value intval($result);
  620.         $first $this->limits[$result_value][0];
  621.         for(;$this->limits[$result_value][2$first;$this->limits[$result_value][2]++{
  622.             if (!@OCIFetch($result)) {
  623.                 $this->limits[$result_value][2$first;
  624.                 return($this->raiseError(MDB_ERRORNULLNULL,
  625.                     'Skip first rows: could not skip a query result row'));
  626.             }
  627.         }
  628.         return(MDB_OK);
  629.     }
  630.  
  631.     // }}}
  632.     // {{{ getColumnNames()
  633.  
  634.     /**
  635.      * Retrieve the names of columns returned by the DBMS in a query result.
  636.      * 
  637.      * @param resource $result result identifier
  638.      * @return mixed an associative array variable
  639.      *                                that will hold the names of columns.The
  640.      *                                indexes of the array are the column names
  641.      *                                mapped to lower case and the values are the
  642.      *                                respective numbers of the columns starting
  643.      *                                from 0. Some DBMS may not return any
  644.      *                                columns when the result set does not
  645.      *                                contain any rows.
  646.      * 
  647.      *                                a MDB error on failure
  648.      * @access public
  649.      */
  650.     function getColumnNames($result)
  651.     {
  652.         $result_value intval($result);
  653.         if (!isset($this->highest_fetched_row[$result_value])) {
  654.             return($this->raiseError(MDB_ERRORNULLNULL,
  655.                 'Get column names: it was specified an inexisting result set'));
  656.         }
  657.         if (!isset($this->columns[$result_value])) {
  658.             $this->columns[$result_value= array();
  659.             $columns @OCINumCols($result);
  660.             for($column = 0; $column $columns$column++{
  661.                 $field_name @OCIColumnName($result$column + 1);
  662.                 if ($this->options['optimize'== 'portability'{
  663.                     $field_name strtolower($field_name);
  664.                 }
  665.                 $this->columns[$result_value][$field_name$column;
  666.             }
  667.         }
  668.         return($this->columns[$result_value]);
  669.     }
  670.  
  671.     // }}}
  672.     // {{{ numCols()
  673.  
  674.     /**
  675.      * Count the number of columns returned by the DBMS in a query result.
  676.      * 
  677.      * @param resource $result result identifier
  678.      * @return mixed integer value with the number of columns, a MDB error
  679.      *       on failure
  680.      * @access public
  681.      */
  682.     function numCols($result)
  683.     {
  684.         $result_value intval($result);
  685.         if (!isset($this->highest_fetched_row[$result_value])) {
  686.             return($this->raiseError(MDB_ERRORNULLNULL,
  687.                 'Number of columns: it was specified an inexisting result set'));
  688.         }
  689.         return(@OCINumCols($result));
  690.     }
  691.  
  692.     // }}}
  693.     // {{{ endOfResult()
  694.  
  695.     /**
  696.      * check if the end of the result set has been reached
  697.      * 
  698.      * @param resource $result result identifier
  699.      * @return mixed TRUE or FALSE on sucess, a MDB error on failure
  700.      * @access public
  701.      */
  702.     function endOfResult($result)
  703.     {
  704.         $result_value intval($result);
  705.         if (!isset($this->current_row[$result_value])) {
  706.             return($this->raiseError(MDB_ERRORNULLNULL,
  707.                 'End of result: attempted to check the end of an unknown result'));
  708.         }
  709.         if (isset($this->results[$result_value]&& end($this->results[$result_value]=== FALSE{
  710.             return(($this->highest_fetched_row[$result_value]-1<= $this->current_row[$result_value]);
  711.         }
  712.         if (isset($this->row_buffer[$result_value])) {
  713.             return(!$this->row_buffer[$result_value]);
  714.         }
  715.         if (isset($this->limits[$result_value])) {
  716.             if (MDB::isError($this->_skipLimitOffset($result))
  717.                 || ($this->current_row[$result_value]$this->limits[$result_value][1]
  718.             {
  719.                 return(TRUE);
  720.             }
  721.         }
  722.         if (@OCIFetchInto($result$this->row_buffer[$result_value]OCI_RETURN_NULLS)) {
  723.             return(FALSE);
  724.         }
  725.         $this->row_buffer[$result_value= FALSE;
  726.         return(TRUE);
  727.     }
  728.  
  729.     // }}}
  730.     // {{{ _retrieveLob()
  731.  
  732.     /**
  733.      * fetch a lob value from a result set
  734.      * 
  735.      * @param int $lob handle to a lob created by the createLob() function
  736.      * @return mixed MDB_OK on success, a MDB error on failure
  737.      * @access private
  738.      */
  739.     function _retrieveLob($lob)
  740.     {
  741.         if (!isset($this->lobs[$lob])) {
  742.             return($this->raiseError(MDB_ERRORNULLNULL,
  743.                 'Retrieve LOB: it was not specified a valid lob'));
  744.         }
  745.         if (!isset($this->lobs[$lob]['Value'])) {
  746.             unset($lob_object);
  747.             $result $this->lobs[$lob]['Result'];
  748.             $row $this->lobs[$lob]['Row'];
  749.             $field $this->lobs[$lob]['Field'];
  750.             $lob_object $this->fetch($result$row$field);
  751.             if (MDB::isError($lob_object)) {
  752.                 return $lob_object;
  753.             }
  754.             if (gettype($lob_object!= 'object'{
  755.                 return($this->raiseError(MDB_ERRORNULLNULL,
  756.                     'Retrieve LOB: attemped to retrieve LOB from non existing or NULL column'));
  757.             }
  758.             $this->lobs[$lob]['Value'$lob_object->load();
  759.         }
  760.         return(MDB_OK);
  761.     }
  762.  
  763.     // }}}
  764.     // {{{ fetch()
  765.  
  766.     /**
  767.      * fetch value from a result set
  768.      * 
  769.      * @param resource $result result identifier
  770.      * @param int $rownum number of the row where the data can be found
  771.      * @param int $colnum field number where the data can be found
  772.      * @return mixed string on success, a MDB error on failure
  773.      * @access public
  774.      */
  775.     function fetch($result$rownum$colnum)
  776.     {
  777.         $fetchmode is_numeric($colnumMDB_FETCHMODE_ORDERED : MDB_FETCHMODE_ASSOC;
  778.         $row $this->fetchInto($result$fetchmode$rownum);
  779.         if (MDB::isError($row)) {
  780.             return($row);
  781.         }
  782.         if (!array_key_exists($colnum$row)) {
  783.             return(NULL);
  784.         }
  785.         return($row[$colnum]);
  786.     }
  787.  
  788.     // }}}
  789.     // {{{ fetchClob()
  790.  
  791.     /**
  792.      * fetch a clob value from a result set
  793.      * 
  794.      * @param resource $result result identifier
  795.      * @param int $row number of the row where the data can be found
  796.      * @param int $field field number where the data can be found
  797.      * @return mixed content of the specified data cell, a MDB error on failure,
  798.      *                 a MDB error on failure
  799.      * @access public
  800.      */
  801.     function fetchClob($result$row$field)
  802.     {
  803.         return($this->fetchLOB($result$row$field));
  804.     }
  805.  
  806.     // }}}
  807.     // {{{ fetchBlob()
  808.     /**
  809.      * fetch a blob value from a result set
  810.      * 
  811.      * @param resource $result result identifier
  812.      * @param int $row number of the row where the data can be found
  813.      * @param int $field field number where the data can be found
  814.      * @return mixed content of the specified data cell, a MDB error on failure
  815.      * @access public
  816.      */
  817.     function fetchBlob($result$row$field)
  818.     {
  819.         return($this->fetchLOB($result$row$field));
  820.     }
  821.  
  822.     // }}}
  823.     // {{{ resultIsNull()
  824.  
  825.     /**
  826.      * Determine whether the value of a query result located in given row and
  827.      *    field is a NULL.
  828.      * 
  829.      * @param resource $result result identifier
  830.      * @param int $rownum number of the row where the data can be found
  831.      * @param int $field field number where the data can be found
  832.      * @return mixed TRUE or FALSE on success, a MDB error on failure
  833.      * @access public
  834.      */
  835.     function resultIsNull($result$rownum$field)
  836.     {
  837.         $value $this->fetch($result$rownum$field);
  838.         if (MDB::isError($value)) {
  839.             return($value);
  840.         }
  841.         return(!isset($value));
  842.     }
  843.  
  844.     // }}}
  845.     // {{{ convertResult()
  846.  
  847.     /**
  848.      * convert a value to a RDBMS indepdenant MDB type
  849.      * 
  850.      * @param mixed $value value to be converted
  851.      * @param int $type constant that specifies which type to convert to
  852.      * @return mixed converted value
  853.      * @access public
  854.      */
  855.     function convertResult($value$type)
  856.     {
  857.         switch ($type{
  858.             case MDB_TYPE_DATE:
  859.                 return(substr($value0strlen('YYYY-MM-DD')));
  860.             case MDB_TYPE_TIME:
  861.                 return(substr($valuestrlen('YYYY-MM-DD ')strlen('HH:MI:SS')));
  862.             default:
  863.                 return($this->_baseConvertResult($value$type));
  864.         }
  865.     }
  866.  
  867.     // }}}
  868.     // {{{ numRows()
  869.  
  870.     /**
  871.      * returns the number of rows in a result object
  872.      * 
  873.      * @param ressource $result a valid result ressouce pointer
  874.      * @return mixed MDB_Error or the number of rows
  875.      * @access public
  876.      */
  877.     function numRows($result)
  878.     {
  879.         $result_value intval($result);
  880.         if (!isset($this->current_row[$result_value])) {
  881.             return($this->raiseError(MDB_ERRORNULLNULL,
  882.                 'Number of rows: attemped to obtain the number of rows contained in an unknown query result'));
  883.         }
  884.         if (!isset($this->results[$result_value][$this->highest_fetched_row[$result_value]])
  885.             || $this->results[$result_value][$this->highest_fetched_row[$result_value]] !== FALSE
  886.         {
  887.             if (isset($this->limits[$result_value])) {
  888.                 if (MDB::isError($skipfirstrow $this->_skipLimitOffset($result))) {
  889.                      return($skipfirstrow);
  890.                 }
  891.             }
  892.             if (isset($this->row_buffer[$result_value])) {
  893.                 ++$this->highest_fetched_row[$result_value];
  894.                 $this->results[$result_value][$this->highest_fetched_row[$result_value]]
  895.                     = $this->row_buffer[$result_value];
  896.                 unset($this->row_buffer[$result_value]);
  897.             }
  898.             if (!isset($this->results[$result_value][$this->highest_fetched_row[$result_value]])
  899.                 || $this->results[$result_value][$this->highest_fetched_row[$result_value]] !== FALSE
  900.             {
  901.                 while((!isset($this->limits[$result_value])
  902.                         || ($this->highest_fetched_row[$result_value]+1$this->limits[$result_value][1]
  903.                     )
  904.                     && @OCIFetchInto($result$bufferOCI_RETURN_NULLS)
  905.                 {
  906.                     ++$this->highest_fetched_row[$result_value];
  907.                     $this->results[$result_value][$this->highest_fetched_row[$result_value]] $buffer;
  908.                 }
  909.                 ++$this->highest_fetched_row[$result_value];
  910.                 $this->results[$result_value][$this->highest_fetched_row[$result_value]] = FALSE;
  911.             }
  912.         }
  913.         return(max(0$this->highest_fetched_row[$result_value]));
  914.     }
  915.  
  916.     // }}}
  917.     // {{{ freeResult()
  918.  
  919.     /**
  920.      * Free the internal resources associated with $result.
  921.      * 
  922.      * @param  $result result identifier
  923.      * @return bool TRUE on success, FALSE if $result is invalid
  924.      * @access public
  925.      */
  926.     function freeResult($result)
  927.     {
  928.         $result_value intval($result);
  929.         if (!isset($this->current_row[$result_value])) {
  930.            return($this->raiseError(MDB_ERRORNULLNULL,
  931.                'Free result: attemped to free an unknown query result'));
  932.         }
  933.         if(isset($this->highest_fetched_row[$result_value])) {
  934.             unset($this->highest_fetched_row[$result_value]);
  935.         }
  936.         if(isset($this->row_buffer[$result_value])) {
  937.             unset($this->row_buffer[$result_value]);
  938.         }
  939.         if(isset($this->limits[$result_value])) {
  940.             unset($this->limits[$result_value]);
  941.         }
  942.         if(isset($this->current_row[$result_value])) {
  943.             unset($this->current_row[$result_value]);
  944.         }
  945.         if(isset($this->results[$result_value])) {
  946.             unset($this->results[$result_value]);
  947.         }
  948.         if(isset($this->columns[$result_value])) {
  949.             unset($this->columns[$result_value]);
  950.         }
  951.         if(isset($this->result_types[$result_value])) {
  952.             unset($this->result_types[$result_value]);
  953.         }
  954.         return(@OCIFreeCursor($result));
  955.     }
  956.  
  957.     // }}}
  958.     // {{{ getTypeDeclaration()
  959.  
  960.     /**
  961.      * Obtain DBMS specific native datatype as a string
  962.      * 
  963.      * @param string $field associative array with the name of the properties
  964.      *         of the field being declared as array indexes. Currently, the types
  965.      *         of supported field properties are as follows:
  966.      * 
  967.      * @return string with the correct RDBMS native type
  968.      * @access public
  969.      */
  970.     function getTypeDeclaration($field)
  971.     {
  972.         switch ($field['type']{
  973.             case 'integer':
  974.                 return('INT');
  975.             case 'text':
  976.                 return('VARCHAR ('.(isset($field['length'])
  977.                     ? $field['length'(isset($this->options['DefaultTextFieldLength'])
  978.                         ? $this->options['DefaultTextFieldLength': 4000)).')');
  979.             case 'boolean':
  980.                 return('CHAR (1)');
  981.             case 'date':
  982.             case 'time':
  983.             case 'timestamp':
  984.                 return('DATE');
  985.             case 'float':
  986.                 return('NUMBER');
  987.             case 'decimal':
  988.                 return('NUMBER(*,'.$this->decimal_places.')');
  989.         }
  990.         return('');
  991.     }
  992.  
  993.     // }}}
  994.     // {{{ getIntegerDeclaration()
  995.  
  996.     /**
  997.      * Obtain DBMS specific SQL code portion needed to declare an integer type
  998.      * field to be used in statements like CREATE TABLE.
  999.      * 
  1000.      * @param string $name name the field to be declared.
  1001.      * @param string $field associative array with the name of the properties
  1002.      *         of the field being declared as array indexes. Id
  1003.      *  ently, the types
  1004.      *         of supported field properties are as follows:
  1005.      * 
  1006.      *         unsigned
  1007.      *             Boolean flag that indicates whether the field should be
  1008.      *             declared as unsigned integer if possible.
  1009.      * 
  1010.      *         default
  1011.      *             Integer value to be used as default for this field.
  1012.      * 
  1013.      *         notnull
  1014.      *             Boolean flag that indicates whether this field is constrained
  1015.      *             to not be set to NULL.
  1016.      * @return string DBMS specific SQL code portion that should be used to
  1017.      *         declare the specified field.
  1018.      * @access public
  1019.      */
  1020.     function getIntegerDeclaration($name$field)
  1021.     {
  1022.         if (isset($field['unsigned']))
  1023.             $this->warning = "unsigned integer field \"$name\" is being declared as signed integer";
  1024.         return("$name ".$this->getTypeDeclaration($field)
  1025.             .(isset($field['default']' DEFAULT '.$field['default''')
  1026.             .(isset($field['notnull']' NOT NULL' ''));
  1027.     }
  1028.  
  1029.     // }}}
  1030.     // {{{ getTextDeclaration()
  1031.  
  1032.     /**
  1033.      * Obtain DBMS specific SQL code portion needed to declare an text type
  1034.      * field to be used in statements like CREATE TABLE.
  1035.      * 
  1036.      * @param string $name name the field to be declared.
  1037.      * @param string $field associative array with the name of the properties
  1038.      *         of the field being declared as array indexes. Currently, the types
  1039.      *         of supported field properties are as follows:
  1040.      * 
  1041.      *         length
  1042.      *             Integer value that determines the maximum length of the text
  1043.      *             field. If this argument is missing the field should be
  1044.      *             declared to have the longest length allowed by the DBMS.
  1045.      * 
  1046.      *         default
  1047.      *             Text value to be used as default for this field.
  1048.      * 
  1049.      *         notnull
  1050.      *             Boolean flag that indicates whether this field is constrained
  1051.      *             to not be set to NULL.
  1052.      * @return string DBMS specific SQL code portion that should be used to
  1053.      *         declare the specified field.
  1054.      * @access public
  1055.      */
  1056.     function getTextDeclaration($name$field)
  1057.     {
  1058.         return("$name ".$this->getTypeDeclaration($field)
  1059.             .(isset($field['default']' DEFAULT '.$this->getTextValue($field['default']'')
  1060.             .(isset($field['notnull']' NOT NULL' ''));
  1061.     }
  1062.  
  1063.     // }}}
  1064.     // {{{ getClobDeclaration()
  1065.  
  1066.     /**
  1067.      * Obtain DBMS specific SQL code portion needed to declare an character
  1068.      * large object type field to be used in statements like CREATE TABLE.
  1069.      * 
  1070.      * @param string $name name the field to be declared.
  1071.      * @param string $field associative array with the name of the properties
  1072.      *         of the field being declared as array indexes. Currently, the types
  1073.      *         of supported field properties are as follows:
  1074.      * 
  1075.      *         length
  1076.      *             Integer value that determines the maximum length of the large
  1077.      *             object field. If this argument is missing the field should be
  1078.      *             declared to have the longest length allowed by the DBMS.
  1079.      * 
  1080.      *         notnull
  1081.      *             Boolean flag that indicates whether this field is constrained
  1082.      *             to not be set to NULL.
  1083.      * @return string DBMS specific SQL code portion that should be used to
  1084.      *         declare the specified field.
  1085.      * @access public
  1086.      */
  1087.     function getClobDeclaration($name$field)
  1088.     {
  1089.         return("$name CLOB".(isset($field['notnull']' NOT NULL' ''));
  1090.     }
  1091.  
  1092.     // }}}
  1093.     // {{{ getBlobDeclaration()
  1094.  
  1095.     /**
  1096.      * Obtain DBMS specific SQL code portion needed to declare an binary large
  1097.      * object type field to be used in statements like CREATE TABLE.
  1098.      * 
  1099.      * @param string $name name the field to be declared.
  1100.      * @param string $field associative array with the name of the properties
  1101.      *         of the field being declared as array indexes. Currently, the types
  1102.      *         of supported field properties are as follows:
  1103.      * 
  1104.      *         length
  1105.      *             Integer value that determines the maximum length of the large
  1106.      *             object field. If this argument is missing the field should be
  1107.      *             declared to have the longest length allowed by the DBMS.
  1108.      * 
  1109.      *         notnull
  1110.      *             Boolean flag that indicates whether this field is constrained
  1111.      *             to not be set to NULL.
  1112.      * @return string DBMS specific SQL code portion that should be used to
  1113.      *         declare the specified field.
  1114.      * @access public
  1115.      */
  1116.     function getBlobDeclaration($name$field)
  1117.     {
  1118.         return("$name BLOB".(isset($field['notnull']' NOT NULL' ''));
  1119.     }
  1120.  
  1121.     // }}}
  1122.     // {{{ getBooleanDeclaration()
  1123.  
  1124.     /**
  1125.      * Obtain DBMS specific SQL code portion needed to declare a boolean type
  1126.      * field to be used in statements like CREATE TABLE.
  1127.      * 
  1128.      * @param string $name name the field to be declared.
  1129.      * @param string $field associative array with the name of the properties
  1130.      *         of the field being declared as array indexes. Currently, the types
  1131.      *         of supported field properties are as follows:
  1132.      * 
  1133.      *         default
  1134.      *             Boolean value to be used as default for this field.
  1135.      * 
  1136.      *         notnullL
  1137.      *             Boolean flag that indicates whether this field is constrained
  1138.      *             to not be set to NULL.
  1139.      * @return string DBMS specific SQL code portion that should be used to
  1140.      *         declare the specified field.
  1141.      * @access public
  1142.      */
  1143.     function getBooleanDeclaration($name$field)
  1144.     {
  1145.         return("$name ".$this->getTypeDeclaration($field)
  1146.             .(isset($field['default']' DEFAULT '
  1147.             .$this->getBooleanValue($field['default']'')
  1148.             .(isset($field['notnull']' NOT NULL' ''));
  1149.     }
  1150.  
  1151.     // }}}
  1152.     // {{{ getDateDeclaration()
  1153.  
  1154.     /**
  1155.      * Obtain DBMS specific SQL code portion needed to declare a date type
  1156.      * field to be used in statements like CREATE TABLE.
  1157.      * 
  1158.      * @param string $name name the field to be declared.
  1159.      * @param string $field associative array with the name of the properties
  1160.      *         of the field being declared as array indexes. Currently, the types
  1161.      *         of supported field properties are as follows:
  1162.      * 
  1163.      *         default
  1164.      *             Date value to be used as default for this field.
  1165.      * 
  1166.      *         notnull
  1167.      *             Boolean flag that indicates whether this field is constrained
  1168.      *             to not be set to NULL.
  1169.      * @return string DBMS specific SQL code portion that should be used to
  1170.      *         declare the specified field.
  1171.      * @access public
  1172.      */
  1173.     function getDateDeclaration($name$field)
  1174.     {
  1175.         return("$name ".$this->getTypeDeclaration($field)
  1176.             .(isset($field['default']' DEFAULT '
  1177.             .$this->getDateValue($field['default']'')
  1178.             .(isset($field['notnull']' NOT NULL' ''));
  1179.     }
  1180.  
  1181.     // }}}
  1182.     // {{{ getTimestampDeclaration()
  1183.  
  1184.     /**
  1185.      * Obtain DBMS specific SQL code portion needed to declare a timestamp
  1186.      * field to be used in statements like CREATE TABLE.
  1187.      * 
  1188.      * @param string $name name the field to be declared.
  1189.      * @param string $field associative array with the name of the properties
  1190.      *         of the field being declared as array indexes. Currently, the types
  1191.      *         of supported field properties are as follows:
  1192.      * 
  1193.      *         default
  1194.      *             Timestamp value to be used as default for this field.
  1195.      * 
  1196.      *         notnull
  1197.      *             Boolean flag that indicates whether this field is constrained
  1198.      *             to not be set to NULL.
  1199.      * @return string DBMS specific SQL code portion that should be used to
  1200.      *         declare the specified field.
  1201.      * @access public
  1202.      */
  1203.     function getTimestampDeclaration($name$field)
  1204.     {
  1205.         return("$name ".$this->getTypeDeclaration($field)
  1206.             .(isset($field['default']' DEFAULT '
  1207.             .$this->getTimestampValue($field['default']'')
  1208.             .(isset($field['notnull']' NOT NULL' ''));
  1209.     }
  1210.  
  1211.     // }}}
  1212.     // {{{ getTimeDeclaration()
  1213.  
  1214.     /**
  1215.      * Obtain DBMS specific SQL code portion needed to declare a time
  1216.      * field to be used in statements like CREATE TABLE.
  1217.      * 
  1218.      * @param string $name name the field to be declared.
  1219.      * @param string $field associative array with the name of the properties
  1220.      *         of the field being declared as array indexes. Currently, the types
  1221.      *         of supported field properties are as follows:
  1222.      * 
  1223.      *         default
  1224.      *             Time value to be used as default for this field.
  1225.      * 
  1226.      *         notnull
  1227.      *             Boolean flag that indicates whether this field is constrained
  1228.      *             to not be set to NULL.
  1229.      * @return string DBMS specific SQL code portion that should be used to
  1230.      *         declare the specified field.
  1231.      * @access public
  1232.      */
  1233.     function getTimeDeclaration($name$field)
  1234.     {
  1235.         return("$name ".$this->getTypeDeclaration($field)
  1236.             .(isset($field['default']' DEFAULT '
  1237.             .$this->getTimeValue($field['default']'')
  1238.             .(isset($field['notnull']' NOT NULL' ''));
  1239.     }
  1240.  
  1241.     // }}}
  1242.     // {{{ getFloatDeclaration()
  1243.  
  1244.     /**
  1245.      * Obtain DBMS specific SQL code portion needed to declare a float type
  1246.      * field to be used in statements like CREATE TABLE.
  1247.      * 
  1248.      * @param string $name name the field to be declared.
  1249.      * @param string $field associative array with the name of the properties
  1250.      *         of the field being declared as array indexes. Currently, the types
  1251.      *         of supported field properties are as follows:
  1252.      * 
  1253.      *         default
  1254.      *             Float value to be used as default for this field.
  1255.      * 
  1256.      *         notnull
  1257.      *             Boolean flag that indicates whether this field is constrained
  1258.      *             to not be set to NULL.
  1259.      * @return string DBMS specific SQL code portion that should be used to
  1260.      *         declare the specified field.
  1261.      * @access public
  1262.      */
  1263.     function getFloatDeclaration($name$field)
  1264.     {
  1265.         return("$name ".$this->getTypeDeclaration($field)
  1266.             .(isset($field['default']' DEFAULT '
  1267.             .$this->getFloatValue($field['default']'')
  1268.             .(isset($field['notnull']' NOT NULL' ''));
  1269.     }
  1270.  
  1271.     // }}}
  1272.     // {{{ getDecimalDeclaration()
  1273.  
  1274.     /**
  1275.      * Obtain DBMS specific SQL code portion needed to declare a decimal type
  1276.      * field to be used in statements like CREATE TABLE.
  1277.      * 
  1278.      * @param string $name name the field to be declared.
  1279.      * @param string $field associative array with the name of the properties
  1280.      *         of the field being declared as array indexes. Currently, the types
  1281.      *         of supported field properties are as follows:
  1282.      * 
  1283.      *         default
  1284.      *             Decimal value to be used as default for this field.
  1285.      * 
  1286.      *         notnull
  1287.      *             Boolean flag that indicates whether this field is constrained
  1288.      *             to not be set to NULL.
  1289.      * @return string DBMS specific SQL code portion that should be used to
  1290.      *         declare the specified field.
  1291.      * @access public
  1292.      */
  1293.     function getDecimalDeclaration($name$field)
  1294.     {
  1295.         return("$name ".$this->getTypeDeclaration($field)
  1296.             .(isset($field['default']' DEFAULT '
  1297.             .$this->getDecimalValue($field['default']'')
  1298.             .(isset($field['notnull']' NOT NULL' ''));
  1299.     }
  1300.  
  1301.     // }}}
  1302.     // {{{ getClobValue()
  1303.  
  1304.     /**
  1305.      * Convert a text value into a DBMS specific format that is suitable to
  1306.      * compose query statements.
  1307.      * 
  1308.      * @param resource $prepared_query query handle from prepare()
  1309.      * @param  $parameter 
  1310.      * @param  $clob 
  1311.      * @return string text string that represents the given argument value in
  1312.      *         a DBMS specific format.
  1313.      * @access public
  1314.      */
  1315.     function getClobValue($prepared_query$parameter$clob)
  1316.     {
  1317.         return('EMPTY_CLOB()');
  1318.     }
  1319.  
  1320.     // }}}
  1321.     // {{{ freeClobValue()
  1322.  
  1323.     /**
  1324.      * free a character large object
  1325.      * 
  1326.      * @param resource $prepared_query query handle from prepare()
  1327.      * @param string $blob 
  1328.      * @param string $value 
  1329.      * @access public
  1330.      */
  1331.     function freeClobValue($prepared_query$clob&$value)
  1332.     {
  1333.         unset($value);
  1334.     }
  1335.  
  1336.     // }}}
  1337.     // {{{ getBlobValue()
  1338.  
  1339.     /**
  1340.      * Convert a text value into a DBMS specific format that is suitable to
  1341.      * compose query statements.
  1342.      * 
  1343.      * @param resource $prepared_query query handle from prepare()
  1344.      * @param  $parameter 
  1345.      * @param  $blob 
  1346.      * @return string text string that represents the given argument value in
  1347.      *         a DBMS specific format.
  1348.      * @access public
  1349.      */
  1350.     function getBlobValue($prepared_query$parameter$blob)
  1351.     {
  1352.         return('EMPTY_BLOB()');
  1353.     }
  1354.  
  1355.     // }}}
  1356.     // {{{ freeBlobValue()
  1357.  
  1358.     /**
  1359.      * free a binary large object
  1360.      * 
  1361.      * @param resource $prepared_query query handle from prepare()
  1362.      * @param string $blob 
  1363.      * @param string $value 
  1364.      * @access public
  1365.      */
  1366.     function freeBlobValue($prepared_query$blob&$value)
  1367.     {
  1368.         unset($value);
  1369.     }
  1370.  
  1371.     // }}}
  1372.     // {{{ getDateValue()
  1373.  
  1374.     /**
  1375.      * Convert a text value into a DBMS specific format that is suitable to
  1376.      * compose query statements.
  1377.      * 
  1378.      * @param string $value text string value that is intended to be converted.
  1379.      * @return string text string that represents the given argument value in
  1380.      *         a DBMS specific format.
  1381.      * @access public
  1382.      */
  1383.     function getDateValue($value)
  1384.     {
  1385.         return(($value === NULL'NULL' : "TO_DATE('$value','YYYY-MM-DD')");
  1386.     }
  1387.  
  1388.     // }}}
  1389.     // {{{ getTimestampValue()
  1390.  
  1391.     /**
  1392.      * Convert a text value into a DBMS specific format that is suitable to
  1393.      * compose query statements.
  1394.      * 
  1395.      * @param string $value text string value that is intended to be converted.
  1396.      * @return string text string that represents the given argument value in
  1397.      *         a DBMS specific format.
  1398.      * @access public
  1399.      */
  1400.     function getTimestampValue($value)
  1401.     {
  1402.         return(($value === NULL'NULL' : "TO_DATE('$value','YYYY-MM-DD HH24:MI:SS')");
  1403.     }
  1404.  
  1405.     // }}}
  1406.     // {{{ getTimeValue()
  1407.  
  1408.     /**
  1409.      * Convert a text value into a DBMS specific format that is suitable to
  1410.      *        compose query statements.
  1411.      * 
  1412.      * @param string $value text string value that is intended to be converted.
  1413.      * @return string text string that represents the given argument value in
  1414.      *         a DBMS specific format.
  1415.      * @access public
  1416.      */
  1417.     function getTimeValue($value)
  1418.     {
  1419.         return(($value === NULL'NULL' : "TO_DATE('0001-01-01 $value','YYYY-MM-DD HH24:MI:SS')");
  1420.     }
  1421.  
  1422.     // }}}
  1423.     // {{{ getFloatValue()
  1424.  
  1425.     /**
  1426.      * Convert a text value into a DBMS specific format that is suitable to
  1427.      * compose query statements.
  1428.      * 
  1429.      * @param string $value text string value that is intended to be converted.
  1430.      * @return string text string that represents the given argument value in
  1431.      *         a DBMS specific format.
  1432.      * @access public
  1433.      */
  1434.     function getFloatValue($value)
  1435.     {
  1436.         return(($value === NULL'NULL' : (float)$value);
  1437.     }
  1438.  
  1439.     // }}}
  1440.     // {{{ getDecimalValue()
  1441.  
  1442.     /**
  1443.      * Convert a text value into a DBMS specific format that is suitable to
  1444.      * compose query statements.
  1445.      * 
  1446.      * @param string $value text string value that is intended to be converted.
  1447.      * @return string text string that represents the given argument value in
  1448.      *         a DBMS specific format.
  1449.      * @access public
  1450.      */
  1451.     function getDecimalValue($value)
  1452.     {
  1453.         return(($value === NULL'NULL' $value);
  1454.     }
  1455.  
  1456.     // }}}
  1457.     // {{{ nextId()
  1458.  
  1459.     /**
  1460.      * returns the next free id of a sequence
  1461.      * 
  1462.      * @param string $seq_name name of the sequence
  1463.      * @param boolean $ondemand when TRUE the seqence is
  1464.      *                            automatic created, if it
  1465.      *                            not exists
  1466.      * @return mixed MDB_Error or id
  1467.      * @access public
  1468.      */
  1469.     function nextId($seq_name$ondemand = TRUE)
  1470.     {
  1471.         if (MDB::isError($connect $this->connect())) {
  1472.             return($connect);
  1473.         }
  1474.         $sequence_name $this->getSequenceName($seq_name);
  1475.         $this->expectError(MDB_ERROR_NOSUCHTABLE);
  1476.         $result $this->_doQuery("SELECT $sequence_name.nextval FROM DUAL");
  1477.         $this->popExpect();
  1478.         if ($ondemand && MDB::isError($result)
  1479.             && $result->getCode(== MDB_ERROR_NOSUCHTABLE)
  1480.         {
  1481.             $result $this->createSequence($seq_name1);
  1482.             if (MDB::isError($result)) {
  1483.                 return $result;
  1484.             }
  1485.             return $this->nextId($seq_namefalse);
  1486.         }
  1487.         return($this->fetchOne($result));
  1488.     }
  1489.  
  1490.     // }}}
  1491.     // {{{ currId()
  1492.  
  1493.     /**
  1494.      * returns the current id of a sequence
  1495.      *
  1496.      * @param string $seq_name name of the sequence
  1497.      * @return mixed MDB_Error or id
  1498.      * @access public
  1499.      */
  1500.     function currId($seq_name)
  1501.     {
  1502.         $sequence_name $this->getSequenceName($seq_name);
  1503.         $result $this->_doQuery("SELECT $sequence_name.currval FROM DUAL");
  1504.         if (MDB::isError($result)) {
  1505.             return($this->raiseError(MDB_ERRORNULLNULL,
  1506.                 'currId: unable to select from ' $seq_name) );
  1507.         }
  1508.         $result $this->fetchOne($result);
  1509.         if (!is_numeric($result)) {
  1510.             return($this->raiseError(MDB_ERRORNULLNULL,
  1511.                 'currId: could not find value in sequence table'));
  1512.         }
  1513.         return($result);
  1514.     }
  1515.  
  1516.     // }}}
  1517.     // {{{ fetchInto()
  1518.  
  1519.     /**
  1520.      * Fetch a row and return data in an array.
  1521.      *
  1522.      * @param resource $result result identifier
  1523.      * @param int $fetchmode how the array data should be indexed
  1524.      * @param int $rownum the row number to fetch
  1525.      * @return mixed data array or NULL on success, a MDB error on failure
  1526.      * @access public
  1527.      */
  1528.     function fetchInto($result$fetchmode = MDB_FETCHMODE_DEFAULT$rownum = NULL)
  1529.     {
  1530.         $result_value intval($result);
  1531.         if (!isset($this->current_row[$result_value])) {
  1532.             return($this->raiseError(MDB_ERRORNULLNULL,
  1533.                 'fetchInto: attemped to fetch on an unknown query result'));
  1534.         }
  1535.         if ($fetchmode == MDB_FETCHMODE_DEFAULT{
  1536.             $fetchmode $this->fetchmode;
  1537.         }
  1538.         if (is_null($rownum)) {
  1539.             $rownum $this->current_row[$result_value+ 1;
  1540.         }
  1541.         if (!isset($this->results[$result_value][$rownum])
  1542.             && (!isset($this->results[$result_value][$this->highest_fetched_row[$result_value]])
  1543.                 || $this->results[$result_value][$this->highest_fetched_row[$result_value]] !== FALSE)
  1544.         {
  1545.             if (isset($this->limits[$result_value])) {
  1546.                 // upper limit
  1547.                 if ($rownum $this->limits[$result_value][1]{
  1548.                     // are all previous rows fetched so that we can set the end
  1549.                     // of the result set and not have any "holes" in between?
  1550.                     if ($rownum == 0
  1551.                         || (isset($this->results[$result_value])
  1552.                             && count($this->results[$result_value]== $rownum
  1553.                         )
  1554.                     {
  1555.                         $this->highest_fetched_row[$result_value$rownum;
  1556.                         $this->current_row[$result_value$rownum;
  1557.                         $this->results[$result_value][$rownum= FALSE;
  1558.                     }
  1559.                     if($this->options['autofree']{
  1560.                         $this->freeResult($result);
  1561.                     }
  1562.                     return(NULL);
  1563.                 }
  1564.                 // offset skipping
  1565.                 if (MDB::isError($this->_skipLimitOffset($result))) {
  1566.                     $this->current_row[$result_value= 0;
  1567.                     $this->results[$result_value= array(FALSE);
  1568.                     if($this->options['autofree']{
  1569.                         $this->freeResult($result);
  1570.                     }
  1571.                     return(NULL);
  1572.                 }
  1573.             }
  1574.             if (isset($this->row_buffer[$result_value])) {
  1575.                 ++$this->current_row[$result_value];
  1576.                 $this->results[$result_value][$this->current_row[$result_value]] =
  1577.                     $this->row_buffer[$result_value];
  1578.                 unset($this->row_buffer[$result_value]);
  1579.             }
  1580.             if (!isset($this->results[$result_value][$rownum])
  1581.                 && (!isset($this->results[$result_value][$this->highest_fetched_row[$result_value]])
  1582.                     || $this->results[$result_value][$this->highest_fetched_row[$result_value]] !== FALSE)
  1583.             {
  1584.                 while($this->current_row[$result_value$rownum
  1585.                     && @OCIFetchInto($result$bufferOCI_RETURN_NULLS)
  1586.                 {
  1587.                     ++$this->current_row[$result_value];
  1588.                     $this->results[$result_value][$this->current_row[$result_value]] $buffer;
  1589.                 }
  1590.                 // end of result set reached
  1591.                 if ($this->current_row[$result_value$rownum{
  1592.                     ++$this->current_row[$result_value];
  1593.                     $this->results[$result_value][$this->current_row[$result_value]] = FALSE;
  1594.                 }
  1595.             }
  1596.             $this->highest_fetched_row[$result_value=
  1597.                 max($this->highest_fetched_row[$result_value],
  1598.                     $this->current_row[$result_value]);
  1599.         else {
  1600.             ++$this->current_row[$result_value];
  1601.         }
  1602.         if (isset($this->results[$result_value][$rownum])
  1603.             && $this->results[$result_value][$rownum]
  1604.         {
  1605.             $row $this->results[$result_value][$rownum];
  1606.         else {
  1607.             if($this->options['autofree']{
  1608.                 $this->freeResult($result);
  1609.             }
  1610.             return(NULL);
  1611.         }
  1612.         if ($fetchmode MDB_FETCHMODE_ASSOC{
  1613.             $column_names $this->getColumnNames($result);
  1614.             foreach($column_names as $name => $i{
  1615.                 $column_names[$name$row[$i];
  1616.             }
  1617.             $row $column_names;
  1618.         }
  1619.         if (isset($this->result_types[$result_value])) {
  1620.             $row $this->convertResultRow($result$row);
  1621.         }
  1622.         return($row);
  1623.     }
  1624.  
  1625.     // }}}
  1626.     // {{{ nextResult()
  1627.  
  1628.     /**
  1629.      * Move the internal oracle result pointer to the next available result
  1630.      * Currently not supported
  1631.      * 
  1632.      * @param $result a oracle valid result resource
  1633.      * @return TRUE if a result is available otherwise return FALSE
  1634.      * @access public
  1635.      */
  1636.     function nextResult($result)
  1637.     {
  1638.         return(FALSE);
  1639.     }
  1640.  
  1641.     // }}}
  1642.     // {{{ tableInfo()
  1643.  
  1644.     /**
  1645.      * returns meta data about the result set
  1646.      * 
  1647.      * @param resource $result result identifier
  1648.      * @param mixed $mode depends on implementation
  1649.      * @return array an nested array, or a MDB error
  1650.      * @access public
  1651.      */
  1652.     function tableInfo($result$mode = NULL)
  1653.     {
  1654.         $count = 0;
  1655.         $res = array();
  1656.         /**
  1657.          * depending on $mode, metadata returns the following values:
  1658.          * 
  1659.          * - mode is FALSE (default):
  1660.          * $res[]:
  1661.          *    [0]['table']       table name
  1662.          *    [0]['name']        field name
  1663.          *    [0]['type']        field type
  1664.          *    [0]['len']         field length
  1665.          *    [0]['nullable']    field can be NULL (boolean)
  1666.          *    [0]['format']      field precision if NUMBER
  1667.          *    [0]['default']     field default value
  1668.          * 
  1669.          * - mode is MDB_TABLEINFO_ORDER
  1670.          * $res[]:
  1671.          *    ['num_fields']     number of fields
  1672.          *    [0]['table']       table name
  1673.          *    [0]['name']        field name
  1674.          *    [0]['type']        field type
  1675.          *    [0]['len']         field length
  1676.          *    [0]['nullable']    field can be NULL (boolean)
  1677.          *    [0]['format']      field precision if NUMBER
  1678.          *    [0]['default']     field default value
  1679.          *    ['order'][field name] index of field named 'field name'
  1680.          *    The last one is used, if you have a field name, but no index.
  1681.          *    Test:  if (isset($result['order']['myfield'])) { ...
  1682.          * 
  1683.          * - mode is MDB_TABLEINFO_ORDERTABLE
  1684.          *     the same as above. but additionally
  1685.          *    ['ordertable'][table name][field name] index of field
  1686.          *       named 'field name'
  1687.          * 
  1688.          *       this is, because if you have fields from different
  1689.          *       tables with the same field name * they override each
  1690.          *       other with MDB_TABLEINFO_ORDER
  1691.          * 
  1692.          *       you can combine DB_TABLEINFO_ORDER and
  1693.          *       MDB_TABLEINFO_ORDERTABLE with MDB_TABLEINFO_ORDER |
  1694.          *       MDB_TABLEINFO_ORDERTABLE * or with MDB_TABLEINFO_FULL
  1695.          */ 
  1696.         // if $result is a string, we collect info for a table only
  1697.         if (is_string($result)) {
  1698.             if (MDB::isError($connect $this->connect())) {
  1699.                 return($connect);
  1700.             }
  1701.             $result strtoupper($result);
  1702.             $q_fields = "select column_name, data_type, data_length, data_precision,
  1703.                      nullable, data_default from user_tab_columns
  1704.                      where table_name='$result' order by column_id";
  1705.             if (!$stmt @OCIParse($this->connection$q_fields)) {
  1706.                 return($this->oci8RaiseError());
  1707.             }
  1708.             if (!@OCIExecute($stmtOCI_DEFAULT)) {
  1709.                 return($this->oci8RaiseError($stmt));
  1710.             while (@OCIFetch($stmt)) {
  1711.                 $res[$count]['table'strtolower($result);
  1712.                 $res[$count]['name'strtolower(@OCIResult($stmt1));
  1713.                 $res[$count]['type'strtolower(@OCIResult($stmt2));
  1714.                 $res[$count]['len'@OCIResult($stmt3);
  1715.                 $res[$count]['format'@OCIResult($stmt4);
  1716.                 $res[$count]['nullable'(@OCIResult($stmt5== 'Y'? TRUE : FALSE;
  1717.                 $res[$count]['default'@OCIResult($stmt6);
  1718.                 if ($mode MDB_TABLEINFO_ORDER{
  1719.                     $res['order'][$res[$count]['name']] $count;
  1720.                 }
  1721.                 if ($mode MDB_TABLEINFO_ORDERTABLE{
  1722.                     $res['ordertable'][$res[$count]['table']][$res[$count]['name']] $count;
  1723.                 }
  1724.                 $count++;
  1725.             }
  1726.             if ($mode{
  1727.                 $res['num_fields'$count;
  1728.             }
  1729.             @OCIFreeStatement($stmt);
  1730.         else // else we want information about a resultset
  1731.             #if ($result === $this->last_stmt) {
  1732.                 $count @OCINumCols($result);
  1733.                 for ($i = 0; $i $count$i++{
  1734.                     $res[$i]['name'strtolower(@OCIColumnName($result$i + 1));
  1735.                     $res[$i]['type'strtolower(@OCIColumnType($result$i + 1));
  1736.                     $res[$i]['len'@OCIColumnSize($result$i + 1);
  1737.  
  1738.                     $q_fields "SELECT table_name, data_precision, nullable, data_default from user_tab_columns WHERE column_name='".$res[$i]['name']."'";
  1739.                     if (!$stmt @OCIParse($this->connection$q_fields)) {
  1740.                         return($this->oci8RaiseError());
  1741.                     }
  1742.                     if (!@OCIExecute($stmtOCI_DEFAULT)) {
  1743.                         return($this->oci8RaiseError($stmt));
  1744.                     }
  1745.                     @OCIFetch($stmt);
  1746.                     $res[$i]['table'strtolower(@OCIResult($stmt1));
  1747.                     $res[$i]['format'@OCIResult($stmt2);
  1748.                     $res[$i]['nullable'(@OCIResult($stmt3== 'Y'? TRUE : FALSE;
  1749.                     $res[$i]['default'@OCIResult($stmt4);
  1750.                     @OCIFreeStatement($stmt);
  1751.  
  1752.                     if ($mode MDB_TABLEINFO_ORDER{
  1753.                         $res['order'][$res[$i]['name']] $i;
  1754.                     }
  1755.                     if ($mode MDB_TABLEINFO_ORDERTABLE{
  1756.                         $res['ordertable'][$res[$i]['table']][$res[$i]['name']] $i;
  1757.                     }
  1758.                 }
  1759.                 if ($mode{
  1760.                     $res['num_fields'$count;
  1761.                 }
  1762.             #} else {
  1763.             #    return($this->raiseError(MDB_ERROR_NOT_CAPABLE));
  1764.             #}
  1765.         }
  1766.         return($res);
  1767.     }
  1768. }
  1769. ?>

Documentation generated on Mon, 11 Mar 2019 10:15:29 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.