[ Index ]
 

Code source de PHP PEAR 1.4.5

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/DB/ -> oci8.php (source)

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


Généré le : Sun Feb 25 14:08:00 2007 par Balluche grâce à PHPXref 0.7