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-2005 The PHP Group
23 * @license http://www.php.net/license/3_0.txt PHP License 3.0
24 * @version CVS: $Id: pgsql.php 12 2005-10-02 11:36:35Z sparc $
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-2005 The PHP Group
45 * @license http://www.php.net/license/3_0.txt PHP License 3.0
46 * @version Release: @package_version@
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 = DB::isManip($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();
339 // Determine which queries that should return data, and which
340 // should return an error code only.
342 $this->affected = @pg_affected_rows($result);
344 } elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|SHOW)\s/si', $query)) {
345 /* PostgreSQL commands:
346 ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY,
347 CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH,
348 GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET,
349 REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW,
350 UNLISTEN, UPDATE, VACUUM
352 $this->row[(int)$result] = 0; // reset the row counter.
353 $numrows = $this->numRows($result);
354 if (is_object($numrows)) {
357 $this->_num_rows[(int)$result] = $numrows;
370 * Move the internal pgsql result pointer to the next available result
372 * @param a valid fbsql result resource
376 * @return true if a result is available otherwise return false
378 function nextResult($result)
387 * Places a row from the result set into the given array
389 * Formating of the array and the data therein are configurable.
390 * See DB_result::fetchInto() for more information.
392 * This method is not meant to be called directly. Use
393 * DB_result::fetchInto() instead. It can't be declared "protected"
394 * because DB_result is a separate object.
396 * @param resource $result the query result resource
397 * @param array $arr the referenced array to put the data in
398 * @param int $fetchmode how the resulting array should be indexed
399 * @param int $rownum the row number to fetch (0 = first row)
401 * @return mixed DB_OK on success, NULL when the end of a result set is
402 * reached or on failure
404 * @see DB_result::fetchInto()
406 function fetchInto($result, &$arr, $fetchmode, $rownum = null)
408 $result_int = (int)$result;
409 $rownum = ($rownum !== null) ? $rownum : $this->row[$result_int];
410 if ($rownum >= $this->_num_rows[$result_int]) {
413 if ($fetchmode & DB_FETCHMODE_ASSOC) {
414 $arr = @pg_fetch_array($result, $rownum, PGSQL_ASSOC);
415 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
416 $arr = array_change_key_case($arr, CASE_LOWER);
419 $arr = @pg_fetch_row($result, $rownum);
424 if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
425 $this->_rtrimArrayValues($arr);
427 if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
428 $this->_convertNullArrayValuesToEmpty($arr);
430 $this->row[$result_int] = ++$rownum;
438 * Deletes the result set and frees the memory occupied by the result set
440 * This method is not meant to be called directly. Use
441 * DB_result::free() instead. It can't be declared "protected"
442 * because DB_result is a separate object.
444 * @param resource $result PHP's query result resource
446 * @return bool TRUE on success, FALSE if $result is invalid
448 * @see DB_result::free()
450 function freeResult($result)
452 if (is_resource($result)) {
453 unset($this->row[(int)$result]);
454 unset($this->_num_rows[(int)$result]);
456 return @pg_freeresult($result);
465 * @deprecated Deprecated in release 1.6.0
470 return $this->quoteSmart($str);
477 * Formats input so it can be safely used in a query
479 * @param mixed $in the data to be formatted
481 * @return mixed the formatted data. The format depends on the input's
483 * + null = the string <samp>NULL</samp>
484 * + boolean = string <samp>TRUE</samp> or <samp>FALSE</samp>
485 * + integer or double = the unquoted number
486 * + other (including strings and numeric strings) =
487 * the data escaped according to MySQL's settings
488 * then encapsulated between single quotes
490 * @see DB_common::quoteSmart()
491 * @since Method available since Release 1.6.0
493 function quoteSmart($in)
495 if (is_int($in) || is_double($in)) {
497 } elseif (is_bool($in)) {
498 return $in ? 'TRUE' : 'FALSE';
499 } elseif (is_null($in)) {
502 return "'" . $this->escapeSimple($in) . "'";
507 // {{{ escapeSimple()
510 * Escapes a string according to the current DBMS's standards
512 * {@internal PostgreSQL treats a backslash as an escape character,
513 * so they are escaped as well.
515 * Not using pg_escape_string() yet because it requires PostgreSQL
516 * to be at version 7.2 or greater.}}
518 * @param string $str the string to be escaped
520 * @return string the escaped string
522 * @see DB_common::quoteSmart()
523 * @since Method available since Release 1.6.0
525 function escapeSimple($str)
527 return str_replace("'", "''", str_replace('\\', '\\\\', $str));
534 * Gets the number of columns in a result set
536 * This method is not meant to be called directly. Use
537 * DB_result::numCols() instead. It can't be declared "protected"
538 * because DB_result is a separate object.
540 * @param resource $result PHP's query result resource
542 * @return int the number of columns. A DB_Error object on failure.
544 * @see DB_result::numCols()
546 function numCols($result)
548 $cols = @pg_numfields($result);
550 return $this->pgsqlRaiseError();
559 * Gets the number of rows in a result set
561 * This method is not meant to be called directly. Use
562 * DB_result::numRows() instead. It can't be declared "protected"
563 * because DB_result is a separate object.
565 * @param resource $result PHP's query result resource
567 * @return int the number of rows. A DB_Error object on failure.
569 * @see DB_result::numRows()
571 function numRows($result)
573 $rows = @pg_numrows($result);
574 if ($rows === null) {
575 return $this->pgsqlRaiseError();
584 * Enables or disables automatic commits
586 * @param bool $onoff true turns it on, false turns it off
588 * @return int DB_OK on success. A DB_Error object if the driver
589 * doesn't support auto-committing transactions.
591 function autoCommit($onoff = false)
593 // XXX if $this->transaction_opcount > 0, we should probably
594 // issue a warning here.
595 $this->autocommit = $onoff ? true : false;
603 * Commits the current transaction
605 * @return int DB_OK on success. A DB_Error object on failure.
609 if ($this->transaction_opcount > 0) {
610 // (disabled) hack to shut up error messages from libpq.a
611 //@fclose(@fopen("php://stderr", "w"));
612 $result = @pg_exec($this->connection, 'end;');
613 $this->transaction_opcount = 0;
615 return $this->pgsqlRaiseError();
625 * Reverts the current transaction
627 * @return int DB_OK on success. A DB_Error object on failure.
631 if ($this->transaction_opcount > 0) {
632 $result = @pg_exec($this->connection, 'abort;');
633 $this->transaction_opcount = 0;
635 return $this->pgsqlRaiseError();
642 // {{{ affectedRows()
645 * Determines the number of rows affected by a data maniuplation query
647 * 0 is returned for queries that don't manipulate data.
649 * @return int the number of rows. A DB_Error object on failure.
651 function affectedRows()
653 return $this->affected;
660 * Returns the next free id in a sequence
662 * @param string $seq_name name of the sequence
663 * @param boolean $ondemand when true, the seqence is automatically
664 * created if it does not exist
666 * @return int the next id number in the sequence.
667 * A DB_Error object on failure.
669 * @see DB_common::nextID(), DB_common::getSequenceName(),
670 * DB_pgsql::createSequence(), DB_pgsql::dropSequence()
672 function nextId($seq_name, $ondemand = true)
674 $seqname = $this->getSequenceName($seq_name);
677 $this->pushErrorHandling(PEAR_ERROR_RETURN);
678 $result =& $this->query("SELECT NEXTVAL('${seqname}')");
679 $this->popErrorHandling();
680 if ($ondemand && DB::isError($result) &&
681 $result->getCode() == DB_ERROR_NOSUCHTABLE) {
683 $this->pushErrorHandling(PEAR_ERROR_RETURN);
684 $result = $this->createSequence($seq_name);
685 $this->popErrorHandling();
686 if (DB::isError($result)) {
687 return $this->raiseError($result);
693 if (DB::isError($result)) {
694 return $this->raiseError($result);
696 $arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
702 // {{{ createSequence()
705 * Creates a new sequence
707 * @param string $seq_name name of the new sequence
709 * @return int DB_OK on success. A DB_Error object on failure.
711 * @see DB_common::createSequence(), DB_common::getSequenceName(),
712 * DB_pgsql::nextID(), DB_pgsql::dropSequence()
714 function createSequence($seq_name)
716 $seqname = $this->getSequenceName($seq_name);
717 $result = $this->query("CREATE SEQUENCE ${seqname}");
722 // {{{ dropSequence()
727 * @param string $seq_name name of the sequence to be deleted
729 * @return int DB_OK on success. A DB_Error object on failure.
731 * @see DB_common::dropSequence(), DB_common::getSequenceName(),
732 * DB_pgsql::nextID(), DB_pgsql::createSequence()
734 function dropSequence($seq_name)
736 return $this->query('DROP SEQUENCE '
737 . $this->getSequenceName($seq_name));
741 // {{{ modifyLimitQuery()
744 * Adds LIMIT clauses to a query string according to current DBMS standards
746 * @param string $query the query to modify
747 * @param int $from the row to start to fetching (0 = the first row)
748 * @param int $count the numbers of rows to fetch
749 * @param mixed $params array, string or numeric data to be used in
750 * execution of the statement. Quantity of items
751 * passed must match quantity of placeholders in
752 * query: meaning 1 placeholder for non-array
753 * parameters or 1 placeholder per array element.
755 * @return string the query string with LIMIT clauses added
759 function modifyLimitQuery($query, $from, $count, $params = array())
761 return "$query LIMIT $count OFFSET $from";
765 // {{{ pgsqlRaiseError()
768 * Produces a DB_Error object regarding the current problem
770 * @param int $errno if the error is being manually raised pass a
771 * DB_ERROR* constant here. If this isn't passed
772 * the error information gathered from the DBMS.
774 * @return object the DB_Error object
776 * @see DB_common::raiseError(),
777 * DB_pgsql::errorNative(), DB_pgsql::errorCode()
779 function pgsqlRaiseError($errno = null)
781 $native = $this->errorNative();
782 if ($errno === null) {
783 $errno = $this->errorCode($native);
785 return $this->raiseError($errno, null, null, null, $native);
792 * Gets the DBMS' native error message produced by the last query
794 * {@internal Error messages are used instead of error codes
795 * in order to support older versions of PostgreSQL.}}
797 * @return string the DBMS' error message
799 function errorNative()
801 return @pg_errormessage($this->connection);
808 * Determines PEAR::DB error code from the database's text error message.
810 * @param string $errormsg error message returned from the database
811 * @return integer an error number from a DB error constant
813 function errorCode($errormsg)
815 static $error_regexps;
816 if (!isset($error_regexps)) {
817 $error_regexps = array(
818 '/(relation|sequence|table).*does not exist|class .* not found/i'
819 => DB_ERROR_NOSUCHTABLE,
820 '/index .* does not exist/'
821 => DB_ERROR_NOT_FOUND,
822 '/column .* does not exist/i'
823 => DB_ERROR_NOSUCHFIELD,
824 '/relation .* already exists/i'
825 => DB_ERROR_ALREADY_EXISTS,
826 '/(divide|division) by zero$/i'
828 '/pg_atoi: error in .*: can\'t parse /i'
829 => DB_ERROR_INVALID_NUMBER,
830 '/invalid input syntax for( type)? (integer|numeric)/i'
831 => DB_ERROR_INVALID_NUMBER,
832 '/value .* is out of range for type \w*int/i'
833 => DB_ERROR_INVALID_NUMBER,
834 '/integer out of range/i'
835 => DB_ERROR_INVALID_NUMBER,
836 '/value too long for type character/i'
838 '/attribute .* not found|relation .* does not have attribute/i'
839 => DB_ERROR_NOSUCHFIELD,
840 '/column .* specified in USING clause does not exist in (left|right) table/i'
841 => DB_ERROR_NOSUCHFIELD,
842 '/parser: parse error at or near/i'
846 '/column reference .* is ambiguous/i'
848 '/permission denied/'
849 => DB_ERROR_ACCESS_VIOLATION,
850 '/violates not-null constraint/'
851 => DB_ERROR_CONSTRAINT_NOT_NULL,
852 '/violates [\w ]+ constraint/'
853 => DB_ERROR_CONSTRAINT,
854 '/referential integrity violation/'
855 => DB_ERROR_CONSTRAINT,
856 '/more expressions than target columns/i'
857 => DB_ERROR_VALUE_COUNT_ON_ROW,
860 foreach ($error_regexps as $regexp => $code) {
861 if (preg_match($regexp, $errormsg)) {
865 // Fall back to DB_ERROR if there was no mapping.
873 * Returns information about a table or a result set
875 * NOTE: only supports 'table' and 'flags' if <var>$result</var>
878 * @param object|string $result DB_result object from a query or a
879 * string containing the name of a table.
880 * While this also accepts a query result
881 * resource identifier, this behavior is
883 * @param int $mode a valid tableInfo mode
885 * @return array an associative array with the information requested.
886 * A DB_Error object on failure.
888 * @see DB_common::tableInfo()
890 function tableInfo($result, $mode = null)
892 if (is_string($result)) {
894 * Probably received a table name.
895 * Create a result resource identifier.
897 $id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0");
899 } elseif (isset($result->result)) {
901 * Probably received a result object.
902 * Extract the result resource identifier.
904 $id = $result->result;
908 * Probably received a result resource identifier.
910 * Deprecated. Here for compatibility only.
916 if (!is_resource($id)) {
917 return $this->pgsqlRaiseError(DB_ERROR_NEED_MORE_DATA);
920 if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
921 $case_func = 'strtolower';
923 $case_func = 'strval';
926 $count = @pg_numfields($id);
930 $res['num_fields'] = $count;
933 for ($i = 0; $i < $count; $i++) {
935 'table' => $got_string ? $case_func($result) : '',
936 'name' => $case_func(@pg_fieldname($id, $i)),
937 'type' => @pg_fieldtype($id, $i),
938 'len' => @pg_fieldsize($id, $i),
939 'flags' => $got_string
940 ? $this->_pgFieldFlags($id, $i, $result)
943 if ($mode & DB_TABLEINFO_ORDER) {
944 $res['order'][$res[$i]['name']] = $i;
946 if ($mode & DB_TABLEINFO_ORDERTABLE) {
947 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
951 // free the result only if we were called on a table
959 // {{{ _pgFieldFlags()
962 * Get a column's flags
964 * Supports "not_null", "default_value", "primary_key", "unique_key"
965 * and "multiple_key". The default value is passed through
966 * rawurlencode() in case there are spaces in it.
968 * @param int $resource the PostgreSQL result identifier
969 * @param int $num_field the field number
971 * @return string the flags
975 function _pgFieldFlags($resource, $num_field, $table_name)
977 $field_name = @pg_fieldname($resource, $num_field);
979 $result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef
980 FROM pg_attribute f, pg_class tab, pg_type typ
981 WHERE tab.relname = typ.typname
982 AND typ.typrelid = f.attrelid
983 AND f.attname = '$field_name'
984 AND tab.relname = '$table_name'");
985 if (@pg_numrows($result) > 0) {
986 $row = @pg_fetch_row($result, 0);
987 $flags = ($row[0] == 't') ? 'not_null ' : '';
989 if ($row[1] == 't') {
990 $result = @pg_exec($this->connection, "SELECT a.adsrc
991 FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a
992 WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid
993 AND f.attrelid = a.adrelid AND f.attname = '$field_name'
994 AND tab.relname = '$table_name' AND f.attnum = a.adnum");
995 $row = @pg_fetch_row($result, 0);
996 $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]);
997 $flags .= 'default_' . rawurlencode($num) . ' ';
1002 $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey
1003 FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i
1004 WHERE tab.relname = typ.typname
1005 AND typ.typrelid = f.attrelid
1006 AND f.attrelid = i.indrelid
1007 AND f.attname = '$field_name'
1008 AND tab.relname = '$table_name'");
1009 $count = @pg_numrows($result);
1011 for ($i = 0; $i < $count ; $i++) {
1012 $row = @pg_fetch_row($result, $i);
1013 $keys = explode(' ', $row[2]);
1015 if (in_array($num_field + 1, $keys)) {
1016 $flags .= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : '';
1017 $flags .= ($row[1] == 't') ? 'primary_key ' : '';
1018 if (count($keys) > 1)
1019 $flags .= 'multiple_key ';
1023 return trim($flags);
1027 // {{{ getSpecialQuery()
1030 * Obtains the query string needed for listing a given type of objects
1032 * @param string $type the kind of objects you want to retrieve
1034 * @return string the SQL query string or null if the driver doesn't
1035 * support the object type requested
1038 * @see DB_common::getListOf()
1040 function getSpecialQuery($type)
1044 return 'SELECT c.relname AS "Name"'
1045 . ' FROM pg_class c, pg_user u'
1046 . ' WHERE c.relowner = u.usesysid'
1047 . " AND c.relkind = 'r'"
1049 . ' (SELECT 1 FROM pg_views'
1050 . ' WHERE viewname = c.relname)'
1051 . " AND c.relname !~ '^(pg_|sql_)'"
1053 . ' SELECT c.relname AS "Name"'
1054 . ' FROM pg_class c'
1055 . " WHERE c.relkind = 'r'"
1057 . ' (SELECT 1 FROM pg_views'
1058 . ' WHERE viewname = c.relname)'
1060 . ' (SELECT 1 FROM pg_user'
1061 . ' WHERE usesysid = c.relowner)'
1062 . " AND c.relname !~ '^pg_'";
1063 case 'schema.tables':
1064 return "SELECT schemaname || '.' || tablename"
1066 . ' FROM pg_catalog.pg_tables'
1067 . ' WHERE schemaname NOT IN'
1068 . " ('pg_catalog', 'information_schema', 'pg_toast')";
1070 // Table cols: viewname | viewowner | definition
1071 return 'SELECT viewname from pg_views WHERE schemaname'
1072 . " NOT IN ('information_schema', 'pg_catalog')";
1074 // cols: usename |usesysid|usecreatedb|usetrace|usesuper|usecatupd|passwd |valuntil
1075 return 'SELECT usename FROM pg_user';
1077 return 'SELECT datname FROM pg_database';
1080 return 'SELECT proname FROM pg_proc WHERE proowner <> 1';