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