"TYPO3 4.0.1: typo3_src-4.0.1/typo3/sysext/adodb/adodb/drivers/adodb-postgres64.inc.php Source File", "datetime" => "Sat Dec 2 19:22:26 2006", "date" => "2 Dec 2006", "doxygenversion" => "1.4.6", "projectname" => "TYPO3 4.0.1", "projectnumber" => "4.0.1" ); get_header($doxygen_vars); ?>
00001 <?php 00002 /* 00003 V4.90 8 June 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 ".$this->_transmode); 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 $schema = false; 00468 $false = false; 00469 $this->_findschema($table,$schema); 00470 00471 if ($normalize) $table = strtolower($table); 00472 00473 $save = $ADODB_FETCH_MODE; 00474 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 00475 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); 00476 00477 if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema)); 00478 else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table)); 00479 if (isset($savem)) $this->SetFetchMode($savem); 00480 $ADODB_FETCH_MODE = $save; 00481 00482 if ($rs === false) { 00483 return $false; 00484 } 00485 if (!empty($this->metaKeySQL)) { 00486 // If we want the primary keys, we have to issue a separate query 00487 // Of course, a modified version of the metaColumnsSQL query using a 00488 // LEFT JOIN would have been much more elegant, but postgres does 00489 // not support OUTER JOINS. So here is the clumsy way. 00490 00491 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; 00492 00493 $rskey = $this->Execute(sprintf($this->metaKeySQL,($table))); 00494 // fetch all result in once for performance. 00495 $keys =& $rskey->GetArray(); 00496 if (isset($savem)) $this->SetFetchMode($savem); 00497 $ADODB_FETCH_MODE = $save; 00498 00499 $rskey->Close(); 00500 unset($rskey); 00501 } 00502 00503 $rsdefa = array(); 00504 if (!empty($this->metaDefaultsSQL)) { 00505 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; 00506 $sql = sprintf($this->metaDefaultsSQL, ($table)); 00507 $rsdef = $this->Execute($sql); 00508 if (isset($savem)) $this->SetFetchMode($savem); 00509 $ADODB_FETCH_MODE = $save; 00510 00511 if ($rsdef) { 00512 while (!$rsdef->EOF) { 00513 $num = $rsdef->fields['num']; 00514 $s = $rsdef->fields['def']; 00515 if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */ 00516 $s = substr($s, 1); 00517 $s = substr($s, 0, strlen($s) - 1); 00518 } 00519 00520 $rsdefa[$num] = $s; 00521 $rsdef->MoveNext(); 00522 } 00523 } else { 00524 ADOConnection::outp( "==> SQL => " . $sql); 00525 } 00526 unset($rsdef); 00527 } 00528 00529 $retarr = array(); 00530 while (!$rs->EOF) { 00531 $fld = new ADOFieldObject(); 00532 $fld->name = $rs->fields[0]; 00533 $fld->type = $rs->fields[1]; 00534 $fld->max_length = $rs->fields[2]; 00535 $fld->attnum = $rs->fields[6]; 00536 00537 if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4; 00538 if ($fld->max_length <= 0) $fld->max_length = -1; 00539 if ($fld->type == 'numeric') { 00540 $fld->scale = $fld->max_length & 0xFFFF; 00541 $fld->max_length >>= 16; 00542 } 00543 // dannym 00544 // 5 hasdefault; 6 num-of-column 00545 $fld->has_default = ($rs->fields[5] == 't'); 00546 if ($fld->has_default) { 00547 $fld->default_value = $rsdefa[$rs->fields[6]]; 00548 } 00549 00550 //Freek 00551 $fld->not_null = $rs->fields[4] == 't'; 00552 00553 00554 // Freek 00555 if (is_array($keys)) { 00556 foreach($keys as $key) { 00557 if ($fld->name == $key['column_name'] AND $key['primary_key'] == 't') 00558 $fld->primary_key = true; 00559 if ($fld->name == $key['column_name'] AND $key['unique_key'] == 't') 00560 $fld->unique = true; // What name is more compatible? 00561 } 00562 } 00563 00564 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; 00565 else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld; 00566 00567 $rs->MoveNext(); 00568 } 00569 $rs->Close(); 00570 if (empty($retarr)) 00571 return $false; 00572 else 00573 return $retarr; 00574 00575 } 00576 00577 function &MetaIndexes ($table, $primary = FALSE) 00578 { 00579 global $ADODB_FETCH_MODE; 00580 00581 $schema = false; 00582 $this->_findschema($table,$schema); 00583 00584 if ($schema) { // requires pgsql 7.3+ - pg_namespace used. 00585 $sql = ' 00586 SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" 00587 FROM pg_catalog.pg_class c 00588 JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid 00589 JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid 00590 ,pg_namespace n 00591 WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\')) and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\''; 00592 } else { 00593 $sql = ' 00594 SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" 00595 FROM pg_catalog.pg_class c 00596 JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid 00597 JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid 00598 WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))'; 00599 } 00600 00601 if ($primary == FALSE) { 00602 $sql .= ' AND i.indisprimary=false;'; 00603 } 00604 00605 $save = $ADODB_FETCH_MODE; 00606 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 00607 if ($this->fetchMode !== FALSE) { 00608 $savem = $this->SetFetchMode(FALSE); 00609 } 00610 00611 $rs = $this->Execute(sprintf($sql,$table,$table,$schema)); 00612 if (isset($savem)) { 00613 $this->SetFetchMode($savem); 00614 } 00615 $ADODB_FETCH_MODE = $save; 00616 00617 if (!is_object($rs)) { 00618 $false = false; 00619 return $false; 00620 } 00621 00622 $col_names = $this->MetaColumnNames($table,true,true); 00623 //3rd param is use attnum, 00624 // see http://sourceforge.net/tracker/index.php?func=detail&aid=1451245&group_id=42718&atid=433976 00625 $indexes = array(); 00626 while ($row = $rs->FetchRow()) { 00627 $columns = array(); 00628 foreach (explode(' ', $row[2]) as $col) { 00629 $columns[] = $col_names[$col]; 00630 } 00631 00632 $indexes[$row[0]] = array( 00633 'unique' => ($row[1] == 't'), 00634 'columns' => $columns 00635 ); 00636 } 00637 return $indexes; 00638 } 00639 00640 // returns true or false 00641 // 00642 // examples: 00643 // $db->Connect("host=host1 user=user1 password=secret port=4341"); 00644 // $db->Connect('host1','user1','secret'); 00645 function _connect($str,$user='',$pwd='',$db='',$ctype=0) 00646 { 00647 00648 if (!function_exists('pg_connect')) return null; 00649 00650 $this->_errorMsg = false; 00651 00652 if ($user || $pwd || $db) { 00653 $user = adodb_addslashes($user); 00654 $pwd = adodb_addslashes($pwd); 00655 if (strlen($db) == 0) $db = 'template1'; 00656 $db = adodb_addslashes($db); 00657 if ($str) { 00658 $host = split(":", $str); 00659 if ($host[0]) $str = "host=".adodb_addslashes($host[0]); 00660 else $str = 'host=localhost'; 00661 if (isset($host[1])) $str .= " port=$host[1]"; 00662 else if (!empty($this->port)) $str .= " port=".$this->port; 00663 } 00664 if ($user) $str .= " user=".$user; 00665 if ($pwd) $str .= " password=".$pwd; 00666 if ($db) $str .= " dbname=".$db; 00667 } 00668 00669 //if ($user) $linea = "user=$user host=$linea password=$pwd dbname=$db port=5432"; 00670 00671 if ($ctype === 1) { // persistent 00672 $this->_connectionID = pg_pconnect($str); 00673 } else { 00674 if ($ctype === -1) { // nconnect, we trick pgsql ext by changing the connection str 00675 static $ncnt; 00676 00677 if (empty($ncnt)) $ncnt = 1; 00678 else $ncnt += 1; 00679 00680 $str .= str_repeat(' ',$ncnt); 00681 } 00682 $this->_connectionID = pg_connect($str); 00683 } 00684 if ($this->_connectionID === false) return false; 00685 $this->Execute("set datestyle='ISO'"); 00686 return true; 00687 } 00688 00689 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) 00690 { 00691 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName,-1); 00692 } 00693 00694 // returns true or false 00695 // 00696 // examples: 00697 // $db->PConnect("host=host1 user=user1 password=secret port=4341"); 00698 // $db->PConnect('host1','user1','secret'); 00699 function _pconnect($str,$user='',$pwd='',$db='') 00700 { 00701 return $this->_connect($str,$user,$pwd,$db,1); 00702 } 00703 00704 00705 // returns queryID or false 00706 function _query($sql,$inputarr) 00707 { 00708 $this->_errorMsg = false; 00709 if ($inputarr) { 00710 /* 00711 It appears that PREPARE/EXECUTE is slower for many queries. 00712 00713 For query executed 1000 times: 00714 "select id,firstname,lastname from adoxyz 00715 where firstname not like ? and lastname not like ? and id = ?" 00716 00717 with plan = 1.51861286163 secs 00718 no plan = 1.26903700829 secs 00719 00720 00721 00722 */ 00723 $plan = 'P'.md5($sql); 00724 00725 $execp = ''; 00726 foreach($inputarr as $v) { 00727 if ($execp) $execp .= ','; 00728 if (is_string($v)) { 00729 if (strncmp($v,"'",1) !== 0) $execp .= $this->qstr($v); 00730 } else { 00731 $execp .= $v; 00732 } 00733 } 00734 00735 if ($execp) $exsql = "EXECUTE $plan ($execp)"; 00736 else $exsql = "EXECUTE $plan"; 00737 00738 00739 $rez = @pg_exec($this->_connectionID,$exsql); 00740 if (!$rez) { 00741 # Perhaps plan does not exist? Prepare/compile plan. 00742 $params = ''; 00743 foreach($inputarr as $v) { 00744 if ($params) $params .= ','; 00745 if (is_string($v)) { 00746 $params .= 'VARCHAR'; 00747 } else if (is_integer($v)) { 00748 $params .= 'INTEGER'; 00749 } else { 00750 $params .= "REAL"; 00751 } 00752 } 00753 $sqlarr = explode('?',$sql); 00754 //print_r($sqlarr); 00755 $sql = ''; 00756 $i = 1; 00757 foreach($sqlarr as $v) { 00758 $sql .= $v.' $'.$i; 00759 $i++; 00760 } 00761 $s = "PREPARE $plan ($params) AS ".substr($sql,0,strlen($sql)-2); 00762 //adodb_pr($s); 00763 pg_exec($this->_connectionID,$s); 00764 //echo $this->ErrorMsg(); 00765 } 00766 00767 $rez = pg_exec($this->_connectionID,$exsql); 00768 } else { 00769 //adodb_backtrace(); 00770 $rez = pg_exec($this->_connectionID,$sql); 00771 } 00772 // check if no data returned, then no need to create real recordset 00773 if ($rez && pg_numfields($rez) <= 0) { 00774 if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') { 00775 pg_freeresult($this->_resultid); 00776 } 00777 $this->_resultid = $rez; 00778 return true; 00779 } 00780 00781 return $rez; 00782 } 00783 00784 function _errconnect() 00785 { 00786 if (defined('DB_ERROR_CONNECT_FAILED')) return DB_ERROR_CONNECT_FAILED; 00787 else return 'Database connection failed'; 00788 } 00789 00790 /* Returns: the last error message from previous database operation */ 00791 function ErrorMsg() 00792 { 00793 if ($this->_errorMsg !== false) return $this->_errorMsg; 00794 if (ADODB_PHPVER >= 0x4300) { 00795 if (!empty($this->_resultid)) { 00796 $this->_errorMsg = @pg_result_error($this->_resultid); 00797 if ($this->_errorMsg) return $this->_errorMsg; 00798 } 00799 00800 if (!empty($this->_connectionID)) { 00801 $this->_errorMsg = @pg_last_error($this->_connectionID); 00802 } else $this->_errorMsg = $this->_errconnect(); 00803 } else { 00804 if (empty($this->_connectionID)) $this->_errconnect(); 00805 else $this->_errorMsg = @pg_errormessage($this->_connectionID); 00806 } 00807 return $this->_errorMsg; 00808 } 00809 00810 function ErrorNo() 00811 { 00812 $e = $this->ErrorMsg(); 00813 if (strlen($e)) { 00814 return ADOConnection::MetaError($e); 00815 } 00816 return 0; 00817 } 00818 00819 // returns true or false 00820 function _close() 00821 { 00822 if ($this->transCnt) $this->RollbackTrans(); 00823 if ($this->_resultid) { 00824 @pg_freeresult($this->_resultid); 00825 $this->_resultid = false; 00826 } 00827 @pg_close($this->_connectionID); 00828 $this->_connectionID = false; 00829 return true; 00830 } 00831 00832 00833 /* 00834 * Maximum size of C field 00835 */ 00836 function CharMax() 00837 { 00838 return 1000000000; // should be 1 Gb? 00839 } 00840 00841 /* 00842 * Maximum size of X field 00843 */ 00844 function TextMax() 00845 { 00846 return 1000000000; // should be 1 Gb? 00847 } 00848 00849 00850 } 00851 00852 /*-------------------------------------------------------------------------------------- 00853 Class Name: Recordset 00854 --------------------------------------------------------------------------------------*/ 00855 00856 class ADORecordSet_postgres64 extends ADORecordSet{ 00857 var $_blobArr; 00858 var $databaseType = "postgres64"; 00859 var $canSeek = true; 00860 function ADORecordSet_postgres64($queryID,$mode=false) 00861 { 00862 if ($mode === false) { 00863 global $ADODB_FETCH_MODE; 00864 $mode = $ADODB_FETCH_MODE; 00865 } 00866 switch ($mode) 00867 { 00868 case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break; 00869 case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break; 00870 00871 case ADODB_FETCH_DEFAULT: 00872 case ADODB_FETCH_BOTH: 00873 default: $this->fetchMode = PGSQL_BOTH; break; 00874 } 00875 $this->adodbFetchMode = $mode; 00876 $this->ADORecordSet($queryID); 00877 } 00878 00879 function &GetRowAssoc($upper=true) 00880 { 00881 if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields; 00882 $row =& ADORecordSet::GetRowAssoc($upper); 00883 return $row; 00884 } 00885 00886 function _initrs() 00887 { 00888 global $ADODB_COUNTRECS; 00889 $qid = $this->_queryID; 00890 $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($qid):-1; 00891 $this->_numOfFields = @pg_numfields($qid); 00892 00893 // cache types for blob decode check 00894 // apparently pg_fieldtype actually performs an sql query on the database to get the type. 00895 if (empty($this->connection->noBlobs)) 00896 for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { 00897 if (pg_fieldtype($qid,$i) == 'bytea') { 00898 $this->_blobArr[$i] = pg_fieldname($qid,$i); 00899 } 00900 } 00901 } 00902 00903 /* Use associative array to get fields array */ 00904 function Fields($colname) 00905 { 00906 if ($this->fetchMode != PGSQL_NUM) return @$this->fields[$colname]; 00907 00908 if (!$this->bind) { 00909 $this->bind = array(); 00910 for ($i=0; $i < $this->_numOfFields; $i++) { 00911 $o = $this->FetchField($i); 00912 $this->bind[strtoupper($o->name)] = $i; 00913 } 00914 } 00915 return $this->fields[$this->bind[strtoupper($colname)]]; 00916 } 00917 00918 function &FetchField($off = 0) 00919 { 00920 // offsets begin at 0 00921 00922 $o= new ADOFieldObject(); 00923 $o->name = @pg_fieldname($this->_queryID,$off); 00924 $o->type = @pg_fieldtype($this->_queryID,$off); 00925 $o->max_length = @pg_fieldsize($this->_queryID,$off); 00926 return $o; 00927 } 00928 00929 function _seek($row) 00930 { 00931 return @pg_fetch_row($this->_queryID,$row); 00932 } 00933 00934 function _decode($blob) 00935 { 00936 eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";'); 00937 return $realblob; 00938 } 00939 00940 function _fixblobs() 00941 { 00942 if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) { 00943 foreach($this->_blobArr as $k => $v) { 00944 $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]); 00945 } 00946 } 00947 if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) { 00948 foreach($this->_blobArr as $k => $v) { 00949 $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]); 00950 } 00951 } 00952 } 00953 00954 // 10% speedup to move MoveNext to child class 00955 function MoveNext() 00956 { 00957 if (!$this->EOF) { 00958 $this->_currentRow++; 00959 if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) { 00960 $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode); 00961 if (is_array($this->fields) && $this->fields) { 00962 if (isset($this->_blobArr)) $this->_fixblobs(); 00963 return true; 00964 } 00965 } 00966 $this->fields = false; 00967 $this->EOF = true; 00968 } 00969 return false; 00970 } 00971 00972 function _fetch() 00973 { 00974 00975 if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0) 00976 return false; 00977 00978 $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode); 00979 00980 if ($this->fields && isset($this->_blobArr)) $this->_fixblobs(); 00981 00982 return (is_array($this->fields)); 00983 } 00984 00985 function _close() 00986 { 00987 return @pg_freeresult($this->_queryID); 00988 } 00989 00990 function MetaType($t,$len=-1,$fieldobj=false) 00991 { 00992 if (is_object($t)) { 00993 $fieldobj = $t; 00994 $t = $fieldobj->type; 00995 $len = $fieldobj->max_length; 00996 } 00997 switch (strtoupper($t)) { 00998 case 'MONEY': // stupid, postgres expects money to be a string 00999 case 'INTERVAL': 01000 case 'CHAR': 01001 case 'CHARACTER': 01002 case 'VARCHAR': 01003 case 'NAME': 01004 case 'BPCHAR': 01005 case '_VARCHAR': 01006 case 'INET': 01007 case 'MACADDR': 01008 if ($len <= $this->blobSize) return 'C'; 01009 01010 case 'TEXT': 01011 return 'X'; 01012 01013 case 'IMAGE': // user defined type 01014 case 'BLOB': // user defined type 01015 case 'BIT': // This is a bit string, not a single bit, so don't return 'L' 01016 case 'VARBIT': 01017 case 'BYTEA': 01018 return 'B'; 01019 01020 case 'BOOL': 01021 case 'BOOLEAN': 01022 return 'L'; 01023 01024 case 'DATE': 01025 return 'D'; 01026 01027 01028 case 'TIMESTAMP WITHOUT TIME ZONE': 01029 case 'TIME': 01030 case 'DATETIME': 01031 case 'TIMESTAMP': 01032 case 'TIMESTAMPTZ': 01033 return 'T'; 01034 01035 case 'SMALLINT': 01036 case 'BIGINT': 01037 case 'INTEGER': 01038 case 'INT8': 01039 case 'INT4': 01040 case 'INT2': 01041 if (isset($fieldobj) && 01042 empty($fieldobj->primary_key) && empty($fieldobj->unique)) return 'I'; 01043 01044 case 'OID': 01045 case 'SERIAL': 01046 return 'R'; 01047 01048 default: 01049 return 'N'; 01050 } 01051 } 01052 01053 } 01054 ?>