| [ 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 pgsql extension 7 * for interacting with PostgreSQL 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 Rui Hirokawa <hirokawa@php.net> 20 * @author Stig Bakken <ssb@php.net> 21 * @author Daniel Convissor <danielc@php.net> 22 * @copyright 1997-2005 The PHP Group 23 * @license http://www.php.net/license/3_0.txt PHP License 3.0 24 * @version CVS: $Id: pgsql.php,v 1.134 2007/01/12 05:45:09 aharvey Exp $ 25 * @link http://pear.php.net/package/DB 26 */ 27 28 /** 29 * Obtain the DB_common class so it can be extended from 30 */ 31 require_once 'DB/common.php'; 32 33 /** 34 * The methods PEAR DB uses to interact with PHP's pgsql extension 35 * for interacting with PostgreSQL databases 36 * 37 * These methods overload the ones declared in DB_common. 38 * 39 * @category Database 40 * @package DB 41 * @author Rui Hirokawa <hirokawa@php.net> 42 * @author Stig Bakken <ssb@php.net> 43 * @author Daniel Convissor <danielc@php.net> 44 * @copyright 1997-2005 The PHP Group 45 * @license http://www.php.net/license/3_0.txt PHP License 3.0 46 * @version Release: 1.7.9 47 * @link http://pear.php.net/package/DB 48 */ 49 class DB_pgsql extends DB_common 50 { 51 // {{{ properties 52 53 /** 54 * The DB driver type (mysql, oci8, odbc, etc.) 55 * @var string 56 */ 57 var $phptype = 'pgsql'; 58 59 /** 60 * The database syntax variant to be used (db2, access, etc.), if any 61 * @var string 62 */ 63 var $dbsyntax = 'pgsql'; 64 65 /** 66 * The capabilities of this DB implementation 67 * 68 * The 'new_link' element contains the PHP version that first provided 69 * new_link support for this DBMS. Contains false if it's unsupported. 70 * 71 * Meaning of the 'limit' element: 72 * + 'emulate' = emulate with fetch row by number 73 * + 'alter' = alter the query 74 * + false = skip rows 75 * 76 * @var array 77 */ 78 var $features = array( 79 'limit' => 'alter', 80 'new_link' => '4.3.0', 81 'numrows' => true, 82 'pconnect' => true, 83 'prepare' => false, 84 'ssl' => true, 85 'transactions' => true, 86 ); 87 88 /** 89 * A mapping of native error codes to DB error codes 90 * @var array 91 */ 92 var $errorcode_map = array( 93 ); 94 95 /** 96 * The raw database connection created by PHP 97 * @var resource 98 */ 99 var $connection; 100 101 /** 102 * The DSN information for connecting to a database 103 * @var array 104 */ 105 var $dsn = array(); 106 107 108 /** 109 * Should data manipulation queries be committed automatically? 110 * @var bool 111 * @access private 112 */ 113 var $autocommit = true; 114 115 /** 116 * The quantity of transactions begun 117 * 118 * {@internal While this is private, it can't actually be designated 119 * private in PHP 5 because it is directly accessed in the test suite.}} 120 * 121 * @var integer 122 * @access private 123 */ 124 var $transaction_opcount = 0; 125 126 /** 127 * The number of rows affected by a data manipulation query 128 * @var integer 129 */ 130 var $affected = 0; 131 132 /** 133 * The current row being looked at in fetchInto() 134 * @var array 135 * @access private 136 */ 137 var $row = array(); 138 139 /** 140 * The number of rows in a given result set 141 * @var array 142 * @access private 143 */ 144 var $_num_rows = array(); 145 146 147 // }}} 148 // {{{ constructor 149 150 /** 151 * This constructor calls <kbd>$this->DB_common()</kbd> 152 * 153 * @return void 154 */ 155 function DB_pgsql() 156 { 157 $this->DB_common(); 158 } 159 160 // }}} 161 // {{{ connect() 162 163 /** 164 * Connect to the database server, log in and open the database 165 * 166 * Don't call this method directly. Use DB::connect() instead. 167 * 168 * PEAR DB's pgsql driver supports the following extra DSN options: 169 * + connect_timeout How many seconds to wait for a connection to 170 * be established. Available since PEAR DB 1.7.0. 171 * + new_link If set to true, causes subsequent calls to 172 * connect() to return a new connection link 173 * instead of the existing one. WARNING: this is 174 * not portable to other DBMS's. Available only 175 * if PHP is >= 4.3.0 and PEAR DB is >= 1.7.0. 176 * + options Command line options to be sent to the server. 177 * Available since PEAR DB 1.6.4. 178 * + service Specifies a service name in pg_service.conf that 179 * holds additional connection parameters. 180 * Available since PEAR DB 1.7.0. 181 * + sslmode How should SSL be used when connecting? Values: 182 * disable, allow, prefer or require. 183 * Available since PEAR DB 1.7.0. 184 * + tty This was used to specify where to send server 185 * debug output. Available since PEAR DB 1.6.4. 186 * 187 * Example of connecting to a new link via a socket: 188 * <code> 189 * require_once 'DB.php'; 190 * 191 * $dsn = 'pgsql://user:pass@unix(/tmp)/dbname?new_link=true'; 192 * $options = array( 193 * 'portability' => DB_PORTABILITY_ALL, 194 * ); 195 * 196 * $db =& DB::connect($dsn, $options); 197 * if (PEAR::isError($db)) { 198 * die($db->getMessage()); 199 * } 200 * </code> 201 * 202 * @param array $dsn the data source name 203 * @param bool $persistent should the connection be persistent? 204 * 205 * @return int DB_OK on success. A DB_Error object on failure. 206 * 207 * @link http://www.postgresql.org/docs/current/static/libpq.html#LIBPQ-CONNECT 208 */ 209 function connect($dsn, $persistent = false) 210 { 211 if (!PEAR::loadExtension('pgsql')) { 212 return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); 213 } 214 215 $this->dsn = $dsn; 216 if ($dsn['dbsyntax']) { 217 $this->dbsyntax = $dsn['dbsyntax']; 218 } 219 220 $protocol = $dsn['protocol'] ? $dsn['protocol'] : 'tcp'; 221 222 $params = array(''); 223 if ($protocol == 'tcp') { 224 if ($dsn['hostspec']) { 225 $params[0] .= 'host=' . $dsn['hostspec']; 226 } 227 if ($dsn['port']) { 228 $params[0] .= ' port=' . $dsn['port']; 229 } 230 } elseif ($protocol == 'unix') { 231 // Allow for pg socket in non-standard locations. 232 if ($dsn['socket']) { 233 $params[0] .= 'host=' . $dsn['socket']; 234 } 235 if ($dsn['port']) { 236 $params[0] .= ' port=' . $dsn['port']; 237 } 238 } 239 if ($dsn['database']) { 240 $params[0] .= ' dbname=\'' . addslashes($dsn['database']) . '\''; 241 } 242 if ($dsn['username']) { 243 $params[0] .= ' user=\'' . addslashes($dsn['username']) . '\''; 244 } 245 if ($dsn['password']) { 246 $params[0] .= ' password=\'' . addslashes($dsn['password']) . '\''; 247 } 248 if (!empty($dsn['options'])) { 249 $params[0] .= ' options=' . $dsn['options']; 250 } 251 if (!empty($dsn['tty'])) { 252 $params[0] .= ' tty=' . $dsn['tty']; 253 } 254 if (!empty($dsn['connect_timeout'])) { 255 $params[0] .= ' connect_timeout=' . $dsn['connect_timeout']; 256 } 257 if (!empty($dsn['sslmode'])) { 258 $params[0] .= ' sslmode=' . $dsn['sslmode']; 259 } 260 if (!empty($dsn['service'])) { 261 $params[0] .= ' service=' . $dsn['service']; 262 } 263 264 if (isset($dsn['new_link']) 265 && ($dsn['new_link'] == 'true' || $dsn['new_link'] === true)) 266 { 267 if (version_compare(phpversion(), '4.3.0', '>=')) { 268 $params[] = PGSQL_CONNECT_FORCE_NEW; 269 } 270 } 271 272 $connect_function = $persistent ? 'pg_pconnect' : 'pg_connect'; 273 274 $ini = ini_get('track_errors'); 275 $php_errormsg = ''; 276 if ($ini) { 277 $this->connection = @call_user_func_array($connect_function, 278 $params); 279 } else { 280 @ini_set('track_errors', 1); 281 $this->connection = @call_user_func_array($connect_function, 282 $params); 283 @ini_set('track_errors', $ini); 284 } 285 286 if (!$this->connection) { 287 return $this->raiseError(DB_ERROR_CONNECT_FAILED, 288 null, null, null, 289 $php_errormsg); 290 } 291 return DB_OK; 292 } 293 294 // }}} 295 // {{{ disconnect() 296 297 /** 298 * Disconnects from the database server 299 * 300 * @return bool TRUE on success, FALSE on failure 301 */ 302 function disconnect() 303 { 304 $ret = @pg_close($this->connection); 305 $this->connection = null; 306 return $ret; 307 } 308 309 // }}} 310 // {{{ simpleQuery() 311 312 /** 313 * Sends a query to the database server 314 * 315 * @param string the SQL query string 316 * 317 * @return mixed + a PHP result resrouce for successful SELECT queries 318 * + the DB_OK constant for other successful queries 319 * + a DB_Error object on failure 320 */ 321 function simpleQuery($query) 322 { 323 $ismanip = $this->_checkManip($query); 324 $this->last_query = $query; 325 $query = $this->modifyQuery($query); 326 if (!$this->autocommit && $ismanip) { 327 if ($this->transaction_opcount == 0) { 328 $result = @pg_exec($this->connection, 'begin;'); 329 if (!$result) { 330 return $this->pgsqlRaiseError(); 331 } 332 } 333 $this->transaction_opcount++; 334 } 335 $result = @pg_exec($this->connection, $query); 336 if (!$result) { 337 return $this->pgsqlRaiseError(); 338 } 339 340 /* 341 * Determine whether queries produce affected rows, result or nothing. 342 * 343 * This logic was introduced in version 1.1 of the file by ssb, 344 * though the regex has been modified slightly since then. 345 * 346 * PostgreSQL commands: 347 * ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY, 348 * CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH, 349 * GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET, 350 * REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW, 351 * UNLISTEN, UPDATE, VACUUM 352 */ 353 if ($ismanip) { 354 $this->affected = @pg_affected_rows($result); 355 return DB_OK; 356 } elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|FETCH|SHOW)\s/si', 357 $query)) 358 { 359 $this->row[(int)$result] = 0; // reset the row counter. 360 $numrows = $this->numRows($result); 361 if (is_object($numrows)) { 362 return $numrows; 363 } 364 $this->_num_rows[(int)$result] = $numrows; 365 $this->affected = 0; 366 return $result; 367 } else { 368 $this->affected = 0; 369 return DB_OK; 370 } 371 } 372 373 // }}} 374 // {{{ nextResult() 375 376 /** 377 * Move the internal pgsql result pointer to the next available result 378 * 379 * @param a valid fbsql result resource 380 * 381 * @access public 382 * 383 * @return true if a result is available otherwise return false 384 */ 385 function nextResult($result) 386 { 387 return false; 388 } 389 390 // }}} 391 // {{{ fetchInto() 392 393 /** 394 * Places a row from the result set into the given array 395 * 396 * Formating of the array and the data therein are configurable. 397 * See DB_result::fetchInto() for more information. 398 * 399 * This method is not meant to be called directly. Use 400 * DB_result::fetchInto() instead. It can't be declared "protected" 401 * because DB_result is a separate object. 402 * 403 * @param resource $result the query result resource 404 * @param array $arr the referenced array to put the data in 405 * @param int $fetchmode how the resulting array should be indexed 406 * @param int $rownum the row number to fetch (0 = first row) 407 * 408 * @return mixed DB_OK on success, NULL when the end of a result set is 409 * reached or on failure 410 * 411 * @see DB_result::fetchInto() 412 */ 413 function fetchInto($result, &$arr, $fetchmode, $rownum = null) 414 { 415 $result_int = (int)$result; 416 $rownum = ($rownum !== null) ? $rownum : $this->row[$result_int]; 417 if ($rownum >= $this->_num_rows[$result_int]) { 418 return null; 419 } 420 if ($fetchmode & DB_FETCHMODE_ASSOC) { 421 $arr = @pg_fetch_array($result, $rownum, PGSQL_ASSOC); 422 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { 423 $arr = array_change_key_case($arr, CASE_LOWER); 424 } 425 } else { 426 $arr = @pg_fetch_row($result, $rownum); 427 } 428 if (!$arr) { 429 return null; 430 } 431 if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { 432 $this->_rtrimArrayValues($arr); 433 } 434 if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { 435 $this->_convertNullArrayValuesToEmpty($arr); 436 } 437 $this->row[$result_int] = ++$rownum; 438 return DB_OK; 439 } 440 441 // }}} 442 // {{{ freeResult() 443 444 /** 445 * Deletes the result set and frees the memory occupied by the result set 446 * 447 * This method is not meant to be called directly. Use 448 * DB_result::free() instead. It can't be declared "protected" 449 * because DB_result is a separate object. 450 * 451 * @param resource $result PHP's query result resource 452 * 453 * @return bool TRUE on success, FALSE if $result is invalid 454 * 455 * @see DB_result::free() 456 */ 457 function freeResult($result) 458 { 459 if (is_resource($result)) { 460 unset($this->row[(int)$result]); 461 unset($this->_num_rows[(int)$result]); 462 $this->affected = 0; 463 return @pg_freeresult($result); 464 } 465 return false; 466 } 467 468 // }}} 469 // {{{ quote() 470 471 /** 472 * @deprecated Deprecated in release 1.6.0 473 * @internal 474 */ 475 function quote($str) 476 { 477 return $this->quoteSmart($str); 478 } 479 480 // }}} 481 // {{{ quoteBoolean() 482 483 /** 484 * Formats a boolean value for use within a query in a locale-independent 485 * manner. 486 * 487 * @param boolean the boolean value to be quoted. 488 * @return string the quoted string. 489 * @see DB_common::quoteSmart() 490 * @since Method available since release 1.7.8. 491 */ 492 function quoteBoolean($boolean) { 493 return $boolean ? 'TRUE' : 'FALSE'; 494 } 495 496 // }}} 497 // {{{ escapeSimple() 498 499 /** 500 * Escapes a string according to the current DBMS's standards 501 * 502 * {@internal PostgreSQL treats a backslash as an escape character, 503 * so they are escaped as well. 504 * 505 * @param string $str the string to be escaped 506 * 507 * @return string the escaped string 508 * 509 * @see DB_common::quoteSmart() 510 * @since Method available since Release 1.6.0 511 */ 512 function escapeSimple($str) 513 { 514 if (function_exists('pg_escape_string')) { 515 return pg_escape_string($str); 516 } else { 517 return str_replace("'", "''", str_replace('\\', '\\\\', $str)); 518 } 519 } 520 521 // }}} 522 // {{{ numCols() 523 524 /** 525 * Gets the number of columns in a result set 526 * 527 * This method is not meant to be called directly. Use 528 * DB_result::numCols() instead. It can't be declared "protected" 529 * because DB_result is a separate object. 530 * 531 * @param resource $result PHP's query result resource 532 * 533 * @return int the number of columns. A DB_Error object on failure. 534 * 535 * @see DB_result::numCols() 536 */ 537 function numCols($result) 538 { 539 $cols = @pg_numfields($result); 540 if (!$cols) { 541 return $this->pgsqlRaiseError(); 542 } 543 return $cols; 544 } 545 546 // }}} 547 // {{{ numRows() 548 549 /** 550 * Gets the number of rows in a result set 551 * 552 * This method is not meant to be called directly. Use 553 * DB_result::numRows() instead. It can't be declared "protected" 554 * because DB_result is a separate object. 555 * 556 * @param resource $result PHP's query result resource 557 * 558 * @return int the number of rows. A DB_Error object on failure. 559 * 560 * @see DB_result::numRows() 561 */ 562 function numRows($result) 563 { 564 $rows = @pg_numrows($result); 565 if ($rows === null) { 566 return $this->pgsqlRaiseError(); 567 } 568 return $rows; 569 } 570 571 // }}} 572 // {{{ autoCommit() 573 574 /** 575 * Enables or disables automatic commits 576 * 577 * @param bool $onoff true turns it on, false turns it off 578 * 579 * @return int DB_OK on success. A DB_Error object if the driver 580 * doesn't support auto-committing transactions. 581 */ 582 function autoCommit($onoff = false) 583 { 584 // XXX if $this->transaction_opcount > 0, we should probably 585 // issue a warning here. 586 $this->autocommit = $onoff ? true : false; 587 return DB_OK; 588 } 589 590 // }}} 591 // {{{ commit() 592 593 /** 594 * Commits the current transaction 595 * 596 * @return int DB_OK on success. A DB_Error object on failure. 597 */ 598 function commit() 599 { 600 if ($this->transaction_opcount > 0) { 601 // (disabled) hack to shut up error messages from libpq.a 602 //@fclose(@fopen("php://stderr", "w")); 603 $result = @pg_exec($this->connection, 'end;'); 604 $this->transaction_opcount = 0; 605 if (!$result) { 606 return $this->pgsqlRaiseError(); 607 } 608 } 609 return DB_OK; 610 } 611 612 // }}} 613 // {{{ rollback() 614 615 /** 616 * Reverts the current transaction 617 * 618 * @return int DB_OK on success. A DB_Error object on failure. 619 */ 620 function rollback() 621 { 622 if ($this->transaction_opcount > 0) { 623 $result = @pg_exec($this->connection, 'abort;'); 624 $this->transaction_opcount = 0; 625 if (!$result) { 626 return $this->pgsqlRaiseError(); 627 } 628 } 629 return DB_OK; 630 } 631 632 // }}} 633 // {{{ affectedRows() 634 635 /** 636 * Determines the number of rows affected by a data maniuplation query 637 * 638 * 0 is returned for queries that don't manipulate data. 639 * 640 * @return int the number of rows. A DB_Error object on failure. 641 */ 642 function affectedRows() 643 { 644 return $this->affected; 645 } 646 647 // }}} 648 // {{{ nextId() 649 650 /** 651 * Returns the next free id in a sequence 652 * 653 * @param string $seq_name name of the sequence 654 * @param boolean $ondemand when true, the seqence is automatically 655 * created if it does not exist 656 * 657 * @return int the next id number in the sequence. 658 * A DB_Error object on failure. 659 * 660 * @see DB_common::nextID(), DB_common::getSequenceName(), 661 * DB_pgsql::createSequence(), DB_pgsql::dropSequence() 662 */ 663 function nextId($seq_name, $ondemand = true) 664 { 665 $seqname = $this->getSequenceName($seq_name); 666 $repeat = false; 667 do { 668 $this->pushErrorHandling(PEAR_ERROR_RETURN); 669 $result =& $this->query("SELECT NEXTVAL('$seqname}')"); 670 $this->popErrorHandling(); 671 if ($ondemand && DB::isError($result) && 672 $result->getCode() == DB_ERROR_NOSUCHTABLE) { 673 $repeat = true; 674 $this->pushErrorHandling(PEAR_ERROR_RETURN); 675 $result = $this->createSequence($seq_name); 676 $this->popErrorHandling(); 677 if (DB::isError($result)) { 678 return $this->raiseError($result); 679 } 680 } else { 681 $repeat = false; 682 } 683 } while ($repeat); 684 if (DB::isError($result)) { 685 return $this->raiseError($result); 686 } 687 $arr = $result->fetchRow(DB_FETCHMODE_ORDERED); 688 $result->free(); 689 return $arr[0]; 690 } 691 692 // }}} 693 // {{{ createSequence() 694 695 /** 696 * Creates a new sequence 697 * 698 * @param string $seq_name name of the new sequence 699 * 700 * @return int DB_OK on success. A DB_Error object on failure. 701 * 702 * @see DB_common::createSequence(), DB_common::getSequenceName(), 703 * DB_pgsql::nextID(), DB_pgsql::dropSequence() 704 */ 705 function createSequence($seq_name) 706 { 707 $seqname = $this->getSequenceName($seq_name); 708 $result = $this->query("CREATE SEQUENCE $seqname}"); 709 return $result; 710 } 711 712 // }}} 713 // {{{ dropSequence() 714 715 /** 716 * Deletes a sequence 717 * 718 * @param string $seq_name name of the sequence to be deleted 719 * 720 * @return int DB_OK on success. A DB_Error object on failure. 721 * 722 * @see DB_common::dropSequence(), DB_common::getSequenceName(), 723 * DB_pgsql::nextID(), DB_pgsql::createSequence() 724 */ 725 function dropSequence($seq_name) 726 { 727 return $this->query('DROP SEQUENCE ' 728 . $this->getSequenceName($seq_name)); 729 } 730 731 // }}} 732 // {{{ modifyLimitQuery() 733 734 /** 735 * Adds LIMIT clauses to a query string according to current DBMS standards 736 * 737 * @param string $query the query to modify 738 * @param int $from the row to start to fetching (0 = the first row) 739 * @param int $count the numbers of rows to fetch 740 * @param mixed $params array, string or numeric data to be used in 741 * execution of the statement. Quantity of items 742 * passed must match quantity of placeholders in 743 * query: meaning 1 placeholder for non-array 744 * parameters or 1 placeholder per array element. 745 * 746 * @return string the query string with LIMIT clauses added 747 * 748 * @access protected 749 */ 750 function modifyLimitQuery($query, $from, $count, $params = array()) 751 { 752 return "$query LIMIT $count OFFSET $from"; 753 } 754 755 // }}} 756 // {{{ pgsqlRaiseError() 757 758 /** 759 * Produces a DB_Error object regarding the current problem 760 * 761 * @param int $errno if the error is being manually raised pass a 762 * DB_ERROR* constant here. If this isn't passed 763 * the error information gathered from the DBMS. 764 * 765 * @return object the DB_Error object 766 * 767 * @see DB_common::raiseError(), 768 * DB_pgsql::errorNative(), DB_pgsql::errorCode() 769 */ 770 function pgsqlRaiseError($errno = null) 771 { 772 $native = $this->errorNative(); 773 if (!$native) { 774 $native = 'Database connection has been lost.'; 775 $errno = DB_ERROR_CONNECT_FAILED; 776 } 777 if ($errno === null) { 778 $errno = $this->errorCode($native); 779 } 780 return $this->raiseError($errno, null, null, null, $native); 781 } 782 783 // }}} 784 // {{{ errorNative() 785 786 /** 787 * Gets the DBMS' native error message produced by the last query 788 * 789 * {@internal Error messages are used instead of error codes 790 * in order to support older versions of PostgreSQL.}} 791 * 792 * @return string the DBMS' error message 793 */ 794 function errorNative() 795 { 796 return @pg_errormessage($this->connection); 797 } 798 799 // }}} 800 // {{{ errorCode() 801 802 /** 803 * Determines PEAR::DB error code from the database's text error message. 804 * 805 * @param string $errormsg error message returned from the database 806 * @return integer an error number from a DB error constant 807 */ 808 function errorCode($errormsg) 809 { 810 static $error_regexps; 811 if (!isset($error_regexps)) { 812 $error_regexps = array( 813 '/column .* (of relation .*)?does not exist/i' 814 => DB_ERROR_NOSUCHFIELD, 815 '/(relation|sequence|table).*does not exist|class .* not found/i' 816 => DB_ERROR_NOSUCHTABLE, 817 '/index .* does not exist/' 818 => DB_ERROR_NOT_FOUND, 819 '/relation .* already exists/i' 820 => DB_ERROR_ALREADY_EXISTS, 821 '/(divide|division) by zero$/i' 822 => DB_ERROR_DIVZERO, 823 '/pg_atoi: error in .*: can\'t parse /i' 824 => DB_ERROR_INVALID_NUMBER, 825 '/invalid input syntax for( type)? (integer|numeric)/i' 826 => DB_ERROR_INVALID_NUMBER, 827 '/value .* is out of range for type \w*int/i' 828 => DB_ERROR_INVALID_NUMBER, 829 '/integer out of range/i' 830 => DB_ERROR_INVALID_NUMBER, 831 '/value too long for type character/i' 832 => DB_ERROR_INVALID, 833 '/attribute .* not found|relation .* does not have attribute/i' 834 => DB_ERROR_NOSUCHFIELD, 835 '/column .* specified in USING clause does not exist in (left|right) table/i' 836 => DB_ERROR_NOSUCHFIELD, 837 '/parser: parse error at or near/i' 838 => DB_ERROR_SYNTAX, 839 '/syntax error at/' 840 => DB_ERROR_SYNTAX, 841 '/column reference .* is ambiguous/i' 842 => DB_ERROR_SYNTAX, 843 '/permission denied/' 844 => DB_ERROR_ACCESS_VIOLATION, 845 '/violates not-null constraint/' 846 => DB_ERROR_CONSTRAINT_NOT_NULL, 847 '/violates [\w ]+ constraint/' 848 => DB_ERROR_CONSTRAINT, 849 '/referential integrity violation/' 850 => DB_ERROR_CONSTRAINT, 851 '/more expressions than target columns/i' 852 => DB_ERROR_VALUE_COUNT_ON_ROW, 853 ); 854 } 855 foreach ($error_regexps as $regexp => $code) { 856 if (preg_match($regexp, $errormsg)) { 857 return $code; 858 } 859 } 860 // Fall back to DB_ERROR if there was no mapping. 861 return DB_ERROR; 862 } 863 864 // }}} 865 // {{{ tableInfo() 866 867 /** 868 * Returns information about a table or a result set 869 * 870 * NOTE: only supports 'table' and 'flags' if <var>$result</var> 871 * is a table name. 872 * 873 * @param object|string $result DB_result object from a query or a 874 * string containing the name of a table. 875 * While this also accepts a query result 876 * resource identifier, this behavior is 877 * deprecated. 878 * @param int $mode a valid tableInfo mode 879 * 880 * @return array an associative array with the information requested. 881 * A DB_Error object on failure. 882 * 883 * @see DB_common::tableInfo() 884 */ 885 function tableInfo($result, $mode = null) 886 { 887 if (is_string($result)) { 888 /* 889 * Probably received a table name. 890 * Create a result resource identifier. 891 */ 892 $id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0"); 893 $got_string = true; 894 } elseif (isset($result->result)) { 895 /* 896 * Probably received a result object. 897 * Extract the result resource identifier. 898 */ 899 $id = $result->result; 900 $got_string = false; 901 } else { 902 /* 903 * Probably received a result resource identifier. 904 * Copy it. 905 * Deprecated. Here for compatibility only. 906 */ 907 $id = $result; 908 $got_string = false; 909 } 910 911 if (!is_resource($id)) { 912 return $this->pgsqlRaiseError(DB_ERROR_NEED_MORE_DATA); 913 } 914 915 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { 916 $case_func = 'strtolower'; 917 } else { 918 $case_func = 'strval'; 919 } 920 921 $count = @pg_numfields($id); 922 $res = array(); 923 924 if ($mode) { 925 $res['num_fields'] = $count; 926 } 927 928 for ($i = 0; $i < $count; $i++) { 929 $res[$i] = array( 930 'table' => $got_string ? $case_func($result) : '', 931 'name' => $case_func(@pg_fieldname($id, $i)), 932 'type' => @pg_fieldtype($id, $i), 933 'len' => @pg_fieldsize($id, $i), 934 'flags' => $got_string 935 ? $this->_pgFieldFlags($id, $i, $result) 936 : '', 937 ); 938 if ($mode & DB_TABLEINFO_ORDER) { 939 $res['order'][$res[$i]['name']] = $i; 940 } 941 if ($mode & DB_TABLEINFO_ORDERTABLE) { 942 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; 943 } 944 } 945 946 // free the result only if we were called on a table 947 if ($got_string) { 948 @pg_freeresult($id); 949 } 950 return $res; 951 } 952 953 // }}} 954 // {{{ _pgFieldFlags() 955 956 /** 957 * Get a column's flags 958 * 959 * Supports "not_null", "default_value", "primary_key", "unique_key" 960 * and "multiple_key". The default value is passed through 961 * rawurlencode() in case there are spaces in it. 962 * 963 * @param int $resource the PostgreSQL result identifier 964 * @param int $num_field the field number 965 * 966 * @return string the flags 967 * 968 * @access private 969 */ 970 function _pgFieldFlags($resource, $num_field, $table_name) 971 { 972 $field_name = @pg_fieldname($resource, $num_field); 973 974 // Check if there's a schema in $table_name and update things 975 // accordingly. 976 $from = 'pg_attribute f, pg_class tab, pg_type typ'; 977 if (strpos($table_name, '.') !== false) { 978 $from .= ', pg_namespace nsp'; 979 list($schema, $table) = explode('.', $table_name); 980 $tableWhere = "tab.relname = '$table' AND tab.relnamespace = nsp.oid AND nsp.nspname = '$schema'"; 981 } else { 982 $tableWhere = "tab.relname = '$table_name'"; 983 } 984 985 $result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef 986 FROM $from 987 WHERE tab.relname = typ.typname 988 AND typ.typrelid = f.attrelid 989 AND f.attname = '$field_name' 990 AND $tableWhere"); 991 if (@pg_numrows($result) > 0) { 992 $row = @pg_fetch_row($result, 0); 993 $flags = ($row[0] == 't') ? 'not_null ' : ''; 994 995 if ($row[1] == 't') { 996 $result = @pg_exec($this->connection, "SELECT a.adsrc 997 FROM $from, pg_attrdef a 998 WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid 999 AND f.attrelid = a.adrelid AND f.attname = '$field_name' 1000 AND $tableWhere AND f.attnum = a.adnum"); 1001 $row = @pg_fetch_row($result, 0); 1002 $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]); 1003 $flags .= 'default_' . rawurlencode($num) . ' '; 1004 } 1005 } else { 1006 $flags = ''; 1007 } 1008 $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey 1009 FROM $from, pg_index i 1010 WHERE tab.relname = typ.typname 1011 AND typ.typrelid = f.attrelid 1012 AND f.attrelid = i.indrelid 1013 AND f.attname = '$field_name' 1014 AND $tableWhere"); 1015 $count = @pg_numrows($result); 1016 1017 for ($i = 0; $i < $count ; $i++) { 1018 $row = @pg_fetch_row($result, $i); 1019 $keys = explode(' ', $row[2]); 1020 1021 if (in_array($num_field + 1, $keys)) { 1022 $flags .= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : ''; 1023 $flags .= ($row[1] == 't') ? 'primary_key ' : ''; 1024 if (count($keys) > 1) 1025 $flags .= 'multiple_key '; 1026 } 1027 } 1028 1029 return trim($flags); 1030 } 1031 1032 // }}} 1033 // {{{ getSpecialQuery() 1034 1035 /** 1036 * Obtains the query string needed for listing a given type of objects 1037 * 1038 * @param string $type the kind of objects you want to retrieve 1039 * 1040 * @return string the SQL query string or null if the driver doesn't 1041 * support the object type requested 1042 * 1043 * @access protected 1044 * @see DB_common::getListOf() 1045 */ 1046 function getSpecialQuery($type) 1047 { 1048 switch ($type) { 1049 case 'tables': 1050 return 'SELECT c.relname AS "Name"' 1051 . ' FROM pg_class c, pg_user u' 1052 . ' WHERE c.relowner = u.usesysid' 1053 . " AND c.relkind = 'r'" 1054 . ' AND NOT EXISTS' 1055 . ' (SELECT 1 FROM pg_views' 1056 . ' WHERE viewname = c.relname)' 1057 . " AND c.relname !~ '^(pg_|sql_)'" 1058 . ' UNION' 1059 . ' SELECT c.relname AS "Name"' 1060 . ' FROM pg_class c' 1061 . " WHERE c.relkind = 'r'" 1062 . ' AND NOT EXISTS' 1063 . ' (SELECT 1 FROM pg_views' 1064 . ' WHERE viewname = c.relname)' 1065 . ' AND NOT EXISTS' 1066 . ' (SELECT 1 FROM pg_user' 1067 . ' WHERE usesysid = c.relowner)' 1068 . " AND c.relname !~ '^pg_'"; 1069 case 'schema.tables': 1070 return "SELECT schemaname || '.' || tablename" 1071 . ' AS "Name"' 1072 . ' FROM pg_catalog.pg_tables' 1073 . ' WHERE schemaname NOT IN' 1074 . " ('pg_catalog', 'information_schema', 'pg_toast')"; 1075 case 'views': 1076 // Table cols: viewname | viewowner | definition 1077 return 'SELECT viewname from pg_views WHERE schemaname' 1078 . " NOT IN ('information_schema', 'pg_catalog')"; 1079 case 'users': 1080 // cols: usename |usesysid|usecreatedb|usetrace|usesuper|usecatupd|passwd |valuntil 1081 return 'SELECT usename FROM pg_user'; 1082 case 'databases': 1083 return 'SELECT datname FROM pg_database'; 1084 case 'functions': 1085 case 'procedures': 1086 return 'SELECT proname FROM pg_proc WHERE proowner <> 1'; 1087 default: 1088 return null; 1089 } 1090 } 1091 1092 // }}} 1093 1094 } 1095 1096 /* 1097 * Local variables: 1098 * tab-width: 4 1099 * c-basic-offset: 4 1100 * End: 1101 */ 1102 1103 ?>
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 |