]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/pear/DB/pgsql.php
phpdoc_params
[SourceForge/phpwiki.git] / lib / pear / DB / pgsql.php
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
3 // +----------------------------------------------------------------------+
4 // | PHP Version 4                                                        |
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1997-2004 The PHP Group                                |
7 // +----------------------------------------------------------------------+
8 // | This source file is subject to version 2.02 of the PHP license,      |
9 // | that is bundled with this package in the file LICENSE, and is        |
10 // | available at through the world-wide-web at                           |
11 // | http://www.php.net/license/2_02.txt.                                 |
12 // | If you did not receive a copy of the PHP license and are unable to   |
13 // | obtain it through the world-wide-web, please send a note to          |
14 // | license@php.net so we can mail you a copy immediately.               |
15 // +----------------------------------------------------------------------+
16 // | Authors: Rui Hirokawa <hirokawa@php.net>                             |
17 // |          Stig Bakken <ssb@php.net>                                   |
18 // | Maintainer: Daniel Convissor <danielc@php.net>                       |
19 // +----------------------------------------------------------------------+
20 //
21 // $Id$
22
23 require_once 'DB/common.php';
24
25 /**
26  * Database independent query interface definition for PHP's PostgreSQL
27  * extension.
28  *
29  * @package  DB
30  * @version  $Id$
31  * @category Database
32  * @author   Rui Hirokawa <hirokawa@php.net>
33  * @author   Stig Bakken <ssb@php.net>
34  */
35 class DB_pgsql extends DB_common
36 {
37     // {{{ properties
38
39     var $connection;
40     var $phptype, $dbsyntax;
41     var $prepare_tokens = array();
42     var $prepare_types = array();
43     var $transaction_opcount = 0;
44     var $dsn = array();
45     var $row = array();
46     var $num_rows = array();
47     var $affected = 0;
48     var $autocommit = true;
49     var $fetchmode = DB_FETCHMODE_ORDERED;
50
51     // }}}
52     // {{{ constructor
53
54     function DB_pgsql()
55     {
56         $this->DB_common();
57         $this->phptype = 'pgsql';
58         $this->dbsyntax = 'pgsql';
59         $this->features = array(
60             'prepare' => false,
61             'pconnect' => true,
62             'transactions' => true,
63             'limit' => 'alter'
64         );
65         $this->errorcode_map = array(
66         );
67     }
68
69     // }}}
70     // {{{ connect()
71
72     /**
73      * Connect to a database and log in as the specified user.
74      *
75      * @param $dsn the data source name (see DB::parseDSN for syntax)
76      * @param $persistent (optional) whether the connection should
77      *        be persistent
78      *
79      * @return int DB_OK on success, a DB error code on failure.
80      */
81     function connect($dsninfo, $persistent = false)
82     {
83         if (!DB::assertExtension('pgsql')) {
84             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
85         }
86
87         $this->dsn = $dsninfo;
88         $protocol = $dsninfo['protocol'] ? $dsninfo['protocol'] : 'tcp';
89         $connstr = '';
90
91         if ($protocol == 'tcp') {
92             if ($dsninfo['hostspec']) {
93                 $connstr .= 'host=' . $dsninfo['hostspec'];
94             }
95             if ($dsninfo['port']) {
96                 $connstr .= ' port=' . $dsninfo['port'];
97             }
98         } elseif ($protocol == 'unix') {
99             // Allow for pg socket in non-standard locations.
100             if ($dsninfo['socket']) {
101                 $connstr .= 'host=' . $dsninfo['socket'];
102             }
103         }
104
105         if ($dsninfo['database']) {
106             $connstr .= ' dbname=\'' . addslashes($dsninfo['database']) . '\'';
107         }
108         if ($dsninfo['username']) {
109             $connstr .= ' user=\'' . addslashes($dsninfo['username']) . '\'';
110         }
111         if ($dsninfo['password']) {
112             $connstr .= ' password=\'' . addslashes($dsninfo['password']) . '\'';
113         }
114         if (isset($dsninfo['options'])) {
115             $connstr .= ' options=' . $dsninfo['options'];
116         }
117         if (isset($dsninfo['tty'])) {
118             $connstr .= ' tty=' . $dsninfo['tty'];
119         }
120
121         $connect_function = $persistent ? 'pg_pconnect' : 'pg_connect';
122         // catch error
123         ob_start();
124         $conn = $connect_function($connstr);
125         $error = ob_get_contents();
126         ob_end_clean();
127         if ($conn == false) {
128             return $this->raiseError(DB_ERROR_CONNECT_FAILED, null,
129                                      null, null, strip_tags($error));
130         }
131         $this->connection = $conn;
132         return DB_OK;
133     }
134
135     // }}}
136     // {{{ disconnect()
137
138     /**
139      * Log out and disconnect from the database.
140      *
141      * @return bool true on success, false if not connected.
142      */
143     function disconnect()
144     {
145         $ret = @pg_close($this->connection);
146         $this->connection = null;
147         return $ret;
148     }
149
150     // }}}
151     // {{{ simpleQuery()
152
153     /**
154      * Send a query to PostgreSQL and return the results as a
155      * PostgreSQL resource identifier.
156      *
157      * @param $query the SQL query
158      *
159      * @return int returns a valid PostgreSQL result for successful SELECT
160      * queries, DB_OK for other successful queries.  A DB error code
161      * is returned on failure.
162      */
163     function simpleQuery($query)
164     {
165         $ismanip = DB::isManip($query);
166         $this->last_query = $query;
167         $query = $this->modifyQuery($query);
168         if (!$this->autocommit && $ismanip) {
169             if ($this->transaction_opcount == 0) {
170                 $result = @pg_exec($this->connection, 'begin;');
171                 if (!$result) {
172                     return $this->pgsqlRaiseError();
173                 }
174             }
175             $this->transaction_opcount++;
176         }
177         $result = @pg_exec($this->connection, $query);
178         if (!$result) {
179             return $this->pgsqlRaiseError();
180         }
181         // Determine which queries that should return data, and which
182         // should return an error code only.
183         if ($ismanip) {
184             $this->affected = @pg_cmdtuples($result);
185             return DB_OK;
186         } elseif (preg_match('/^\s*\(?\s*(SELECT(?!\s+INTO)|EXPLAIN|SHOW)\s/si', $query)) {
187             /* PostgreSQL commands:
188                ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY,
189                CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH,
190                GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET,
191                REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW,
192                UNLISTEN, UPDATE, VACUUM
193             */
194             $this->row[(int)$result] = 0; // reset the row counter.
195             $numrows = $this->numrows($result);
196             if (is_object($numrows)) {
197                 return $numrows;
198             }
199             $this->num_rows[(int)$result] = $numrows;
200             $this->affected = 0;
201             return $result;
202         } else {
203             $this->affected = 0;
204             return DB_OK;
205         }
206     }
207
208     // }}}
209     // {{{ nextResult()
210
211     /**
212      * Move the internal pgsql result pointer to the next available result
213      *
214      * @param a valid fbsql result resource
215      *
216      * @access public
217      *
218      * @return true if a result is available otherwise return false
219      */
220     function nextResult($result)
221     {
222         return false;
223     }
224
225     // }}}
226     // {{{ errorCode()
227
228     /**
229      * Determine PEAR::DB error code from the database's text error message.
230      *
231      * @param  string  $errormsg error message returned from the database
232      * @return integer an error number from a DB error constant
233      */
234     function errorCode($errormsg)
235     {
236         static $error_regexps;
237         if (!isset($error_regexps)) {
238             $error_regexps = array(
239                 '/(([Rr]elation|[Ss]equence|[Tt]able)( [\"\'].*[\"\'])? does not exist|[Cc]lass ".+" not found)$/' => DB_ERROR_NOSUCHTABLE,
240                 '/[Cc]olumn [\"\'].*[\"\'] does not exist/' => DB_ERROR_NOSUCHFIELD,
241                 '/[Rr]elation [\"\'].*[\"\'] already exists|[Cc]annot insert a duplicate key into (a )?unique index.*/' => DB_ERROR_ALREADY_EXISTS,
242                 '/(divide|division) by zero$/'          => DB_ERROR_DIVZERO,
243                 '/pg_atoi: error in .*: can\'t parse /' => DB_ERROR_INVALID_NUMBER,
244                 '/invalid input syntax for integer/'    => DB_ERROR_INVALID_NUMBER,
245                 '/ttribute [\"\'].*[\"\'] not found$|[Rr]elation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => DB_ERROR_NOSUCHFIELD,
246                 '/parser: parse error at or near \"/'   => DB_ERROR_SYNTAX,
247                 '/syntax error at/'                     => DB_ERROR_SYNTAX,
248                 '/violates not-null constraint/'        => DB_ERROR_CONSTRAINT_NOT_NULL,
249                 '/violates [\w ]+ constraint/'          => DB_ERROR_CONSTRAINT,
250                 '/referential integrity violation/'     => DB_ERROR_CONSTRAINT
251             );
252         }
253         foreach ($error_regexps as $regexp => $code) {
254             if (preg_match($regexp, $errormsg)) {
255                 return $code;
256             }
257         }
258         // Fall back to DB_ERROR if there was no mapping.
259         return DB_ERROR;
260     }
261
262     // }}}
263     // {{{ fetchInto()
264
265     /**
266      * Fetch a row and insert the data into an existing array.
267      *
268      * Formating of the array and the data therein are configurable.
269      * See DB_result::fetchInto() for more information.
270      *
271      * @param resource $result query result identifier
272      * @param array    $arr    (reference) array where data from the row
273      *                            should be placed
274      * @param int $fetchmode how the resulting array should be indexed
275      * @param int $rownum    the row number to fetch
276      *
277      * @return mixed DB_OK on success, null when end of result set is
278      *               reached or on failure
279      *
280      * @see DB_result::fetchInto()
281      * @access private
282      */
283     function fetchInto($result, &$arr, $fetchmode, $rownum=null)
284     {
285         $rownum = ($rownum !== null) ? $rownum : $this->row[$result];
286         if ($rownum >= $this->num_rows[$result]) {
287             return null;
288         }
289         if ($fetchmode & DB_FETCHMODE_ASSOC) {
290             $arr = @pg_fetch_array($result, $rownum, PGSQL_ASSOC);
291             if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
292                 $arr = array_change_key_case($arr, CASE_LOWER);
293             }
294         } else {
295             $arr = @pg_fetch_row($result, $rownum);
296         }
297         if (!$arr) {
298             $err = pg_errormessage($this->connection);
299             if (!$err) {
300                 return null;
301             }
302             return $this->pgsqlRaiseError();
303         }
304         if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
305             $this->_rtrimArrayValues($arr);
306         }
307         if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
308             $this->_convertNullArrayValuesToEmpty($arr);
309         }
310         $this->row[$result] = ++$rownum;
311         return DB_OK;
312     }
313
314     // }}}
315     // {{{ freeResult()
316
317     /**
318      * Free the internal resources associated with $result.
319      *
320      * @param $result int PostgreSQL result identifier
321      *
322      * @return bool true on success, false if $result is invalid
323      */
324     function freeResult($result)
325     {
326         if (is_resource($result)) {
327             unset($this->row[(int)$result]);
328             unset($this->num_rows[(int)$result]);
329             $this->affected = 0;
330             return @pg_freeresult($result);
331         }
332         return false;
333     }
334
335     // }}}
336     // {{{ quote()
337
338     /**
339      * @deprecated  Deprecated in release 1.6.0
340      * @internal
341      */
342     function quote($str) {
343         return $this->quoteSmart($str);
344     }
345
346     // }}}
347     // {{{ quoteSmart()
348
349     /**
350      * Format input so it can be safely used in a query
351      *
352      * @param mixed $in data to be quoted
353      *
354      * @return mixed Submitted variable's type = returned value:
355      *               + null = the string <samp>NULL</samp>
356      *               + boolean = string <samp>TRUE</samp> or <samp>FALSE</samp>
357      *               + integer or double = the unquoted number
358      *               + other (including strings and numeric strings) =
359      *                 the data escaped according to MySQL's settings
360      *                 then encapsulated between single quotes
361      *
362      * @internal
363      */
364     function quoteSmart($in)
365     {
366         if (is_int($in) || is_double($in)) {
367             return $in;
368         } elseif (is_bool($in)) {
369             return $in ? 'TRUE' : 'FALSE';
370         } elseif (is_null($in)) {
371             return 'NULL';
372         } else {
373             return "'" . $this->escapeSimple($in) . "'";
374         }
375     }
376
377     // }}}
378     // {{{ escapeSimple()
379
380     /**
381      * Escapes a string according to the current DBMS's standards
382      *
383      * {@internal PostgreSQL treats a backslash as an escape character,
384      * so they are escaped as well.
385      *
386      * @param string $str the string to be escaped
387      *
388      * @return string the escaped string
389      *
390      * @see DB_common::quoteSmart()
391      * @since Method available since Release 1.6.0
392      */
393     function escapeSimple($str)
394     {
395         if (function_exists('pg_escape_string')) {
396             /* This fixes an undocumented BC break in PHP 5.2.0 which changed
397              * the prototype of pg_escape_string. I'm not thrilled about having
398              * to sniff the PHP version, quite frankly, but it's the only way
399              * to deal with the problem. Revision 1.331.2.13.2.10 on
400              * php-src/ext/pgsql/pgsql.c (PHP_5_2 branch) is to blame, for the
401              * record. */
402             if (version_compare(PHP_VERSION, '5.2.0', '>=')) {
403                 return pg_escape_string($this->connection, $str);
404             } else {
405                 return pg_escape_string($str);
406             }
407         } else {
408             return str_replace("'", "''", str_replace('\\', '\\\\', $str));
409         }
410     }
411
412     // }}}
413     // {{{ numCols()
414
415     /**
416      * Get the number of columns in a result set.
417      *
418      * @param $result resource PostgreSQL result identifier
419      *
420      * @return int the number of columns per row in $result
421      */
422     function numCols($result)
423     {
424         $cols = @pg_numfields($result);
425         if (!$cols) {
426             return $this->pgsqlRaiseError();
427         }
428         return $cols;
429     }
430
431     // }}}
432     // {{{ numRows()
433
434     /**
435      * Get the number of rows in a result set.
436      *
437      * @param $result resource PostgreSQL result identifier
438      *
439      * @return int the number of rows in $result
440      */
441     function numRows($result)
442     {
443         $rows = @pg_numrows($result);
444         if ($rows === null) {
445             return $this->pgsqlRaiseError();
446         }
447         return $rows;
448     }
449
450     // }}}
451     // {{{ errorNative()
452
453     /**
454      * Get the native error code of the last error (if any) that
455      * occured on the current connection.
456      *
457      * @return int native PostgreSQL error code
458      */
459     function errorNative()
460     {
461         return pg_errormessage($this->connection);
462     }
463
464     // }}}
465     // {{{ autoCommit()
466
467     /**
468      * Enable/disable automatic commits
469      */
470     function autoCommit($onoff = false)
471     {
472         // XXX if $this->transaction_opcount > 0, we should probably
473         // issue a warning here.
474         $this->autocommit = $onoff ? true : false;
475         return DB_OK;
476     }
477
478     // }}}
479     // {{{ commit()
480
481     /**
482      * Commit the current transaction.
483      */
484     function commit()
485     {
486         if ($this->transaction_opcount > 0) {
487             // (disabled) hack to shut up error messages from libpq.a
488             //@fclose(@fopen("php://stderr", "w"));
489             $result = @pg_exec($this->connection, 'end;');
490             $this->transaction_opcount = 0;
491             if (!$result) {
492                 return $this->pgsqlRaiseError();
493             }
494         }
495         return DB_OK;
496     }
497
498     // }}}
499     // {{{ rollback()
500
501     /**
502      * Roll back (undo) the current transaction.
503      */
504     function rollback()
505     {
506         if ($this->transaction_opcount > 0) {
507             $result = @pg_exec($this->connection, 'abort;');
508             $this->transaction_opcount = 0;
509             if (!$result) {
510                 return $this->pgsqlRaiseError();
511             }
512         }
513         return DB_OK;
514     }
515
516     // }}}
517     // {{{ affectedRows()
518
519     /**
520      * Gets the number of rows affected by the last query.
521      * if the last query was a select, returns 0.
522      *
523      * @return int number of rows affected by the last query or DB_ERROR
524      */
525     function affectedRows()
526     {
527         return $this->affected;
528     }
529
530     // }}}
531     // {{{ nextId()
532
533     /**
534      * Returns the next free id in a sequence
535      *
536      * @param string  $seq_name name of the sequence
537      * @param boolean $ondemand when true, the seqence is automatically
538      *                           created if it does not exist
539      *
540      * @return int the next id number in the sequence.  DB_Error if problem.
541      *
542      * @internal
543      * @see DB_common::nextID()
544      * @access public
545      */
546     function nextId($seq_name, $ondemand = true)
547     {
548         $seqname = $this->getSequenceName($seq_name);
549         $repeat = false;
550         do {
551             $this->pushErrorHandling(PEAR_ERROR_RETURN);
552             $result =& $this->query("SELECT NEXTVAL('${seqname}')");
553             $this->popErrorHandling();
554             if ($ondemand && DB::isError($result) &&
555                 $result->getCode() == DB_ERROR_NOSUCHTABLE) {
556                 $repeat = true;
557                 $this->pushErrorHandling(PEAR_ERROR_RETURN);
558                 $result = $this->createSequence($seq_name);
559                 $this->popErrorHandling();
560                 if (DB::isError($result)) {
561                     return $this->raiseError($result);
562                 }
563             } else {
564                 $repeat = false;
565             }
566         } while ($repeat);
567         if (DB::isError($result)) {
568             return $this->raiseError($result);
569         }
570         $arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
571         $result->free();
572         return $arr[0];
573     }
574
575     // }}}
576     // {{{ createSequence()
577
578     /**
579      * Create the sequence
580      *
581      * @param  string $seq_name the name of the sequence
582      * @return mixed  DB_OK on success or DB error on error
583      * @access public
584      */
585     function createSequence($seq_name)
586     {
587         $seqname = $this->getSequenceName($seq_name);
588         $result = $this->query("CREATE SEQUENCE ${seqname}");
589         return $result;
590     }
591
592     // }}}
593     // {{{ dropSequence()
594
595     /**
596      * Drop a sequence
597      *
598      * @param  string $seq_name the name of the sequence
599      * @return mixed  DB_OK on success or DB error on error
600      * @access public
601      */
602     function dropSequence($seq_name)
603     {
604         $seqname = $this->getSequenceName($seq_name);
605         return $this->query("DROP SEQUENCE ${seqname}");
606     }
607
608     // }}}
609     // {{{ modifyLimitQuery()
610
611     function modifyLimitQuery($query, $from, $count)
612     {
613         $query = $query . " LIMIT $count OFFSET $from";
614         return $query;
615     }
616
617     // }}}
618     // {{{ pgsqlRaiseError()
619
620     /**
621      * Gather information about an error, then use that info to create a
622      * DB error object and finally return that object.
623      *
624      * @param integer $errno PEAR error number (usually a DB constant) if
625      *                          manually raising an error
626      * @return object DB error object
627      * @see errorNative()
628      * @see errorCode()
629      * @see DB_common::raiseError()
630      */
631     function pgsqlRaiseError($errno = null)
632     {
633         $native = $this->errorNative();
634         if ($errno === null) {
635             $err = $this->errorCode($native);
636         } else {
637             $err = $errno;
638         }
639         return $this->raiseError($err, null, null, null, $native);
640     }
641
642     // }}}
643     // {{{ _pgFieldFlags()
644
645     /**
646      * Flags of a Field
647      *
648      * @param int $resource  PostgreSQL result identifier
649      * @param int $num_field the field number
650      *
651      * @return string The flags of the field ("not_null", "default_value",
652      *                "primary_key", "unique_key" and "multiple_key"
653      *                are supported).  The default value is passed
654      *                through rawurlencode() in case there are spaces in it.
655      * @access private
656      */
657     function _pgFieldFlags($resource, $num_field, $table_name)
658     {
659         $field_name = @pg_fieldname($resource, $num_field);
660
661         $result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef
662                                 FROM pg_attribute f, pg_class tab, pg_type typ
663                                 WHERE tab.relname = typ.typname
664                                 AND typ.typrelid = f.attrelid
665                                 AND f.attname = '$field_name'
666                                 AND tab.relname = '$table_name'");
667         if (@pg_numrows($result) > 0) {
668             $row = @pg_fetch_row($result, 0);
669             $flags  = ($row[0] == 't') ? 'not_null ' : '';
670
671             if ($row[1] == 't') {
672                 $result = @pg_exec($this->connection, "SELECT a.adsrc
673                                     FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a
674                                     WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid
675                                     AND f.attrelid = a.adrelid AND f.attname = '$field_name'
676                                     AND tab.relname = '$table_name' AND f.attnum = a.adnum");
677                 $row = @pg_fetch_row($result, 0);
678                 $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]);
679                 $flags .= 'default_' . rawurlencode($num) . ' ';
680             }
681         } else {
682             $flags = '';
683         }
684         $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey
685                                 FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i
686                                 WHERE tab.relname = typ.typname
687                                 AND typ.typrelid = f.attrelid
688                                 AND f.attrelid = i.indrelid
689                                 AND f.attname = '$field_name'
690                                 AND tab.relname = '$table_name'");
691         $count = @pg_numrows($result);
692
693         for ($i = 0; $i < $count ; $i++) {
694             $row = @pg_fetch_row($result, $i);
695             $keys = explode(' ', $row[2]);
696
697             if (in_array($num_field + 1, $keys)) {
698                 $flags .= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : '';
699                 $flags .= ($row[1] == 't') ? 'primary_key ' : '';
700                 if (count($keys) > 1)
701                     $flags .= 'multiple_key ';
702             }
703         }
704
705         return trim($flags);
706     }
707
708     // }}}
709     // {{{ tableInfo()
710
711     /**
712      * Returns information about a table or a result set.
713      *
714      * NOTE: only supports 'table' and 'flags' if <var>$result</var>
715      * is a table name.
716      *
717      * @param object|string $result DB_result object from a query or a
718      *                                string containing the name of a table
719      * @param  int   $mode a valid tableInfo mode
720      * @return array an associative array with the information requested
721      *                or an error object if something is wrong
722      * @access public
723      * @internal
724      * @see DB_common::tableInfo()
725      */
726     function tableInfo($result, $mode = null)
727     {
728         if (isset($result->result)) {
729             /*
730              * Probably received a result object.
731              * Extract the result resource identifier.
732              */
733             $id = $result->result;
734             $got_string = false;
735         } elseif (is_string($result)) {
736             /*
737              * Probably received a table name.
738              * Create a result resource identifier.
739              */
740             $id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0");
741             $got_string = true;
742         } else {
743             /*
744              * Probably received a result resource identifier.
745              * Copy it.
746              * Deprecated.  Here for compatibility only.
747              */
748             $id = $result;
749             $got_string = false;
750         }
751
752         if (!is_resource($id)) {
753             return $this->pgsqlRaiseError(DB_ERROR_NEED_MORE_DATA);
754         }
755
756         if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
757             $case_func = 'strtolower';
758         } else {
759             $case_func = 'strval';
760         }
761
762         $count = @pg_numfields($id);
763
764         // made this IF due to performance (one if is faster than $count if's)
765         if (!$mode) {
766
767             for ($i=0; $i<$count; $i++) {
768                 $res[$i]['table'] = $got_string ? $case_func($result) : '';
769                 $res[$i]['name']  = $case_func(@pg_fieldname($id, $i));
770                 $res[$i]['type']  = @pg_fieldtype($id, $i);
771                 $res[$i]['len']   = @pg_fieldsize($id, $i);
772                 $res[$i]['flags'] = $got_string ? $this->_pgFieldflags($id, $i, $result) : '';
773             }
774
775         } else { // full
776             $res['num_fields']= $count;
777
778             for ($i=0; $i<$count; $i++) {
779                 $res[$i]['table'] = $got_string ? $case_func($result) : '';
780                 $res[$i]['name']  = $case_func(@pg_fieldname($id, $i));
781                 $res[$i]['type']  = @pg_fieldtype($id, $i);
782                 $res[$i]['len']   = @pg_fieldsize($id, $i);
783                 $res[$i]['flags'] = $got_string ? $this->_pgFieldFlags($id, $i, $result) : '';
784
785                 if ($mode & DB_TABLEINFO_ORDER) {
786                     $res['order'][$res[$i]['name']] = $i;
787                 }
788                 if ($mode & DB_TABLEINFO_ORDERTABLE) {
789                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
790                 }
791             }
792         }
793
794         // free the result only if we were called on a table
795         if ($got_string) {
796             @pg_freeresult($id);
797         }
798         return $res;
799     }
800
801     // }}}
802     // {{{ getTablesQuery()
803
804     /**
805      * Returns the query needed to get some backend info
806      * @param  string $type What kind of info you want to retrieve
807      * @return string The SQL query string
808      */
809     function getSpecialQuery($type)
810     {
811         switch ($type) {
812             case 'tables':
813                 return "SELECT c.relname as \"Name\"
814                         FROM pg_class c, pg_user u
815                         WHERE c.relowner = u.usesysid AND c.relkind = 'r'
816                         AND not exists (select 1 from pg_views where viewname = c.relname)
817                         AND c.relname !~ '^pg_'
818                         UNION
819                         SELECT c.relname as \"Name\"
820                         FROM pg_class c
821                         WHERE c.relkind = 'r'
822                         AND not exists (select 1 from pg_views where viewname = c.relname)
823                         AND not exists (select 1 from pg_user where usesysid = c.relowner)
824                         AND c.relname !~ '^pg_'";
825             case 'views':
826                 // Table cols: viewname | viewowner | definition
827                 return 'SELECT viewname FROM pg_views';
828             case 'users':
829                 // cols: usename |usesysid|usecreatedb|usetrace|usesuper|usecatupd|passwd  |valuntil
830                 return 'SELECT usename FROM pg_user';
831             case 'databases':
832                 return 'SELECT datname FROM pg_database';
833             case 'functions':
834                 return 'SELECT proname FROM pg_proc';
835             default:
836                 return null;
837         }
838     }
839
840     // }}}
841
842 }
843
844 /*
845  * Local variables:
846  * tab-width: 4
847  * c-basic-offset: 4
848  * End:
849  */
850
851 ?>