| [ Index ] |
|
Code source de PHP PEAR 1.4.5 |
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 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Feb 25 14:08:00 2007 | par Balluche grâce à PHPXref 0.7 |