]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/pear/DB/pgsql.php
Activated Id substitution for Subversion
[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      * Escape a string according to the current DBMS's standards
382      *
383      * PostgreSQL treats a backslash as an escape character, so they are
384      * removed.
385      *
386      * Not using pg_escape_string() yet because it requires PostgreSQL
387      * to be at version 7.2 or greater.
388      *
389      * @param string $str  the string to be escaped
390      *
391      * @return string  the escaped string
392      *
393      * @internal
394      */
395     function escapeSimple($str) {
396         return str_replace("'", "''", str_replace('\\', '\\\\', $str));
397     }
398
399     // }}}
400     // {{{ numCols()
401
402     /**
403      * Get the number of columns in a result set.
404      *
405      * @param $result resource PostgreSQL result identifier
406      *
407      * @return int the number of columns per row in $result
408      */
409     function numCols($result)
410     {
411         $cols = @pg_numfields($result);
412         if (!$cols) {
413             return $this->pgsqlRaiseError();
414         }
415         return $cols;
416     }
417
418     // }}}
419     // {{{ numRows()
420
421     /**
422      * Get the number of rows in a result set.
423      *
424      * @param $result resource PostgreSQL result identifier
425      *
426      * @return int the number of rows in $result
427      */
428     function numRows($result)
429     {
430         $rows = @pg_numrows($result);
431         if ($rows === null) {
432             return $this->pgsqlRaiseError();
433         }
434         return $rows;
435     }
436
437     // }}}
438     // {{{ errorNative()
439
440     /**
441      * Get the native error code of the last error (if any) that
442      * occured on the current connection.
443      *
444      * @return int native PostgreSQL error code
445      */
446     function errorNative()
447     {
448         return pg_errormessage($this->connection);
449     }
450
451     // }}}
452     // {{{ autoCommit()
453
454     /**
455      * Enable/disable automatic commits
456      */
457     function autoCommit($onoff = false)
458     {
459         // XXX if $this->transaction_opcount > 0, we should probably
460         // issue a warning here.
461         $this->autocommit = $onoff ? true : false;
462         return DB_OK;
463     }
464
465     // }}}
466     // {{{ commit()
467
468     /**
469      * Commit the current transaction.
470      */
471     function commit()
472     {
473         if ($this->transaction_opcount > 0) {
474             // (disabled) hack to shut up error messages from libpq.a
475             //@fclose(@fopen("php://stderr", "w"));
476             $result = @pg_exec($this->connection, 'end;');
477             $this->transaction_opcount = 0;
478             if (!$result) {
479                 return $this->pgsqlRaiseError();
480             }
481         }
482         return DB_OK;
483     }
484
485     // }}}
486     // {{{ rollback()
487
488     /**
489      * Roll back (undo) the current transaction.
490      */
491     function rollback()
492     {
493         if ($this->transaction_opcount > 0) {
494             $result = @pg_exec($this->connection, 'abort;');
495             $this->transaction_opcount = 0;
496             if (!$result) {
497                 return $this->pgsqlRaiseError();
498             }
499         }
500         return DB_OK;
501     }
502
503     // }}}
504     // {{{ affectedRows()
505
506     /**
507      * Gets the number of rows affected by the last query.
508      * if the last query was a select, returns 0.
509      *
510      * @return int number of rows affected by the last query or DB_ERROR
511      */
512     function affectedRows()
513     {
514         return $this->affected;
515     }
516
517     // }}}
518     // {{{ nextId()
519
520     /**
521      * Returns the next free id in a sequence
522      *
523      * @param string  $seq_name  name of the sequence
524      * @param boolean $ondemand  when true, the seqence is automatically
525      *                           created if it does not exist
526      *
527      * @return int  the next id number in the sequence.  DB_Error if problem.
528      *
529      * @internal
530      * @see DB_common::nextID()
531      * @access public
532      */
533     function nextId($seq_name, $ondemand = true)
534     {
535         $seqname = $this->getSequenceName($seq_name);
536         $repeat = false;
537         do {
538             $this->pushErrorHandling(PEAR_ERROR_RETURN);
539             $result =& $this->query("SELECT NEXTVAL('${seqname}')");
540             $this->popErrorHandling();
541             if ($ondemand && DB::isError($result) &&
542                 $result->getCode() == DB_ERROR_NOSUCHTABLE) {
543                 $repeat = true;
544                 $this->pushErrorHandling(PEAR_ERROR_RETURN);
545                 $result = $this->createSequence($seq_name);
546                 $this->popErrorHandling();
547                 if (DB::isError($result)) {
548                     return $this->raiseError($result);
549                 }
550             } else {
551                 $repeat = false;
552             }
553         } while ($repeat);
554         if (DB::isError($result)) {
555             return $this->raiseError($result);
556         }
557         $arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
558         $result->free();
559         return $arr[0];
560     }
561
562     // }}}
563     // {{{ createSequence()
564
565     /**
566      * Create the sequence
567      *
568      * @param string $seq_name the name of the sequence
569      * @return mixed DB_OK on success or DB error on error
570      * @access public
571      */
572     function createSequence($seq_name)
573     {
574         $seqname = $this->getSequenceName($seq_name);
575         $result = $this->query("CREATE SEQUENCE ${seqname}");
576         return $result;
577     }
578
579     // }}}
580     // {{{ dropSequence()
581
582     /**
583      * Drop a sequence
584      *
585      * @param string $seq_name the name of the sequence
586      * @return mixed DB_OK on success or DB error on error
587      * @access public
588      */
589     function dropSequence($seq_name)
590     {
591         $seqname = $this->getSequenceName($seq_name);
592         return $this->query("DROP SEQUENCE ${seqname}");
593     }
594
595     // }}}
596     // {{{ modifyLimitQuery()
597
598     function modifyLimitQuery($query, $from, $count)
599     {
600         $query = $query . " LIMIT $count OFFSET $from";
601         return $query;
602     }
603
604     // }}}
605     // {{{ pgsqlRaiseError()
606
607     /**
608      * Gather information about an error, then use that info to create a
609      * DB error object and finally return that object.
610      *
611      * @param  integer  $errno  PEAR error number (usually a DB constant) if
612      *                          manually raising an error
613      * @return object  DB error object
614      * @see errorNative()
615      * @see errorCode()
616      * @see DB_common::raiseError()
617      */
618     function pgsqlRaiseError($errno = null)
619     {
620         $native = $this->errorNative();
621         if ($errno === null) {
622             $err = $this->errorCode($native);
623         } else {
624             $err = $errno;
625         }
626         return $this->raiseError($err, null, null, null, $native);
627     }
628
629     // }}}
630     // {{{ _pgFieldFlags()
631
632     /**
633      * Flags of a Field
634      *
635      * @param int $resource PostgreSQL result identifier
636      * @param int $num_field the field number
637      *
638      * @return string The flags of the field ("not_null", "default_value",
639      *                "primary_key", "unique_key" and "multiple_key"
640      *                are supported).  The default value is passed
641      *                through rawurlencode() in case there are spaces in it.
642      * @access private
643      */
644     function _pgFieldFlags($resource, $num_field, $table_name)
645     {
646         $field_name = @pg_fieldname($resource, $num_field);
647
648         $result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef
649                                 FROM pg_attribute f, pg_class tab, pg_type typ
650                                 WHERE tab.relname = typ.typname
651                                 AND typ.typrelid = f.attrelid
652                                 AND f.attname = '$field_name'
653                                 AND tab.relname = '$table_name'");
654         if (@pg_numrows($result) > 0) {
655             $row = @pg_fetch_row($result, 0);
656             $flags  = ($row[0] == 't') ? 'not_null ' : '';
657
658             if ($row[1] == 't') {
659                 $result = @pg_exec($this->connection, "SELECT a.adsrc
660                                     FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a
661                                     WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid
662                                     AND f.attrelid = a.adrelid AND f.attname = '$field_name'
663                                     AND tab.relname = '$table_name' AND f.attnum = a.adnum");
664                 $row = @pg_fetch_row($result, 0);
665                 $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]);
666                 $flags .= 'default_' . rawurlencode($num) . ' ';
667             }
668         } else {
669             $flags = '';
670         }
671         $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey
672                                 FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i
673                                 WHERE tab.relname = typ.typname
674                                 AND typ.typrelid = f.attrelid
675                                 AND f.attrelid = i.indrelid
676                                 AND f.attname = '$field_name'
677                                 AND tab.relname = '$table_name'");
678         $count = @pg_numrows($result);
679
680         for ($i = 0; $i < $count ; $i++) {
681             $row = @pg_fetch_row($result, $i);
682             $keys = explode(' ', $row[2]);
683
684             if (in_array($num_field + 1, $keys)) {
685                 $flags .= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : '';
686                 $flags .= ($row[1] == 't') ? 'primary_key ' : '';
687                 if (count($keys) > 1)
688                     $flags .= 'multiple_key ';
689             }
690         }
691
692         return trim($flags);
693     }
694
695     // }}}
696     // {{{ tableInfo()
697
698     /**
699      * Returns information about a table or a result set.
700      *
701      * NOTE: only supports 'table' and 'flags' if <var>$result</var>
702      * is a table name.
703      *
704      * @param object|string  $result  DB_result object from a query or a
705      *                                string containing the name of a table
706      * @param int            $mode    a valid tableInfo mode
707      * @return array  an associative array with the information requested
708      *                or an error object if something is wrong
709      * @access public
710      * @internal
711      * @see DB_common::tableInfo()
712      */
713     function tableInfo($result, $mode = null)
714     {
715         if (isset($result->result)) {
716             /*
717              * Probably received a result object.
718              * Extract the result resource identifier.
719              */
720             $id = $result->result;
721             $got_string = false;
722         } elseif (is_string($result)) {
723             /*
724              * Probably received a table name.
725              * Create a result resource identifier.
726              */
727             $id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0");
728             $got_string = true;
729         } else {
730             /*
731              * Probably received a result resource identifier.
732              * Copy it.
733              * Deprecated.  Here for compatibility only.
734              */
735             $id = $result;
736             $got_string = false;
737         }
738
739         if (!is_resource($id)) {
740             return $this->pgsqlRaiseError(DB_ERROR_NEED_MORE_DATA);
741         }
742
743         if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
744             $case_func = 'strtolower';
745         } else {
746             $case_func = 'strval';
747         }
748
749         $count = @pg_numfields($id);
750
751         // made this IF due to performance (one if is faster than $count if's)
752         if (!$mode) {
753
754             for ($i=0; $i<$count; $i++) {
755                 $res[$i]['table'] = $got_string ? $case_func($result) : '';
756                 $res[$i]['name']  = $case_func(@pg_fieldname($id, $i));
757                 $res[$i]['type']  = @pg_fieldtype($id, $i);
758                 $res[$i]['len']   = @pg_fieldsize($id, $i);
759                 $res[$i]['flags'] = $got_string ? $this->_pgFieldflags($id, $i, $result) : '';
760             }
761
762         } else { // full
763             $res['num_fields']= $count;
764
765             for ($i=0; $i<$count; $i++) {
766                 $res[$i]['table'] = $got_string ? $case_func($result) : '';
767                 $res[$i]['name']  = $case_func(@pg_fieldname($id, $i));
768                 $res[$i]['type']  = @pg_fieldtype($id, $i);
769                 $res[$i]['len']   = @pg_fieldsize($id, $i);
770                 $res[$i]['flags'] = $got_string ? $this->_pgFieldFlags($id, $i, $result) : '';
771
772                 if ($mode & DB_TABLEINFO_ORDER) {
773                     $res['order'][$res[$i]['name']] = $i;
774                 }
775                 if ($mode & DB_TABLEINFO_ORDERTABLE) {
776                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
777                 }
778             }
779         }
780
781         // free the result only if we were called on a table
782         if ($got_string) {
783             @pg_freeresult($id);
784         }
785         return $res;
786     }
787
788     // }}}
789     // {{{ getTablesQuery()
790
791     /**
792      * Returns the query needed to get some backend info
793      * @param string $type What kind of info you want to retrieve
794      * @return string The SQL query string
795      */
796     function getSpecialQuery($type)
797     {
798         switch ($type) {
799             case 'tables':
800                 return "SELECT c.relname as \"Name\"
801                         FROM pg_class c, pg_user u
802                         WHERE c.relowner = u.usesysid AND c.relkind = 'r'
803                         AND not exists (select 1 from pg_views where viewname = c.relname)
804                         AND c.relname !~ '^pg_'
805                         UNION
806                         SELECT c.relname as \"Name\"
807                         FROM pg_class c
808                         WHERE c.relkind = 'r'
809                         AND not exists (select 1 from pg_views where viewname = c.relname)
810                         AND not exists (select 1 from pg_user where usesysid = c.relowner)
811                         AND c.relname !~ '^pg_'";
812             case 'views':
813                 // Table cols: viewname | viewowner | definition
814                 return 'SELECT viewname FROM pg_views';
815             case 'users':
816                 // cols: usename |usesysid|usecreatedb|usetrace|usesuper|usecatupd|passwd  |valuntil
817                 return 'SELECT usename FROM pg_user';
818             case 'databases':
819                 return 'SELECT datname FROM pg_database';
820             case 'functions':
821                 return 'SELECT proname FROM pg_proc';
822             default:
823                 return null;
824         }
825     }
826
827     // }}}
828
829 }
830
831 /*
832  * Local variables:
833  * tab-width: 4
834  * c-basic-offset: 4
835  * End:
836  */
837
838 ?>