3 V4.22 15 Apr 2004 (c) 2000-2004 John Lim (jlim@natsoft.com.my). All rights reserved.
4 Released under both BSD license and Lesser GPL library license.
5 Whenever there is any discrepancy between the two licenses,
6 the BSD license will take precedence.
9 Original version derived from Alberto Cerezal (acerezalp@dbnet.es) - DBNet Informatica & Comunicaciones.
10 08 Nov 2000 jlim - Minor corrections, removing mysql stuff
11 09 Nov 2000 jlim - added insertid support suggested by "Christopher Kings-Lynne" <chriskl@familyhealth.com.au>
12 jlim - changed concat operator to || and data types to MetaType to match documented pgsql types
13 see http://www.postgresql.org/devel-corner/docs/postgres/datatype.htm
14 22 Nov 2000 jlim - added changes to FetchField() and MetaTables() contributed by "raser" <raser@mail.zen.com.tw>
15 27 Nov 2000 jlim - added changes to _connect/_pconnect from ideas by "Lennie" <leen@wirehub.nl>
16 15 Dec 2000 jlim - added changes suggested by Additional code changes by "Eric G. Werk" egw@netguide.dk.
17 31 Jan 2002 jlim - finally installed postgresql. testing
18 01 Mar 2001 jlim - Freek Dijkstra changes, also support for text type
20 See http://www.varlena.com/varlena/GeneralBits/47.php
22 -- What indexes are on my table?
23 select * from pg_indexes where tablename = 'tablename';
25 -- What triggers are on my table?
26 select c.relname as "Table", t.tgname as "Trigger Name",
27 t.tgconstrname as "Constraint Name", t.tgenabled as "Enabled",
28 t.tgisconstraint as "Is Constraint", cc.relname as "Referenced Table",
29 p.proname as "Function Name"
30 from pg_trigger t, pg_class c, pg_class cc, pg_proc p
31 where t.tgfoid = p.oid and t.tgrelid = c.oid
32 and t.tgconstrrelid = cc.oid
33 and c.relname = 'tablename';
35 -- What constraints are on my table?
36 select r.relname as "Table", c.conname as "Constraint Name",
37 contype as "Constraint Type", conkey as "Key Columns",
38 confkey as "Foreign Columns", consrc as "Source"
39 from pg_class r, pg_constraint c
40 where r.oid = c.conrelid
41 and relname = 'tablename';
45 function adodb_addslashes($s)
48 if ($len == 0) return "''";
49 if (strncmp($s, "'", 1) === 0 && substr(s, $len - 1) == "'") return $s; // already quoted
51 return "'" . addslashes($s) . "'";
54 class ADODB_postgres64 extends ADOConnection
56 var $databaseType = 'postgres64';
57 var $dataProvider = 'postgres';
58 var $hasInsertID = true;
59 var $_resultid = false;
60 var $concat_operator = '||';
61 var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1";
62 var $metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' union
63 select viewname,'V' from pg_views where viewname not like 'pg\_%'";
64 //"select tablename from pg_tables where tablename not like 'pg_%' order by 1";
65 var $isoDates = true; // accepts dates in ISO format
66 var $sysDate = "CURRENT_DATE";
67 var $sysTimeStamp = "CURRENT_TIMESTAMP";
68 var $blobEncodeType = 'C';
69 var $metaColumnsSQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum
70 FROM pg_class c, pg_attribute a,pg_type t
71 WHERE relkind = 'r' AND (c.relname='%s' or c.relname = lower('%s')) and a.attname not like '....%%'
72 AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
74 var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum
75 FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n
76 WHERE relkind = 'r' AND (c.relname='%s' or c.relname = lower('%s'))
77 and c.relnamespace=n.oid and n.nspname='%s'
78 and a.attname not like '....%%' AND a.attnum > 0
79 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
81 // get primary key etc -- from Freek Dijkstra
82 var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key
83 FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'";
85 var $hasAffectedRows = true;
86 var $hasLimit = false; // set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10
87 // below suggested by Freek Dijkstra
88 var $true = 't'; // string that represents TRUE for a database
89 var $false = 'f'; // string that represents FALSE for a database
90 var $fmtDate = "'Y-m-d'"; // used by DBDate() as the default date format used by the database
91 var $fmtTimeStamp = "'Y-m-d G:i:s'"; // used by DBTimeStamp as the default timestamp fmt.
92 var $hasMoveFirst = true;
94 var $_genIDSQL = "SELECT NEXTVAL('%s')";
95 var $_genSeqSQL = "CREATE SEQUENCE %s START %s";
96 var $_dropSeqSQL = "DROP SEQUENCE %s";
97 var $metaDefaultsSQL = "SELECT d.adnum as num, d.adsrc as def from pg_attrdef d, pg_class c where d.adrelid=c.oid and c.relname='%s' order by d.adnum";
98 var $random = 'random()'; /// random function
99 var $autoRollback = true; // apparently pgsql does not autorollback properly before 4.3.4
100 // http://bugs.php.net/bug.php?id=25404
102 var $_bindInputArray = false; // requires postgresql 7.3+ and ability to modify database
104 // The last (fmtTimeStamp is not entirely correct:
105 // PostgreSQL also has support for time zones,
106 // and writes these time in this format: "2001-03-01 18:59:26+02".
107 // There is no code for the "+02" time zone information, so I just left that out.
108 // I'm not familiar enough with both ADODB as well as Postgres
109 // to know what the concequences are. The other values are correct (wheren't in 0.94)
112 function ADODB_postgres64()
114 // changes the metaColumnsSQL, adds columns: attnum[6]
117 function ServerInfo()
119 if (isset($this->version)) return $this->version;
121 $arr['description'] = $this->GetOne("select version()");
122 $arr['version'] = ADOConnection::_findvers($arr['description']);
123 $this->version = $arr;
128 function IfNull( $field, $ifNull )
130 return " NULLIF($field, $ifNull) "; // if PGSQL
133 // get the last id - never tested
134 function pg_insert_id($tablename, $fieldname)
136 $result = pg_exec($this->_connectionID, "SELECT last_value FROM ${tablename}_${fieldname}_seq");
138 $arr = @pg_fetch_row($result, 0);
139 pg_freeresult($result);
140 if (isset($arr[0])) return $arr[0];
145 /* Warning from http://www.php.net/manual/function.pg-getlastoid.php:
146 Using a OID as a unique identifier is not generally wise.
147 Unless you are very careful, you might end up with a tuple having
148 a different OID if a database must be reloaded. */
151 if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;
152 return pg_getlastoid($this->_resultid);
155 // I get this error with PHP before 4.0.6 - jlim
156 // Warning: This compilation does not support pg_cmdtuples() in d:/inetpub/wwwroot/php/adodb/adodb-postgres.inc.php on line 44
157 function _affectedrows()
159 if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;
160 return pg_cmdtuples($this->_resultid);
163 // returns true/false
164 function BeginTrans()
166 if ($this->transOff) return true;
167 $this->transCnt += 1;
168 return @pg_Exec($this->_connectionID, "begin");
171 function RowLock($tables, $where)
173 if (!$this->transCnt) $this->BeginTrans();
174 return $this->GetOne("select 1 as ignore from $tables where $where for update");
177 // returns true/false.
178 function CommitTrans($ok = true)
180 if ($this->transOff) return true;
181 if (!$ok) return $this->RollbackTrans();
183 $this->transCnt -= 1;
184 return @pg_Exec($this->_connectionID, "commit");
187 // returns true/false
188 function RollbackTrans()
190 if ($this->transOff) return true;
191 $this->transCnt -= 1;
192 return @pg_Exec($this->_connectionID, "rollback");
195 function &MetaTables($ttype = false, $showSchema = false, $mask = false)
198 $save = $this->metaTablesSQL;
199 $mask = $this->qstr(strtolower($mask));
200 $this->metaTablesSQL = "
201 select tablename,'T' from pg_tables where tablename like $mask union
202 select viewname,'V' from pg_views where viewname like $mask";
204 $ret =& ADOConnection::MetaTables($ttype, $showSchema);
207 $this->metaTablesSQL = $save;
213 // if magic quotes disabled, use pg_escape_string()
214 function qstr($s,$magic_quotes=false)
216 if (!$magic_quotes) {
217 if (ADODB_PHPVER >= 0x4200) {
218 return "'".pg_escape_string($s)."'";
220 if ($this->replaceQuote[0] == '\\'){
221 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
223 return "'".str_replace("'",$this->replaceQuote,$s)."'";
226 // undo magic quotes for "
227 $s = str_replace('\\"','"',$s);
233 // Format date column in sql string given an input format that understands Y M D
234 function SQLDate($fmt, $col = false)
236 if (!$col) $col = $this->sysTimeStamp;
237 $s = 'TO_CHAR(' . $col . ",'";
240 for ($i = 0; $i < $len; $i++) {
286 // handle escape characters...
289 $ch = substr($fmt, $i, 1);
291 if (strpos('-/.:;, ', $ch) !== false) $s .= $ch;
292 else $s .= '"' . $ch . '"';
301 * Load a Large Object from a file
302 * - the procedure stores the object id in the table and imports the object using
303 * postgres proprietary blob handling routines
305 * contributed by Mattia Rossi mattia@technologist.com
306 * modified for safe mode by juraj chlebec
308 function UpdateBlobFile($table, $column, $path, $where, $blobtype = 'BLOB')
310 pg_exec($this->_connectionID, "begin");
312 $fd = fopen($path, 'r');
313 $contents = fread($fd, filesize($path));
316 $oid = pg_lo_create($this->_connectionID);
317 $handle = pg_lo_open($this->_connectionID, $oid, 'w');
318 pg_lo_write($handle, $contents);
319 pg_lo_close($handle);
321 // $oid = pg_lo_import ($path);
322 pg_exec($this->_connectionID, "commit");
323 $rs = ADOConnection::UpdateBlob($table, $column, $oid, $where, $blobtype);
329 * If an OID is detected, then we use pg_lo_* to open the oid file and read the
330 * real blob from the db using the oid supplied as a parameter. If you are storing
331 * blobs using bytea, we autodetect and process it so this function is not needed.
333 * contributed by Mattia Rossi mattia@technologist.com
335 * see http://www.postgresql.org/idocs/index.php?largeobjects.html
337 function BlobDecode($blob)
339 if (strlen($blob) > 24) return $blob;
341 @pg_exec($this->_connectionID, "begin");
342 $fd = @pg_lo_open($this->_connectionID, $blob, "r");
344 @pg_exec($this->_connectionID, "commit");
347 $realblob = @pg_loreadall($fd);
349 @pg_exec($this->_connectionID, "commit");
354 See http://www.postgresql.org/idocs/index.php?datatype-binary.html
356 NOTE: SQL string literals (input strings) must be preceded with two backslashes
357 due to the fact that they must pass through two parsers in the PostgreSQL
360 function BlobEncode($blob)
362 if (ADODB_PHPVER >= 0x4200) return pg_escape_bytea($blob);
364 /*92=backslash, 0=null, 39=single-quote*/
365 $badch = array(chr(92), chr(0), chr(39)); # \ null '
366 $fixch = array('\\\\134', '\\\\000', '\\\\047');
367 return adodb_str_replace($badch, $fixch, $blob);
369 // note that there is a pg_escape_bytea function only for php 4.2.0 or later
372 function UpdateBlob($table, $column, $val, $where, $blobtype = 'BLOB')
374 // do not use bind params which uses qstr(), as blobencode() already quotes data
375 return $this->Execute("UPDATE $table SET $column='" . $this->BlobEncode($val) . "'::bytea WHERE $where");
378 function OffsetDate($dayFraction, $date = false)
380 if (!$date) $date = $this->sysDate;
381 return "($date+interval'$dayFraction days')";
385 // for schema support, pass in the $table param "$schema.$tabname".
386 // converts field names to lowercase, $upper is ignored
387 function &MetaColumns($table, $upper = true)
389 global $ADODB_FETCH_MODE;
392 $this->_findschema($table, $schema);
394 $table = strtolower($table);
396 $save = $ADODB_FETCH_MODE;
397 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
398 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
400 if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1, $table, $table, $schema));
401 else $rs =& $this->Execute(sprintf($this->metaColumnsSQL, $table, $table));
402 if (isset($savem)) $this->SetFetchMode($savem);
403 $ADODB_FETCH_MODE = $save;
405 if ($rs === false) return false;
407 if (!empty($this->metaKeySQL)) {
408 // If we want the primary keys, we have to issue a separate query
409 // Of course, a modified version of the metaColumnsSQL query using a
410 // LEFT JOIN would have been much more elegant, but postgres does
411 // not support OUTER JOINS. So here is the clumsy way.
413 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
415 $rskey = $this->Execute(sprintf($this->metaKeySQL, ($table)));
416 // fetch all result in once for performance.
417 $keys =& $rskey->GetArray();
418 if (isset($savem)) $this->SetFetchMode($savem);
419 $ADODB_FETCH_MODE = $save;
426 if (!empty($this->metaDefaultsSQL)) {
427 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
428 $sql = sprintf($this->metaDefaultsSQL, ($table));
429 $rsdef = $this->Execute($sql);
430 if (isset($savem)) $this->SetFetchMode($savem);
431 $ADODB_FETCH_MODE = $save;
434 while (!$rsdef->EOF) {
435 $num = $rsdef->fields['num'];
436 $s = $rsdef->fields['def'];
437 if (substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */
439 $s = substr($s, 0, strlen($s) - 1);
446 ADOConnection::outp("==> SQL => " . $sql);
453 $fld = new ADOFieldObject();
454 $fld->name = $rs->fields[0];
455 $fld->type = $rs->fields[1];
456 $fld->max_length = $rs->fields[2];
457 if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3] - 4;
458 if ($fld->max_length <= 0) $fld->max_length = -1;
461 // 5 hasdefault; 6 num-of-column
462 $fld->has_default = ($rs->fields[5] == 't');
463 if ($fld->has_default) {
464 $fld->default_value = $rsdefa[$rs->fields[6]];
468 if ($rs->fields[4] == $this->true) {
469 $fld->not_null = true;
473 if (is_array($keys)) {
474 foreach ($keys as $key) {
475 if ($fld->name == $key['column_name'] AND $key['primary_key'] == $this->true)
476 $fld->primary_key = true;
477 if ($fld->name == $key['column_name'] AND $key['unique_key'] == $this->true)
478 $fld->unique = true; // What name is more compatible?
482 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
483 else $retarr[($upper) ? strtoupper($fld->name) : $fld->name] = $fld;
492 function &MetaIndexes($table, $primary = FALSE)
494 global $ADODB_FETCH_MODE;
497 $this->_findschema($table, $schema);
499 if ($schema) { // requires pgsql 7.3+ - pg_namespace used.
501 SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns"
502 FROM pg_catalog.pg_class c
503 JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid
504 JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid
506 WHERE c2.relname=\'%s\' and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\' AND i.indisprimary=false';
509 SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns"
510 FROM pg_catalog.pg_class c
511 JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid
512 JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid
513 WHERE c2.relname=\'%s\'';
516 if ($primary == FALSE) {
517 $sql .= ' AND i.indisprimary=false;';
520 $save = $ADODB_FETCH_MODE;
521 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
522 if ($this->fetchMode !== FALSE) {
523 $savem = $this->SetFetchMode(FALSE);
526 $rs = $this->Execute(sprintf($sql, $table, $schema));
529 $this->SetFetchMode($savem);
531 $ADODB_FETCH_MODE = $save;
533 if (!is_object($rs)) {
537 $col_names = $this->MetaColumnNames($table);
540 while ($row = $rs->FetchRow()) {
543 foreach (explode(' ', $row[2]) as $col) {
544 $columns[] = $col_names[$col - 1];
547 $indexes[$row[0]] = array(
548 'unique' => ($row[1] == 't'),
549 'columns' => $columns
556 // returns true or false
559 // $db->Connect("host=host1 user=user1 password=secret port=4341");
560 // $db->Connect('host1','user1','secret');
561 function _connect($str, $user = '', $pwd = '', $db = '', $ctype = 0)
564 if (!function_exists('pg_pconnect')) return false;
566 $this->_errorMsg = false;
568 if ($user || $pwd || $db) {
569 $user = adodb_addslashes($user);
570 $pwd = adodb_addslashes($pwd);
571 if (strlen($db) == 0) $db = 'template1';
572 $db = adodb_addslashes($db);
574 $host = explode(":", $str);
575 if ($host[0]) $str = "host=" . adodb_addslashes($host[0]);
576 else $str = 'host=localhost';
577 if (isset($host[1])) $str .= " port=$host[1]";
579 if ($user) $str .= " user=" . $user;
580 if ($pwd) $str .= " password=" . $pwd;
581 if ($db) $str .= " dbname=" . $db;
584 //if ($user) $linea = "user=$user host=$linea password=$pwd dbname=$db port=5432";
586 if ($ctype === 1) { // persistent
587 $this->_connectionID = pg_pconnect($str);
589 if ($ctype === -1) { // nconnect, we trick pgsql ext by changing the connection str
592 if (empty($ncnt)) $ncnt = 1;
595 $str .= str_repeat(' ', $ncnt);
597 $this->_connectionID = pg_connect($str);
599 if ($this->_connectionID === false) return false;
600 $this->Execute("set datestyle='ISO'");
604 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
606 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName, -1);
609 // returns true or false
612 // $db->PConnect("host=host1 user=user1 password=secret port=4341");
613 // $db->PConnect('host1','user1','secret');
614 function _pconnect($str, $user = '', $pwd = '', $db = '')
616 return $this->_connect($str, $user, $pwd, $db, 1);
619 // returns queryID or false
620 function _query($sql, $inputarr)
625 It appears that PREPARE/EXECUTE is slower for many queries.
627 For query executed 1000 times:
628 "select id,firstname,lastname from adoxyz
629 where firstname not like ? and lastname not like ? and id = ?"
631 with plan = 1.51861286163 secs
632 no plan = 1.26903700829 secs
635 $plan = 'P' . md5($sql);
638 foreach ($inputarr as $v) {
639 if ($execp) $execp .= ',';
641 if (strncmp($v, "'", 1) !== 0) $execp .= $this->qstr($v);
647 if ($execp) $exsql = "EXECUTE $plan ($execp)";
648 else $exsql = "EXECUTE $plan";
650 $rez = @pg_exec($this->_connectionID, $exsql);
652 # Perhaps plan does not exist? Prepare/compile plan.
654 foreach ($inputarr as $v) {
655 if ($params) $params .= ',';
657 $params .= 'VARCHAR';
658 } elseif (is_integer($v)) {
659 $params .= 'INTEGER';
664 $sqlarr = explode('?', $sql);
668 foreach ($sqlarr as $v) {
669 $sql .= $v . ' $' . $i;
672 $s = "PREPARE $plan ($params) AS " . substr($sql, 0, strlen($sql) - 2);
674 pg_exec($this->_connectionID, $s);
675 echo $this->ErrorMsg();
678 $rez = pg_exec($this->_connectionID, $exsql);
680 $this->_errorMsg = false;
682 $rez = pg_exec($this->_connectionID, $sql);
684 // check if no data returned, then no need to create real recordset
685 if ($rez && pg_numfields($rez) <= 0) {
686 if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') {
687 pg_freeresult($this->_resultid);
689 $this->_resultid = $rez;
696 /* Returns: the last error message from previous database operation */
699 if ($this->_errorMsg !== false) return $this->_errorMsg;
700 if (ADODB_PHPVER >= 0x4300) {
701 if (!empty($this->_resultid)) {
702 $this->_errorMsg = @pg_result_error($this->_resultid);
703 if ($this->_errorMsg) return $this->_errorMsg;
706 if (!empty($this->_connectionID)) {
707 $this->_errorMsg = @pg_last_error($this->_connectionID);
708 } else $this->_errorMsg = @pg_last_error();
710 if (empty($this->_connectionID)) $this->_errorMsg = @pg_errormessage();
711 else $this->_errorMsg = @pg_errormessage($this->_connectionID);
713 return $this->_errorMsg;
718 $e = $this->ErrorMsg();
719 return strlen($e) ? $e : 0;
722 // returns true or false
725 if ($this->transCnt) $this->RollbackTrans();
726 if ($this->_resultid) {
727 @pg_freeresult($this->_resultid);
728 $this->_resultid = false;
730 @pg_close($this->_connectionID);
731 $this->_connectionID = false;
736 * Maximum size of C field
740 return 1000000000; // should be 1 Gb?
744 * Maximum size of X field
748 return 1000000000; // should be 1 Gb?
753 /*--------------------------------------------------------------------------------------
754 Class Name: Recordset
755 --------------------------------------------------------------------------------------*/
757 class ADORecordSet_postgres64 extends ADORecordSet
760 var $databaseType = "postgres64";
763 function ADORecordSet_postgres64($queryID, $mode = false)
765 if ($mode === false) {
766 global $ADODB_FETCH_MODE;
767 $mode = $ADODB_FETCH_MODE;
770 case ADODB_FETCH_NUM:
771 $this->fetchMode = PGSQL_NUM;
773 case ADODB_FETCH_ASSOC:
774 $this->fetchMode = PGSQL_ASSOC;
777 case ADODB_FETCH_DEFAULT:
778 case ADODB_FETCH_BOTH:
779 $this->fetchMode = PGSQL_BOTH;
782 $this->ADORecordSet($queryID);
785 function &GetRowAssoc($upper = true)
787 if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields;
788 $row =& ADORecordSet::GetRowAssoc($upper);
794 global $ADODB_COUNTRECS;
795 $qid = $this->_queryID;
796 $this->_numOfRows = ($ADODB_COUNTRECS) ? @pg_numrows($qid) : -1;
797 $this->_numOfFields = @pg_numfields($qid);
799 // cache types for blob decode check
800 for ($i = 0, $max = $this->_numOfFields; $i < $max; $i++) {
801 if (pg_fieldtype($qid, $i) == 'bytea') {
802 $this->_blobArr[$i] = pg_fieldname($qid, $off);
807 /* Use associative array to get fields array */
808 function Fields($colname)
810 if ($this->fetchMode != PGSQL_NUM) return @$this->fields[$colname];
813 $this->bind = array();
814 for ($i = 0; $i < $this->_numOfFields; $i++) {
815 $o = $this->FetchField($i);
816 $this->bind[strtoupper($o->name)] = $i;
819 return $this->fields[$this->bind[strtoupper($colname)]];
822 function &FetchField($fieldOffset = 0)
824 $off = $fieldOffset; // offsets begin at 0
826 $o = new ADOFieldObject();
827 $o->name = @pg_fieldname($this->_queryID, $off);
828 $o->type = @pg_fieldtype($this->_queryID, $off);
829 $o->max_length = @pg_fieldsize($this->_queryID, $off);
835 return @pg_fetch_row($this->_queryID, $row);
838 function _decode($blob)
840 eval('$realblob="' . adodb_str_replace(array('"', '$'), array('\"', '\$'), $blob) . '";');
846 if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) {
847 foreach ($this->_blobArr as $k => $v) {
848 $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]);
851 if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) {
852 foreach ($this->_blobArr as $k => $v) {
853 $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]);
858 // 10% speedup to move MoveNext to child class
862 $this->_currentRow++;
863 if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
864 $this->fields = @pg_fetch_array($this->_queryID, $this->_currentRow, $this->fetchMode);
865 if (is_array($this->fields) && $this->fields) {
866 if ($this->fields && isset($this->_blobArr)) $this->_fixblobs();
870 $this->fields = false;
879 if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)
882 $this->fields = @pg_fetch_array($this->_queryID, $this->_currentRow, $this->fetchMode);
884 if ($this->fields && isset($this->_blobArr)) $this->_fixblobs();
886 return (is_array($this->fields));
891 return @pg_freeresult($this->_queryID);
894 function MetaType($t, $len = -1, $fieldobj = false)
898 $t = $fieldobj->type;
899 $len = $fieldobj->max_length;
901 switch (strtoupper($t)) {
902 case 'MONEY': // stupid, postgres expects money to be a string
910 if ($len <= $this->blobSize) return 'C';
915 case 'IMAGE': // user defined type
916 case 'BLOB': // user defined type
917 case 'BIT': // This is a bit string, not a single bit, so don't return 'L'
941 if (isset($fieldobj) &&
942 empty($fieldobj->primary_key) && empty($fieldobj->unique)