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{
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);
161 // returns true/false
162 function BeginTrans()
164 if ($this->transOff) return true;
165 $this->transCnt += 1;
166 return @pg_Exec($this->_connectionID, "begin");
169 function RowLock($tables,$where)
171 if (!$this->transCnt) $this->BeginTrans();
172 return $this->GetOne("select 1 as ignore from $tables where $where for update");
175 // returns true/false.
176 function CommitTrans($ok=true)
178 if ($this->transOff) return true;
179 if (!$ok) return $this->RollbackTrans();
181 $this->transCnt -= 1;
182 return @pg_Exec($this->_connectionID, "commit");
185 // returns true/false
186 function RollbackTrans()
188 if ($this->transOff) return true;
189 $this->transCnt -= 1;
190 return @pg_Exec($this->_connectionID, "rollback");
193 function &MetaTables($ttype=false,$showSchema=false,$mask=false)
196 $save = $this->metaTablesSQL;
197 $mask = $this->qstr(strtolower($mask));
198 $this->metaTablesSQL = "
199 select tablename,'T' from pg_tables where tablename like $mask union
200 select viewname,'V' from pg_views where viewname like $mask";
202 $ret =& ADOConnection::MetaTables($ttype,$showSchema);
205 $this->metaTablesSQL = $save;
211 // if magic quotes disabled, use pg_escape_string()
212 function qstr($s,$magic_quotes=false)
214 if (!$magic_quotes) {
215 if (ADODB_PHPVER >= 0x4200) {
216 return "'".pg_escape_string($s)."'";
218 if ($this->replaceQuote[0] == '\\'){
219 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
221 return "'".str_replace("'",$this->replaceQuote,$s)."'";
224 // undo magic quotes for "
225 $s = str_replace('\\"','"',$s);
231 // Format date column in sql string given an input format that understands Y M D
232 function SQLDate($fmt, $col=false)
234 if (!$col) $col = $this->sysTimeStamp;
235 $s = 'TO_CHAR('.$col.",'";
238 for ($i=0; $i < $len; $i++) {
284 // handle escape characters...
287 $ch = substr($fmt,$i,1);
289 if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;
290 else $s .= '"'.$ch.'"';
300 * Load a Large Object from a file
301 * - the procedure stores the object id in the table and imports the object using
302 * postgres proprietary blob handling routines
304 * contributed by Mattia Rossi mattia@technologist.com
305 * modified for safe mode by juraj chlebec
307 function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
309 pg_exec ($this->_connectionID, "begin");
311 $fd = fopen($path,'r');
312 $contents = fread($fd,filesize($path));
315 $oid = pg_lo_create($this->_connectionID);
316 $handle = pg_lo_open($this->_connectionID, $oid, 'w');
317 pg_lo_write($handle, $contents);
318 pg_lo_close($handle);
320 // $oid = pg_lo_import ($path);
321 pg_exec($this->_connectionID, "commit");
322 $rs = ADOConnection::UpdateBlob($table,$column,$oid,$where,$blobtype);
328 * If an OID is detected, then we use pg_lo_* to open the oid file and read the
329 * real blob from the db using the oid supplied as a parameter. If you are storing
330 * blobs using bytea, we autodetect and process it so this function is not needed.
332 * contributed by Mattia Rossi mattia@technologist.com
334 * see http://www.postgresql.org/idocs/index.php?largeobjects.html
336 function BlobDecode( $blob)
338 if (strlen($blob) > 24) return $blob;
340 @pg_exec($this->_connectionID,"begin");
341 $fd = @pg_lo_open($this->_connectionID,$blob,"r");
343 @pg_exec($this->_connectionID,"commit");
346 $realblob = @pg_loreadall($fd);
348 @pg_exec($this->_connectionID,"commit");
353 See http://www.postgresql.org/idocs/index.php?datatype-binary.html
355 NOTE: SQL string literals (input strings) must be preceded with two backslashes
356 due to the fact that they must pass through two parsers in the PostgreSQL
359 function BlobEncode($blob)
361 if (ADODB_PHPVER >= 0x4200) return pg_escape_bytea($blob);
363 /*92=backslash, 0=null, 39=single-quote*/
364 $badch = array(chr(92),chr(0),chr(39)); # \ null '
365 $fixch = array('\\\\134','\\\\000','\\\\047');
366 return adodb_str_replace($badch,$fixch,$blob);
368 // note that there is a pg_escape_bytea function only for php 4.2.0 or later
371 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
373 // do not use bind params which uses qstr(), as blobencode() already quotes data
374 return $this->Execute("UPDATE $table SET $column='".$this->BlobEncode($val)."'::bytea WHERE $where");
377 function OffsetDate($dayFraction,$date=false)
379 if (!$date) $date = $this->sysDate;
380 return "($date+interval'$dayFraction days')";
384 // for schema support, pass in the $table param "$schema.$tabname".
385 // converts field names to lowercase, $upper is ignored
386 function &MetaColumns($table,$upper=true)
388 global $ADODB_FETCH_MODE;
391 $this->_findschema($table,$schema);
393 $table = strtolower($table);
395 $save = $ADODB_FETCH_MODE;
396 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
397 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
399 if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema));
400 else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table));
401 if (isset($savem)) $this->SetFetchMode($savem);
402 $ADODB_FETCH_MODE = $save;
404 if ($rs === false) return false;
406 if (!empty($this->metaKeySQL)) {
407 // If we want the primary keys, we have to issue a separate query
408 // Of course, a modified version of the metaColumnsSQL query using a
409 // LEFT JOIN would have been much more elegant, but postgres does
410 // not support OUTER JOINS. So here is the clumsy way.
412 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
414 $rskey = $this->Execute(sprintf($this->metaKeySQL,($table)));
415 // fetch all result in once for performance.
416 $keys =& $rskey->GetArray();
417 if (isset($savem)) $this->SetFetchMode($savem);
418 $ADODB_FETCH_MODE = $save;
425 if (!empty($this->metaDefaultsSQL)) {
426 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
427 $sql = sprintf($this->metaDefaultsSQL, ($table));
428 $rsdef = $this->Execute($sql);
429 if (isset($savem)) $this->SetFetchMode($savem);
430 $ADODB_FETCH_MODE = $save;
433 while (!$rsdef->EOF) {
434 $num = $rsdef->fields['num'];
435 $s = $rsdef->fields['def'];
436 if (substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */
438 $s = substr($s, 0, strlen($s) - 1);
445 ADOConnection::outp( "==> SQL => " . $sql);
452 $fld = new ADOFieldObject();
453 $fld->name = $rs->fields[0];
454 $fld->type = $rs->fields[1];
455 $fld->max_length = $rs->fields[2];
456 if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4;
457 if ($fld->max_length <= 0) $fld->max_length = -1;
460 // 5 hasdefault; 6 num-of-column
461 $fld->has_default = ($rs->fields[5] == 't');
462 if ($fld->has_default) {
463 $fld->default_value = $rsdefa[$rs->fields[6]];
467 if ($rs->fields[4] == $this->true) {
468 $fld->not_null = true;
472 if (is_array($keys)) {
473 foreach($keys as $key) {
474 if ($fld->name == $key['column_name'] AND $key['primary_key'] == $this->true)
475 $fld->primary_key = true;
476 if ($fld->name == $key['column_name'] AND $key['unique_key'] == $this->true)
477 $fld->unique = true; // What name is more compatible?
481 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
482 else $retarr[($upper) ? strtoupper($fld->name) : $fld->name] = $fld;
491 function &MetaIndexes ($table, $primary = FALSE)
493 global $ADODB_FETCH_MODE;
496 $this->_findschema($table,$schema);
498 if ($schema) { // requires pgsql 7.3+ - pg_namespace used.
500 SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns"
501 FROM pg_catalog.pg_class c
502 JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid
503 JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid
505 WHERE c2.relname=\'%s\' and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\' AND i.indisprimary=false';
508 SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns"
509 FROM pg_catalog.pg_class c
510 JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid
511 JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid
512 WHERE c2.relname=\'%s\'';
515 if ($primary == FALSE) {
516 $sql .= ' AND i.indisprimary=false;';
519 $save = $ADODB_FETCH_MODE;
520 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
521 if ($this->fetchMode !== FALSE) {
522 $savem = $this->SetFetchMode(FALSE);
525 $rs = $this->Execute(sprintf($sql,$table,$schema));
528 $this->SetFetchMode($savem);
530 $ADODB_FETCH_MODE = $save;
532 if (!is_object($rs)) {
536 $col_names = $this->MetaColumnNames($table);
539 while ($row = $rs->FetchRow()) {
542 foreach (explode(' ', $row[2]) as $col) {
543 $columns[] = $col_names[$col - 1];
546 $indexes[$row[0]] = array(
547 'unique' => ($row[1] == 't'),
548 'columns' => $columns
555 // returns true or false
558 // $db->Connect("host=host1 user=user1 password=secret port=4341");
559 // $db->Connect('host1','user1','secret');
560 function _connect($str,$user='',$pwd='',$db='',$ctype=0)
563 if (!function_exists('pg_pconnect')) return false;
565 $this->_errorMsg = false;
567 if ($user || $pwd || $db) {
568 $user = adodb_addslashes($user);
569 $pwd = adodb_addslashes($pwd);
570 if (strlen($db) == 0) $db = 'template1';
571 $db = adodb_addslashes($db);
573 $host = explode(":", $str);
574 if ($host[0]) $str = "host=".adodb_addslashes($host[0]);
575 else $str = 'host=localhost';
576 if (isset($host[1])) $str .= " port=$host[1]";
578 if ($user) $str .= " user=".$user;
579 if ($pwd) $str .= " password=".$pwd;
580 if ($db) $str .= " dbname=".$db;
583 //if ($user) $linea = "user=$user host=$linea password=$pwd dbname=$db port=5432";
585 if ($ctype === 1) { // persistent
586 $this->_connectionID = pg_pconnect($str);
588 if ($ctype === -1) { // nconnect, we trick pgsql ext by changing the connection str
591 if (empty($ncnt)) $ncnt = 1;
594 $str .= str_repeat(' ',$ncnt);
596 $this->_connectionID = pg_connect($str);
598 if ($this->_connectionID === false) return false;
599 $this->Execute("set datestyle='ISO'");
603 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
605 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName,-1);
608 // returns true or false
611 // $db->PConnect("host=host1 user=user1 password=secret port=4341");
612 // $db->PConnect('host1','user1','secret');
613 function _pconnect($str,$user='',$pwd='',$db='')
615 return $this->_connect($str,$user,$pwd,$db,1);
618 // returns queryID or false
619 function _query($sql,$inputarr)
624 It appears that PREPARE/EXECUTE is slower for many queries.
626 For query executed 1000 times:
627 "select id,firstname,lastname from adoxyz
628 where firstname not like ? and lastname not like ? and id = ?"
630 with plan = 1.51861286163 secs
631 no plan = 1.26903700829 secs
634 $plan = 'P'.md5($sql);
637 foreach($inputarr as $v) {
638 if ($execp) $execp .= ',';
640 if (strncmp($v,"'",1) !== 0) $execp .= $this->qstr($v);
646 if ($execp) $exsql = "EXECUTE $plan ($execp)";
647 else $exsql = "EXECUTE $plan";
649 $rez = @pg_exec($this->_connectionID,$exsql);
651 # Perhaps plan does not exist? Prepare/compile plan.
653 foreach($inputarr as $v) {
654 if ($params) $params .= ',';
656 $params .= 'VARCHAR';
657 } elseif (is_integer($v)) {
658 $params .= 'INTEGER';
663 $sqlarr = explode('?',$sql);
667 foreach($sqlarr as $v) {
671 $s = "PREPARE $plan ($params) AS ".substr($sql,0,strlen($sql)-2);
673 pg_exec($this->_connectionID,$s);
674 echo $this->ErrorMsg();
677 $rez = pg_exec($this->_connectionID,$exsql);
679 $this->_errorMsg = false;
681 $rez = pg_exec($this->_connectionID,$sql);
683 // check if no data returned, then no need to create real recordset
684 if ($rez && pg_numfields($rez) <= 0) {
685 if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') {
686 pg_freeresult($this->_resultid);
688 $this->_resultid = $rez;
695 /* Returns: the last error message from previous database operation */
698 if ($this->_errorMsg !== false) return $this->_errorMsg;
699 if (ADODB_PHPVER >= 0x4300) {
700 if (!empty($this->_resultid)) {
701 $this->_errorMsg = @pg_result_error($this->_resultid);
702 if ($this->_errorMsg) return $this->_errorMsg;
705 if (!empty($this->_connectionID)) {
706 $this->_errorMsg = @pg_last_error($this->_connectionID);
707 } else $this->_errorMsg = @pg_last_error();
709 if (empty($this->_connectionID)) $this->_errorMsg = @pg_errormessage();
710 else $this->_errorMsg = @pg_errormessage($this->_connectionID);
712 return $this->_errorMsg;
717 $e = $this->ErrorMsg();
718 return strlen($e) ? $e : 0;
721 // returns true or false
724 if ($this->transCnt) $this->RollbackTrans();
725 if ($this->_resultid) {
726 @pg_freeresult($this->_resultid);
727 $this->_resultid = false;
729 @pg_close($this->_connectionID);
730 $this->_connectionID = false;
735 * Maximum size of C field
739 return 1000000000; // should be 1 Gb?
743 * Maximum size of X field
747 return 1000000000; // should be 1 Gb?
752 /*--------------------------------------------------------------------------------------
753 Class Name: Recordset
754 --------------------------------------------------------------------------------------*/
756 class ADORecordSet_postgres64 extends ADORecordSet{
758 var $databaseType = "postgres64";
760 function ADORecordSet_postgres64($queryID,$mode=false)
762 if ($mode === false) {
763 global $ADODB_FETCH_MODE;
764 $mode = $ADODB_FETCH_MODE;
768 case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break;
769 case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break;
771 case ADODB_FETCH_DEFAULT:
772 case ADODB_FETCH_BOTH:$this->fetchMode = PGSQL_BOTH; break;
774 $this->ADORecordSet($queryID);
777 function &GetRowAssoc($upper=true)
779 if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields;
780 $row =& ADORecordSet::GetRowAssoc($upper);
786 global $ADODB_COUNTRECS;
787 $qid = $this->_queryID;
788 $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($qid):-1;
789 $this->_numOfFields = @pg_numfields($qid);
791 // cache types for blob decode check
792 for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) {
793 if (pg_fieldtype($qid,$i) == 'bytea') {
794 $this->_blobArr[$i] = pg_fieldname($qid,$off);
799 /* Use associative array to get fields array */
800 function Fields($colname)
802 if ($this->fetchMode != PGSQL_NUM) return @$this->fields[$colname];
805 $this->bind = array();
806 for ($i=0; $i < $this->_numOfFields; $i++) {
807 $o = $this->FetchField($i);
808 $this->bind[strtoupper($o->name)] = $i;
811 return $this->fields[$this->bind[strtoupper($colname)]];
814 function &FetchField($fieldOffset = 0)
816 $off=$fieldOffset; // offsets begin at 0
818 $o= new ADOFieldObject();
819 $o->name = @pg_fieldname($this->_queryID,$off);
820 $o->type = @pg_fieldtype($this->_queryID,$off);
821 $o->max_length = @pg_fieldsize($this->_queryID,$off);
827 return @pg_fetch_row($this->_queryID,$row);
830 function _decode($blob)
832 eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";');
838 if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) {
839 foreach($this->_blobArr as $k => $v) {
840 $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]);
843 if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) {
844 foreach($this->_blobArr as $k => $v) {
845 $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]);
850 // 10% speedup to move MoveNext to child class
854 $this->_currentRow++;
855 if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
856 $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
857 if (is_array($this->fields) && $this->fields) {
858 if ($this->fields && isset($this->_blobArr)) $this->_fixblobs();
862 $this->fields = false;
871 if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)
874 $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
876 if ($this->fields && isset($this->_blobArr)) $this->_fixblobs();
878 return (is_array($this->fields));
883 return @pg_freeresult($this->_queryID);
886 function MetaType($t,$len=-1,$fieldobj=false)
890 $t = $fieldobj->type;
891 $len = $fieldobj->max_length;
893 switch (strtoupper($t)) {
894 case 'MONEY': // stupid, postgres expects money to be a string
902 if ($len <= $this->blobSize) return 'C';
907 case 'IMAGE': // user defined type
908 case 'BLOB': // user defined type
909 case 'BIT': // This is a bit string, not a single bit, so don't return 'L'
933 if (isset($fieldobj) &&
934 empty($fieldobj->primary_key) && empty($fieldobj->unique)) return 'I';