3 V4.20 22 Feb 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
{
55 var $databaseType = 'postgres64';
56 var $dataProvider = 'postgres';
57 var $hasInsertID = true;
58 var $_resultid = false;
59 var $concat_operator='||';
60 var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1";
61 var $metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' union
62 select viewname,'V' from pg_views where viewname not like 'pg\_%'";
63 //"select tablename from pg_tables where tablename not like 'pg_%' order by 1";
64 var $isoDates = true; // accepts dates in ISO format
65 var $sysDate = "CURRENT_DATE";
66 var $sysTimeStamp = "CURRENT_TIMESTAMP";
67 var $blobEncodeType = 'C';
68 var $metaColumnsSQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum
69 FROM pg_class c, pg_attribute a,pg_type t
70 WHERE relkind = 'r' AND (c.relname='%s' or c.relname = lower('%s')) and a.attname not like '....%%'
71 AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
73 var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum
74 FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n
75 WHERE relkind = 'r' AND (c.relname='%s' or c.relname = lower('%s'))
76 and c.relnamespace=n.oid and n.nspname='%s'
77 and a.attname not like '....%%' AND a.attnum > 0
78 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
80 // get primary key etc -- from Freek Dijkstra
81 var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key
82 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'";
84 var $hasAffectedRows = true;
85 var $hasLimit = false; // set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10
86 // below suggested by Freek Dijkstra
87 var $true = 't'; // string that represents TRUE for a database
88 var $false = 'f'; // string that represents FALSE for a database
89 var $fmtDate = "'Y-m-d'"; // used by DBDate() as the default date format used by the database
90 var $fmtTimeStamp = "'Y-m-d G:i:s'"; // used by DBTimeStamp as the default timestamp fmt.
91 var $hasMoveFirst = true;
93 var $_genIDSQL = "SELECT NEXTVAL('%s')";
94 var $_genSeqSQL = "CREATE SEQUENCE %s START %s";
95 var $_dropSeqSQL = "DROP SEQUENCE %s";
96 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";
97 var $random = 'random()'; /// random function
98 var $autoRollback = true; // apparently pgsql does not autorollback properly before 4.3.4
99 // http://bugs.php.net/bug.php?id=25404
101 var $_bindInputArray = false; // requires postgresql 7.3+ and ability to modify database
103 // The last (fmtTimeStamp is not entirely correct:
104 // PostgreSQL also has support for time zones,
105 // and writes these time in this format: "2001-03-01 18:59:26+02".
106 // There is no code for the "+02" time zone information, so I just left that out.
107 // I'm not familiar enough with both ADODB as well as Postgres
108 // to know what the concequences are. The other values are correct (wheren't in 0.94)
111 function ADODB_postgres64()
113 // changes the metaColumnsSQL, adds columns: attnum[6]
116 function ServerInfo()
118 if (isset($this->version
)) return $this->version
;
120 $arr['description'] = $this->GetOne("select version()");
121 $arr['version'] = ADOConnection
::_findvers($arr['description']);
122 $this->version
= $arr;
126 function IfNull( $field, $ifNull )
128 return " NULLIF($field, $ifNull) "; // if PGSQL
131 // get the last id - never tested
132 function pg_insert_id($tablename,$fieldname)
134 $result=pg_exec($this->_connectionID
, "SELECT last_value FROM ${tablename}_${fieldname}_seq");
136 $arr = @pg_fetch_row
($result,0);
137 pg_freeresult($result);
138 if (isset($arr[0])) return $arr[0];
143 /* Warning from http://www.php.net/manual/function.pg-getlastoid.php:
144 Using a OID as a unique identifier is not generally wise.
145 Unless you are very careful, you might end up with a tuple having
146 a different OID if a database must be reloaded. */
149 if (!is_resource($this->_resultid
) ||
get_resource_type($this->_resultid
) !== 'pgsql result') return false;
150 return pg_getlastoid($this->_resultid
);
153 // I get this error with PHP before 4.0.6 - jlim
154 // Warning: This compilation does not support pg_cmdtuples() in d:/inetpub/wwwroot/php/adodb/adodb-postgres.inc.php on line 44
155 function _affectedrows()
157 if (!is_resource($this->_resultid
) ||
get_resource_type($this->_resultid
) !== 'pgsql result') return false;
158 return pg_cmdtuples($this->_resultid
);
162 // returns true/false
163 function BeginTrans()
165 if ($this->transOff
) return true;
166 $this->transCnt +
= 1;
167 return @pg_Exec
($this->_connectionID
, "begin");
170 function RowLock($tables,$where)
172 if (!$this->transCnt
) $this->BeginTrans();
173 return $this->GetOne("select 1 as ignore from $tables where $where for update");
176 // returns true/false.
177 function CommitTrans($ok=true)
179 if ($this->transOff
) return true;
180 if (!$ok) return $this->RollbackTrans();
182 $this->transCnt
-= 1;
183 return @pg_Exec
($this->_connectionID
, "commit");
186 // returns true/false
187 function RollbackTrans()
189 if ($this->transOff
) return true;
190 $this->transCnt
-= 1;
191 return @pg_Exec
($this->_connectionID
, "rollback");
194 function &MetaTables($ttype=false,$showSchema=false,$mask=false)
197 $save = $this->metaTablesSQL
;
198 $mask = $this->qstr(strtolower($mask));
199 $this->metaTablesSQL
= "
200 select tablename,'T' from pg_tables where tablename like $mask union
201 select viewname,'V' from pg_views where viewname like $mask";
203 $ret =& ADOConnection
::MetaTables($ttype,$showSchema);
206 $this->metaTablesSQL
= $save;
212 // if magic quotes disabled, use pg_escape_string()
213 function qstr($s,$magic_quotes=false)
215 if (!$magic_quotes) {
216 if (ADODB_PHPVER >= 0x4200) {
217 return "'".pg_escape_string($s)."'";
219 if ($this->replaceQuote[0] == '\\'){
220 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
222 return "'".str_replace("'",$this->replaceQuote,$s)."'";
225 // undo magic quotes for "
226 $s = str_replace('\\"','"',$s);
232 // Format date column in sql string given an input format that understands Y M D
233 function SQLDate($fmt, $col=false)
235 if (!$col) $col = $this->sysTimeStamp
;
236 $s = 'TO_CHAR('.$col.",'";
239 for ($i=0; $i < $len; $i++
) {
285 // handle escape characters...
288 $ch = substr($fmt,$i,1);
290 if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;
291 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 = split(":", $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);
620 // returns queryID or false
621 function _query($sql,$inputarr)
626 It appears that PREPARE/EXECUTE is slower for many queries.
628 For query executed 1000 times:
629 "select id,firstname,lastname from adoxyz
630 where firstname not like ? and lastname not like ? and id = ?"
632 with plan = 1.51861286163 secs
633 no plan = 1.26903700829 secs
638 $plan = 'P'.md5($sql);
641 foreach($inputarr as $v) {
642 if ($execp) $execp .= ',';
644 if (strncmp($v,"'",1) !== 0) $execp .= $this->qstr($v);
650 if ($execp) $exsql = "EXECUTE $plan ($execp)";
651 else $exsql = "EXECUTE $plan";
653 $rez = @pg_exec
($this->_connectionID
,$exsql);
655 # Perhaps plan does not exist? Prepare/compile plan.
657 foreach($inputarr as $v) {
658 if ($params) $params .= ',';
660 $params .= 'VARCHAR';
661 } else if (is_integer($v)) {
662 $params .= 'INTEGER';
667 $sqlarr = explode('?',$sql);
671 foreach($sqlarr as $v) {
675 $s = "PREPARE $plan ($params) AS ".substr($sql,0,strlen($sql)-2);
677 pg_exec($this->_connectionID
,$s);
678 echo $this->ErrorMsg();
681 $rez = pg_exec($this->_connectionID
,$exsql);
683 $this->_errorMsg
= false;
685 $rez = pg_exec($this->_connectionID
,$sql);
687 // check if no data returned, then no need to create real recordset
688 if ($rez && pg_numfields($rez) <= 0) {
689 if (is_resource($this->_resultid
) && get_resource_type($this->_resultid
) === 'pgsql result') {
690 pg_freeresult($this->_resultid
);
692 $this->_resultid
= $rez;
700 /* Returns: the last error message from previous database operation */
703 if ($this->_errorMsg
!== false) return $this->_errorMsg
;
704 if (ADODB_PHPVER
>= 0x4300) {
705 if (!empty($this->_resultid
)) {
706 $this->_errorMsg
= @pg_result_error
($this->_resultid
);
707 if ($this->_errorMsg
) return $this->_errorMsg
;
710 if (!empty($this->_connectionID
)) {
711 $this->_errorMsg
= @pg_last_error
($this->_connectionID
);
712 } else $this->_errorMsg
= @pg_last_error
();
714 if (empty($this->_connectionID
)) $this->_errorMsg
= @pg_errormessage
();
715 else $this->_errorMsg
= @pg_errormessage
($this->_connectionID
);
717 return $this->_errorMsg
;
722 $e = $this->ErrorMsg();
723 return strlen($e) ?
$e : 0;
726 // returns true or false
729 if ($this->transCnt
) $this->RollbackTrans();
730 if ($this->_resultid
) {
731 @pg_freeresult
($this->_resultid
);
732 $this->_resultid
= false;
734 @pg_close
($this->_connectionID
);
735 $this->_connectionID
= false;
741 * Maximum size of C field
745 return 1000000000; // should be 1 Gb?
749 * Maximum size of X field
753 return 1000000000; // should be 1 Gb?
759 /*--------------------------------------------------------------------------------------
760 Class Name: Recordset
761 --------------------------------------------------------------------------------------*/
763 class ADORecordSet_postgres64
extends ADORecordSet
{
765 var $databaseType = "postgres64";
767 function ADORecordSet_postgres64($queryID,$mode=false)
769 if ($mode === false) {
770 global $ADODB_FETCH_MODE;
771 $mode = $ADODB_FETCH_MODE;
775 case ADODB_FETCH_NUM
: $this->fetchMode
= PGSQL_NUM
; break;
776 case ADODB_FETCH_ASSOC
:$this->fetchMode
= PGSQL_ASSOC
; break;
778 case ADODB_FETCH_DEFAULT
:
779 case ADODB_FETCH_BOTH
:$this->fetchMode
= PGSQL_BOTH
; break;
781 $this->ADORecordSet($queryID);
784 function &GetRowAssoc($upper=true)
786 if ($this->fetchMode
== PGSQL_ASSOC
&& !$upper) return $this->fields
;
787 $row =& ADORecordSet
::GetRowAssoc($upper);
793 global $ADODB_COUNTRECS;
794 $this->_numOfRows
= ($ADODB_COUNTRECS)? @pg_numrows
($this->_queryID
):-1;
795 $this->_numOfFields
= @pg_numfields
($this->_queryID
);
797 // cache types for blob decode check
798 for ($i=0, $max = $this->_numOfFields
; $i < $max; $i++
) {
799 $f1 = $this->FetchField($i);
801 if ($f1->type
== 'bytea') $this->_blobArr
[$i] = $f1->name
;
805 /* Use associative array to get fields array */
806 function Fields($colname)
808 if ($this->fetchMode
!= PGSQL_NUM
) return @$this->fields
[$colname];
811 $this->bind
= array();
812 for ($i=0; $i < $this->_numOfFields
; $i++
) {
813 $o = $this->FetchField($i);
814 $this->bind
[strtoupper($o->name
)] = $i;
817 return $this->fields
[$this->bind
[strtoupper($colname)]];
820 function &FetchField($fieldOffset = 0)
822 $off=$fieldOffset; // offsets begin at 0
824 $o= new ADOFieldObject();
825 $o->name
= @pg_fieldname
($this->_queryID
,$off);
826 $o->type
= @pg_fieldtype
($this->_queryID
,$off);
827 $o->max_length
= @pg_fieldsize
($this->_queryID
,$off);
829 //print "off=$off name=$o->name type=$o->type len=$o->max_length<br>";
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
)) return 'I';