Fixed Bug #1329196: bytea doesn't display as NULL when NULL
authormr-russ <mr-russ>
Fri, 13 Apr 2007 11:08:01 +0000 (11:08 +0000)
committermr-russ <mr-russ>
Fri, 13 Apr 2007 11:08:01 +0000 (11:08 +0000)
Should return NULL from ADO when the blob is NULL.

HISTORY
libraries/adodb/drivers/adodb-postgres64.inc.php

diff --git a/HISTORY b/HISTORY
index 73dba1ec06bacdc625a01859080da24622504c56..2c3337295104dbecbeb59db395a9598fe1e941d6 100644 (file)
--- a/HISTORY
+++ b/HISTORY
@@ -7,6 +7,7 @@ Version 4.1.2
 Bugs
 * Fix PHP5 Strict mode complaints 
 * Fix IN/NOT IN to accept text input lists 'a','b'.
+* Fix bytea doesn't display as NULL when NULL
 
 Version 4.1.1
 -------------
index 469bd463cc028d6c64ffa47e3178befadb041bfd..aabe63ade4b7ab3e8597da69a4d50b37bcb29d62 100644 (file)
-<?php\r
-/*\r
- V4.65 22 July 2005  (c) 2000-2005 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-  Set tabs to 8.\r
-  \r
-  Original version derived from Alberto Cerezal (acerezalp@dbnet.es) - DBNet Informatica & Comunicaciones. \r
-  08 Nov 2000 jlim - Minor corrections, removing mysql stuff\r
-  09 Nov 2000 jlim - added insertid support suggested by "Christopher Kings-Lynne" <chriskl@familyhealth.com.au>\r
-                                       jlim - changed concat operator to || and data types to MetaType to match documented pgsql types \r
-                       see http://www.postgresql.org/devel-corner/docs/postgres/datatype.htm  \r
-  22 Nov 2000 jlim - added changes to FetchField() and MetaTables() contributed by "raser" <raser@mail.zen.com.tw>\r
-  27 Nov 2000 jlim - added changes to _connect/_pconnect from ideas by "Lennie" <leen@wirehub.nl>\r
-  15 Dec 2000 jlim - added changes suggested by Additional code changes by "Eric G. Werk" egw@netguide.dk. \r
-  31 Jan 2002 jlim - finally installed postgresql. testing\r
-  01 Mar 2001 jlim - Freek Dijkstra changes, also support for text type\r
-  \r
-  See http://www.varlena.com/varlena/GeneralBits/47.php\r
-  \r
-       -- What indexes are on my table?\r
-       select * from pg_indexes where tablename = 'tablename';\r
-       \r
-       -- What triggers are on my table?\r
-       select c.relname as "Table", t.tgname as "Trigger Name", \r
-          t.tgconstrname as "Constraint Name", t.tgenabled as "Enabled",\r
-          t.tgisconstraint as "Is Constraint", cc.relname as "Referenced Table",\r
-          p.proname as "Function Name"\r
-       from pg_trigger t, pg_class c, pg_class cc, pg_proc p\r
-       where t.tgfoid = p.oid and t.tgrelid = c.oid\r
-          and t.tgconstrrelid = cc.oid\r
-          and c.relname = 'tablename';\r
-       \r
-       -- What constraints are on my table?\r
-       select r.relname as "Table", c.conname as "Constraint Name",\r
-          contype as "Constraint Type", conkey as "Key Columns",\r
-          confkey as "Foreign Columns", consrc as "Source"\r
-       from pg_class r, pg_constraint c\r
-       where r.oid = c.conrelid\r
-          and relname = 'tablename';\r
-\r
-*/\r
-\r
-// security - hide paths\r
-if (!defined('ADODB_DIR')) die();\r
-\r
-function adodb_addslashes($s)\r
-{\r
-       $len = strlen($s);\r
-       if ($len == 0) return "''";\r
-       if (strncmp($s,"'",1) === 0 && substr(s,$len-1) == "'") return $s; // already quoted\r
-       \r
-       return "'".addslashes($s)."'";\r
-}\r
-\r
-class ADODB_postgres64 extends ADOConnection{\r
-       var $databaseType = 'postgres64';\r
-       var $dataProvider = 'postgres';\r
-       var $hasInsertID = true;\r
-       var $_resultid = false;\r
-       var $concat_operator='||';\r
-       var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1";\r
-    var $metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%'\r
-       and tablename not in ('sql_features', 'sql_implementation_info', 'sql_languages',\r
-        'sql_packages', 'sql_sizing', 'sql_sizing_profiles') \r
-       union \r
-        select viewname,'V' from pg_views where viewname not like 'pg\_%'";\r
-       //"select tablename from pg_tables where tablename not like 'pg_%' order by 1";\r
-       var $isoDates = true; // accepts dates in ISO format\r
-       var $sysDate = "CURRENT_DATE";\r
-       var $sysTimeStamp = "CURRENT_TIMESTAMP";\r
-       var $blobEncodeType = 'C';\r
-       var $metaColumnsSQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum \r
-               FROM pg_class c, pg_attribute a,pg_type t \r
-               WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) and a.attname not like '....%%'\r
-AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";\r
-\r
-       // used when schema defined\r
-       var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum \r
-FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n \r
-WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s'))\r
- and c.relnamespace=n.oid and n.nspname='%s' \r
-       and a.attname not like '....%%' AND a.attnum > 0 \r
-       AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";\r
-       \r
-       // get primary key etc -- from Freek Dijkstra\r
-       var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key \r
-       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'";\r
-       \r
-       var $hasAffectedRows = true;\r
-       var $hasLimit = false;  // set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10\r
-       // below suggested by Freek Dijkstra \r
-       var $true = 'TRUE';             // string that represents TRUE for a database\r
-       var $false = 'FALSE';           // string that represents FALSE for a database\r
-       var $fmtDate = "'Y-m-d'";       // used by DBDate() as the default date format used by the database\r
-       var $fmtTimeStamp = "'Y-m-d G:i:s'"; // used by DBTimeStamp as the default timestamp fmt.\r
-       var $hasMoveFirst = true;\r
-       var $hasGenID = true;\r
-       var $_genIDSQL = "SELECT NEXTVAL('%s')";\r
-       var $_genSeqSQL = "CREATE SEQUENCE %s START %s";\r
-       var $_dropSeqSQL = "DROP SEQUENCE %s";\r
-       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";\r
-       var $random = 'random()';               /// random function\r
-       var $autoRollback = true; // apparently pgsql does not autorollback properly before php 4.3.4\r
-                                                       // http://bugs.php.net/bug.php?id=25404\r
-                                                       \r
-       var $_bindInputArray = false; // requires postgresql 7.3+ and ability to modify database\r
-       var $disableBlobs = false; // set to true to disable blob checking, resulting in 2-5% improvement in performance.\r
-       \r
-       // The last (fmtTimeStamp is not entirely correct: \r
-       // PostgreSQL also has support for time zones, \r
-       // and writes these time in this format: "2001-03-01 18:59:26+02". \r
-       // There is no code for the "+02" time zone information, so I just left that out. \r
-       // I'm not familiar enough with both ADODB as well as Postgres \r
-       // to know what the concequences are. The other values are correct (wheren't in 0.94)\r
-       // -- Freek Dijkstra \r
-\r
-       function ADODB_postgres64() \r
-       {\r
-       // changes the metaColumnsSQL, adds columns: attnum[6]\r
-       }\r
-       \r
-       function ServerInfo()\r
-       {\r
-               if (isset($this->version)) return $this->version;\r
-               \r
-               $arr['description'] = $this->GetOne("select version()");\r
-               $arr['version'] = ADOConnection::_findvers($arr['description']);\r
-               $this->version = $arr;\r
-               return $arr;\r
-       }\r
-\r
-       function IfNull( $field, $ifNull ) \r
-       {\r
-               return " coalesce($field, $ifNull) "; \r
-       }\r
-\r
-       // get the last id - never tested\r
-       function pg_insert_id($tablename,$fieldname)\r
-       {\r
-               $result=pg_exec($this->_connectionID, "SELECT last_value FROM ${tablename}_${fieldname}_seq");\r
-               if ($result) {\r
-                       $arr = @pg_fetch_row($result,0);\r
-                       pg_freeresult($result);\r
-                       if (isset($arr[0])) return $arr[0];\r
-               }\r
-               return false;\r
-       }\r
-       \r
-/* Warning from http://www.php.net/manual/function.pg-getlastoid.php:\r
-Using a OID as a unique identifier is not generally wise. \r
-Unless you are very careful, you might end up with a tuple having \r
-a different OID if a database must be reloaded. */\r
-       function _insertid($table,$column)\r
-       {\r
-               if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;\r
-               $oid = pg_getlastoid($this->_resultid);\r
-               // to really return the id, we need the table and column-name, else we can only return the oid != id\r
-               return empty($table) || empty($column) ? $oid : $this->GetOne("SELECT $column FROM $table WHERE oid=".(int)$oid);\r
-       }\r
-\r
-// I get this error with PHP before 4.0.6 - jlim\r
-// Warning: This compilation does not support pg_cmdtuples() in d:/inetpub/wwwroot/php/adodb/adodb-postgres.inc.php on line 44\r
-   function _affectedrows()\r
-   {\r
-               if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;\r
-               return pg_cmdtuples($this->_resultid);\r
-   }\r
-   \r
-       \r
-               // returns true/false\r
-       function BeginTrans()\r
-       {\r
-               if ($this->transOff) return true;\r
-               $this->transCnt += 1;\r
-               return @pg_Exec($this->_connectionID, "begin");\r
-       }\r
-       \r
-       function RowLock($tables,$where,$flds='1 as ignore') \r
-       {\r
-               if (!$this->transCnt) $this->BeginTrans();\r
-               return $this->GetOne("select $flds from $tables where $where for update");\r
-       }\r
-\r
-       // returns true/false. \r
-       function CommitTrans($ok=true) \r
-       { \r
-               if ($this->transOff) return true;\r
-               if (!$ok) return $this->RollbackTrans();\r
-               \r
-               $this->transCnt -= 1;\r
-               return @pg_Exec($this->_connectionID, "commit");\r
-       }\r
-       \r
-       // returns true/false\r
-       function RollbackTrans()\r
-       {\r
-               if ($this->transOff) return true;\r
-               $this->transCnt -= 1;\r
-               return @pg_Exec($this->_connectionID, "rollback");\r
-       }\r
-       \r
-       function &MetaTables($ttype=false,$showSchema=false,$mask=false) \r
-       {\r
-               $info = $this->ServerInfo();\r
-               if ($info['version'] >= 7.3) {\r
-               $this->metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%'\r
-                         and schemaname  not in ( 'pg_catalog','information_schema')\r
-       union \r
-        select viewname,'V' from pg_views where viewname not like 'pg\_%'  and schemaname  not in ( 'pg_catalog','information_schema') ";\r
-               }\r
-               if ($mask) {\r
-                       $save = $this->metaTablesSQL;\r
-                       $mask = $this->qstr(strtolower($mask));\r
-                       if ($info['version']>=7.3)\r
-                               $this->metaTablesSQL = "\r
-select tablename,'T' from pg_tables where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema')  \r
- union \r
-select viewname,'V' from pg_views where viewname like $mask and schemaname  not in ( 'pg_catalog','information_schema')  ";\r
-                       else\r
-                               $this->metaTablesSQL = "\r
-select tablename,'T' from pg_tables where tablename like $mask \r
- union \r
-select viewname,'V' from pg_views where viewname like $mask";\r
-               }\r
-               $ret =& ADOConnection::MetaTables($ttype,$showSchema);\r
-               \r
-               if ($mask) {\r
-                       $this->metaTablesSQL = $save;\r
-               }\r
-               return $ret;\r
-       }\r
-       \r
-       /*\r
-       // if magic quotes disabled, use pg_escape_string()\r
-       function qstr($s,$magic_quotes=false)\r
-       {\r
-               if (!$magic_quotes) {\r
-                       if (ADODB_PHPVER >= 0x4200) {\r
-                               return  "'".pg_escape_string($s)."'";\r
-                       }\r
-                       if ($this->replaceQuote[0] == '\\'){\r
-                               $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);\r
-                       }\r
-                       return  "'".str_replace("'",$this->replaceQuote,$s)."'"; \r
-               }\r
-               \r
-               // undo magic quotes for "\r
-               $s = str_replace('\\"','"',$s);\r
-               return "'$s'";\r
-       }\r
-       */\r
-       \r
-       \r
-       // Format date column in sql string given an input format that understands Y M D\r
-       function SQLDate($fmt, $col=false)\r
-       {       \r
-               if (!$col) $col = $this->sysTimeStamp;\r
-               $s = 'TO_CHAR('.$col.",'";\r
-               \r
-               $len = strlen($fmt);\r
-               for ($i=0; $i < $len; $i++) {\r
-                       $ch = $fmt[$i];\r
-                       switch($ch) {\r
-                       case 'Y':\r
-                       case 'y':\r
-                               $s .= 'YYYY';\r
-                               break;\r
-                       case 'Q':\r
-                       case 'q':\r
-                               $s .= 'Q';\r
-                               break;\r
-                               \r
-                       case 'M':\r
-                               $s .= 'Mon';\r
-                               break;\r
-                               \r
-                       case 'm':\r
-                               $s .= 'MM';\r
-                               break;\r
-                       case 'D':\r
-                       case 'd':\r
-                               $s .= 'DD';\r
-                               break;\r
-                       \r
-                       case 'H':\r
-                               $s.= 'HH24';\r
-                               break;\r
-                               \r
-                       case 'h':\r
-                               $s .= 'HH';\r
-                               break;\r
-                               \r
-                       case 'i':\r
-                               $s .= 'MI';\r
-                               break;\r
-                       \r
-                       case 's':\r
-                               $s .= 'SS';\r
-                               break;\r
-                       \r
-                       case 'a':\r
-                       case 'A':\r
-                               $s .= 'AM';\r
-                               break;\r
-                               \r
-                       case 'w':\r
-                               $s .= 'D';\r
-                               break;\r
-                       \r
-                       case 'l':\r
-                               $s .= 'DAY';\r
-                               break;\r
-                               \r
-                       default:\r
-                       // handle escape characters...\r
-                               if ($ch == '\\') {\r
-                                       $i++;\r
-                                       $ch = substr($fmt,$i,1);\r
-                               }\r
-                               if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;\r
-                               else $s .= '"'.$ch.'"';\r
-                               \r
-                       }\r
-               }\r
-               return $s. "')";\r
-       }\r
-       \r
-       \r
-       \r
-       /* \r
-       * Load a Large Object from a file \r
-       * - the procedure stores the object id in the table and imports the object using \r
-       * postgres proprietary blob handling routines \r
-       *\r
-       * contributed by Mattia Rossi mattia@technologist.com\r
-       * modified for safe mode by juraj chlebec\r
-       */ \r
-       function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') \r
-       { \r
-               pg_exec ($this->_connectionID, "begin"); \r
-               \r
-               $fd = fopen($path,'r');\r
-               $contents = fread($fd,filesize($path));\r
-               fclose($fd);\r
-               \r
-               $oid = pg_lo_create($this->_connectionID);\r
-               $handle = pg_lo_open($this->_connectionID, $oid, 'w');\r
-               pg_lo_write($handle, $contents);\r
-               pg_lo_close($handle);\r
-               \r
-               // $oid = pg_lo_import ($path); \r
-               pg_exec($this->_connectionID, "commit"); \r
-               $rs = ADOConnection::UpdateBlob($table,$column,$oid,$where,$blobtype); \r
-               $rez = !empty($rs); \r
-               return $rez; \r
-       } \r
-       \r
-       /*\r
-               Hueristic - not guaranteed to work.\r
-       */\r
-       function GuessOID($oid)\r
-       {\r
-               if (strlen($oid)>16) return false;\r
-               return is_numeric($oid);\r
-       }\r
-       \r
-       /* \r
-       * If an OID is detected, then we use pg_lo_* to open the oid file and read the\r
-       * real blob from the db using the oid supplied as a parameter. If you are storing\r
-       * blobs using bytea, we autodetect and process it so this function is not needed.\r
-       *\r
-       * contributed by Mattia Rossi mattia@technologist.com\r
-       *\r
-       * see http://www.postgresql.org/idocs/index.php?largeobjects.html\r
-       *\r
-       * Since adodb 4.54, this returns the blob, instead of sending it to stdout. Also\r
-       * added maxsize parameter, which defaults to $db->maxblobsize if not defined.\r
-       */ \r
-       function BlobDecode($blob,$maxsize=false,$hastrans=true) \r
-       {\r
-               if (!$this->GuessOID($blob)) return $blob;\r
-               \r
-               if ($hastrans) @pg_exec($this->_connectionID,"begin"); \r
-               $fd = @pg_lo_open($this->_connectionID,$blob,"r");\r
-               if ($fd === false) {\r
-                       if ($hastrans) @pg_exec($this->_connectionID,"commit");\r
-                       return $blob;\r
-               }\r
-               if (!$maxsize) $maxsize = $this->maxblobsize;\r
-               $realblob = @pg_loread($fd,$maxsize); \r
-               @pg_loclose($fd); \r
-               if ($hastrans) @pg_exec($this->_connectionID,"commit"); \r
-               return $realblob;\r
-       } \r
-       \r
-       /* \r
-               See http://www.postgresql.org/idocs/index.php?datatype-binary.html\r
-               \r
-               NOTE: SQL string literals (input strings) must be preceded with two backslashes \r
-               due to the fact that they must pass through two parsers in the PostgreSQL \r
-               backend.\r
-       */\r
-       function BlobEncode($blob)\r
-       {\r
-               if (ADODB_PHPVER >= 0x4200) return pg_escape_bytea($blob);\r
-               \r
-               /*92=backslash, 0=null, 39=single-quote*/\r
-               $badch = array(chr(92),chr(0),chr(39)); # \  null  '\r
-               $fixch = array('\\\\134','\\\\000','\\\\047');\r
-               return adodb_str_replace($badch,$fixch,$blob);\r
-               \r
-               // note that there is a pg_escape_bytea function only for php 4.2.0 or later\r
-       }\r
-       \r
-       // assumes bytea for blob, and varchar for clob\r
-       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')\r
-       {\r
-       \r
-               if ($blobtype == 'CLOB') {\r
-               return $this->Execute("UPDATE $table SET $column=" . $this->qstr($val) . " WHERE $where");\r
-               }\r
-               // do not use bind params which uses qstr(), as blobencode() already quotes data\r
-               return $this->Execute("UPDATE $table SET $column='".$this->BlobEncode($val)."'::bytea WHERE $where");\r
-       }\r
-       \r
-       function OffsetDate($dayFraction,$date=false)\r
-       {               \r
-               if (!$date) $date = $this->sysDate;\r
-               return "($date+interval'$dayFraction days')";\r
-       }\r
-       \r
-\r
-       // for schema support, pass in the $table param "$schema.$tabname".\r
-       // converts field names to lowercase, $upper is ignored\r
-       function &MetaColumns($table,$normalize=true) \r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-       \r
-               $schema = false;\r
-               $false = false;\r
-               $this->_findschema($table,$schema);\r
-               \r
-               if ($normalize) $table = strtolower($table);\r
-\r
-               $save = $ADODB_FETCH_MODE;\r
-               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-               if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);\r
-               \r
-               if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema));\r
-               else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table));\r
-               if (isset($savem)) $this->SetFetchMode($savem);\r
-               $ADODB_FETCH_MODE = $save;\r
-               \r
-               if ($rs === false) {\r
-                       return $false;\r
-               }\r
-               if (!empty($this->metaKeySQL)) {\r
-                       // If we want the primary keys, we have to issue a separate query\r
-                       // Of course, a modified version of the metaColumnsSQL query using a \r
-                       // LEFT JOIN would have been much more elegant, but postgres does \r
-                       // not support OUTER JOINS. So here is the clumsy way.\r
-                       \r
-                       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-                       \r
-                       $rskey = $this->Execute(sprintf($this->metaKeySQL,($table)));\r
-                       // fetch all result in once for performance.\r
-                       $keys =& $rskey->GetArray();\r
-                       if (isset($savem)) $this->SetFetchMode($savem);\r
-                       $ADODB_FETCH_MODE = $save;\r
-                       \r
-                       $rskey->Close();\r
-                       unset($rskey);\r
-               }\r
-\r
-               $rsdefa = array();\r
-               if (!empty($this->metaDefaultsSQL)) {\r
-                       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-                       $sql = sprintf($this->metaDefaultsSQL, ($table));\r
-                       $rsdef = $this->Execute($sql);\r
-                       if (isset($savem)) $this->SetFetchMode($savem);\r
-                       $ADODB_FETCH_MODE = $save;\r
-                       \r
-                       if ($rsdef) {\r
-                               while (!$rsdef->EOF) {\r
-                                       $num = $rsdef->fields['num'];\r
-                                       $s = $rsdef->fields['def'];\r
-                                       if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */\r
-                                               $s = substr($s, 1);\r
-                                               $s = substr($s, 0, strlen($s) - 1);\r
-                                       }\r
-\r
-                                       $rsdefa[$num] = $s;\r
-                                       $rsdef->MoveNext();\r
-                               }\r
-                       } else {\r
-                               ADOConnection::outp( "==> SQL => " . $sql);\r
-                       }\r
-                       unset($rsdef);\r
-               }\r
-       \r
-               $retarr = array();\r
-               while (!$rs->EOF) {     \r
-                       $fld = new ADOFieldObject();\r
-                       $fld->name = $rs->fields[0];\r
-                       $fld->type = $rs->fields[1];\r
-                       $fld->max_length = $rs->fields[2];\r
-                       if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4;\r
-                       if ($fld->max_length <= 0) $fld->max_length = -1;\r
-                       if ($fld->type == 'numeric') {\r
-                               $fld->scale = $fld->max_length & 0xFFFF;\r
-                               $fld->max_length >>= 16;\r
-                       }\r
-                       // dannym\r
-                       // 5 hasdefault; 6 num-of-column\r
-                       $fld->has_default = ($rs->fields[5] == 't');\r
-                       if ($fld->has_default) {\r
-                               $fld->default_value = $rsdefa[$rs->fields[6]];\r
-                       }\r
-\r
-                       //Freek\r
-                       if ($rs->fields[4] == 't') {\r
-                               $fld->not_null = true;\r
-                       }\r
-                       \r
-                       // Freek\r
-                       if (is_array($keys)) {\r
-                               foreach($keys as $key) {\r
-                                       if ($fld->name == $key['column_name'] AND $key['primary_key'] == 't') \r
-                                               $fld->primary_key = true;\r
-                                       if ($fld->name == $key['column_name'] AND $key['unique_key'] == 't') \r
-                                               $fld->unique = true; // What name is more compatible?\r
-                               }\r
-                       }\r
-                       \r
-                       if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;     \r
-                       else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld;\r
-                       \r
-                       $rs->MoveNext();\r
-               }\r
-               $rs->Close();\r
-               if (empty($retarr))\r
-                       return  $false;\r
-               else\r
-                       return $retarr; \r
-               \r
-       }\r
-\r
-         function &MetaIndexes ($table, $primary = FALSE)\r
-      {\r
-         global $ADODB_FETCH_MODE;\r
-                \r
-                               $schema = false;\r
-                               $this->_findschema($table,$schema);\r
-\r
-                               if ($schema) { // requires pgsql 7.3+ - pg_namespace used.\r
-                                       $sql = '\r
-SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" \r
-FROM pg_catalog.pg_class c \r
-JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid \r
-JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid\r
-       ,pg_namespace n \r
-WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\')) and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\' AND i.indisprimary=false';\r
-                               } else {\r
-                       $sql = '\r
-SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns"\r
-FROM pg_catalog.pg_class c\r
-JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid\r
-JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid\r
-WHERE c2.relname=\'%s\' or c2.relname=lower(\'%s\')';\r
-                       }\r
-                                           \r
-                if ($primary == FALSE) {\r
-                       $sql .= ' AND i.indisprimary=false;';\r
-                }\r
-                \r
-                $save = $ADODB_FETCH_MODE;\r
-                $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-                if ($this->fetchMode !== FALSE) {\r
-                        $savem = $this->SetFetchMode(FALSE);\r
-                }\r
-                \r
-                $rs = $this->Execute(sprintf($sql,$table,$table,$schema));\r
-                if (isset($savem)) {\r
-                        $this->SetFetchMode($savem);\r
-                }\r
-                $ADODB_FETCH_MODE = $save;\r
-\r
-                if (!is_object($rs)) {\r
-                       $false = false;\r
-                                       return $false;\r
-                }\r
-                               \r
-                $col_names = $this->MetaColumnNames($table,true);\r
-                $indexes = array();\r
-                while ($row = $rs->FetchRow()) {\r
-                        $columns = array();\r
-                        foreach (explode(' ', $row[2]) as $col) {\r
-                                $columns[] = $col_names[$col - 1];\r
-                        }\r
-                        \r
-                        $indexes[$row[0]] = array(\r
-                                'unique' => ($row[1] == 't'),\r
-                                'columns' => $columns\r
-                        );\r
-                }\r
-                return $indexes;\r
-        }\r
-\r
-       // returns true or false\r
-       //\r
-       // examples:\r
-       //      $db->Connect("host=host1 user=user1 password=secret port=4341");\r
-       //      $db->Connect('host1','user1','secret');\r
-       function _connect($str,$user='',$pwd='',$db='',$ctype=0)\r
-       {\r
-               \r
-               if (!function_exists('pg_pconnect')) return null;\r
-               \r
-               $this->_errorMsg = false;\r
-               \r
-               if ($user || $pwd || $db) {\r
-                       $user = adodb_addslashes($user);\r
-                       $pwd = adodb_addslashes($pwd);\r
-                       if (strlen($db) == 0) $db = 'template1';\r
-                       $db = adodb_addslashes($db);\r
-                       if ($str)  {\r
-                               $host = split(":", $str);\r
-                               if ($host[0]) $str = "host=".adodb_addslashes($host[0]);\r
-                               else $str = '';\r
-                               if (isset($host[1])) $str .= " port=$host[1]";\r
-                               else if (!empty($this->port)) $str .= " port=".$this->port;\r
-                               if (isset($host[2])) $str .= " sslmode=".adodb_addslashes($host[2]);\r
-                               else if (!empty($this->sslmode)) $str .= " sslmode=".$this->sslmode;\r
-                       }\r
-                               if ($user) $str .= " user=".$user;\r
-                               if ($pwd)  $str .= " password=".$pwd;\r
-                               if ($db)   $str .= " dbname=".$db;\r
-               }\r
-\r
-               //if ($user) $linea = "user=$user host=$linea password=$pwd dbname=$db port=5432";\r
-               \r
-               if ($ctype === 1) { // persistent\r
-                       $this->_connectionID = pg_pconnect($str);\r
-               } else {\r
-                       if ($ctype === -1) { // nconnect, we trick pgsql ext by changing the connection str\r
-                       static $ncnt;\r
-                       \r
-                               if (empty($ncnt)) $ncnt = 1;\r
-                               else $ncnt += 1;\r
-                               \r
-                               $str .= str_repeat(' ',$ncnt);\r
-                       }\r
-                       $this->_connectionID = @pg_connect($str);\r
-               }\r
-               if ($this->_connectionID === false) return false;\r
-               $this->Execute("set datestyle='ISO'");\r
-               return true;\r
-       }\r
-       \r
-       function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)\r
-       {\r
-               return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName,-1);\r
-       }\r
-        \r
-       // returns true or false\r
-       //\r
-       // examples:\r
-       //      $db->PConnect("host=host1 user=user1 password=secret port=4341");\r
-       //      $db->PConnect('host1','user1','secret');\r
-       function _pconnect($str,$user='',$pwd='',$db='')\r
-       {\r
-               return $this->_connect($str,$user,$pwd,$db,1);\r
-       }\r
-       \r
-\r
-       // returns queryID or false\r
-       function _query($sql,$inputarr)\r
-       {\r
-               \r
-               if ($inputarr) {\r
-               /*\r
-                       It appears that PREPARE/EXECUTE is slower for many queries.\r
-                       \r
-                       For query executed 1000 times:\r
-                       "select id,firstname,lastname from adoxyz \r
-                               where firstname not like ? and lastname not like ? and id = ?"\r
-                               \r
-                       with plan = 1.51861286163 secs\r
-                       no plan =   1.26903700829 secs\r
-\r
-                       \r
-\r
-               */\r
-                       $plan = 'P'.md5($sql);\r
-                               \r
-                       $execp = '';\r
-                       foreach($inputarr as $v) {\r
-                               if ($execp) $execp .= ',';\r
-                               if (is_string($v)) {\r
-                                       if (strncmp($v,"'",1) !== 0) $execp .= $this->qstr($v);\r
-                               } else {\r
-                                       $execp .= $v;\r
-                               }\r
-                       }\r
-                       \r
-                       if ($execp) $exsql = "EXECUTE $plan ($execp)";\r
-                       else $exsql = "EXECUTE $plan";\r
-                       \r
-                       $rez = @pg_exec($this->_connectionID,$exsql);\r
-                       if (!$rez) {\r
-                       # Perhaps plan does not exist? Prepare/compile plan.\r
-                               $params = '';\r
-                               foreach($inputarr as $v) {\r
-                                       if ($params) $params .= ',';\r
-                                       if (is_string($v)) {\r
-                                               $params .= 'VARCHAR';\r
-                                       } else if (is_integer($v)) {\r
-                                               $params .= 'INTEGER';\r
-                                       } else {\r
-                                               $params .= "REAL";\r
-                                       }\r
-                               }\r
-                               $sqlarr = explode('?',$sql);\r
-                               //print_r($sqlarr);\r
-                               $sql = '';\r
-                               $i = 1;\r
-                               foreach($sqlarr as $v) {\r
-                                       $sql .= $v.' $'.$i;\r
-                                       $i++;\r
-                               }\r
-                               $s = "PREPARE $plan ($params) AS ".substr($sql,0,strlen($sql)-2);               \r
-                               //adodb_pr($s);\r
-                               pg_exec($this->_connectionID,$s);\r
-                               echo $this->ErrorMsg();\r
-                       }\r
-                       \r
-                       $rez = pg_exec($this->_connectionID,$exsql);\r
-               } else {\r
-                       $this->_errorMsg = false;\r
-                       //adodb_backtrace();\r
-                       $rez = pg_exec($this->_connectionID,$sql);\r
-               }\r
-               // check if no data returned, then no need to create real recordset\r
-               if ($rez && pg_numfields($rez) <= 0) {\r
-                       if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') {\r
-                               pg_freeresult($this->_resultid);\r
-                       }\r
-                       $this->_resultid = $rez;\r
-                       return true;\r
-               }\r
-               \r
-               return $rez;\r
-       }\r
-       \r
-\r
-       /*      Returns: the last error message from previous database operation        */      \r
-       function ErrorMsg() \r
-       {\r
-               if ($this->_errorMsg !== false) return $this->_errorMsg;\r
-               if (ADODB_PHPVER >= 0x4300) {\r
-                       if (!empty($this->_resultid)) {\r
-                               $this->_errorMsg = @pg_result_error($this->_resultid);\r
-                               if ($this->_errorMsg) return $this->_errorMsg;\r
-                       }\r
-                       \r
-                       if (!empty($this->_connectionID)) {\r
-                               $this->_errorMsg = @pg_last_error($this->_connectionID);\r
-                       } else $this->_errorMsg = @pg_last_error();\r
-               } else {\r
-                       if (empty($this->_connectionID)) $this->_errorMsg = @pg_errormessage();\r
-                       else $this->_errorMsg = @pg_errormessage($this->_connectionID);\r
-               }\r
-               return $this->_errorMsg;\r
-       }\r
-       \r
-       function ErrorNo()\r
-       {\r
-               $e = $this->ErrorMsg();\r
-               if (strlen($e)) {\r
-                       return ADOConnection::MetaError($e);\r
-                }\r
-                return 0;\r
-       }\r
-\r
-       // returns true or false\r
-       function _close()\r
-       {\r
-               if ($this->transCnt) $this->RollbackTrans();\r
-               if ($this->_resultid) {\r
-                       @pg_freeresult($this->_resultid);\r
-                       $this->_resultid = false;\r
-               }\r
-               @pg_close($this->_connectionID);\r
-               $this->_connectionID = false;\r
-               return true;\r
-       }\r
-       \r
-       \r
-       /*\r
-       * Maximum size of C field\r
-       */\r
-       function CharMax()\r
-       {\r
-               return 1000000000;  // should be 1 Gb?\r
-       }\r
-       \r
-       /*\r
-       * Maximum size of X field\r
-       */\r
-       function TextMax()\r
-       {\r
-               return 1000000000; // should be 1 Gb?\r
-       }\r
-       \r
-               \r
-}\r
-       \r
-/*--------------------------------------------------------------------------------------\r
-        Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordSet_postgres64 extends ADORecordSet{\r
-       var $_blobArr;\r
-       var $databaseType = "postgres64";\r
-       var $canSeek = true;\r
-       function ADORecordSet_postgres64($queryID,$mode=false) \r
-       {\r
-               if ($mode === false) { \r
-                       global $ADODB_FETCH_MODE;\r
-                       $mode = $ADODB_FETCH_MODE;\r
-               }\r
-               switch ($mode)\r
-               {\r
-               case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break;\r
-               case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break;\r
-               \r
-               case ADODB_FETCH_DEFAULT:\r
-               case ADODB_FETCH_BOTH:\r
-               default: $this->fetchMode = PGSQL_BOTH; break;\r
-               }\r
-               $this->adodbFetchMode = $mode;\r
-               $this->ADORecordSet($queryID);\r
-       }\r
-       \r
-       function &GetRowAssoc($upper=true)\r
-       {\r
-               if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields;\r
-               $row =& ADORecordSet::GetRowAssoc($upper);\r
-               return $row;\r
-       }\r
-\r
-       function _initrs()\r
-       {\r
-       global $ADODB_COUNTRECS;\r
-               $qid = $this->_queryID;\r
-               $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($qid):-1;\r
-               $this->_numOfFields = @pg_numfields($qid);\r
-               \r
-               // cache types for blob decode check\r
-               // apparently pg_fieldtype actually performs an sql query on the database to get the type.\r
-               if (empty($this->connection->noBlobs))\r
-               for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) {  \r
-                       if (pg_fieldtype($qid,$i) == 'bytea') {\r
-                               $this->_blobArr[$i] = pg_fieldname($qid,$i);\r
-                       }\r
-               }\r
-       }\r
-\r
-               /* Use associative array to get fields array */\r
-       function Fields($colname)\r
-       {\r
-               if ($this->fetchMode != PGSQL_NUM) return @$this->fields[$colname];\r
-               \r
-               if (!$this->bind) {\r
-                       $this->bind = array();\r
-                       for ($i=0; $i < $this->_numOfFields; $i++) {\r
-                               $o = $this->FetchField($i);\r
-                               $this->bind[strtoupper($o->name)] = $i;\r
-                       }\r
-               }\r
-                return $this->fields[$this->bind[strtoupper($colname)]];\r
-       }\r
-\r
-       function &FetchField($off = 0) \r
-       {\r
-               // offsets begin at 0\r
-               \r
-               $o= new ADOFieldObject();\r
-               $o->name = @pg_fieldname($this->_queryID,$off);\r
-               $o->type = @pg_fieldtype($this->_queryID,$off);\r
-               $o->max_length = @pg_fieldsize($this->_queryID,$off);\r
-               return $o;      \r
-       }\r
-\r
-       function _seek($row)\r
-       {\r
-               return @pg_fetch_row($this->_queryID,$row);\r
-       }\r
-       \r
-       function _decode($blob)\r
-       {\r
-               eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";');\r
-               return $realblob;       \r
-       }\r
-       \r
-       function _fixblobs()\r
-       {\r
-               if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) {\r
-                       foreach($this->_blobArr as $k => $v) {\r
-                               $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]);\r
-                       }\r
-               }\r
-               if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) {\r
-                       foreach($this->_blobArr as $k => $v) {\r
-                               $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]);\r
-                       }\r
-               }\r
-       }\r
-       \r
-       // 10% speedup to move MoveNext to child class\r
-       function MoveNext() \r
-       {\r
-               if (!$this->EOF) {\r
-                       $this->_currentRow++;\r
-                       if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {\r
-                               $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);\r
-                               if (is_array($this->fields) && $this->fields) {\r
-                                       if (isset($this->_blobArr)) $this->_fixblobs();\r
-                                       return true;\r
-                               }\r
-                       }\r
-                       $this->fields = false;\r
-                       $this->EOF = true;\r
-               }\r
-               return false;\r
-       }               \r
-       \r
-       function _fetch()\r
-       {\r
-                               \r
-               if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)\r
-               return false;\r
-\r
-               $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);\r
-               \r
-               if ($this->fields && isset($this->_blobArr)) $this->_fixblobs();\r
-                       \r
-               return (is_array($this->fields));\r
-       }\r
-\r
-       function _close() \r
-       { \r
-               return @pg_freeresult($this->_queryID);\r
-       }\r
-\r
-       function MetaType($t,$len=-1,$fieldobj=false)\r
-       {\r
-               if (is_object($t)) {\r
-                       $fieldobj = $t;\r
-                       $t = $fieldobj->type;\r
-                       $len = $fieldobj->max_length;\r
-               }\r
-               switch (strtoupper($t)) {\r
-                               case 'MONEY': // stupid, postgres expects money to be a string\r
-                               case 'INTERVAL':\r
-                               case 'CHAR':\r
-                               case 'CHARACTER':\r
-                               case 'VARCHAR':\r
-                               case 'NAME':\r
-                               case 'BPCHAR':\r
-                               case '_VARCHAR':\r
-                               case 'INET':\r
-                                       if ($len <= $this->blobSize) return 'C';\r
-                               \r
-                               case 'TEXT':\r
-                                       return 'X';\r
-               \r
-                               case 'IMAGE': // user defined type\r
-                               case 'BLOB': // user defined type\r
-                               case 'BIT':     // This is a bit string, not a single bit, so don't return 'L'\r
-                               case 'VARBIT':\r
-                               case 'BYTEA':\r
-                                       return 'B';\r
-                               \r
-                               case 'BOOL':\r
-                               case 'BOOLEAN':\r
-                                       return 'L';\r
-                               \r
-                               case 'DATE':\r
-                                       return 'D';\r
-                               \r
-                               case 'TIME':\r
-                               case 'DATETIME':\r
-                               case 'TIMESTAMP':\r
-                               case 'TIMESTAMPTZ':\r
-                                       return 'T';\r
-                               \r
-                               case 'SMALLINT': \r
-                               case 'BIGINT': \r
-                               case 'INTEGER': \r
-                               case 'INT8': \r
-                               case 'INT4':\r
-                               case 'INT2':\r
-                                       if (isset($fieldobj) &&\r
-                               empty($fieldobj->primary_key) && empty($fieldobj->unique)) return 'I';\r
-                               \r
-                               case 'OID':\r
-                               case 'SERIAL':\r
-                                       return 'R';\r
-                               \r
-                                default:\r
-                                       return 'N';\r
-                       }\r
-       }\r
-\r
-}\r
+<?php
+/*
+ V4.65 22 July 2005  (c) 2000-2005 John Lim (jlim@natsoft.com.my). All rights reserved.
+  Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence.
+  Set tabs to 8.
+  
+  Original version derived from Alberto Cerezal (acerezalp@dbnet.es) - DBNet Informatica & Comunicaciones. 
+  08 Nov 2000 jlim - Minor corrections, removing mysql stuff
+  09 Nov 2000 jlim - added insertid support suggested by "Christopher Kings-Lynne" <chriskl@familyhealth.com.au>
+                                       jlim - changed concat operator to || and data types to MetaType to match documented pgsql types 
+                       see http://www.postgresql.org/devel-corner/docs/postgres/datatype.htm  
+  22 Nov 2000 jlim - added changes to FetchField() and MetaTables() contributed by "raser" <raser@mail.zen.com.tw>
+  27 Nov 2000 jlim - added changes to _connect/_pconnect from ideas by "Lennie" <leen@wirehub.nl>
+  15 Dec 2000 jlim - added changes suggested by Additional code changes by "Eric G. Werk" egw@netguide.dk. 
+  31 Jan 2002 jlim - finally installed postgresql. testing
+  01 Mar 2001 jlim - Freek Dijkstra changes, also support for text type
+  
+  See http://www.varlena.com/varlena/GeneralBits/47.php
+  
+       -- What indexes are on my table?
+       select * from pg_indexes where tablename = 'tablename';
+       
+       -- What triggers are on my table?
+       select c.relname as "Table", t.tgname as "Trigger Name", 
+          t.tgconstrname as "Constraint Name", t.tgenabled as "Enabled",
+          t.tgisconstraint as "Is Constraint", cc.relname as "Referenced Table",
+          p.proname as "Function Name"
+       from pg_trigger t, pg_class c, pg_class cc, pg_proc p
+       where t.tgfoid = p.oid and t.tgrelid = c.oid
+          and t.tgconstrrelid = cc.oid
+          and c.relname = 'tablename';
+       
+       -- What constraints are on my table?
+       select r.relname as "Table", c.conname as "Constraint Name",
+          contype as "Constraint Type", conkey as "Key Columns",
+          confkey as "Foreign Columns", consrc as "Source"
+       from pg_class r, pg_constraint c
+       where r.oid = c.conrelid
+          and relname = 'tablename';
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+function adodb_addslashes($s)
+{
+       $len = strlen($s);
+       if ($len == 0) return "''";
+       if (strncmp($s,"'",1) === 0 && substr(s,$len-1) == "'") return $s; // already quoted
+       
+       return "'".addslashes($s)."'";
+}
+
+class ADODB_postgres64 extends ADOConnection{
+       var $databaseType = 'postgres64';
+       var $dataProvider = 'postgres';
+       var $hasInsertID = true;
+       var $_resultid = false;
+       var $concat_operator='||';
+       var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1";
+    var $metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%'
+       and tablename not in ('sql_features', 'sql_implementation_info', 'sql_languages',
+        'sql_packages', 'sql_sizing', 'sql_sizing_profiles') 
+       union 
+        select viewname,'V' from pg_views where viewname not like 'pg\_%'";
+       //"select tablename from pg_tables where tablename not like 'pg_%' order by 1";
+       var $isoDates = true; // accepts dates in ISO format
+       var $sysDate = "CURRENT_DATE";
+       var $sysTimeStamp = "CURRENT_TIMESTAMP";
+       var $blobEncodeType = 'C';
+       var $metaColumnsSQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum 
+               FROM pg_class c, pg_attribute a,pg_type t 
+               WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) and a.attname not like '....%%'
+AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
+
+       // used when schema defined
+       var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum 
+FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n 
+WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s'))
+ and c.relnamespace=n.oid and n.nspname='%s' 
+       and a.attname not like '....%%' AND a.attnum > 0 
+       AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
+       
+       // get primary key etc -- from Freek Dijkstra
+       var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key 
+       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'";
+       
+       var $hasAffectedRows = true;
+       var $hasLimit = false;  // set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10
+       // below suggested by Freek Dijkstra 
+       var $true = 'TRUE';             // string that represents TRUE for a database
+       var $false = 'FALSE';           // string that represents FALSE for a database
+       var $fmtDate = "'Y-m-d'";       // used by DBDate() as the default date format used by the database
+       var $fmtTimeStamp = "'Y-m-d G:i:s'"; // used by DBTimeStamp as the default timestamp fmt.
+       var $hasMoveFirst = true;
+       var $hasGenID = true;
+       var $_genIDSQL = "SELECT NEXTVAL('%s')";
+       var $_genSeqSQL = "CREATE SEQUENCE %s START %s";
+       var $_dropSeqSQL = "DROP SEQUENCE %s";
+       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";
+       var $random = 'random()';               /// random function
+       var $autoRollback = true; // apparently pgsql does not autorollback properly before php 4.3.4
+                                                       // http://bugs.php.net/bug.php?id=25404
+                                                       
+       var $_bindInputArray = false; // requires postgresql 7.3+ and ability to modify database
+       var $disableBlobs = false; // set to true to disable blob checking, resulting in 2-5% improvement in performance.
+       
+       // The last (fmtTimeStamp is not entirely correct: 
+       // PostgreSQL also has support for time zones, 
+       // and writes these time in this format: "2001-03-01 18:59:26+02". 
+       // There is no code for the "+02" time zone information, so I just left that out. 
+       // I'm not familiar enough with both ADODB as well as Postgres 
+       // to know what the concequences are. The other values are correct (wheren't in 0.94)
+       // -- Freek Dijkstra 
+
+       function ADODB_postgres64() 
+       {
+       // changes the metaColumnsSQL, adds columns: attnum[6]
+       }
+       
+       function ServerInfo()
+       {
+               if (isset($this->version)) return $this->version;
+               
+               $arr['description'] = $this->GetOne("select version()");
+               $arr['version'] = ADOConnection::_findvers($arr['description']);
+               $this->version = $arr;
+               return $arr;
+       }
+
+       function IfNull( $field, $ifNull ) 
+       {
+               return " coalesce($field, $ifNull) "; 
+       }
+
+       // get the last id - never tested
+       function pg_insert_id($tablename,$fieldname)
+       {
+               $result=pg_exec($this->_connectionID, "SELECT last_value FROM ${tablename}_${fieldname}_seq");
+               if ($result) {
+                       $arr = @pg_fetch_row($result,0);
+                       pg_freeresult($result);
+                       if (isset($arr[0])) return $arr[0];
+               }
+               return false;
+       }
+       
+/* Warning from http://www.php.net/manual/function.pg-getlastoid.php:
+Using a OID as a unique identifier is not generally wise. 
+Unless you are very careful, you might end up with a tuple having 
+a different OID if a database must be reloaded. */
+       function _insertid($table,$column)
+       {
+               if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;
+               $oid = pg_getlastoid($this->_resultid);
+               // to really return the id, we need the table and column-name, else we can only return the oid != id
+               return empty($table) || empty($column) ? $oid : $this->GetOne("SELECT $column FROM $table WHERE oid=".(int)$oid);
+       }
+
+// I get this error with PHP before 4.0.6 - jlim
+// Warning: This compilation does not support pg_cmdtuples() in d:/inetpub/wwwroot/php/adodb/adodb-postgres.inc.php on line 44
+   function _affectedrows()
+   {
+               if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;
+               return pg_cmdtuples($this->_resultid);
+   }
+   
+       
+               // returns true/false
+       function BeginTrans()
+       {
+               if ($this->transOff) return true;
+               $this->transCnt += 1;
+               return @pg_Exec($this->_connectionID, "begin");
+       }
+       
+       function RowLock($tables,$where,$flds='1 as ignore') 
+       {
+               if (!$this->transCnt) $this->BeginTrans();
+               return $this->GetOne("select $flds from $tables where $where for update");
+       }
+
+       // returns true/false. 
+       function CommitTrans($ok=true) 
+       { 
+               if ($this->transOff) return true;
+               if (!$ok) return $this->RollbackTrans();
+               
+               $this->transCnt -= 1;
+               return @pg_Exec($this->_connectionID, "commit");
+       }
+       
+       // returns true/false
+       function RollbackTrans()
+       {
+               if ($this->transOff) return true;
+               $this->transCnt -= 1;
+               return @pg_Exec($this->_connectionID, "rollback");
+       }
+       
+       function &MetaTables($ttype=false,$showSchema=false,$mask=false) 
+       {
+               $info = $this->ServerInfo();
+               if ($info['version'] >= 7.3) {
+               $this->metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%'
+                         and schemaname  not in ( 'pg_catalog','information_schema')
+       union 
+        select viewname,'V' from pg_views where viewname not like 'pg\_%'  and schemaname  not in ( 'pg_catalog','information_schema') ";
+               }
+               if ($mask) {
+                       $save = $this->metaTablesSQL;
+                       $mask = $this->qstr(strtolower($mask));
+                       if ($info['version']>=7.3)
+                               $this->metaTablesSQL = "
+select tablename,'T' from pg_tables where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema')  
+ union 
+select viewname,'V' from pg_views where viewname like $mask and schemaname  not in ( 'pg_catalog','information_schema')  ";
+                       else
+                               $this->metaTablesSQL = "
+select tablename,'T' from pg_tables where tablename like $mask 
+ union 
+select viewname,'V' from pg_views where viewname like $mask";
+               }
+               $ret =& ADOConnection::MetaTables($ttype,$showSchema);
+               
+               if ($mask) {
+                       $this->metaTablesSQL = $save;
+               }
+               return $ret;
+       }
+       
+       /*
+       // if magic quotes disabled, use pg_escape_string()
+       function qstr($s,$magic_quotes=false)
+       {
+               if (!$magic_quotes) {
+                       if (ADODB_PHPVER >= 0x4200) {
+                               return  "'".pg_escape_string($s)."'";
+                       }
+                       if ($this->replaceQuote[0] == '\\'){
+                               $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+                       }
+                       return  "'".str_replace("'",$this->replaceQuote,$s)."'"; 
+               }
+               
+               // undo magic quotes for "
+               $s = str_replace('\\"','"',$s);
+               return "'$s'";
+       }
+       */
+       
+       
+       // Format date column in sql string given an input format that understands Y M D
+       function SQLDate($fmt, $col=false)
+       {       
+               if (!$col) $col = $this->sysTimeStamp;
+               $s = 'TO_CHAR('.$col.",'";
+               
+               $len = strlen($fmt);
+               for ($i=0; $i < $len; $i++) {
+                       $ch = $fmt[$i];
+                       switch($ch) {
+                       case 'Y':
+                       case 'y':
+                               $s .= 'YYYY';
+                               break;
+                       case 'Q':
+                       case 'q':
+                               $s .= 'Q';
+                               break;
+                               
+                       case 'M':
+                               $s .= 'Mon';
+                               break;
+                               
+                       case 'm':
+                               $s .= 'MM';
+                               break;
+                       case 'D':
+                       case 'd':
+                               $s .= 'DD';
+                               break;
+                       
+                       case 'H':
+                               $s.= 'HH24';
+                               break;
+                               
+                       case 'h':
+                               $s .= 'HH';
+                               break;
+                               
+                       case 'i':
+                               $s .= 'MI';
+                               break;
+                       
+                       case 's':
+                               $s .= 'SS';
+                               break;
+                       
+                       case 'a':
+                       case 'A':
+                               $s .= 'AM';
+                               break;
+                               
+                       case 'w':
+                               $s .= 'D';
+                               break;
+                       
+                       case 'l':
+                               $s .= 'DAY';
+                               break;
+                               
+                       default:
+                       // handle escape characters...
+                               if ($ch == '\\') {
+                                       $i++;
+                                       $ch = substr($fmt,$i,1);
+                               }
+                               if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;
+                               else $s .= '"'.$ch.'"';
+                               
+                       }
+               }
+               return $s. "')";
+       }
+       
+       
+       
+       /* 
+       * Load a Large Object from a file 
+       * - the procedure stores the object id in the table and imports the object using 
+       * postgres proprietary blob handling routines 
+       *
+       * contributed by Mattia Rossi mattia@technologist.com
+       * modified for safe mode by juraj chlebec
+       */ 
+       function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') 
+       { 
+               pg_exec ($this->_connectionID, "begin"); 
+               
+               $fd = fopen($path,'r');
+               $contents = fread($fd,filesize($path));
+               fclose($fd);
+               
+               $oid = pg_lo_create($this->_connectionID);
+               $handle = pg_lo_open($this->_connectionID, $oid, 'w');
+               pg_lo_write($handle, $contents);
+               pg_lo_close($handle);
+               
+               // $oid = pg_lo_import ($path); 
+               pg_exec($this->_connectionID, "commit"); 
+               $rs = ADOConnection::UpdateBlob($table,$column,$oid,$where,$blobtype); 
+               $rez = !empty($rs); 
+               return $rez; 
+       } 
+       
+       /*
+               Hueristic - not guaranteed to work.
+       */
+       function GuessOID($oid)
+       {
+               if (strlen($oid)>16) return false;
+               return is_numeric($oid);
+       }
+       
+       /* 
+       * If an OID is detected, then we use pg_lo_* to open the oid file and read the
+       * real blob from the db using the oid supplied as a parameter. If you are storing
+       * blobs using bytea, we autodetect and process it so this function is not needed.
+       *
+       * contributed by Mattia Rossi mattia@technologist.com
+       *
+       * see http://www.postgresql.org/idocs/index.php?largeobjects.html
+       *
+       * Since adodb 4.54, this returns the blob, instead of sending it to stdout. Also
+       * added maxsize parameter, which defaults to $db->maxblobsize if not defined.
+       */ 
+       function BlobDecode($blob,$maxsize=false,$hastrans=true) 
+       {
+               if (!$this->GuessOID($blob)) return $blob;
+               
+               if ($hastrans) @pg_exec($this->_connectionID,"begin"); 
+               $fd = @pg_lo_open($this->_connectionID,$blob,"r");
+               if ($fd === false) {
+                       if ($hastrans) @pg_exec($this->_connectionID,"commit");
+                       return $blob;
+               }
+               if (!$maxsize) $maxsize = $this->maxblobsize;
+               $realblob = @pg_loread($fd,$maxsize); 
+               @pg_loclose($fd); 
+               if ($hastrans) @pg_exec($this->_connectionID,"commit"); 
+               return $realblob;
+       } 
+       
+       /* 
+               See http://www.postgresql.org/idocs/index.php?datatype-binary.html
+               
+               NOTE: SQL string literals (input strings) must be preceded with two backslashes 
+               due to the fact that they must pass through two parsers in the PostgreSQL 
+               backend.
+       */
+       function BlobEncode($blob)
+       {
+               if (ADODB_PHPVER >= 0x4200) return pg_escape_bytea($blob);
+               
+               /*92=backslash, 0=null, 39=single-quote*/
+               $badch = array(chr(92),chr(0),chr(39)); # \  null  '
+               $fixch = array('\\\\134','\\\\000','\\\\047');
+               return adodb_str_replace($badch,$fixch,$blob);
+               
+               // note that there is a pg_escape_bytea function only for php 4.2.0 or later
+       }
+       
+       // assumes bytea for blob, and varchar for clob
+       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+       {
+       
+               if ($blobtype == 'CLOB') {
+               return $this->Execute("UPDATE $table SET $column=" . $this->qstr($val) . " WHERE $where");
+               }
+               // do not use bind params which uses qstr(), as blobencode() already quotes data
+               return $this->Execute("UPDATE $table SET $column='".$this->BlobEncode($val)."'::bytea WHERE $where");
+       }
+       
+       function OffsetDate($dayFraction,$date=false)
+       {               
+               if (!$date) $date = $this->sysDate;
+               return "($date+interval'$dayFraction days')";
+       }
+       
+
+       // for schema support, pass in the $table param "$schema.$tabname".
+       // converts field names to lowercase, $upper is ignored
+       function &MetaColumns($table,$normalize=true) 
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $schema = false;
+               $false = false;
+               $this->_findschema($table,$schema);
+               
+               if ($normalize) $table = strtolower($table);
+
+               $save = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+               
+               if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema));
+               else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table));
+               if (isset($savem)) $this->SetFetchMode($savem);
+               $ADODB_FETCH_MODE = $save;
+               
+               if ($rs === false) {
+                       return $false;
+               }
+               if (!empty($this->metaKeySQL)) {
+                       // If we want the primary keys, we have to issue a separate query
+                       // Of course, a modified version of the metaColumnsSQL query using a 
+                       // LEFT JOIN would have been much more elegant, but postgres does 
+                       // not support OUTER JOINS. So here is the clumsy way.
+                       
+                       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+                       
+                       $rskey = $this->Execute(sprintf($this->metaKeySQL,($table)));
+                       // fetch all result in once for performance.
+                       $keys =& $rskey->GetArray();
+                       if (isset($savem)) $this->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save;
+                       
+                       $rskey->Close();
+                       unset($rskey);
+               }
+
+               $rsdefa = array();
+               if (!empty($this->metaDefaultsSQL)) {
+                       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+                       $sql = sprintf($this->metaDefaultsSQL, ($table));
+                       $rsdef = $this->Execute($sql);
+                       if (isset($savem)) $this->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save;
+                       
+                       if ($rsdef) {
+                               while (!$rsdef->EOF) {
+                                       $num = $rsdef->fields['num'];
+                                       $s = $rsdef->fields['def'];
+                                       if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */
+                                               $s = substr($s, 1);
+                                               $s = substr($s, 0, strlen($s) - 1);
+                                       }
+
+                                       $rsdefa[$num] = $s;
+                                       $rsdef->MoveNext();
+                               }
+                       } else {
+                               ADOConnection::outp( "==> SQL => " . $sql);
+                       }
+                       unset($rsdef);
+               }
+       
+               $retarr = array();
+               while (!$rs->EOF) {     
+                       $fld = new ADOFieldObject();
+                       $fld->name = $rs->fields[0];
+                       $fld->type = $rs->fields[1];
+                       $fld->max_length = $rs->fields[2];
+                       if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4;
+                       if ($fld->max_length <= 0) $fld->max_length = -1;
+                       if ($fld->type == 'numeric') {
+                               $fld->scale = $fld->max_length & 0xFFFF;
+                               $fld->max_length >>= 16;
+                       }
+                       // dannym
+                       // 5 hasdefault; 6 num-of-column
+                       $fld->has_default = ($rs->fields[5] == 't');
+                       if ($fld->has_default) {
+                               $fld->default_value = $rsdefa[$rs->fields[6]];
+                       }
+
+                       //Freek
+                       if ($rs->fields[4] == 't') {
+                               $fld->not_null = true;
+                       }
+                       
+                       // Freek
+                       if (is_array($keys)) {
+                               foreach($keys as $key) {
+                                       if ($fld->name == $key['column_name'] AND $key['primary_key'] == 't') 
+                                               $fld->primary_key = true;
+                                       if ($fld->name == $key['column_name'] AND $key['unique_key'] == 't') 
+                                               $fld->unique = true; // What name is more compatible?
+                               }
+                       }
+                       
+                       if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;     
+                       else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld;
+                       
+                       $rs->MoveNext();
+               }
+               $rs->Close();
+               if (empty($retarr))
+                       return  $false;
+               else
+                       return $retarr; 
+               
+       }
+
+         function &MetaIndexes ($table, $primary = FALSE)
+      {
+         global $ADODB_FETCH_MODE;
+                
+                               $schema = false;
+                               $this->_findschema($table,$schema);
+
+                               if ($schema) { // requires pgsql 7.3+ - pg_namespace used.
+                                       $sql = '
+SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" 
+FROM pg_catalog.pg_class c 
+JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid 
+JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid
+       ,pg_namespace n 
+WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\')) and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\' AND i.indisprimary=false';
+                               } else {
+                       $sql = '
+SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns"
+FROM pg_catalog.pg_class c
+JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid
+JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid
+WHERE c2.relname=\'%s\' or c2.relname=lower(\'%s\')';
+                       }
+                                           
+                if ($primary == FALSE) {
+                       $sql .= ' AND i.indisprimary=false;';
+                }
+                
+                $save = $ADODB_FETCH_MODE;
+                $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+                if ($this->fetchMode !== FALSE) {
+                        $savem = $this->SetFetchMode(FALSE);
+                }
+                
+                $rs = $this->Execute(sprintf($sql,$table,$table,$schema));
+                if (isset($savem)) {
+                        $this->SetFetchMode($savem);
+                }
+                $ADODB_FETCH_MODE = $save;
+
+                if (!is_object($rs)) {
+                       $false = false;
+                                       return $false;
+                }
+                               
+                $col_names = $this->MetaColumnNames($table,true);
+                $indexes = array();
+                while ($row = $rs->FetchRow()) {
+                        $columns = array();
+                        foreach (explode(' ', $row[2]) as $col) {
+                                $columns[] = $col_names[$col - 1];
+                        }
+                        
+                        $indexes[$row[0]] = array(
+                                'unique' => ($row[1] == 't'),
+                                'columns' => $columns
+                        );
+                }
+                return $indexes;
+        }
+
+       // returns true or false
+       //
+       // examples:
+       //      $db->Connect("host=host1 user=user1 password=secret port=4341");
+       //      $db->Connect('host1','user1','secret');
+       function _connect($str,$user='',$pwd='',$db='',$ctype=0)
+       {
+               
+               if (!function_exists('pg_pconnect')) return null;
+               
+               $this->_errorMsg = false;
+               
+               if ($user || $pwd || $db) {
+                       $user = adodb_addslashes($user);
+                       $pwd = adodb_addslashes($pwd);
+                       if (strlen($db) == 0) $db = 'template1';
+                       $db = adodb_addslashes($db);
+                       if ($str)  {
+                               $host = split(":", $str);
+                               if ($host[0]) $str = "host=".adodb_addslashes($host[0]);
+                               else $str = '';
+                               if (isset($host[1])) $str .= " port=$host[1]";
+                               else if (!empty($this->port)) $str .= " port=".$this->port;
+                               if (isset($host[2])) $str .= " sslmode=".adodb_addslashes($host[2]);
+                               else if (!empty($this->sslmode)) $str .= " sslmode=".$this->sslmode;
+                       }
+                               if ($user) $str .= " user=".$user;
+                               if ($pwd)  $str .= " password=".$pwd;
+                               if ($db)   $str .= " dbname=".$db;
+               }
+
+               //if ($user) $linea = "user=$user host=$linea password=$pwd dbname=$db port=5432";
+               
+               if ($ctype === 1) { // persistent
+                       $this->_connectionID = pg_pconnect($str);
+               } else {
+                       if ($ctype === -1) { // nconnect, we trick pgsql ext by changing the connection str
+                       static $ncnt;
+                       
+                               if (empty($ncnt)) $ncnt = 1;
+                               else $ncnt += 1;
+                               
+                               $str .= str_repeat(' ',$ncnt);
+                       }
+                       $this->_connectionID = @pg_connect($str);
+               }
+               if ($this->_connectionID === false) return false;
+               $this->Execute("set datestyle='ISO'");
+               return true;
+       }
+       
+       function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
+       {
+               return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName,-1);
+       }
+        
+       // returns true or false
+       //
+       // examples:
+       //      $db->PConnect("host=host1 user=user1 password=secret port=4341");
+       //      $db->PConnect('host1','user1','secret');
+       function _pconnect($str,$user='',$pwd='',$db='')
+       {
+               return $this->_connect($str,$user,$pwd,$db,1);
+       }
+       
+
+       // returns queryID or false
+       function _query($sql,$inputarr)
+       {
+               
+               if ($inputarr) {
+               /*
+                       It appears that PREPARE/EXECUTE is slower for many queries.
+                       
+                       For query executed 1000 times:
+                       "select id,firstname,lastname from adoxyz 
+                               where firstname not like ? and lastname not like ? and id = ?"
+                               
+                       with plan = 1.51861286163 secs
+                       no plan =   1.26903700829 secs
+
+                       
+
+               */
+                       $plan = 'P'.md5($sql);
+                               
+                       $execp = '';
+                       foreach($inputarr as $v) {
+                               if ($execp) $execp .= ',';
+                               if (is_string($v)) {
+                                       if (strncmp($v,"'",1) !== 0) $execp .= $this->qstr($v);
+                               } else {
+                                       $execp .= $v;
+                               }
+                       }
+                       
+                       if ($execp) $exsql = "EXECUTE $plan ($execp)";
+                       else $exsql = "EXECUTE $plan";
+                       
+                       $rez = @pg_exec($this->_connectionID,$exsql);
+                       if (!$rez) {
+                       # Perhaps plan does not exist? Prepare/compile plan.
+                               $params = '';
+                               foreach($inputarr as $v) {
+                                       if ($params) $params .= ',';
+                                       if (is_string($v)) {
+                                               $params .= 'VARCHAR';
+                                       } else if (is_integer($v)) {
+                                               $params .= 'INTEGER';
+                                       } else {
+                                               $params .= "REAL";
+                                       }
+                               }
+                               $sqlarr = explode('?',$sql);
+                               //print_r($sqlarr);
+                               $sql = '';
+                               $i = 1;
+                               foreach($sqlarr as $v) {
+                                       $sql .= $v.' $'.$i;
+                                       $i++;
+                               }
+                               $s = "PREPARE $plan ($params) AS ".substr($sql,0,strlen($sql)-2);               
+                               //adodb_pr($s);
+                               pg_exec($this->_connectionID,$s);
+                               echo $this->ErrorMsg();
+                       }
+                       
+                       $rez = pg_exec($this->_connectionID,$exsql);
+               } else {
+                       $this->_errorMsg = false;
+                       //adodb_backtrace();
+                       $rez = pg_exec($this->_connectionID,$sql);
+               }
+               // check if no data returned, then no need to create real recordset
+               if ($rez && pg_numfields($rez) <= 0) {
+                       if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') {
+                               pg_freeresult($this->_resultid);
+                       }
+                       $this->_resultid = $rez;
+                       return true;
+               }
+               
+               return $rez;
+       }
+       
+
+       /*      Returns: the last error message from previous database operation        */      
+       function ErrorMsg() 
+       {
+               if ($this->_errorMsg !== false) return $this->_errorMsg;
+               if (ADODB_PHPVER >= 0x4300) {
+                       if (!empty($this->_resultid)) {
+                               $this->_errorMsg = @pg_result_error($this->_resultid);
+                               if ($this->_errorMsg) return $this->_errorMsg;
+                       }
+                       
+                       if (!empty($this->_connectionID)) {
+                               $this->_errorMsg = @pg_last_error($this->_connectionID);
+                       } else $this->_errorMsg = @pg_last_error();
+               } else {
+                       if (empty($this->_connectionID)) $this->_errorMsg = @pg_errormessage();
+                       else $this->_errorMsg = @pg_errormessage($this->_connectionID);
+               }
+               return $this->_errorMsg;
+       }
+       
+       function ErrorNo()
+       {
+               $e = $this->ErrorMsg();
+               if (strlen($e)) {
+                       return ADOConnection::MetaError($e);
+                }
+                return 0;
+       }
+
+       // returns true or false
+       function _close()
+       {
+               if ($this->transCnt) $this->RollbackTrans();
+               if ($this->_resultid) {
+                       @pg_freeresult($this->_resultid);
+                       $this->_resultid = false;
+               }
+               @pg_close($this->_connectionID);
+               $this->_connectionID = false;
+               return true;
+       }
+       
+       
+       /*
+       * Maximum size of C field
+       */
+       function CharMax()
+       {
+               return 1000000000;  // should be 1 Gb?
+       }
+       
+       /*
+       * Maximum size of X field
+       */
+       function TextMax()
+       {
+               return 1000000000; // should be 1 Gb?
+       }
+       
+               
+}
+       
+/*--------------------------------------------------------------------------------------
+        Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_postgres64 extends ADORecordSet{
+       var $_blobArr;
+       var $databaseType = "postgres64";
+       var $canSeek = true;
+       function ADORecordSet_postgres64($queryID,$mode=false) 
+       {
+               if ($mode === false) { 
+                       global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               }
+               switch ($mode)
+               {
+               case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break;
+               case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break;
+               
+               case ADODB_FETCH_DEFAULT:
+               case ADODB_FETCH_BOTH:
+               default: $this->fetchMode = PGSQL_BOTH; break;
+               }
+               $this->adodbFetchMode = $mode;
+               $this->ADORecordSet($queryID);
+       }
+       
+       function &GetRowAssoc($upper=true)
+       {
+               if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields;
+               $row =& ADORecordSet::GetRowAssoc($upper);
+               return $row;
+       }
+
+       function _initrs()
+       {
+       global $ADODB_COUNTRECS;
+               $qid = $this->_queryID;
+               $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($qid):-1;
+               $this->_numOfFields = @pg_numfields($qid);
+               
+               // cache types for blob decode check
+               // apparently pg_fieldtype actually performs an sql query on the database to get the type.
+               if (empty($this->connection->noBlobs))
+               for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) {  
+                       if (pg_fieldtype($qid,$i) == 'bytea') {
+                               $this->_blobArr[$i] = pg_fieldname($qid,$i);
+                       }
+               }
+       }
+
+               /* Use associative array to get fields array */
+       function Fields($colname)
+       {
+               if ($this->fetchMode != PGSQL_NUM) return @$this->fields[$colname];
+               
+               if (!$this->bind) {
+                       $this->bind = array();
+                       for ($i=0; $i < $this->_numOfFields; $i++) {
+                               $o = $this->FetchField($i);
+                               $this->bind[strtoupper($o->name)] = $i;
+                       }
+               }
+                return $this->fields[$this->bind[strtoupper($colname)]];
+       }
+
+       function &FetchField($off = 0) 
+       {
+               // offsets begin at 0
+               
+               $o= new ADOFieldObject();
+               $o->name = @pg_fieldname($this->_queryID,$off);
+               $o->type = @pg_fieldtype($this->_queryID,$off);
+               $o->max_length = @pg_fieldsize($this->_queryID,$off);
+               return $o;      
+       }
+
+       function _seek($row)
+       {
+               return @pg_fetch_row($this->_queryID,$row);
+       }
+       
+       function _decode($blob)
+       {
+               if ($blob === NULL)
+                       return NULL;
+
+               eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";');
+               return $realblob;       
+       }
+       
+       function _fixblobs()
+       {
+               if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) {
+                       foreach($this->_blobArr as $k => $v) {
+                               $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]);
+                       }
+               }
+               if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) {
+                       foreach($this->_blobArr as $k => $v) {
+                               $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]);
+                       }
+               }
+       }
+       
+       // 10% speedup to move MoveNext to child class
+       function MoveNext() 
+       {
+               if (!$this->EOF) {
+                       $this->_currentRow++;
+                       if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
+                               $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+                               if (is_array($this->fields) && $this->fields) {
+                                       if (isset($this->_blobArr)) $this->_fixblobs();
+                                       return true;
+                               }
+                       }
+                       $this->fields = false;
+                       $this->EOF = true;
+               }
+               return false;
+       }               
+       
+       function _fetch()
+       {
+                               
+               if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)
+               return false;
+
+               $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+               
+               if ($this->fields && isset($this->_blobArr)) $this->_fixblobs();
+                       
+               return (is_array($this->fields));
+       }
+
+       function _close() 
+       { 
+               return @pg_freeresult($this->_queryID);
+       }
+
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               switch (strtoupper($t)) {
+                               case 'MONEY': // stupid, postgres expects money to be a string
+                               case 'INTERVAL':
+                               case 'CHAR':
+                               case 'CHARACTER':
+                               case 'VARCHAR':
+                               case 'NAME':
+                               case 'BPCHAR':
+                               case '_VARCHAR':
+                               case 'INET':
+                                       if ($len <= $this->blobSize) return 'C';
+                               
+                               case 'TEXT':
+                                       return 'X';
+               
+                               case 'IMAGE': // user defined type
+                               case 'BLOB': // user defined type
+                               case 'BIT':     // This is a bit string, not a single bit, so don't return 'L'
+                               case 'VARBIT':
+                               case 'BYTEA':
+                                       return 'B';
+                               
+                               case 'BOOL':
+                               case 'BOOLEAN':
+                                       return 'L';
+                               
+                               case 'DATE':
+                                       return 'D';
+                               
+                               case 'TIME':
+                               case 'DATETIME':
+                               case 'TIMESTAMP':
+                               case 'TIMESTAMPTZ':
+                                       return 'T';
+                               
+                               case 'SMALLINT': 
+                               case 'BIGINT': 
+                               case 'INTEGER': 
+                               case 'INT8': 
+                               case 'INT4':
+                               case 'INT2':
+                                       if (isset($fieldobj) &&
+                               empty($fieldobj->primary_key) && empty($fieldobj->unique)) return 'I';
+                               
+                               case 'OID':
+                               case 'SERIAL':
+                                       return 'R';
+                               
+                                default:
+                                       return 'N';
+                       }
+       }
+
+}
 ?>