Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/adodb/drivers/adodb-postgres64.inc.php
Go to the documentation of this file.
00001 <?php
00002 /*
00003  V5.14 8 Sept 2011  (c) 2000-2011 John Lim (jlim#natsoft.com). All rights reserved.
00004   Released under both BSD license and Lesser GPL library license. 
00005   Whenever there is any discrepancy between the two licenses, 
00006   the BSD license will take precedence.
00007   Set tabs to 8.
00008   
00009   Original version derived from Alberto Cerezal (acerezalp@dbnet.es) - DBNet Informatica & Comunicaciones. 
00010   08 Nov 2000 jlim - Minor corrections, removing mysql stuff
00011   09 Nov 2000 jlim - added insertid support suggested by "Christopher Kings-Lynne" <chriskl@familyhealth.com.au>
00012                                         jlim - changed concat operator to || and data types to MetaType to match documented pgsql types 
00013                         see http://www.postgresql.org/devel-corner/docs/postgres/datatype.htm  
00014   22 Nov 2000 jlim - added changes to FetchField() and MetaTables() contributed by "raser" <raser@mail.zen.com.tw>
00015   27 Nov 2000 jlim - added changes to _connect/_pconnect from ideas by "Lennie" <leen@wirehub.nl>
00016   15 Dec 2000 jlim - added changes suggested by Additional code changes by "Eric G. Werk" egw@netguide.dk. 
00017   31 Jan 2002 jlim - finally installed postgresql. testing
00018   01 Mar 2001 jlim - Freek Dijkstra changes, also support for text type
00019   
00020   See http://www.varlena.com/varlena/GeneralBits/47.php
00021   
00022         -- What indexes are on my table?
00023         select * from pg_indexes where tablename = 'tablename';
00024         
00025         -- What triggers are on my table?
00026         select c.relname as "Table", t.tgname as "Trigger Name", 
00027            t.tgconstrname as "Constraint Name", t.tgenabled as "Enabled",
00028            t.tgisconstraint as "Is Constraint", cc.relname as "Referenced Table",
00029            p.proname as "Function Name"
00030         from pg_trigger t, pg_class c, pg_class cc, pg_proc p
00031         where t.tgfoid = p.oid and t.tgrelid = c.oid
00032            and t.tgconstrrelid = cc.oid
00033            and c.relname = 'tablename';
00034         
00035         -- What constraints are on my table?
00036         select r.relname as "Table", c.conname as "Constraint Name",
00037            contype as "Constraint Type", conkey as "Key Columns",
00038            confkey as "Foreign Columns", consrc as "Source"
00039         from pg_class r, pg_constraint c
00040         where r.oid = c.conrelid
00041            and relname = 'tablename';
00042 
00043 */
00044 
00045 // security - hide paths
00046 if (!defined('ADODB_DIR')) die();
00047 
00048 function adodb_addslashes($s)
00049 {
00050         $len = strlen($s);
00051         if ($len == 0) return "''";
00052         if (strncmp($s,"'",1) === 0 && substr($s,$len-1) == "'") return $s; // already quoted
00053         
00054         return "'".addslashes($s)."'";
00055 }
00056 
00057 class ADODB_postgres64 extends ADOConnection{
00058         var $databaseType = 'postgres64';
00059         var $dataProvider = 'postgres';
00060         var $hasInsertID = true;
00061         var $_resultid = false;
00062         var $concat_operator='||';
00063         var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1";
00064     var $metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%'
00065         and tablename not in ('sql_features', 'sql_implementation_info', 'sql_languages',
00066          'sql_packages', 'sql_sizing', 'sql_sizing_profiles') 
00067         union 
00068         select viewname,'V' from pg_views where viewname not like 'pg\_%'";
00069         //"select tablename from pg_tables where tablename not like 'pg_%' order by 1";
00070         var $isoDates = true; // accepts dates in ISO format
00071         var $sysDate = "CURRENT_DATE";
00072         var $sysTimeStamp = "CURRENT_TIMESTAMP";
00073         var $blobEncodeType = 'C';
00074         var $metaColumnsSQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum 
00075                 FROM pg_class c, pg_attribute a,pg_type t 
00076                 WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) and a.attname not like '....%%'
00077 AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
00078 
00079         // used when schema defined
00080         var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum 
00081 FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n 
00082 WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s'))
00083  and c.relnamespace=n.oid and n.nspname='%s' 
00084         and a.attname not like '....%%' AND a.attnum > 0 
00085         AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
00086         
00087         // get primary key etc -- from Freek Dijkstra
00088         var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key 
00089         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'";
00090         
00091         var $hasAffectedRows = true;
00092         var $hasLimit = false;  // set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10
00093         // below suggested by Freek Dijkstra 
00094         var $true = 'TRUE';             // string that represents TRUE for a database
00095         var $false = 'FALSE';           // string that represents FALSE for a database
00096         var $fmtDate = "'Y-m-d'";       // used by DBDate() as the default date format used by the database
00097         var $fmtTimeStamp = "'Y-m-d H:i:s'"; // used by DBTimeStamp as the default timestamp fmt.
00098         var $hasMoveFirst = true;
00099         var $hasGenID = true;
00100         var $_genIDSQL = "SELECT NEXTVAL('%s')";
00101         var $_genSeqSQL = "CREATE SEQUENCE %s START %s";
00102         var $_dropSeqSQL = "DROP SEQUENCE %s";
00103         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";
00104         var $random = 'random()';               
00105         var $autoRollback = true; // apparently pgsql does not autorollback properly before php 4.3.4
00106                                                         // http://bugs.php.net/bug.php?id=25404
00107         
00108         var $uniqueIisR = true;
00109         var $_bindInputArray = false; // requires postgresql 7.3+ and ability to modify database
00110         var $disableBlobs = false; // set to true to disable blob checking, resulting in 2-5% improvement in performance.
00111         
00112         var $_pnum = 0;
00113         
00114         // The last (fmtTimeStamp is not entirely correct: 
00115         // PostgreSQL also has support for time zones, 
00116         // and writes these time in this format: "2001-03-01 18:59:26+02". 
00117         // There is no code for the "+02" time zone information, so I just left that out. 
00118         // I'm not familiar enough with both ADODB as well as Postgres 
00119         // to know what the concequences are. The other values are correct (wheren't in 0.94)
00120         // -- Freek Dijkstra 
00121 
00122         function ADODB_postgres64() 
00123         {
00124         // changes the metaColumnsSQL, adds columns: attnum[6]
00125         }
00126         
00127         function ServerInfo()
00128         {
00129                 if (isset($this->version)) return $this->version;
00130                 
00131                 $arr['description'] = $this->GetOne("select version()");
00132                 $arr['version'] = ADOConnection::_findvers($arr['description']);
00133                 $this->version = $arr;
00134                 return $arr;
00135         }
00136 
00137         function IfNull( $field, $ifNull ) 
00138         {
00139                 return " coalesce($field, $ifNull) "; 
00140         }
00141 
00142         // get the last id - never tested
00143         function pg_insert_id($tablename,$fieldname)
00144         {
00145                 $result=pg_exec($this->_connectionID, "SELECT last_value FROM ${tablename}_${fieldname}_seq");
00146                 if ($result) {
00147                         $arr = @pg_fetch_row($result,0);
00148                         pg_freeresult($result);
00149                         if (isset($arr[0])) return $arr[0];
00150                 }
00151                 return false;
00152         }
00153         
00154 /* Warning from http://www.php.net/manual/function.pg-getlastoid.php:
00155 Using a OID as a unique identifier is not generally wise. 
00156 Unless you are very careful, you might end up with a tuple having 
00157 a different OID if a database must be reloaded. */
00158         function _insertid($table,$column)
00159         {
00160                 if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;
00161                 $oid = pg_getlastoid($this->_resultid);
00162                 // to really return the id, we need the table and column-name, else we can only return the oid != id
00163                 return empty($table) || empty($column) ? $oid : $this->GetOne("SELECT $column FROM $table WHERE oid=".(int)$oid);
00164         }
00165 
00166 // I get this error with PHP before 4.0.6 - jlim
00167 // Warning: This compilation does not support pg_cmdtuples() in adodb-postgres.inc.php on line 44
00168    function _affectedrows()
00169    {
00170                 if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;
00171                 return pg_cmdtuples($this->_resultid);
00172    }
00173    
00174         
00175                 // returns true/false
00176         function BeginTrans()
00177         {
00178                 if ($this->transOff) return true;
00179                 $this->transCnt += 1;
00180                 return @pg_Exec($this->_connectionID, "begin ".$this->_transmode);
00181         }
00182         
00183         function RowLock($tables,$where,$col='1 as adodbignore') 
00184         {
00185                 if (!$this->transCnt) $this->BeginTrans();
00186                 return $this->GetOne("select $col from $tables where $where for update");
00187         }
00188 
00189         // returns true/false. 
00190         function CommitTrans($ok=true) 
00191         { 
00192                 if ($this->transOff) return true;
00193                 if (!$ok) return $this->RollbackTrans();
00194                 
00195                 $this->transCnt -= 1;
00196                 return @pg_Exec($this->_connectionID, "commit");
00197         }
00198         
00199         // returns true/false
00200         function RollbackTrans()
00201         {
00202                 if ($this->transOff) return true;
00203                 $this->transCnt -= 1;
00204                 return @pg_Exec($this->_connectionID, "rollback");
00205         }
00206         
00207         function MetaTables($ttype=false,$showSchema=false,$mask=false) 
00208         {
00209                 $info = $this->ServerInfo();
00210                 if ($info['version'] >= 7.3) {
00211                 $this->metaTablesSQL = "select table_name,'T' from information_schema.tables where table_schema not in ( 'pg_catalog','information_schema')
00212                         union
00213                        select table_name,'V' from information_schema.views where table_schema not in ( 'pg_catalog','information_schema') ";
00214                 }
00215                 if ($mask) {
00216                         $save = $this->metaTablesSQL;
00217                         $mask = $this->qstr(strtolower($mask));
00218                         if ($info['version']>=7.3)
00219                                 $this->metaTablesSQL = "select table_name,'T' from information_schema.tables where table_name like $mask and table_schema not in ( 'pg_catalog','information_schema')
00220                         union
00221                        select table_name,'V' from information_schema.views where table_name like $mask and table_schema not in ( 'pg_catalog','information_schema') ";
00222                         else
00223                                 $this->metaTablesSQL = "
00224 select tablename,'T' from pg_tables where tablename like $mask 
00225  union 
00226 select viewname,'V' from pg_views where viewname like $mask";
00227                 }
00228                 $ret = ADOConnection::MetaTables($ttype,$showSchema);
00229                 
00230                 if ($mask) {
00231                         $this->metaTablesSQL = $save;
00232                 }
00233                 return $ret;
00234         }
00235         
00236         
00237         // if magic quotes disabled, use pg_escape_string()
00238         function qstr($s,$magic_quotes=false)
00239         {
00240                 if (is_bool($s)) return $s ? 'true' : 'false';
00241                  
00242                 if (!$magic_quotes) {
00243                         if (ADODB_PHPVER >= 0x5200) {
00244                                 return  "'".pg_escape_string($this->_connectionID,$s)."'";
00245                         } 
00246                         if (ADODB_PHPVER >= 0x4200) {
00247                                 return  "'".pg_escape_string($s)."'";
00248                         }
00249                         if ($this->replaceQuote[0] == '\\'){
00250                                 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\\000"),$s);
00251                         }
00252                         return  "'".str_replace("'",$this->replaceQuote,$s)."'"; 
00253                 }
00254                 
00255                 // undo magic quotes for "
00256                 $s = str_replace('\\"','"',$s);
00257                 return "'$s'";
00258         }
00259         
00260         
00261         
00262         // Format date column in sql string given an input format that understands Y M D
00263         function SQLDate($fmt, $col=false)
00264         {       
00265                 if (!$col) $col = $this->sysTimeStamp;
00266                 $s = 'TO_CHAR('.$col.",'";
00267                 
00268                 $len = strlen($fmt);
00269                 for ($i=0; $i < $len; $i++) {
00270                         $ch = $fmt[$i];
00271                         switch($ch) {
00272                         case 'Y':
00273                         case 'y':
00274                                 $s .= 'YYYY';
00275                                 break;
00276                         case 'Q':
00277                         case 'q':
00278                                 $s .= 'Q';
00279                                 break;
00280                                 
00281                         case 'M':
00282                                 $s .= 'Mon';
00283                                 break;
00284                                 
00285                         case 'm':
00286                                 $s .= 'MM';
00287                                 break;
00288                         case 'D':
00289                         case 'd':
00290                                 $s .= 'DD';
00291                                 break;
00292                         
00293                         case 'H':
00294                                 $s.= 'HH24';
00295                                 break;
00296                                 
00297                         case 'h':
00298                                 $s .= 'HH';
00299                                 break;
00300                                 
00301                         case 'i':
00302                                 $s .= 'MI';
00303                                 break;
00304                         
00305                         case 's':
00306                                 $s .= 'SS';
00307                                 break;
00308                         
00309                         case 'a':
00310                         case 'A':
00311                                 $s .= 'AM';
00312                                 break;
00313                                 
00314                         case 'w':
00315                                 $s .= 'D';
00316                                 break;
00317                         
00318                         case 'l':
00319                                 $s .= 'DAY';
00320                                 break;
00321                         
00322                          case 'W':
00323                                 $s .= 'WW';
00324                                 break;
00325 
00326                         default:
00327                         // handle escape characters...
00328                                 if ($ch == '\\') {
00329                                         $i++;
00330                                         $ch = substr($fmt,$i,1);
00331                                 }
00332                                 if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;
00333                                 else $s .= '"'.$ch.'"';
00334                                 
00335                         }
00336                 }
00337                 return $s. "')";
00338         }
00339         
00340         
00341         
00342         /* 
00343         * Load a Large Object from a file 
00344         * - the procedure stores the object id in the table and imports the object using 
00345         * postgres proprietary blob handling routines 
00346         *
00347         * contributed by Mattia Rossi mattia@technologist.com
00348         * modified for safe mode by juraj chlebec
00349         */ 
00350         function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') 
00351         { 
00352                 pg_exec ($this->_connectionID, "begin"); 
00353                 
00354                 $fd = fopen($path,'r');
00355                 $contents = fread($fd,filesize($path));
00356                 fclose($fd);
00357                 
00358                 $oid = pg_lo_create($this->_connectionID);
00359                 $handle = pg_lo_open($this->_connectionID, $oid, 'w');
00360                 pg_lo_write($handle, $contents);
00361                 pg_lo_close($handle);
00362                 
00363                 // $oid = pg_lo_import ($path); 
00364                 pg_exec($this->_connectionID, "commit"); 
00365                 $rs = ADOConnection::UpdateBlob($table,$column,$oid,$where,$blobtype); 
00366                 $rez = !empty($rs); 
00367                 return $rez; 
00368         } 
00369         
00370         /*
00371         * Deletes/Unlinks a Blob from the database, otherwise it 
00372         * will be left behind
00373         *
00374         * Returns TRUE on success or FALSE on failure.
00375         *
00376         * contributed by Todd Rogers todd#windfox.net
00377         */
00378         function BlobDelete( $blob )
00379         {
00380                 pg_exec ($this->_connectionID, "begin");
00381                 $result = @pg_lo_unlink($blob);
00382                 pg_exec ($this->_connectionID, "commit");
00383                 return( $result );
00384         }
00385 
00386         /*
00387                 Hueristic - not guaranteed to work.
00388         */
00389         function GuessOID($oid)
00390         {
00391                 if (strlen($oid)>16) return false;
00392                 return is_numeric($oid);
00393         }
00394         
00395         /* 
00396         * If an OID is detected, then we use pg_lo_* to open the oid file and read the
00397         * real blob from the db using the oid supplied as a parameter. If you are storing
00398         * blobs using bytea, we autodetect and process it so this function is not needed.
00399         *
00400         * contributed by Mattia Rossi mattia@technologist.com
00401         *
00402         * see http://www.postgresql.org/idocs/index.php?largeobjects.html
00403         *
00404         * Since adodb 4.54, this returns the blob, instead of sending it to stdout. Also
00405         * added maxsize parameter, which defaults to $db->maxblobsize if not defined.
00406         */ 
00407         function BlobDecode($blob,$maxsize=false,$hastrans=true) 
00408         {
00409                 if (!$this->GuessOID($blob)) return $blob;
00410                 
00411                 if ($hastrans) @pg_exec($this->_connectionID,"begin"); 
00412                 $fd = @pg_lo_open($this->_connectionID,$blob,"r");
00413                 if ($fd === false) {
00414                         if ($hastrans) @pg_exec($this->_connectionID,"commit");
00415                         return $blob;
00416                 }
00417                 if (!$maxsize) $maxsize = $this->maxblobsize;
00418                 $realblob = @pg_loread($fd,$maxsize); 
00419                 @pg_loclose($fd); 
00420                 if ($hastrans) @pg_exec($this->_connectionID,"commit"); 
00421                 return $realblob;
00422         }
00423         
00424         /* 
00425                 See http://www.postgresql.org/idocs/index.php?datatype-binary.html
00426                 
00427                 NOTE: SQL string literals (input strings) must be preceded with two backslashes 
00428                 due to the fact that they must pass through two parsers in the PostgreSQL 
00429                 backend.
00430         */
00431         function BlobEncode($blob)
00432         {
00433                 if (ADODB_PHPVER >= 0x5200) return pg_escape_bytea($this->_connectionID, $blob);
00434                 if (ADODB_PHPVER >= 0x4200) return pg_escape_bytea($blob);
00435                 
00436                 /*92=backslash, 0=null, 39=single-quote*/
00437                 $badch = array(chr(92),chr(0),chr(39)); # \  null  '
00438                 $fixch = array('\\\\134','\\\\000','\\\\047');
00439                 return adodb_str_replace($badch,$fixch,$blob);
00440                 
00441                 // note that there is a pg_escape_bytea function only for php 4.2.0 or later
00442         }
00443         
00444         // assumes bytea for blob, and varchar for clob
00445         function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
00446         {
00447                 if ($blobtype == 'CLOB') {
00448                 return $this->Execute("UPDATE $table SET $column=" . $this->qstr($val) . " WHERE $where");
00449                 }
00450                 // do not use bind params which uses qstr(), as blobencode() already quotes data
00451                 return $this->Execute("UPDATE $table SET $column='".$this->BlobEncode($val)."'::bytea WHERE $where");
00452         }
00453         
00454         function OffsetDate($dayFraction,$date=false)
00455         {               
00456                 if (!$date) $date = $this->sysDate;
00457                 else if (strncmp($date,"'",1) == 0) {
00458                         $len = strlen($date);
00459                         if (10 <= $len && $len <= 12) $date = 'date '.$date;
00460                         else $date = 'timestamp '.$date;
00461                 }
00462                 
00463                 
00464                 return "($date+interval'".($dayFraction * 1440)." minutes')";
00465                 #return "($date+interval'$dayFraction days')";
00466         }
00467         
00468 
00469         // for schema support, pass in the $table param "$schema.$tabname".
00470         // converts field names to lowercase, $upper is ignored
00471         // see http://phplens.com/lens/lensforum/msgs.php?id=14018 for more info
00472         function MetaColumns($table,$normalize=true) 
00473         {
00474         global $ADODB_FETCH_MODE;
00475         
00476                 $schema = false;
00477                 $false = false;
00478                 $this->_findschema($table,$schema);
00479                 
00480                 if ($normalize) $table = strtolower($table);
00481 
00482                 $save = $ADODB_FETCH_MODE;
00483                 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
00484                 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
00485                 
00486                 if ($schema) $rs = $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema));
00487                 else $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table,$table));
00488                 if (isset($savem)) $this->SetFetchMode($savem);
00489                 $ADODB_FETCH_MODE = $save;
00490                 
00491                 if ($rs === false) {
00492                         return $false;
00493                 }
00494                 if (!empty($this->metaKeySQL)) {
00495                         // If we want the primary keys, we have to issue a separate query
00496                         // Of course, a modified version of the metaColumnsSQL query using a 
00497                         // LEFT JOIN would have been much more elegant, but postgres does 
00498                         // not support OUTER JOINS. So here is the clumsy way.
00499                         
00500                         $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
00501                         
00502                         $rskey = $this->Execute(sprintf($this->metaKeySQL,($table)));
00503                         // fetch all result in once for performance.
00504                         $keys = $rskey->GetArray();
00505                         if (isset($savem)) $this->SetFetchMode($savem);
00506                         $ADODB_FETCH_MODE = $save;
00507                         
00508                         $rskey->Close();
00509                         unset($rskey);
00510                 }
00511 
00512                 $rsdefa = array();
00513                 if (!empty($this->metaDefaultsSQL)) {
00514                         $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
00515                         $sql = sprintf($this->metaDefaultsSQL, ($table));
00516                         $rsdef = $this->Execute($sql);
00517                         if (isset($savem)) $this->SetFetchMode($savem);
00518                         $ADODB_FETCH_MODE = $save;
00519                         
00520                         if ($rsdef) {
00521                                 while (!$rsdef->EOF) {
00522                                         $num = $rsdef->fields['num'];
00523                                         $s = $rsdef->fields['def'];
00524                                         if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */
00525                                                 $s = substr($s, 1);
00526                                                 $s = substr($s, 0, strlen($s) - 1);
00527                                         }
00528 
00529                                         $rsdefa[$num] = $s;
00530                                         $rsdef->MoveNext();
00531                                 }
00532                         } else {
00533                                 ADOConnection::outp( "==> SQL => " . $sql);
00534                         }
00535                         unset($rsdef);
00536                 }
00537         
00538                 $retarr = array();
00539                 while (!$rs->EOF) {     
00540                         $fld = new ADOFieldObject();
00541                         $fld->name = $rs->fields[0];
00542                         $fld->type = $rs->fields[1];
00543                         $fld->max_length = $rs->fields[2];
00544                         $fld->attnum = $rs->fields[6];
00545                         
00546                         if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4;
00547                         if ($fld->max_length <= 0) $fld->max_length = -1;
00548                         if ($fld->type == 'numeric') {
00549                                 $fld->scale = $fld->max_length & 0xFFFF;
00550                                 $fld->max_length >>= 16;
00551                         }
00552                         // dannym
00553                         // 5 hasdefault; 6 num-of-column
00554                         $fld->has_default = ($rs->fields[5] == 't');
00555                         if ($fld->has_default) {
00556                                 $fld->default_value = $rsdefa[$rs->fields[6]];
00557                         }
00558 
00559                         //Freek
00560                         $fld->not_null = $rs->fields[4] == 't';
00561                         
00562                         
00563                         // Freek
00564                         if (is_array($keys)) {
00565                                 foreach($keys as $key) {
00566                                         if ($fld->name == $key['column_name'] AND $key['primary_key'] == 't') 
00567                                                 $fld->primary_key = true;
00568                                         if ($fld->name == $key['column_name'] AND $key['unique_key'] == 't') 
00569                                                 $fld->unique = true; // What name is more compatible?
00570                                 }
00571                         }
00572                         
00573                         if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;     
00574                         else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld;
00575                         
00576                         $rs->MoveNext();
00577                 }
00578                 $rs->Close();
00579                 if (empty($retarr))
00580                         return  $false;
00581                 else
00582                         return $retarr; 
00583                 
00584         }
00585         
00586         function Param($name)
00587         {
00588                 $this->_pnum += 1;
00589                 return '$'.$this->_pnum;
00590         }
00591         
00592           function MetaIndexes ($table, $primary = FALSE, $owner = false)
00593       {
00594          global $ADODB_FETCH_MODE;
00595                 
00596                                 $schema = false;
00597                                 $this->_findschema($table,$schema);
00598 
00599                                 if ($schema) { // requires pgsql 7.3+ - pg_namespace used.
00600                                         $sql = '
00601 SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" 
00602 FROM pg_catalog.pg_class c 
00603 JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid 
00604 JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid
00605         ,pg_namespace n 
00606 WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\')) and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\'';
00607                                 } else {
00608                         $sql = '
00609 SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns"
00610 FROM pg_catalog.pg_class c
00611 JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid
00612 JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid
00613 WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))';
00614                         }
00615                                             
00616                 if ($primary == FALSE) {
00617                         $sql .= ' AND i.indisprimary=false;';
00618                 }
00619                 
00620                 $save = $ADODB_FETCH_MODE;
00621                 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
00622                 if ($this->fetchMode !== FALSE) {
00623                         $savem = $this->SetFetchMode(FALSE);
00624                 }
00625                 
00626                 $rs = $this->Execute(sprintf($sql,$table,$table,$schema));
00627                 if (isset($savem)) {
00628                         $this->SetFetchMode($savem);
00629                 }
00630                 $ADODB_FETCH_MODE = $save;
00631 
00632                 if (!is_object($rs)) {
00633                         $false = false;
00634                                         return $false;
00635                 }
00636                                 
00637                 $col_names = $this->MetaColumnNames($table,true,true); 
00638                                 //3rd param is use attnum, 
00639                                 // see http://sourceforge.net/tracker/index.php?func=detail&aid=1451245&group_id=42718&atid=433976
00640                 $indexes = array();
00641                 while ($row = $rs->FetchRow()) {
00642                         $columns = array();
00643                         foreach (explode(' ', $row[2]) as $col) {
00644                                 $columns[] = $col_names[$col];
00645                         }
00646                         
00647                         $indexes[$row[0]] = array(
00648                                 'unique' => ($row[1] == 't'),
00649                                 'columns' => $columns
00650                         );
00651                 }
00652                 return $indexes;
00653         }
00654 
00655         // returns true or false
00656         //
00657         // examples:
00658         //      $db->Connect("host=host1 user=user1 password=secret port=4341");
00659         //      $db->Connect('host1','user1','secret');
00660         function _connect($str,$user='',$pwd='',$db='',$ctype=0)
00661         {
00662                 
00663                 if (!function_exists('pg_connect')) return null;
00664                 
00665                 $this->_errorMsg = false;
00666                 
00667                 if ($user || $pwd || $db) {
00668                         $user = adodb_addslashes($user);
00669                         $pwd = adodb_addslashes($pwd);
00670                         if (strlen($db) == 0) $db = 'template1';
00671                         $db = adodb_addslashes($db);
00672                         if ($str)  {
00673                                 $host = explode(":", $str);
00674                                 if ($host[0]) $str = "host=".adodb_addslashes($host[0]);
00675                                 else $str = '';
00676                                 if (isset($host[1])) $str .= " port=$host[1]";
00677                                 else if (!empty($this->port)) $str .= " port=".$this->port;
00678                         }
00679                                 if ($user) $str .= " user=".$user;
00680                                 if ($pwd)  $str .= " password=".$pwd;
00681                                 if ($db)   $str .= " dbname=".$db;
00682                 }
00683 
00684                 //if ($user) $linea = "user=$user host=$linea password=$pwd dbname=$db port=5432";
00685                 
00686                 if ($ctype === 1) { // persistent
00687                         $this->_connectionID = pg_pconnect($str);
00688                 } else {
00689                         if ($ctype === -1) { // nconnect, we trick pgsql ext by changing the connection str
00690                         static $ncnt;
00691                         
00692                                 if (empty($ncnt)) $ncnt = 1;
00693                                 else $ncnt += 1;
00694                                 
00695                                 $str .= str_repeat(' ',$ncnt);
00696                         }
00697                         $this->_connectionID = pg_connect($str);
00698                 }
00699                 if ($this->_connectionID === false) return false;
00700                 $this->Execute("set datestyle='ISO'");
00701                 
00702                 $info = $this->ServerInfo();
00703                 $this->pgVersion = (float) substr($info['version'],0,3);
00704                 if ($this->pgVersion >= 7.1) { // good till version 999
00705                         $this->_nestedSQL = true;
00706                 }
00707                 return true;
00708         }
00709         
00710         function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
00711         {
00712                 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName,-1);
00713         }
00714          
00715         // returns true or false
00716         //
00717         // examples:
00718         //      $db->PConnect("host=host1 user=user1 password=secret port=4341");
00719         //      $db->PConnect('host1','user1','secret');
00720         function _pconnect($str,$user='',$pwd='',$db='')
00721         {
00722                 return $this->_connect($str,$user,$pwd,$db,1);
00723         }
00724         
00725 
00726         // returns queryID or false
00727         function _query($sql,$inputarr=false)
00728         {
00729                 $this->_pnum = 0;
00730                 $this->_errorMsg = false;
00731                 if ($inputarr) {
00732                 /*
00733                         It appears that PREPARE/EXECUTE is slower for many queries.
00734                         
00735                         For query executed 1000 times:
00736                         "select id,firstname,lastname from adoxyz 
00737                                 where firstname not like ? and lastname not like ? and id = ?"
00738                                 
00739                         with plan = 1.51861286163 secs
00740                         no plan =   1.26903700829 secs
00741 
00742                         
00743 
00744                 */
00745                         $plan = 'P'.md5($sql);
00746                                 
00747                         $execp = '';
00748                         foreach($inputarr as $v) {
00749                                 if ($execp) $execp .= ',';
00750                                 if (is_string($v)) {
00751                                         if (strncmp($v,"'",1) !== 0) $execp .= $this->qstr($v);
00752                                 } else {
00753                                         $execp .= $v;
00754                                 }
00755                         }
00756                         
00757                         if ($execp) $exsql = "EXECUTE $plan ($execp)";
00758                         else $exsql = "EXECUTE $plan";
00759                         
00760                         
00761                         $rez = @pg_exec($this->_connectionID,$exsql);
00762                         if (!$rez) {
00763                         # Perhaps plan does not exist? Prepare/compile plan.
00764                                 $params = '';
00765                                 foreach($inputarr as $v) {
00766                                         if ($params) $params .= ',';
00767                                         if (is_string($v)) {
00768                                                 $params .= 'VARCHAR';
00769                                         } else if (is_integer($v)) {
00770                                                 $params .= 'INTEGER';
00771                                         } else {
00772                                                 $params .= "REAL";
00773                                         }
00774                                 }
00775                                 $sqlarr = explode('?',$sql);
00776                                 //print_r($sqlarr);
00777                                 $sql = '';
00778                                 $i = 1;
00779                                 foreach($sqlarr as $v) {
00780                                         $sql .= $v.' $'.$i;
00781                                         $i++;
00782                                 }
00783                                 $s = "PREPARE $plan ($params) AS ".substr($sql,0,strlen($sql)-2);               
00784                                 //adodb_pr($s);
00785                                 $rez = pg_exec($this->_connectionID,$s);
00786                                 //echo $this->ErrorMsg();
00787                         }
00788                         if ($rez)
00789                                 $rez = pg_exec($this->_connectionID,$exsql);
00790                 } else {
00791                         //adodb_backtrace();
00792                         $rez = pg_exec($this->_connectionID,$sql);
00793                 }
00794                 // check if no data returned, then no need to create real recordset
00795                 if ($rez && pg_numfields($rez) <= 0) {
00796                         if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') {
00797                                 pg_freeresult($this->_resultid);
00798                         }
00799                         $this->_resultid = $rez;
00800                         return true;
00801                 }
00802                 
00803                 return $rez;
00804         }
00805         
00806         function _errconnect()
00807         {
00808                 if (defined('DB_ERROR_CONNECT_FAILED')) return DB_ERROR_CONNECT_FAILED;
00809                 else return 'Database connection failed';
00810         }
00811 
00812         /*      Returns: the last error message from previous database operation        */      
00813         function ErrorMsg() 
00814         {
00815                 if ($this->_errorMsg !== false) return $this->_errorMsg;
00816                 if (ADODB_PHPVER >= 0x4300) {
00817                         if (!empty($this->_resultid)) {
00818                                 $this->_errorMsg = @pg_result_error($this->_resultid);
00819                                 if ($this->_errorMsg) return $this->_errorMsg;
00820                         }
00821                         
00822                         if (!empty($this->_connectionID)) {
00823                                 $this->_errorMsg = @pg_last_error($this->_connectionID);
00824                         } else $this->_errorMsg = $this->_errconnect();
00825                 } else {
00826                         if (empty($this->_connectionID)) $this->_errconnect();
00827                         else $this->_errorMsg = @pg_errormessage($this->_connectionID);
00828                 }
00829                 return $this->_errorMsg;
00830         }
00831         
00832         function ErrorNo()
00833         {
00834                 $e = $this->ErrorMsg();
00835                 if (strlen($e)) {
00836                         return ADOConnection::MetaError($e);
00837                  }
00838                  return 0;
00839         }
00840 
00841         // returns true or false
00842         function _close()
00843         {
00844                 if ($this->transCnt) $this->RollbackTrans();
00845                 if ($this->_resultid) {
00846                         @pg_freeresult($this->_resultid);
00847                         $this->_resultid = false;
00848                 }
00849                 @pg_close($this->_connectionID);
00850                 $this->_connectionID = false;
00851                 return true;
00852         }
00853         
00854         
00855         /*
00856         * Maximum size of C field
00857         */
00858         function CharMax()
00859         {
00860                 return 1000000000;  // should be 1 Gb?
00861         }
00862         
00863         /*
00864         * Maximum size of X field
00865         */
00866         function TextMax()
00867         {
00868                 return 1000000000; // should be 1 Gb?
00869         }
00870         
00871                 
00872 }
00873         
00874 /*--------------------------------------------------------------------------------------
00875          Class Name: Recordset
00876 --------------------------------------------------------------------------------------*/
00877 
00878 class ADORecordSet_postgres64 extends ADORecordSet{
00879         var $_blobArr;
00880         var $databaseType = "postgres64";
00881         var $canSeek = true;
00882         function ADORecordSet_postgres64($queryID,$mode=false) 
00883         {
00884                 if ($mode === false) { 
00885                         global $ADODB_FETCH_MODE;
00886                         $mode = $ADODB_FETCH_MODE;
00887                 }
00888                 switch ($mode)
00889                 {
00890                 case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break;
00891                 case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break;
00892                 
00893                 case ADODB_FETCH_DEFAULT:
00894                 case ADODB_FETCH_BOTH:
00895                 default: $this->fetchMode = PGSQL_BOTH; break;
00896                 }
00897                 $this->adodbFetchMode = $mode;
00898                 $this->ADORecordSet($queryID);
00899         }
00900         
00901         function GetRowAssoc($upper=true)
00902         {
00903                 if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields;
00904                 $row = ADORecordSet::GetRowAssoc($upper);
00905                 return $row;
00906         }
00907         
00908 
00909         function _initrs()
00910         {
00911         global $ADODB_COUNTRECS;
00912                 $qid = $this->_queryID;
00913                 $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($qid):-1;
00914                 $this->_numOfFields = @pg_numfields($qid);
00915                 
00916                 // cache types for blob decode check
00917                 // apparently pg_fieldtype actually performs an sql query on the database to get the type.
00918                 if (empty($this->connection->noBlobs))
00919                 for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) {  
00920                         if (pg_fieldtype($qid,$i) == 'bytea') {
00921                                 $this->_blobArr[$i] = pg_fieldname($qid,$i);
00922                         }
00923                 }
00924         }
00925 
00926                 /* Use associative array to get fields array */
00927         function Fields($colname)
00928         {
00929                 if ($this->fetchMode != PGSQL_NUM) return @$this->fields[$colname];
00930                 
00931                 if (!$this->bind) {
00932                         $this->bind = array();
00933                         for ($i=0; $i < $this->_numOfFields; $i++) {
00934                                 $o = $this->FetchField($i);
00935                                 $this->bind[strtoupper($o->name)] = $i;
00936                         }
00937                 }
00938                  return $this->fields[$this->bind[strtoupper($colname)]];
00939         }
00940 
00941         function FetchField($off = 0) 
00942         {
00943                 // offsets begin at 0
00944                 
00945                 $o= new ADOFieldObject();
00946                 $o->name = @pg_fieldname($this->_queryID,$off);
00947                 $o->type = @pg_fieldtype($this->_queryID,$off);
00948                 $o->max_length = @pg_fieldsize($this->_queryID,$off);
00949                 return $o;      
00950         }
00951 
00952         function _seek($row)
00953         {
00954                 return @pg_fetch_row($this->_queryID,$row);
00955         }
00956         
00957         function _decode($blob)
00958         {
00959                 if ($blob === NULL) return NULL;
00960 //              eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";');
00961                 return pg_unescape_bytea($blob);
00962         }
00963         
00964         function _fixblobs()
00965         {
00966                 if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) {
00967                         foreach($this->_blobArr as $k => $v) {
00968                                 $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]);
00969                         }
00970                 }
00971                 if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) {
00972                         foreach($this->_blobArr as $k => $v) {
00973                                 $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]);
00974                         }
00975                 }
00976         }
00977         
00978         // 10% speedup to move MoveNext to child class
00979         function MoveNext() 
00980         {
00981                 if (!$this->EOF) {
00982                         $this->_currentRow++;
00983                         if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
00984                                 $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
00985                                 if (is_array($this->fields) && $this->fields) {
00986                                         if (isset($this->_blobArr)) $this->_fixblobs();
00987                                         return true;
00988                                 }
00989                         }
00990                         $this->fields = false;
00991                         $this->EOF = true;
00992                 }
00993                 return false;
00994         }               
00995         
00996         function _fetch()
00997         {
00998                                 
00999                 if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)
01000                 return false;
01001 
01002                 $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
01003                 
01004                 if ($this->fields && isset($this->_blobArr)) $this->_fixblobs();
01005                         
01006                 return (is_array($this->fields));
01007         }
01008 
01009         function _close() 
01010         { 
01011                 return @pg_freeresult($this->_queryID);
01012         }
01013 
01014         function MetaType($t,$len=-1,$fieldobj=false)
01015         {
01016                 if (is_object($t)) {
01017                         $fieldobj = $t;
01018                         $t = $fieldobj->type;
01019                         $len = $fieldobj->max_length;
01020                 }
01021                 switch (strtoupper($t)) {
01022                                 case 'MONEY': // stupid, postgres expects money to be a string
01023                                 case 'INTERVAL':
01024                                 case 'CHAR':
01025                                 case 'CHARACTER':
01026                                 case 'VARCHAR':
01027                                 case 'NAME':
01028                                 case 'BPCHAR':
01029                                 case '_VARCHAR':
01030                                 case 'INET':
01031                                 case 'MACADDR':
01032                                         if ($len <= $this->blobSize) return 'C';
01033                                 
01034                                 case 'TEXT':
01035                                         return 'X';
01036                 
01037                                 case 'IMAGE': // user defined type
01038                                 case 'BLOB': // user defined type
01039                                 case 'BIT':     // This is a bit string, not a single bit, so don't return 'L'
01040                                 case 'VARBIT':
01041                                 case 'BYTEA':
01042                                         return 'B';
01043                                 
01044                                 case 'BOOL':
01045                                 case 'BOOLEAN':
01046                                         return 'L';
01047                                 
01048                                 case 'DATE':
01049                                         return 'D';
01050                                 
01051                                 
01052                                 case 'TIMESTAMP WITHOUT TIME ZONE':
01053                                 case 'TIME':
01054                                 case 'DATETIME':
01055                                 case 'TIMESTAMP':
01056                                 case 'TIMESTAMPTZ':
01057                                         return 'T';
01058                                 
01059                                 case 'SMALLINT': 
01060                                 case 'BIGINT': 
01061                                 case 'INTEGER': 
01062                                 case 'INT8': 
01063                                 case 'INT4':
01064                                 case 'INT2':
01065                                         if (isset($fieldobj) &&
01066                                 empty($fieldobj->primary_key) && (!$this->connection->uniqueIisR || empty($fieldobj->unique))) return 'I';
01067                                 
01068                                 case 'OID':
01069                                 case 'SERIAL':
01070                                         return 'R';
01071                                 
01072                                  default:
01073                                         return 'N';
01074                         }
01075         }
01076 
01077 }
01078 ?>
 All Data Structures Namespaces Files Functions Variables Enumerations