3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
6 * The PEAR DB driver for PHP's pgsql extension
7 * for interacting with PostgreSQL databases
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.
19 * @author Rui Hirokawa <hirokawa@php.net>
20 * @author Stig Bakken <ssb@php.net>
21 * @author Daniel Convissor <danielc@php.net>
22 * @copyright 1997-2007 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.139 2007/11/28 02:19:44 aharvey Exp $
25 * @link http://pear.php.net/package/DB
29 * Obtain the DB_common class so it can be extended from
31 require_once 'DB/common.php';
34 * The methods PEAR DB uses to interact with PHP's pgsql extension
35 * for interacting with PostgreSQL databases
37 * These methods overload the ones declared in DB_common.
41 * @author Rui Hirokawa <hirokawa@php.net>
42 * @author Stig Bakken <ssb@php.net>
43 * @author Daniel Convissor <danielc@php.net>
44 * @copyright 1997-2007 The PHP Group
45 * @license http://www.php.net/license/3_0.txt PHP License 3.0
46 * @version Release: 1.7.14RC1
47 * @link http://pear.php.net/package/DB
49 class DB_pgsql extends DB_common
54 * The DB driver type (mysql, oci8, odbc, etc.)
57 var $phptype = 'pgsql';
60 * The database syntax variant to be used (db2, access, etc.), if any
63 var $dbsyntax = 'pgsql';
66 * The capabilities of this DB implementation
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.
71 * Meaning of the 'limit' element:
72 * + 'emulate' = emulate with fetch row by number
73 * + 'alter' = alter the query
78 var $features = array(
80 'new_link' => '4.3.0',
85 'transactions' => true,
89 * A mapping of native error codes to DB error codes
92 var $errorcode_map = array(
96 * The raw database connection created by PHP
102 * The DSN information for connecting to a database
109 * Should data manipulation queries be committed automatically?
113 var $autocommit = true;
116 * The quantity of transactions begun
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.}}
124 var $transaction_opcount = 0;
127 * The number of rows affected by a data manipulation query
133 * The current row being looked at in fetchInto()
140 * The number of rows in a given result set
144 var $_num_rows = array();
151 * This constructor calls <kbd>$this->DB_common()</kbd>
164 * Connect to the database server, log in and open the database
166 * Don't call this method directly. Use DB::connect() instead.
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.
187 * Example of connecting to a new link via a socket:
189 * require_once 'DB.php';
191 * $dsn = 'pgsql://user:pass@unix(/tmp)/dbname?new_link=true';
193 * 'portability' => DB_PORTABILITY_ALL,
196 * $db = DB::connect($dsn, $options);
197 * if (PEAR::isError($db)) {
198 * die($db->getMessage());
202 * @param array $dsn the data source name
203 * @param bool $persistent should the connection be persistent?
205 * @return int DB_OK on success. A DB_Error object on failure.
207 * @link http://www.postgresql.org/docs/current/static/libpq.html#LIBPQ-CONNECT
209 function connect($dsn, $persistent = false)
211 if (!PEAR::loadExtension('pgsql')) {
212 return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
216 if ($dsn['dbsyntax']) {
217 $this->dbsyntax = $dsn['dbsyntax'];
220 $protocol = $dsn['protocol'] ? $dsn['protocol'] : 'tcp';
223 if ($protocol == 'tcp') {
224 if ($dsn['hostspec']) {
225 $params[0] .= 'host=' . $dsn['hostspec'];
228 $params[0] .= ' port=' . $dsn['port'];
230 } elseif ($protocol == 'unix') {
231 // Allow for pg socket in non-standard locations.
232 if ($dsn['socket']) {
233 $params[0] .= 'host=' . $dsn['socket'];
236 $params[0] .= ' port=' . $dsn['port'];
239 if ($dsn['database']) {
240 $params[0] .= ' dbname=\'' . addslashes($dsn['database']) . '\'';
242 if ($dsn['username']) {
243 $params[0] .= ' user=\'' . addslashes($dsn['username']) . '\'';
245 if ($dsn['password']) {
246 $params[0] .= ' password=\'' . addslashes($dsn['password']) . '\'';
248 if (!empty($dsn['options'])) {
249 $params[0] .= ' options=' . $dsn['options'];
251 if (!empty($dsn['tty'])) {
252 $params[0] .= ' tty=' . $dsn['tty'];
254 if (!empty($dsn['connect_timeout'])) {
255 $params[0] .= ' connect_timeout=' . $dsn['connect_timeout'];
257 if (!empty($dsn['sslmode'])) {
258 $params[0] .= ' sslmode=' . $dsn['sslmode'];
260 if (!empty($dsn['service'])) {
261 $params[0] .= ' service=' . $dsn['service'];
264 if (isset($dsn['new_link'])
265 && ($dsn['new_link'] == 'true' || $dsn['new_link'] === true))
267 if (version_compare(phpversion(), '4.3.0', '>=')) {
268 $params[] = PGSQL_CONNECT_FORCE_NEW;
272 $connect_function = $persistent ? 'pg_pconnect' : 'pg_connect';
274 $ini = ini_get('track_errors');
277 $this->connection = @call_user_func_array($connect_function,
280 @ini_set('track_errors', 1);
281 $this->connection = @call_user_func_array($connect_function,
283 @ini_set('track_errors', $ini);
286 if (!$this->connection) {
287 return $this->raiseError(DB_ERROR_CONNECT_FAILED,
298 * Disconnects from the database server
300 * @return bool TRUE on success, FALSE on failure
302 function disconnect()
304 $ret = @pg_close($this->connection);
305 $this->connection = null;
313 * Sends a query to the database server
315 * @param string the SQL query string
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
321 function simpleQuery($query)
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;');
330 return $this->pgsqlRaiseError();
333 $this->transaction_opcount++;
335 $result = @pg_exec($this->connection, $query);
337 return $this->pgsqlRaiseError();
341 * Determine whether queries produce affected rows, result or nothing.
343 * This logic was introduced in version 1.1 of the file by ssb,
344 * though the regex has been modified slightly since then.
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
354 $this->affected = @pg_affected_rows($result);
356 } elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|FETCH|SHOW)\s/si',
359 $this->row[(int)$result] = 0; // reset the row counter.
360 $numrows = $this->numRows($result);
361 if (is_object($numrows)) {
364 $this->_num_rows[(int)$result] = $numrows;
377 * Move the internal pgsql result pointer to the next available result
379 * @param a valid fbsql result resource
383 * @return true if a result is available otherwise return false
385 function nextResult($result)
394 * Places a row from the result set into the given array
396 * Formating of the array and the data therein are configurable.
397 * See DB_result::fetchInto() for more information.
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.
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)
408 * @return mixed DB_OK on success, NULL when the end of a result set is
409 * reached or on failure
411 * @see DB_result::fetchInto()
413 function fetchInto($result, &$arr, $fetchmode, $rownum = null)
415 $result_int = (int)$result;
416 $rownum = ($rownum !== null) ? $rownum : $this->row[$result_int];
417 if ($rownum >= $this->_num_rows[$result_int]) {
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);
426 $arr = @pg_fetch_row($result, $rownum);
431 if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
432 $this->_rtrimArrayValues($arr);
434 if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
435 $this->_convertNullArrayValuesToEmpty($arr);
437 $this->row[$result_int] = ++$rownum;
445 * Deletes the result set and frees the memory occupied by the result set
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.
451 * @param resource $result PHP's query result resource
453 * @return bool TRUE on success, FALSE if $result is invalid
455 * @see DB_result::free()
457 function freeResult($result)
459 if (is_resource($result)) {
460 unset($this->row[(int)$result]);
461 unset($this->_num_rows[(int)$result]);
463 return @pg_freeresult($result);
472 * @deprecated Deprecated in release 1.6.0
477 return $this->quoteSmart($str);
481 // {{{ quoteBoolean()
484 * Formats a boolean value for use within a query in a locale-independent
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.
492 function quoteBoolean($boolean) {
493 return $boolean ? 'TRUE' : 'FALSE';
497 // {{{ escapeSimple()
500 * Escapes a string according to the current DBMS's standards
502 * {@internal PostgreSQL treats a backslash as an escape character,
503 * so they are escaped as well.
505 * @param string $str the string to be escaped
507 * @return string the escaped string
509 * @see DB_common::quoteSmart()
510 * @since Method available since Release 1.6.0
512 function escapeSimple($str)
514 if (function_exists('pg_escape_string')) {
515 /* This fixes an undocumented BC break in PHP 5.2.0 which changed
516 * the prototype of pg_escape_string. I'm not thrilled about having
517 * to sniff the PHP version, quite frankly, but it's the only way
518 * to deal with the problem. Revision 1.331.2.13.2.10 on
519 * php-src/ext/pgsql/pgsql.c (PHP_5_2 branch) is to blame, for the
521 if (version_compare(PHP_VERSION, '5.2.0', '>=')) {
522 return pg_escape_string($this->connection, $str);
524 return pg_escape_string($str);
527 return str_replace("'", "''", str_replace('\\', '\\\\', $str));
535 * Gets the number of columns in a result set
537 * This method is not meant to be called directly. Use
538 * DB_result::numCols() instead. It can't be declared "protected"
539 * because DB_result is a separate object.
541 * @param resource $result PHP's query result resource
543 * @return int the number of columns. A DB_Error object on failure.
545 * @see DB_result::numCols()
547 function numCols($result)
549 $cols = @pg_numfields($result);
551 return $this->pgsqlRaiseError();
560 * Gets the number of rows in a result set
562 * This method is not meant to be called directly. Use
563 * DB_result::numRows() instead. It can't be declared "protected"
564 * because DB_result is a separate object.
566 * @param resource $result PHP's query result resource
568 * @return int the number of rows. A DB_Error object on failure.
570 * @see DB_result::numRows()
572 function numRows($result)
574 $rows = @pg_numrows($result);
575 if ($rows === null) {
576 return $this->pgsqlRaiseError();
585 * Enables or disables automatic commits
587 * @param bool $onoff true turns it on, false turns it off
589 * @return int DB_OK on success. A DB_Error object if the driver
590 * doesn't support auto-committing transactions.
592 function autoCommit($onoff = false)
594 // XXX if $this->transaction_opcount > 0, we should probably
595 // issue a warning here.
596 $this->autocommit = $onoff ? true : false;
604 * Commits the current transaction
606 * @return int DB_OK on success. A DB_Error object on failure.
610 if ($this->transaction_opcount > 0) {
611 // (disabled) hack to shut up error messages from libpq.a
612 //@fclose(@fopen("php://stderr", "w"));
613 $result = @pg_exec($this->connection, 'end;');
614 $this->transaction_opcount = 0;
616 return $this->pgsqlRaiseError();
626 * Reverts the current transaction
628 * @return int DB_OK on success. A DB_Error object on failure.
632 if ($this->transaction_opcount > 0) {
633 $result = @pg_exec($this->connection, 'abort;');
634 $this->transaction_opcount = 0;
636 return $this->pgsqlRaiseError();
643 // {{{ affectedRows()
646 * Determines the number of rows affected by a data maniuplation query
648 * 0 is returned for queries that don't manipulate data.
650 * @return int the number of rows. A DB_Error object on failure.
652 function affectedRows()
654 return $this->affected;
661 * Returns the next free id in a sequence
663 * @param string $seq_name name of the sequence
664 * @param boolean $ondemand when true, the seqence is automatically
665 * created if it does not exist
667 * @return int the next id number in the sequence.
668 * A DB_Error object on failure.
670 * @see DB_common::nextID(), DB_common::getSequenceName(),
671 * DB_pgsql::createSequence(), DB_pgsql::dropSequence()
673 function nextId($seq_name, $ondemand = true)
675 $seqname = $this->getSequenceName($seq_name);
678 $this->pushErrorHandling(PEAR_ERROR_RETURN);
679 $result = $this->query("SELECT NEXTVAL('${seqname}')");
680 $this->popErrorHandling();
681 if ($ondemand && DB::isError($result) &&
682 $result->getCode() == DB_ERROR_NOSUCHTABLE) {
684 $this->pushErrorHandling(PEAR_ERROR_RETURN);
685 $result = $this->createSequence($seq_name);
686 $this->popErrorHandling();
687 if (DB::isError($result)) {
688 return $this->raiseError($result);
694 if (DB::isError($result)) {
695 return $this->raiseError($result);
697 $arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
703 // {{{ createSequence()
706 * Creates a new sequence
708 * @param string $seq_name name of the new sequence
710 * @return int DB_OK on success. A DB_Error object on failure.
712 * @see DB_common::createSequence(), DB_common::getSequenceName(),
713 * DB_pgsql::nextID(), DB_pgsql::dropSequence()
715 function createSequence($seq_name)
717 $seqname = $this->getSequenceName($seq_name);
718 $result = $this->query("CREATE SEQUENCE ${seqname}");
723 // {{{ dropSequence()
728 * @param string $seq_name name of the sequence to be deleted
730 * @return int DB_OK on success. A DB_Error object on failure.
732 * @see DB_common::dropSequence(), DB_common::getSequenceName(),
733 * DB_pgsql::nextID(), DB_pgsql::createSequence()
735 function dropSequence($seq_name)
737 return $this->query('DROP SEQUENCE '
738 . $this->getSequenceName($seq_name));
742 // {{{ modifyLimitQuery()
745 * Adds LIMIT clauses to a query string according to current DBMS standards
747 * @param string $query the query to modify
748 * @param int $from the row to start to fetching (0 = the first row)
749 * @param int $count the numbers of rows to fetch
750 * @param mixed $params array, string or numeric data to be used in
751 * execution of the statement. Quantity of items
752 * passed must match quantity of placeholders in
753 * query: meaning 1 placeholder for non-array
754 * parameters or 1 placeholder per array element.
756 * @return string the query string with LIMIT clauses added
760 function modifyLimitQuery($query, $from, $count, $params = array())
762 return "$query LIMIT $count OFFSET $from";
766 // {{{ pgsqlRaiseError()
769 * Produces a DB_Error object regarding the current problem
771 * @param int $errno if the error is being manually raised pass a
772 * DB_ERROR* constant here. If this isn't passed
773 * the error information gathered from the DBMS.
775 * @return object the DB_Error object
777 * @see DB_common::raiseError(),
778 * DB_pgsql::errorNative(), DB_pgsql::errorCode()
780 function pgsqlRaiseError($errno = null)
782 $native = $this->errorNative();
784 $native = 'Database connection has been lost.';
785 $errno = DB_ERROR_CONNECT_FAILED;
787 if ($errno === null) {
788 $errno = $this->errorCode($native);
790 return $this->raiseError($errno, null, null, null, $native);
797 * Gets the DBMS' native error message produced by the last query
799 * {@internal Error messages are used instead of error codes
800 * in order to support older versions of PostgreSQL.}}
802 * @return string the DBMS' error message
804 function errorNative()
806 return @pg_errormessage($this->connection);
813 * Determines PEAR::DB error code from the database's text error message.
815 * @param string $errormsg error message returned from the database
816 * @return integer an error number from a DB error constant
818 function errorCode($errormsg)
820 static $error_regexps;
821 if (!isset($error_regexps)) {
822 $error_regexps = array(
823 '/column .* (of relation .*)?does not exist/i'
824 => DB_ERROR_NOSUCHFIELD,
825 '/(relation|sequence|table).*does not exist|class .* not found/i'
826 => DB_ERROR_NOSUCHTABLE,
827 '/index .* does not exist/'
828 => DB_ERROR_NOT_FOUND,
829 '/relation .* already exists/i'
830 => DB_ERROR_ALREADY_EXISTS,
831 '/(divide|division) by zero$/i'
833 '/pg_atoi: error in .*: can\'t parse /i'
834 => DB_ERROR_INVALID_NUMBER,
835 '/invalid input syntax for( type)? (integer|numeric)/i'
836 => DB_ERROR_INVALID_NUMBER,
837 '/value .* is out of range for type \w*int/i'
838 => DB_ERROR_INVALID_NUMBER,
839 '/integer out of range/i'
840 => DB_ERROR_INVALID_NUMBER,
841 '/value too long for type character/i'
843 '/attribute .* not found|relation .* does not have attribute/i'
844 => DB_ERROR_NOSUCHFIELD,
845 '/column .* specified in USING clause does not exist in (left|right) table/i'
846 => DB_ERROR_NOSUCHFIELD,
847 '/parser: parse error at or near/i'
851 '/column reference .* is ambiguous/i'
853 '/permission denied/'
854 => DB_ERROR_ACCESS_VIOLATION,
855 '/violates not-null constraint/'
856 => DB_ERROR_CONSTRAINT_NOT_NULL,
857 '/violates [\w ]+ constraint/'
858 => DB_ERROR_CONSTRAINT,
859 '/referential integrity violation/'
860 => DB_ERROR_CONSTRAINT,
861 '/more expressions than target columns/i'
862 => DB_ERROR_VALUE_COUNT_ON_ROW,
865 foreach ($error_regexps as $regexp => $code) {
866 if (preg_match($regexp, $errormsg)) {
870 // Fall back to DB_ERROR if there was no mapping.
878 * Returns information about a table or a result set
880 * NOTE: only supports 'table' and 'flags' if <var>$result</var>
883 * @param object|string $result DB_result object from a query or a
884 * string containing the name of a table.
885 * While this also accepts a query result
886 * resource identifier, this behavior is
888 * @param int $mode a valid tableInfo mode
890 * @return array an associative array with the information requested.
891 * A DB_Error object on failure.
893 * @see DB_common::tableInfo()
895 function tableInfo($result, $mode = null)
897 if (is_string($result)) {
899 * Probably received a table name.
900 * Create a result resource identifier.
902 $id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0");
904 } elseif (isset($result->result)) {
906 * Probably received a result object.
907 * Extract the result resource identifier.
909 $id = $result->result;
913 * Probably received a result resource identifier.
915 * Deprecated. Here for compatibility only.
921 if (!is_resource($id)) {
922 return $this->pgsqlRaiseError(DB_ERROR_NEED_MORE_DATA);
925 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
926 $case_func = 'strtolower';
928 $case_func = 'strval';
931 $count = @pg_numfields($id);
935 $res['num_fields'] = $count;
938 for ($i = 0; $i < $count; $i++) {
940 'table' => $got_string ? $case_func($result) : '',
941 'name' => $case_func(@pg_fieldname($id, $i)),
942 'type' => @pg_fieldtype($id, $i),
943 'len' => @pg_fieldsize($id, $i),
944 'flags' => $got_string
945 ? $this->_pgFieldFlags($id, $i, $result)
948 if ($mode & DB_TABLEINFO_ORDER) {
949 $res['order'][$res[$i]['name']] = $i;
951 if ($mode & DB_TABLEINFO_ORDERTABLE) {
952 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
956 // free the result only if we were called on a table
964 // {{{ _pgFieldFlags()
967 * Get a column's flags
969 * Supports "not_null", "default_value", "primary_key", "unique_key"
970 * and "multiple_key". The default value is passed through
971 * rawurlencode() in case there are spaces in it.
973 * @param int $resource the PostgreSQL result identifier
974 * @param int $num_field the field number
976 * @return string the flags
980 function _pgFieldFlags($resource, $num_field, $table_name)
982 $field_name = @pg_fieldname($resource, $num_field);
984 // Check if there's a schema in $table_name and update things
986 $from = 'pg_attribute f, pg_class tab, pg_type typ';
987 if (strpos($table_name, '.') !== false) {
988 $from .= ', pg_namespace nsp';
989 list($schema, $table) = explode('.', $table_name);
990 $tableWhere = "tab.relname = '$table' AND tab.relnamespace = nsp.oid AND nsp.nspname = '$schema'";
992 $tableWhere = "tab.relname = '$table_name'";
995 $result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef
997 WHERE tab.relname = typ.typname
998 AND typ.typrelid = f.attrelid
999 AND f.attname = '$field_name'
1001 if (@pg_numrows($result) > 0) {
1002 $row = @pg_fetch_row($result, 0);
1003 $flags = ($row[0] == 't') ? 'not_null ' : '';
1005 if ($row[1] == 't') {
1006 $result = @pg_exec($this->connection, "SELECT a.adsrc
1007 FROM $from, pg_attrdef a
1008 WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid
1009 AND f.attrelid = a.adrelid AND f.attname = '$field_name'
1010 AND $tableWhere AND f.attnum = a.adnum");
1011 $row = @pg_fetch_row($result, 0);
1012 $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]);
1013 $flags .= 'default_' . rawurlencode($num) . ' ';
1018 $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey
1019 FROM $from, pg_index i
1020 WHERE tab.relname = typ.typname
1021 AND typ.typrelid = f.attrelid
1022 AND f.attrelid = i.indrelid
1023 AND f.attname = '$field_name'
1025 $count = @pg_numrows($result);
1027 for ($i = 0; $i < $count ; $i++) {
1028 $row = @pg_fetch_row($result, $i);
1029 $keys = explode(' ', $row[2]);
1031 if (in_array($num_field + 1, $keys)) {
1032 $flags .= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : '';
1033 $flags .= ($row[1] == 't') ? 'primary_key ' : '';
1034 if (count($keys) > 1)
1035 $flags .= 'multiple_key ';
1039 return trim($flags);
1043 // {{{ getSpecialQuery()
1046 * Obtains the query string needed for listing a given type of objects
1048 * @param string $type the kind of objects you want to retrieve
1050 * @return string the SQL query string or null if the driver doesn't
1051 * support the object type requested
1054 * @see DB_common::getListOf()
1056 function getSpecialQuery($type)
1060 return 'SELECT c.relname AS "Name"'
1061 . ' FROM pg_class c, pg_user u'
1062 . ' WHERE c.relowner = u.usesysid'
1063 . " AND c.relkind = 'r'"
1065 . ' (SELECT 1 FROM pg_views'
1066 . ' WHERE viewname = c.relname)'
1067 . " AND c.relname !~ '^(pg_|sql_)'"
1069 . ' SELECT c.relname AS "Name"'
1070 . ' FROM pg_class c'
1071 . " WHERE c.relkind = 'r'"
1073 . ' (SELECT 1 FROM pg_views'
1074 . ' WHERE viewname = c.relname)'
1076 . ' (SELECT 1 FROM pg_user'
1077 . ' WHERE usesysid = c.relowner)'
1078 . " AND c.relname !~ '^pg_'";
1079 case 'schema.tables':
1080 return "SELECT schemaname || '.' || tablename"
1082 . ' FROM pg_catalog.pg_tables'
1083 . ' WHERE schemaname NOT IN'
1084 . " ('pg_catalog', 'information_schema', 'pg_toast')";
1085 case 'schema.views':
1086 return "SELECT schemaname || '.' || viewname from pg_views WHERE schemaname"
1087 . " NOT IN ('information_schema', 'pg_catalog')";
1089 // Table cols: viewname | viewowner | definition
1090 return 'SELECT viewname from pg_views WHERE schemaname'
1091 . " NOT IN ('information_schema', 'pg_catalog')";
1093 // cols: usename |usesysid|usecreatedb|usetrace|usesuper|usecatupd|passwd |valuntil
1094 return 'SELECT usename FROM pg_user';
1096 return 'SELECT datname FROM pg_database';
1099 return 'SELECT proname FROM pg_proc WHERE proowner <> 1';
1106 // {{{ _checkManip()
1109 * Checks if the given query is a manipulation query. This also takes into
1110 * account the _next_query_manip flag and sets the _last_query_manip flag
1111 * (and resets _next_query_manip) according to the result.
1113 * @param string The query to check.
1115 * @return boolean true if the query is a manipulation query, false
1120 function _checkManip($query)
1122 return (preg_match('/^\s*(SAVEPOINT|RELEASE)\s+/i', $query)
1123 || parent::_checkManip($query));