[ Index ] |
|
Code source de PHP PEAR 1.4.5 |
1 <?php 2 // +----------------------------------------------------------------------+ 3 // | PHP Version 4 | 4 // +----------------------------------------------------------------------+ 5 // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox, | 6 // | Stig. S. Bakken, Lukas Smith | 7 // | All rights reserved. | 8 // +----------------------------------------------------------------------+ 9 // | MDB is a merge of PEAR DB and Metabases that provides a unified DB | 10 // | API as well as database abstraction for PHP applications. | 11 // | This LICENSE is in the BSD license style. | 12 // | | 13 // | Redistribution and use in source and binary forms, with or without | 14 // | modification, are permitted provided that the following conditions | 15 // | are met: | 16 // | | 17 // | Redistributions of source code must retain the above copyright | 18 // | notice, this list of conditions and the following disclaimer. | 19 // | | 20 // | Redistributions in binary form must reproduce the above copyright | 21 // | notice, this list of conditions and the following disclaimer in the | 22 // | documentation and/or other materials provided with the distribution. | 23 // | | 24 // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | 25 // | Lukas Smith nor the names of his contributors may be used to endorse | 26 // | or promote products derived from this software without specific prior| 27 // | written permission. | 28 // | | 29 // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 30 // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 31 // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 32 // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 33 // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 34 // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 35 // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| 36 // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 37 // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 38 // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| 39 // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 40 // | POSSIBILITY OF SUCH DAMAGE. | 41 // +----------------------------------------------------------------------+ 42 // | Author: Paul Cooper <pgc@ucecom.com> | 43 // +----------------------------------------------------------------------+ 44 // 45 // $Id: pgsql.php,v 1.62.4.20 2004/03/12 16:19:30 lsmith Exp $ 46 47 require_once ('MDB/Common.php'); 48 49 /** 50 * MDB PostGreSQL driver 51 * 52 * Notes: 53 * - Creation of new databases is based on database template1. 54 * 55 * - The decimal type fields are emulated with integer fields. 56 * 57 * - PostgreSQL stores large objects in files managed by the server. 58 * Tables with large object fields only store identifiers pointing to those 59 * files. If you delete or update rows of those tables, the actual large 60 * object files are not deleted from the server file system. Therefore you may 61 * need to reclaim large object field space by deleting those files manually. 62 * 63 * @package MDB 64 * @category Database 65 * @author Paul Cooper <pgc@ucecom.com> 66 */ 67 68 class MDB_pgsql extends MDB_Common 69 { 70 var $connection = 0; 71 var $connected_host; 72 var $connected_port; 73 var $selected_database = ''; 74 var $opened_persistent = ''; 75 76 var $escape_quotes = "\\"; 77 var $decimal_factor = 1.0; 78 79 var $highest_fetched_row = array(); 80 var $columns = array(); 81 82 // }}} 83 // {{{ constructor 84 85 /** 86 * Constructor 87 */ 88 function MDB_pgsql() 89 { 90 $this->MDB_Common(); 91 $this->phptype = 'pgsql'; 92 $this->dbsyntax = 'pgsql'; 93 94 $this->supported['Sequences'] = 1; 95 $this->supported['Indexes'] = 1; 96 $this->supported['SummaryFunctions'] = 1; 97 $this->supported['OrderByText'] = 1; 98 $this->supported['Transactions'] = 1; 99 $this->supported['CurrId'] = 1; 100 $this->supported['SelectRowRanges'] = 1; 101 $this->supported['LOBs'] = 1; 102 $this->supported['Replace'] = 1; 103 $this->supported['SubSelects'] = 1; 104 105 $this->decimal_factor = pow(10.0, $this->decimal_places); 106 } 107 108 // }}} 109 // {{{ errorCode() 110 111 /** 112 * Map native error codes to DB's portable ones. Requires that 113 * the DB implementation's constructor fills in the $errorcode_map 114 * property. 115 * 116 * @param $nativecode the native error code, as returned by the backend 117 * database extension (string or integer) 118 * @return int a portable MDB error code, or FALSE if this DB 119 * implementation has no mapping for the given error code. 120 */ 121 function errorCode($errormsg) 122 { 123 static $error_regexps; 124 if (empty($error_regexps)) { 125 $error_regexps = array( 126 '/([Tt]able does not exist\.|[Rr]elation [\"\'].*[\"\'] does not exist|[Ss]equence does not exist|[Cc]lass ".+" not found)$/' => MDB_ERROR_NOSUCHTABLE, 127 '/[Tt]able [\"\'].*[\"\'] does not exist/' => MDB_ERROR_NOSUCHTABLE, 128 '/[Rr]elation [\"\'].*[\"\'] already exists|[Cc]annot insert a duplicate key into (a )?unique index.*/' => MDB_ERROR_ALREADY_EXISTS, 129 '/divide by zero$/' => MDB_ERROR_DIVZERO, 130 '/pg_atoi: error in .*: can\'t parse /' => MDB_ERROR_INVALID_NUMBER, 131 '/ttribute [\"\'].*[\"\'] not found$|[Rr]elation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => MDB_ERROR_NOSUCHFIELD, 132 '/parser: parse error at or near \"/' => MDB_ERROR_SYNTAX, 133 '/syntax error at/' => MDB_ERROR_SYNTAX, 134 '/violates not-null constraint/' => MDB_ERROR_CONSTRAINT_NOT_NULL, 135 '/violates [\w ]+ constraint/' => MDB_ERROR_CONSTRAINT, 136 '/referential integrity violation/' => MDB_ERROR_CONSTRAINT, 137 '/deadlock detected/' => MDB_ERROR_DEADLOCK 138 ); 139 } 140 foreach ($error_regexps as $regexp => $code) { 141 if (preg_match($regexp, $errormsg)) { 142 return($code); 143 } 144 } 145 // Fall back to MDB_ERROR if there was no mapping. 146 return(MDB_ERROR); 147 } 148 149 // }}} 150 // {{{ pgsqlRaiseError() 151 152 /** 153 * This method is used to communicate an error and invoke error 154 * callbacks etc. Basically a wrapper for MDB::raiseError 155 * that checks for native error msgs. 156 * 157 * @param integer $errno error code 158 * @param string $message userinfo message 159 * @return object a PEAR error object 160 * @access public 161 * @see PEAR_Error 162 */ 163 function pgsqlRaiseError($errno = NULL, $message = NULL) 164 { 165 if ($this->connection) { 166 $error = @pg_errormessage($this->connection); 167 } else { 168 $error = @pg_errormessage(); 169 } 170 return($this->raiseError($this->errorCode($error), NULL, NULL, $message, $error)); 171 } 172 173 // }}} 174 // {{{ errorNative() 175 176 /** 177 * Get the native error code of the last error (if any) that 178 * occured on the current connection. 179 * 180 * @access public 181 * 182 * @return int native pgsql error code 183 */ 184 function errorNative() 185 { 186 return @pg_errormessage($this->connection); 187 } 188 189 190 // }}} 191 // {{{ autoCommit() 192 193 /** 194 * Define whether database changes done on the database be automatically 195 * committed. This function may also implicitly start or end a transaction. 196 * 197 * @param boolean $auto_commit flag that indicates whether the database 198 * changes should be committed right after executing every query 199 * statement. If this argument is 0 a transaction implicitly started. 200 * Otherwise, if a transaction is in progress it is ended by committing 201 * any database changes that were pending. 202 * @return mixed MDB_OK on success, a MDB error on failure 203 * @access public 204 */ 205 function autoCommit($auto_commit) 206 { 207 $this->debug('AutoCommit: '.($auto_commit ? 'On' : 'Off')); 208 if ($this->auto_commit == $auto_commit) { 209 return(MDB_OK); 210 } 211 if ($this->connection) { 212 if (MDB::isError($result = $this->_doQuery($auto_commit ? 'END' : 'BEGIN'))) 213 return($result); 214 } 215 $this->auto_commit = $auto_commit; 216 $this->in_transaction = !$auto_commit; 217 return(MDB_OK); 218 } 219 220 // }}} 221 // {{{ commit() 222 223 /** 224 * Commit the database changes done during a transaction that is in 225 * progress. This function may only be called when auto-committing is 226 * disabled, otherwise it will fail. Therefore, a new transaction is 227 * implicitly started after committing the pending changes. 228 * 229 * @return mixed MDB_OK on success, a MDB error on failure 230 * @access public 231 */ 232 function commit() 233 { 234 $this->debug('Commit Transaction'); 235 if ($this->auto_commit) { 236 return($this->raiseError(MDB_ERROR, NULL, NULL, 'Commit: transaction changes are being auto commited')); 237 } 238 return($this->_doQuery('COMMIT') && $this->_doQuery('BEGIN')); 239 } 240 241 // }}} 242 // {{{ rollback() 243 244 /** 245 * Cancel any database changes done during a transaction that is in 246 * progress. This function may only be called when auto-committing is 247 * disabled, otherwise it will fail. Therefore, a new transaction is 248 * implicitly started after canceling the pending changes. 249 * 250 * @return mixed MDB_OK on success, a MDB error on failure 251 * @access public 252 */ 253 function rollback() 254 { 255 $this->debug('Rollback Transaction'); 256 if ($this->auto_commit) { 257 return($this->raiseError(MDB_ERROR, NULL, NULL, 'Rollback: transactions can not be rolled back when changes are auto commited')); 258 } 259 return($this->_doQuery('ROLLBACK') && $this->_doQuery('BEGIN')); 260 } 261 262 // }}} 263 // {{{ _doConnect() 264 265 /** 266 * Does the grunt work of connecting to the database 267 * 268 * @return mixed connection resource on success, MDB_Error on failure 269 * @access private 270 **/ 271 function _doConnect($database_name, $persistent) 272 { 273 $function = ($persistent ? 'pg_pconnect' : 'pg_connect'); 274 if (!function_exists($function)) { 275 return($this->raiseError(MDB_ERROR_UNSUPPORTED, NULL, NULL, 'doConnect: PostgreSQL support is not available in this PHP configuration')); 276 } 277 $port = (isset($this->port) ? $this->port : ''); 278 if ($database_name == '') { 279 $database_name = 'template1'; 280 } 281 $connect_string = 'dbname='.$database_name; 282 if ($this->host != '') { 283 $connect_string .= ' host='.$this->host; 284 } 285 if ($port != '') { 286 $connect_string .= ' port='.strval($port); 287 } 288 if ($this->user != '') { 289 $connect_string .= ' user='.$this->user; 290 } 291 if ($this->password != '') { 292 $connect_string .= ' password='.$this->password; 293 } 294 putenv('PGDATESTYLE=ISO'); 295 if (($connection = @$function($connect_string)) > 0) { 296 return($connection); 297 } 298 if (isset($php_errormsg)) { 299 $error_msg = $php_errormsg; 300 } else { 301 $error_msg = 'Could not connect to PostgreSQL server'; 302 } 303 return($this->raiseError(MDB_ERROR_CONNECT_FAILED, NULL, NULL, 'doConnect: '.$error_msg)); 304 } 305 306 // }}} 307 // {{{ connect() 308 309 /** 310 * Connect to the database 311 * 312 * @return TRUE on success, MDB_Error on failure 313 * @access public 314 **/ 315 function connect() 316 { 317 $port = (isset($this->options['port']) ? $this->options['port'] : ''); 318 if($this->connection != 0) { 319 if (!strcmp($this->connected_host, $this->host) 320 && !strcmp($this->connected_port, $port) 321 && !strcmp($this->selected_database, $this->database_name) 322 && ($this->opened_persistent == $this->options['persistent'])) 323 { 324 return(MDB_OK); 325 } 326 @pg_close($this->connection); 327 $this->affected_rows = -1; 328 $this->connection = 0; 329 } 330 331 if(!PEAR::loadExtension($this->phptype)) { 332 return(PEAR::raiseError(NULL, MDB_ERROR_NOT_FOUND, 333 NULL, NULL, 'extension '.$this->phptype.' is not compiled into PHP', 334 'MDB_Error', TRUE)); 335 } 336 337 if(function_exists('pg_cmdTuples')) { 338 $connection = $this->_doConnect('template1', 0); 339 if (!MDB::isError($connection)) { 340 if (($result = @pg_exec($connection, 'BEGIN'))) { 341 $error_reporting = error_reporting(63); 342 @pg_cmdtuples($result); 343 if (!isset($php_errormsg) || strcmp($php_errormsg, 'This compilation does not support pg_cmdtuples()')) { 344 $this->supported['AffectedRows'] = 1; 345 } 346 error_reporting($error_reporting); 347 } else { 348 $err = $this->raiseError(MDB_ERROR, NULL, NULL, 'Setup: '.@pg_errormessage($connection)); 349 } 350 @pg_close($connection); 351 } else { 352 $err = $this->raiseError(MDB_ERROR, NULL, NULL, 'Setup: could not execute BEGIN'); 353 } 354 if (isset($err) && MDB::isError($err)) { 355 return($err); 356 } 357 } 358 $connection = $this->_doConnect($this->database_name, $this->options['persistent']); 359 if (MDB::isError($connection)) { 360 return($connection); 361 } 362 $this->connection = $connection; 363 364 if (!$this->auto_commit && MDB::isError($trans_result = $this->_doQuery('BEGIN'))) { 365 pg_Close($this->connection); 366 $this->connection = 0; 367 $this->affected_rows = -1; 368 return($trans_result); 369 } 370 $this->connected_host = $this->host; 371 $this->connected_port = $port; 372 $this->selected_database = $this->database_name; 373 $this->opened_persistent = $this->options['persistent']; 374 return(MDB_OK); 375 } 376 377 // }}} 378 // {{{ _close() 379 /** 380 * Close the database connection 381 * 382 * @return boolean 383 * @access private 384 **/ 385 function _close() 386 { 387 if ($this->connection != 0) { 388 if (!$this->auto_commit) { 389 $this->_doQuery('END'); 390 } 391 @pg_close($this->connection); 392 $this->connection = 0; 393 $this->affected_rows = -1; 394 395 unset($GLOBALS['_MDB_databases'][$this->database]); 396 return(MDB_OK); 397 } 398 return(MDB_ERROR); 399 } 400 401 // }}} 402 // {{{ _doQuery() 403 404 /** 405 * Execute a query 406 * @param string $query the SQL query 407 * @return mixed result identifier if query executed, else MDB_error 408 * @access private 409 **/ 410 function _doQuery($query) 411 { 412 if (($result = @pg_Exec($this->connection, $query))) { 413 $this->affected_rows = (isset($this->supported['AffectedRows']) ? @pg_cmdtuples($result) : -1); 414 } else { 415 $error = @pg_errormessage($this->connection); 416 return($this->pgsqlRaiseError()); 417 } 418 return($result); 419 } 420 421 // }}} 422 // {{{ _standaloneQuery() 423 424 /** 425 * execute a query 426 * 427 * @param string $query 428 * @return 429 * @access private 430 */ 431 function _standaloneQuery($query) 432 { 433 if (($connection = $this->_doConnect('template1', 0)) == 0) { 434 return($this->raiseError(MDB_ERROR_CONNECT_FAILED, NULL, NULL, '_standaloneQuery: Cannot connect to template1')); 435 } 436 if (!($result = @pg_Exec($connection, $query))) { 437 $this->raiseError(MDB_ERROR, NULL, NULL, '_standaloneQuery: ' . @pg_errormessage($connection)); 438 } 439 pg_Close($connection); 440 return($result); 441 } 442 443 // }}} 444 // {{{ query() 445 446 /** 447 * Send a query to the database and return any results 448 * 449 * @param string $query the SQL query 450 * @param array $types array that contains the types of the columns in 451 * the result set 452 * @return mixed result identifier if query executed, else MDB_error 453 * @access public 454 **/ 455 function query($query, $types = NULL) 456 { 457 $this->debug("Query: $query"); 458 $ismanip = MDB::isManip($query); 459 $this->last_query = $query; 460 $first = $this->first_selected_row; 461 $limit = $this->selected_row_limit; 462 $this->first_selected_row = $this->selected_row_limit = 0; 463 $connected = $this->connect(); 464 if (MDB::isError($connected)) { 465 return($connected); 466 } 467 468 if (!$ismanip && $limit > 0) { 469 if ($this->auto_commit && MDB::isError($this->_doQuery('BEGIN'))) { 470 return($this->raiseError(MDB_ERROR)); 471 } 472 $result = $this->_doQuery('DECLARE select_cursor SCROLL CURSOR FOR '.$query); 473 if (!MDB::isError($result)) { 474 if ($first > 0 && MDB::isError($result = $this->_doQuery("MOVE FORWARD $first FROM select_cursor"))) { 475 $this->freeResult($result); 476 return($result); 477 } 478 if (MDB::isError($result = $this->_doQuery("FETCH FORWARD $limit FROM select_cursor"))) { 479 $this->freeResult($result); 480 return($result); 481 } 482 } else { 483 return($result); 484 } 485 if ($this->auto_commit && MDB::isError($result2 = $this->_doQuery('END'))) { 486 $this->freeResult($result); 487 return($result2); 488 } 489 } else { 490 $result = $this->_doQuery($query); 491 if (MDB::isError($result)) { 492 return($result); 493 } 494 } 495 if ($ismanip) { 496 $this->affected_rows = @pg_cmdtuples($result); 497 return(MDB_OK); 498 } elseif ((preg_match('/^\s*\(?\s*SELECT\s+/si', $query) 499 && !preg_match('/^\s*\(?\s*SELECT\s+INTO\s/si', $query) 500 ) || preg_match('/^\s*EXPLAIN/si',$query ) 501 ) { 502 /* PostgreSQL commands: 503 ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY, 504 CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH, 505 GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET, 506 REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW, 507 UNLISTEN, UPDATE, VACUUM 508 */ 509 $result_value = intval($result); 510 $this->highest_fetched_row[$result_value] = -1; 511 if ($types != NULL) { 512 if (!is_array($types)) { 513 $types = array($types); 514 } 515 if (MDB::isError($err = $this->setResultTypes($result, $types))) { 516 $this->freeResult($result); 517 return($err); 518 } 519 } 520 return($result); 521 } else { 522 $this->affected_rows = 0; 523 return(MDB_OK); 524 } 525 return($this->raiseError(MDB_ERROR)); 526 } 527 528 // }}} 529 // {{{ getColumnNames() 530 531 /** 532 * Retrieve the names of columns returned by the DBMS in a query result. 533 * 534 * @param resource $result result identifier 535 * @return mixed associative array variable 536 * that holds the names of columns. The indexes of the array are 537 * the column names mapped to lower case and the values are the 538 * respective numbers of the columns starting from 0. Some DBMS may 539 * not return any columns when the result set does not contain any 540 * rows. 541 * a MDB error on failure 542 * @access public 543 */ 544 function getColumnNames($result) 545 { 546 $result_value = intval($result); 547 if (!isset($this->highest_fetched_row[$result_value])) { 548 return($this->raiseError(MDB_ERROR, NULL, NULL, 'Get Column Names: specified an nonexistant result set')); 549 } 550 if (!isset($this->columns[$result_value])) { 551 $this->columns[$result_value] = array(); 552 $columns = @pg_numfields($result); 553 for($column = 0; $column < $columns; $column++) { 554 $field_name = @pg_fieldname($result, $column); 555 if ($this->options['optimize'] == 'portability') { 556 $field_name = strtolower($field_name); 557 } 558 $this->columns[$result_value][$field_name] = $column; 559 } 560 } 561 return($this->columns[$result_value]); 562 } 563 564 // }}} 565 // {{{ numCols() 566 567 /** 568 * Count the number of columns returned by the DBMS in a query result. 569 * 570 * @param resource $result result identifier 571 * @return mixed integer value with the number of columns, a MDB error 572 * on failure 573 * @access public 574 */ 575 function numCols($result) 576 { 577 $result_value = intval($result); 578 if (!isset($this->highest_fetched_row[$result_value])) { 579 return($this->raiseError(MDB_ERROR, NULL, NULL, 'numCols: specified an nonexistant result set')); 580 } 581 return(pg_numfields($result)); 582 } 583 584 // }}} 585 // {{{ endOfResult() 586 587 /** 588 * check if the end of the result set has been reached 589 * 590 * @param resource $result result identifier 591 * @return mixed TRUE or FALSE on sucess, a MDB error on failure 592 * @access public 593 */ 594 function endOfResult($result) 595 { 596 $result_value = intval($result); 597 if (!isset($this->highest_fetched_row[$result_value])) { 598 return($this->raiseError(MDB_ERROR, NULL, NULL, 'End of result attempted to check the end of an unknown result')); 599 } 600 return($this->highest_fetched_row[$result_value] >= $this->numRows($result) - 1); 601 } 602 603 // }}} 604 // {{{ fetch() 605 606 /** 607 * fetch value from a result set 608 * 609 * @param resource $result result identifier 610 * @param int $row number of the row where the data can be found 611 * @param int $field field number where the data can be found 612 * @return mixed string on success, a MDB error on failure 613 * @access public 614 */ 615 function fetch($result, $row, $field) 616 { 617 $result_value = intval($result); 618 $this->highest_fetched_row[$result_value] = max($this->highest_fetched_row[$result_value], $row); 619 $res = @pg_result($result, $row, $field); 620 if ($res === FALSE && $res != NULL) { 621 return($this->pgsqlRaiseError()); 622 } 623 return($res); 624 } 625 626 // }}} 627 // {{{ _retrieveLob() 628 629 /** 630 * fetch a float value from a result set 631 * 632 * @param int $lob handle to a lob created by the createLob() function 633 * @return mixed MDB_OK on success, a MDB error on failure 634 * @access private 635 */ 636 function _retrieveLob($lob) 637 { 638 if (!isset($this->lobs[$lob])) { 639 return($this->raiseError(MDB_ERROR_INVALID, NULL, NULL, 640 'Retrieve LOB: did not specified a valid lob')); 641 } 642 if (!isset($this->lobs[$lob]['Value'])) { 643 if ($this->auto_commit) { 644 if (!@pg_exec($this->connection, 'BEGIN')) { 645 return($this->raiseError(MDB_ERROR, NULL, NULL, 646 'Retrieve LOB: ' . @pg_errormessage($this->connection))); 647 } 648 $this->lobs[$lob]['InTransaction'] = 1; 649 } 650 $this->lobs[$lob]['Value'] = $this->fetch($this->lobs[$lob]['Result'], $this->lobs[$lob]['Row'], $this->lobs[$lob]['Field']); 651 if (!($this->lobs[$lob]['Handle'] = @pg_loopen($this->connection, $this->lobs[$lob]['Value'], 'r'))) { 652 if (isset($this->lobs[$lob]['InTransaction'])) { 653 @pg_exec($this->connection, 'END'); 654 unset($this->lobs[$lob]['InTransaction']); 655 } 656 unset($this->lobs[$lob]['Value']); 657 return($this->raiseError(MDB_ERROR, NULL, NULL, 658 'Retrieve LOB: ' . @pg_errormessage($this->connection))); 659 } 660 } 661 return(MDB_OK); 662 } 663 664 // }}} 665 // {{{ endOfResultLob() 666 667 /** 668 * Determine whether it was reached the end of the large object and 669 * therefore there is no more data to be read for the its input stream. 670 * 671 * @param int $lob handle to a lob created by the createLob() function 672 * @return mixed TRUE or FALSE on success, a MDB error on failure 673 * @access public 674 */ 675 function endOfResultLob($lob) 676 { 677 $lobresult = $this->_retrieveLob($lob); 678 if (MDB::isError($lobresult)) { 679 return($lobresult); 680 } 681 return(isset($this->lobs[$lob]['EndOfLOB'])); 682 } 683 684 // }}} 685 // {{{ _readResultLob() 686 687 /** 688 * Read data from large object input stream. 689 * 690 * @param int $lob handle to a lob created by the createLob() function 691 * @param blob $data reference to a variable that will hold data to be 692 * read from the large object input stream 693 * @param int $length integer value that indicates the largest ammount of 694 * data to be read from the large object input stream. 695 * @return mixed length on success, a MDB error on failure 696 * @access private 697 */ 698 function _readResultLob($lob, &$data, $length) 699 { 700 $lobresult = $this->_retrieveLob($lob); 701 if (MDB::isError($lobresult)) { 702 return($lobresult); 703 } 704 $data = @pg_loread($this->lobs[$lob]['Handle'], $length); 705 if (gettype($data) != 'string') { 706 $this->raiseError(MDB_ERROR, NULL, NULL, 707 'Read Result LOB: ' . @pg_errormessage($this->connection)); 708 } 709 if (($length = strlen($data)) == 0) { 710 $this->lobs[$lob]['EndOfLOB'] = 1; 711 } 712 return($length); 713 } 714 715 // }}} 716 // {{{ _destroyResultLob() 717 718 /** 719 * Free any resources allocated during the lifetime of the large object 720 * handler object. 721 * 722 * @param int $lob handle to a lob created by the createLob() function 723 * @access private 724 */ 725 function _destroyResultLob($lob) 726 { 727 if (isset($this->lobs[$lob])) { 728 if (isset($this->lobs[$lob]['Value'])) { 729 @pg_loclose($this->lobs[$lob]['Handle']); 730 if (isset($this->lobs[$lob]['InTransaction'])) { 731 @pg_exec($this->connection, 'END'); 732 } 733 } 734 $this->lobs[$lob] = ''; 735 } 736 } 737 738 // }}} 739 // {{{ fetchClob() 740 741 /** 742 * fetch a clob value from a result set 743 * 744 * @param resource $result result identifier 745 * @param int $row number of the row where the data can be found 746 * @param int $field field number where the data can be found 747 * @return mixed content of the specified data cell, a MDB error on failure, 748 * a MDB error on failure 749 * @access public 750 */ 751 function fetchClob($result, $row, $field) 752 { 753 return($this->fetchLob($result, $row, $field)); 754 } 755 756 // }}} 757 // {{{ fetchBlob() 758 759 /** 760 * fetch a blob value from a result set 761 * 762 * @param resource $result result identifier 763 * @param int $row number of the row where the data can be found 764 * @param int $field field number where the data can be found 765 * @return mixed content of the specified data cell, a MDB error on failure 766 * @access public 767 */ 768 function fetchBlob($result, $row, $field) 769 { 770 return($this->fetchLob($result, $row, $field)); 771 } 772 773 // }}} 774 // {{{ convertResult() 775 776 /** 777 * convert a value to a RDBMS indepdenant MDB type 778 * 779 * @param mixed $value value to be converted 780 * @param int $type constant that specifies which type to convert to 781 * @return mixed converted value or a MDB error on failure 782 * @access public 783 */ 784 function convertResult($value, $type) 785 { 786 switch ($type) { 787 case MDB_TYPE_DECIMAL: 788 return(sprintf('%.'.$this->decimal_places.'f',doubleval($value)/$this->decimal_factor)); 789 case MDB_TYPE_TIMESTAMP: 790 return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS')); 791 default: 792 return($this->_baseConvertResult($value, $type)); 793 } 794 } 795 796 // }}} 797 // {{{ resultIsNull() 798 799 /** 800 * Determine whether the value of a query result located in given row and 801 * field is a NULL. 802 * 803 * @param resource $result result identifier 804 * @param int $row number of the row where the data can be found 805 * @param int $field field number where the data can be found 806 * @return mixed TRUE or FALSE on success, a MDB error on failure 807 * @access public 808 */ 809 function resultIsNull($result, $row, $field) 810 { 811 $result_value = intval($result); 812 $this->highest_fetched_row[$result_value] = max($this->highest_fetched_row[$result_value], $row); 813 return(@pg_fieldisnull($result, $row, $field)); 814 } 815 816 // }}} 817 // {{{ numRows() 818 819 /** 820 * returns the number of rows in a result object 821 * 822 * @param ressource $result a valid result ressouce pointer 823 * @return mixed MDB_Error or the number of rows 824 * @access public 825 */ 826 function numRows($result) 827 { 828 return(@pg_numrows($result)); 829 } 830 831 // }}} 832 // {{{ freeResult() 833 834 /** 835 * Free the internal resources associated with $result. 836 * 837 * @param $result result identifier 838 * @return boolean TRUE on success, FALSE if $result is invalid 839 * @access public 840 */ 841 function freeResult($result) 842 { 843 $result_value = intval($result); 844 if(isset($this->highest_fetched_row[$result_value])) { 845 unset($this->highest_fetched_row[$result_value]); 846 } 847 if(isset($this->columns[$result_value])) { 848 unset($this->columns[$result_value]); 849 } 850 if(isset($this->result_types[$result_value])) { 851 unset($this->result_types[$result_value]); 852 } 853 return(@pg_freeresult($result)); 854 } 855 856 // }}} 857 // {{{ getTextDeclaration() 858 859 /** 860 * Obtain DBMS specific SQL code portion needed to declare an text type 861 * field to be used in statements like CREATE TABLE. 862 * 863 * @param string $name name the field to be declared. 864 * @param string $field associative array with the name of the properties 865 * of the field being declared as array indexes. Currently, the types 866 * of supported field properties are as follows: 867 * 868 * length 869 * Integer value that determines the maximum length of the text 870 * field. If this argument is missing the field should be 871 * declared to have the longest length allowed by the DBMS. 872 * 873 * default 874 * Text value to be used as default for this field. 875 * 876 * notnull 877 * Boolean flag that indicates whether this field is constrained 878 * to not be set to NULL. 879 * @return string DBMS specific SQL code portion that should be used to 880 * declare the specified field. 881 * @access public 882 */ 883 function getTextDeclaration($name, $field) 884 { 885 return((isset($field['length']) ? "$name VARCHAR (" . $field['length'] . ')' : "$name TEXT") . (isset($field['default']) ? " DEFAULT '" . $field['default'] . "'" : '') . (isset($field['notnull']) ? ' NOT NULL' : '')); 886 } 887 888 // }}} 889 // {{{ getClobDeclaration() 890 891 /** 892 * Obtain DBMS specific SQL code portion needed to declare an character 893 * large object type field to be used in statements like CREATE TABLE. 894 * 895 * @param string $name name the field to be declared. 896 * @param string $field associative array with the name of the properties 897 * of the field being declared as array indexes. Currently, the types 898 * of supported field properties are as follows: 899 * 900 * length 901 * Integer value that determines the maximum length of the large 902 * object field. If this argument is missing the field should be 903 * declared to have the longest length allowed by the DBMS. 904 * 905 * notnull 906 * Boolean flag that indicates whether this field is constrained 907 * to not be set to NULL. 908 * @return string DBMS specific SQL code portion that should be used to 909 * declare the specified field. 910 * @access public 911 */ 912 function getClobDeclaration($name, $field) 913 { 914 return("$name OID".(isset($field['notnull']) ? ' NOT NULL' : '')); 915 } 916 917 // }}} 918 // {{{ getBlobDeclaration() 919 920 /** 921 * Obtain DBMS specific SQL code portion needed to declare an binary large 922 * object type field to be used in statements like CREATE TABLE. 923 * 924 * @param string $name name the field to be declared. 925 * @param string $field associative array with the name of the properties 926 * of the field being declared as array indexes. Currently, the types 927 * of supported field properties are as follows: 928 * 929 * length 930 * Integer value that determines the maximum length of the large 931 * object field. If this argument is missing the field should be 932 * declared to have the longest length allowed by the DBMS. 933 * 934 * notnull 935 * Boolean flag that indicates whether this field is constrained 936 * to not be set to NULL. 937 * @return string DBMS specific SQL code portion that should be used to 938 * declare the specified field. 939 * @access public 940 */ 941 function getBlobDeclaration($name, $field) 942 { 943 return("$name OID".(isset($field['notnull']) ? ' NOT NULL' : '')); 944 } 945 946 // }}} 947 // {{{ getDateDeclaration() 948 949 /** 950 * Obtain DBMS specific SQL code portion needed to declare a date type 951 * field to be used in statements like CREATE TABLE. 952 * 953 * @param string $name name the field to be declared. 954 * @param string $field associative array with the name of the properties 955 * of the field being declared as array indexes. Currently, the types 956 * of supported field properties are as follows: 957 * 958 * default 959 * Date value to be used as default for this field. 960 * 961 * notnull 962 * Boolean flag that indicates whether this field is constrained 963 * to not be set to NULL. 964 * @return string DBMS specific SQL code portion that should be used to 965 * declare the specified field. 966 * @access public 967 */ 968 function getDateDeclaration($name, $field) 969 { 970 return($name.' DATE'.(isset($field['default']) ? ' DEFAULT \''.$field['default'] . "'" : '').(isset($field['notnull']) ? ' NOT NULL' : '')); 971 } 972 973 // }}} 974 // {{{ getTimeDeclaration() 975 976 /** 977 * Obtain DBMS specific SQL code portion needed to declare a time 978 * field to be used in statements like CREATE TABLE. 979 * 980 * @param string $name name the field to be declared. 981 * @param string $field associative array with the name of the properties 982 * of the field being declared as array indexes. Currently, the types 983 * of supported field properties are as follows: 984 * 985 * default 986 * Time value to be used as default for this field. 987 * 988 * notnull 989 * Boolean flag that indicates whether this field is constrained 990 * to not be set to NULL. 991 * @return string DBMS specific SQL code portion that should be used to 992 * declare the specified field. 993 * @access public 994 */ 995 function getTimeDeclaration($name, $field) 996 { 997 return($name.' TIME'.(isset($field['default']) ? ' DEFAULT \''.$field['default'].'\'' : '').(isset($field['notnull']) ? ' NOT NULL' : '')); 998 } 999 1000 // }}} 1001 // {{{ getFloatDeclaration() 1002 1003 /** 1004 * Obtain DBMS specific SQL code portion needed to declare a float type 1005 * field to be used in statements like CREATE TABLE. 1006 * 1007 * @param string $name name the field to be declared. 1008 * @param string $field associative array with the name of the properties 1009 * of the field being declared as array indexes. Currently, the types 1010 * of supported field properties are as follows: 1011 * 1012 * default 1013 * Float value to be used as default for this field. 1014 * 1015 * notnull 1016 * Boolean flag that indicates whether this field is constrained 1017 * to not be set to NULL. 1018 * @return string DBMS specific SQL code portion that should be used to 1019 * declare the specified field. 1020 * @access public 1021 */ 1022 function getFloatDeclaration($name, $field) 1023 { 1024 return("$name FLOAT8 ".(isset($field['default']) ? ' DEFAULT '.$this->getFloatValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : '')); 1025 } 1026 1027 // }}} 1028 // {{{ getDecimalDeclaration() 1029 1030 /** 1031 * Obtain DBMS specific SQL code portion needed to declare a decimal type 1032 * field to be used in statements like CREATE TABLE. 1033 * 1034 * @param string $name name the field to be declared. 1035 * @param string $field associative array with the name of the properties 1036 * of the field being declared as array indexes. Currently, the types 1037 * of supported field properties are as follows: 1038 * 1039 * default 1040 * Decimal value to be used as default for this field. 1041 * 1042 * notnull 1043 * Boolean flag that indicates whether this field is constrained 1044 * to not be set to NULL. 1045 * @return string DBMS specific SQL code portion that should be used to 1046 * declare the specified field. 1047 * @access public 1048 */ 1049 function getDecimalDeclaration($name, $field) 1050 { 1051 return("$name INT8 ".(isset($field['default']) ? ' DEFAULT '.$this->getDecimalValue($field['default']) : '').(isset($field['notnull']) ? ' NOT NULL' : '')); 1052 } 1053 1054 // }}} 1055 // {{{ _getLobValue() 1056 1057 /** 1058 * Convert a text value into a DBMS specific format that is suitable to 1059 * compose query statements. 1060 * 1061 * @param resource $prepared_query query handle from prepare() 1062 * @param $parameter 1063 * @param $lob 1064 * @return string text string that represents the given argument value in 1065 * a DBMS specific format. 1066 * @access private 1067 */ 1068 function _getLobValue($prepared_query, $parameter, $lob) 1069 { 1070 $connect = $this->connect(); 1071 if (MDB::isError($connect)) { 1072 return($connect); 1073 } 1074 if ($this->auto_commit && !@pg_exec($this->connection, 'BEGIN')) { 1075 return($this->raiseError(MDB_ERROR, NULL, NULL, 1076 '_getLobValue: error starting transaction')); 1077 } 1078 if (($lo = @pg_locreate($this->connection))) { 1079 if (($handle = @pg_loopen($this->connection, $lo, 'w'))) { 1080 while (!$this->endOfLob($lob)) { 1081 $result = $this->readLob($lob, $data, $this->options['lob_buffer_length']); 1082 if (MDB::isError($result)) { 1083 break; 1084 } 1085 if (!@pg_lowrite($handle, $data)) { 1086 $result = $this->raiseError(MDB_ERROR, NULL, NULL, 1087 'Get LOB field value: ' . @pg_errormessage($this->connection)); 1088 break; 1089 } 1090 } 1091 @pg_loclose($handle); 1092 if (!MDB::isError($result)) { 1093 $value = strval($lo); 1094 } 1095 } else { 1096 $result = $this->raiseError(MDB_ERROR, NULL, NULL, 1097 'Get LOB field value: ' . @pg_errormessage($this->connection)); 1098 } 1099 if (MDB::isError($result)) { 1100 $result = @pg_lounlink($this->connection, $lo); 1101 } 1102 } else { 1103 $result = $this->raiseError(MDB_ERROR, NULL, NULL, 'Get LOB field value: ' . pg_ErrorMessage($this->connection)); 1104 } 1105 if ($this->auto_commit) { 1106 @pg_exec($this->connection, 'END'); 1107 } 1108 if (MDB::isError($result)) { 1109 return($result); 1110 } 1111 return($value); 1112 } 1113 1114 // }}} 1115 // {{{ getClobValue() 1116 1117 /** 1118 * Convert a text value into a DBMS specific format that is suitable to 1119 * compose query statements. 1120 * 1121 * @param resource $prepared_query query handle from prepare() 1122 * @param $parameter 1123 * @param $clob 1124 * @return string text string that represents the given argument value in 1125 * a DBMS specific format. 1126 * @access public 1127 */ 1128 function getClobValue($prepared_query, $parameter, $clob) 1129 { 1130 return($this->_getLobValue($prepared_query, $parameter, $clob)); 1131 } 1132 1133 // }}} 1134 // {{{ getBlobValue() 1135 1136 /** 1137 * Convert a text value into a DBMS specific format that is suitable to 1138 * compose query statements. 1139 * 1140 * @param resource $prepared_query query handle from prepare() 1141 * @param $parameter 1142 * @param $blob 1143 * @return string text string that represents the given argument value in 1144 * a DBMS specific format. 1145 * @access public 1146 */ 1147 function getBlobValue($prepared_query, $parameter, $blob) 1148 { 1149 return($this->_getLobValue($prepared_query, $parameter, $blob)); 1150 } 1151 1152 // }}} 1153 // {{{ getFloatValue() 1154 1155 /** 1156 * Convert a text value into a DBMS specific format that is suitable to 1157 * compose query statements. 1158 * 1159 * @param string $value text string value that is intended to be converted. 1160 * @return string text string that represents the given argument value in 1161 * a DBMS specific format. 1162 * @access public 1163 */ 1164 function getFloatValue($value) 1165 { 1166 return(($value === NULL) ? 'NULL' : $value); 1167 } 1168 1169 // }}} 1170 // {{{ getDecimalValue() 1171 1172 /** 1173 * Convert a text value into a DBMS specific format that is suitable to 1174 * compose query statements. 1175 * 1176 * @param string $value text string value that is intended to be converted. 1177 * @return string text string that represents the given argument value in 1178 * a DBMS specific format. 1179 * @access public 1180 */ 1181 function getDecimalValue($value) 1182 { 1183 return(($value === NULL) ? 'NULL' : strval(round($value*$this->decimal_factor))); 1184 } 1185 1186 // }}} 1187 // {{{ nextId() 1188 1189 /** 1190 * returns the next free id of a sequence 1191 * 1192 * @param string $seq_name name of the sequence 1193 * @param boolean $ondemand when TRUE the seqence is 1194 * automatic created, if it 1195 * not exists 1196 * @return mixed MDB_Error or id 1197 * @access public 1198 */ 1199 function nextId($seq_name, $ondemand = TRUE) 1200 { 1201 $seqname = $this->getSequenceName($seq_name); 1202 $repeat = 0; 1203 do { 1204 $this->pushErrorHandling(PEAR_ERROR_RETURN); 1205 $result = $this->query("SELECT NEXTVAL('$seqname')"); 1206 $this->popErrorHandling(); 1207 if ($ondemand && MDB::isError($result) && $result->getCode() == MDB_ERROR_NOSUCHTABLE) { 1208 $repeat = 1; 1209 $result = $this->createSequence($seq_name); 1210 if (MDB::isError($result)) { 1211 return($this->raiseError($result)); 1212 } 1213 } else { 1214 $repeat = 0; 1215 } 1216 } while ($repeat); 1217 if (MDB::isError($result)) { 1218 return($this->raiseError($result)); 1219 } 1220 return($this->fetchOne($result)); 1221 } 1222 1223 // }}} 1224 // {{{ currId() 1225 1226 /** 1227 * returns the current id of a sequence 1228 * 1229 * @param string $seq_name name of the sequence 1230 * @return mixed MDB_Error or id 1231 * @access public 1232 */ 1233 function currId($seq_name) 1234 { 1235 $seqname = $this->getSequenceName($seq_name); 1236 if (MDB::isError($result = $this->queryOne("SELECT last_value FROM $seqname"))) { 1237 return($this->raiseError(MDB_ERROR, NULL, NULL, 'currId: Unable to select from ' . $seqname) ); 1238 } 1239 if (!is_numeric($result)) { 1240 return($this->raiseError(MDB_ERROR, NULL, NULL, 'currId: could not find value in sequence table')); 1241 } 1242 return($result); 1243 } 1244 1245 // }}} 1246 // {{{ fetchInto() 1247 1248 /** 1249 * Fetch a row and return data in an array. 1250 * 1251 * @param resource $result result identifier 1252 * @param int $fetchmode ignored 1253 * @param int $rownum the row number to fetch 1254 * @return mixed data array or NULL on success, a MDB error on failure 1255 * @access public 1256 */ 1257 function fetchInto($result, $fetchmode = MDB_FETCHMODE_DEFAULT, $rownum = NULL) 1258 { 1259 $result_value = intval($result); 1260 if ($fetchmode == MDB_FETCHMODE_DEFAULT) { 1261 $fetchmode = $this->fetchmode; 1262 } 1263 1264 if (is_null($rownum)) { 1265 ++$this->highest_fetched_row[$result_value]; 1266 } else { 1267 $this->highest_fetched_row[$result_value] = 1268 max($this->highest_fetched_row[$result_value], $rownum); 1269 } 1270 1271 if ($fetchmode & MDB_FETCHMODE_ASSOC) { 1272 $row = @pg_fetch_array($result, $rownum, PGSQL_ASSOC); 1273 if (is_array($row) && $this->options['optimize'] == 'portability') { 1274 $row = array_change_key_case($row, CASE_LOWER); 1275 } 1276 } else { 1277 $row = @pg_fetch_row($result, $rownum); 1278 } 1279 1280 if (!$row) { 1281 if ($this->options['autofree']) { 1282 $this->freeResult($result); 1283 } 1284 return(NULL); 1285 } 1286 if (isset($this->result_types[$result_value])) { 1287 $row = $this->convertResultRow($result, $row); 1288 } 1289 return($row); 1290 } 1291 1292 // }}} 1293 // {{{ nextResult() 1294 1295 /** 1296 * Move the internal pgsql result pointer to the next available result 1297 * 1298 * @param a valid fbsql result resource 1299 * @return true if a result is available otherwise return false 1300 * @access public 1301 */ 1302 function nextResult($result) 1303 { 1304 return(FALSE); 1305 } 1306 1307 // }}} 1308 // {{{ tableInfo() 1309 1310 /** 1311 * returns meta data about the result set 1312 * 1313 * @param mixed $resource PostgreSQL result identifier or table name 1314 * @param mixed $mode depends on implementation 1315 * @return array an nested array, or a MDB error 1316 * @access public 1317 */ 1318 function tableInfo($result, $mode = NULL) 1319 { 1320 $count = 0; 1321 $id = 0; 1322 $res = array(); 1323 1324 /** 1325 * depending on $mode, metadata returns the following values: 1326 * 1327 * - mode is FALSE (default): 1328 * $result[]: 1329 * [0]['table'] table name 1330 * [0]['name'] field name 1331 * [0]['type'] field type 1332 * [0]['len'] field length 1333 * [0]['flags'] field flags 1334 * 1335 * - mode is MDB_TABLEINFO_ORDER 1336 * $result[]: 1337 * ['num_fields'] number of metadata records 1338 * [0]['table'] table name 1339 * [0]['name'] field name 1340 * [0]['type'] field type 1341 * [0]['len'] field length 1342 * [0]['flags'] field flags 1343 * ['order'][field name] index of field named 'field name' 1344 * The last one is used, if you have a field name, but no index. 1345 * Test: if (isset($result['meta']['myfield'])) { ... 1346 * 1347 * - mode is MDB_TABLEINFO_ORDERTABLE 1348 * the same as above. but additionally 1349 * ['ordertable'][table name][field name] index of field 1350 * named 'field name' 1351 * 1352 * this is, because if you have fields from different 1353 * tables with the same field name * they override each 1354 * other with MDB_TABLEINFO_ORDER 1355 * 1356 * you can combine MDB_TABLEINFO_ORDER and 1357 * MDB_TABLEINFO_ORDERTABLE with MDB_TABLEINFO_ORDER | 1358 * MDB_TABLEINFO_ORDERTABLE * or with MDB_TABLEINFO_FULL 1359 **/ 1360 1361 // if $result is a string, then we want information about a 1362 // table without a resultset 1363 if (is_string($result)) { 1364 $id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0"); 1365 if (empty($id)) { 1366 return($this->pgsqlRaiseError()); 1367 } 1368 } else { // else we want information about a resultset 1369 $id = $result; 1370 if (empty($id)) { 1371 return($this->pgsqlRaiseError()); 1372 } 1373 } 1374 1375 $count = @pg_numfields($id); 1376 1377 // made this IF due to performance (one if is faster than $count if's) 1378 if (empty($mode)) { 1379 for ($i = 0; $i < $count; $i++) { 1380 $res[$i]['table'] = (is_string($result)) ? $result : ''; 1381 $res[$i]['name'] = @pg_fieldname ($id, $i); 1382 $res[$i]['type'] = @pg_fieldtype ($id, $i); 1383 $res[$i]['len'] = @pg_fieldsize ($id, $i); 1384 $res[$i]['flags'] = (is_string($result)) ? $this->_pgFieldflags($id, $i, $result) : ''; 1385 } 1386 } else { // full 1387 $res['num_fields'] = $count; 1388 1389 for ($i = 0; $i < $count; $i++) { 1390 $res[$i]['table'] = (is_string($result)) ? $result : ''; 1391 $res[$i]['name'] = @pg_fieldname ($id, $i); 1392 $res[$i]['type'] = @pg_fieldtype ($id, $i); 1393 $res[$i]['len'] = @pg_fieldsize ($id, $i); 1394 $res[$i]['flags'] = (is_string($result)) ? $this->_pgFieldFlags($id, $i, $result) : ''; 1395 if ($mode & MDB_TABLEINFO_ORDER) { 1396 $res['order'][$res[$i]['name']] = $i; 1397 } 1398 if ($mode & MDB_TABLEINFO_ORDERTABLE) { 1399 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; 1400 } 1401 } 1402 } 1403 1404 // free the result only if we were called on a table 1405 if (is_string($result) && is_resource($id)) { 1406 @pg_freeresult($id); 1407 } 1408 return($res); 1409 } 1410 1411 // }}} 1412 // {{{ _pgFieldFlags() 1413 1414 /** 1415 * Flags of a Field 1416 * 1417 * @param int $resource PostgreSQL result identifier 1418 * @param int $num_field the field number 1419 * @return string The flags of the field ('not_null', 'default_xx', 'primary_key', 1420 * 'unique' and 'multiple_key' are supported) 1421 * @access private 1422 **/ 1423 function _pgFieldFlags($resource, $num_field, $table_name) 1424 { 1425 $field_name = @pg_fieldname($resource, $num_field); 1426 1427 $result = pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef 1428 FROM pg_attribute f, pg_class tab, pg_type typ 1429 WHERE tab.relname = typ.typname 1430 AND typ.typrelid = f.attrelid 1431 AND f.attname = '$field_name' 1432 AND tab.relname = '$table_name'"); 1433 if (@pg_numrows($result) > 0) { 1434 $row = @pg_fetch_row($result, 0); 1435 $flags = ($row[0] == 't') ? 'not_null ' : ''; 1436 1437 if ($row[1] == 't') { 1438 $result = @pg_exec($this->connection, "SELECT a.adsrc 1439 FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a 1440 WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid 1441 AND f.attrelid = a.adrelid AND f.attname = '$field_name' 1442 AND tab.relname = '$table_name'"); 1443 $row = @pg_fetch_row($result, 0); 1444 $num = str_replace('\'', '', $row[0]); 1445 1446 $flags .= "default_$num "; 1447 } 1448 } 1449 $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey 1450 FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i 1451 WHERE tab.relname = typ.typname 1452 AND typ.typrelid = f.attrelid 1453 AND f.attrelid = i.indrelid 1454 AND f.attname = '$field_name' 1455 AND tab.relname = '$table_name'"); 1456 $count = @pg_numrows($result); 1457 1458 for ($i = 0; $i < $count ; $i++) { 1459 $row = @pg_fetch_row($result, $i); 1460 $keys = explode(' ', $row[2]); 1461 1462 if (in_array($num_field + 1, $keys)) { 1463 $flags .= ($row[0] == 't') ? 'unique ' : ''; 1464 $flags .= ($row[1] == 't') ? 'primary ' : ''; 1465 if (count($keys) > 1) 1466 $flags .= 'multiple_key '; 1467 } 1468 } 1469 1470 return trim($flags); 1471 } 1472 } 1473 1474 ?>
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 |