Documentation TYPO3 par Ameos

adodb-postgres64.inc.php

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


Généré par TYPO3 Ameos avec  doxygen 1.4.6