[ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
1 <?php 2 /* 3 V4.65 22 July 2005 (c) 2000-2005 John Lim (jlim@natsoft.com.my). All rights reserved. 4 Released under both BSD license and Lesser GPL library license. 5 Whenever there is any discrepancy between the two licenses, 6 the BSD license will take precedence. 7 Set tabs to 8. 8 9 Original version derived from Alberto Cerezal (acerezalp@dbnet.es) - DBNet Informatica & Comunicaciones. 10 08 Nov 2000 jlim - Minor corrections, removing mysql stuff 11 09 Nov 2000 jlim - added insertid support suggested by "Christopher Kings-Lynne" <chriskl@familyhealth.com.au> 12 jlim - changed concat operator to || and data types to MetaType to match documented pgsql types 13 see http://www.postgresql.org/devel-corner/docs/postgres/datatype.htm 14 22 Nov 2000 jlim - added changes to FetchField() and MetaTables() contributed by "raser" <raser@mail.zen.com.tw> 15 27 Nov 2000 jlim - added changes to _connect/_pconnect from ideas by "Lennie" <leen@wirehub.nl> 16 15 Dec 2000 jlim - added changes suggested by Additional code changes by "Eric G. Werk" egw@netguide.dk. 17 31 Jan 2002 jlim - finally installed postgresql. testing 18 01 Mar 2001 jlim - Freek Dijkstra changes, also support for text type 19 20 See http://www.varlena.com/varlena/GeneralBits/47.php 21 22 -- What indexes are on my table? 23 select * from pg_indexes where tablename = 'tablename'; 24 25 -- What triggers are on my table? 26 select c.relname as "Table", t.tgname as "Trigger Name", 27 t.tgconstrname as "Constraint Name", t.tgenabled as "Enabled", 28 t.tgisconstraint as "Is Constraint", cc.relname as "Referenced Table", 29 p.proname as "Function Name" 30 from pg_trigger t, pg_class c, pg_class cc, pg_proc p 31 where t.tgfoid = p.oid and t.tgrelid = c.oid 32 and t.tgconstrrelid = cc.oid 33 and c.relname = 'tablename'; 34 35 -- What constraints are on my table? 36 select r.relname as "Table", c.conname as "Constraint Name", 37 contype as "Constraint Type", conkey as "Key Columns", 38 confkey as "Foreign Columns", consrc as "Source" 39 from pg_class r, pg_constraint c 40 where r.oid = c.conrelid 41 and relname = 'tablename'; 42 43 */ 44 45 // security - hide paths 46 if (!defined('ADODB_DIR')) die(); 47 48 function adodb_addslashes($s) 49 { 50 $len = strlen($s); 51 if ($len == 0) return "''"; 52 if (strncmp($s,"'",1) === 0 && substr(s,$len-1) == "'") return $s; // already quoted 53 54 return "'".addslashes($s)."'"; 55 } 56 57 class ADODB_postgres64 extends ADOConnection{ 58 var $databaseType = 'postgres64'; 59 var $dataProvider = 'postgres'; 60 var $hasInsertID = true; 61 var $_resultid = false; 62 var $concat_operator='||'; 63 var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1"; 64 var $metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' 65 and tablename not in ('sql_features', 'sql_implementation_info', 'sql_languages', 66 'sql_packages', 'sql_sizing', 'sql_sizing_profiles') 67 union 68 select viewname,'V' from pg_views where viewname not like 'pg\_%'"; 69 //"select tablename from pg_tables where tablename not like 'pg_%' order by 1"; 70 var $isoDates = true; // accepts dates in ISO format 71 var $sysDate = "CURRENT_DATE"; 72 var $sysTimeStamp = "CURRENT_TIMESTAMP"; 73 var $blobEncodeType = 'C'; 74 var $metaColumnsSQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum 75 FROM pg_class c, pg_attribute a,pg_type t 76 WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) and a.attname not like '....%%' 77 AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; 78 79 // used when schema defined 80 var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum 81 FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n 82 WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) 83 and c.relnamespace=n.oid and n.nspname='%s' 84 and a.attname not like '....%%' AND a.attnum > 0 85 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; 86 87 // get primary key etc -- from Freek Dijkstra 88 var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key 89 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'"; 90 91 var $hasAffectedRows = true; 92 var $hasLimit = false; // set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10 93 // below suggested by Freek Dijkstra 94 var $true = 'TRUE'; // string that represents TRUE for a database 95 var $false = 'FALSE'; // string that represents FALSE for a database 96 var $fmtDate = "'Y-m-d'"; // used by DBDate() as the default date format used by the database 97 var $fmtTimeStamp = "'Y-m-d G:i:s'"; // used by DBTimeStamp as the default timestamp fmt. 98 var $hasMoveFirst = true; 99 var $hasGenID = true; 100 var $_genIDSQL = "SELECT NEXTVAL('%s')"; 101 var $_genSeqSQL = "CREATE SEQUENCE %s START %s"; 102 var $_dropSeqSQL = "DROP SEQUENCE %s"; 103 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"; 104 var $random = 'random()'; /// random function 105 var $autoRollback = true; // apparently pgsql does not autorollback properly before php 4.3.4 106 // http://bugs.php.net/bug.php?id=25404 107 108 var $_bindInputArray = false; // requires postgresql 7.3+ and ability to modify database 109 var $disableBlobs = false; // set to true to disable blob checking, resulting in 2-5% improvement in performance. 110 111 // The last (fmtTimeStamp is not entirely correct: 112 // PostgreSQL also has support for time zones, 113 // and writes these time in this format: "2001-03-01 18:59:26+02". 114 // There is no code for the "+02" time zone information, so I just left that out. 115 // I'm not familiar enough with both ADODB as well as Postgres 116 // to know what the concequences are. The other values are correct (wheren't in 0.94) 117 // -- Freek Dijkstra 118 119 function ADODB_postgres64() 120 { 121 // changes the metaColumnsSQL, adds columns: attnum[6] 122 } 123 124 function ServerInfo() 125 { 126 if (isset($this->version)) return $this->version; 127 128 $arr['description'] = $this->GetOne("select version()"); 129 $arr['version'] = ADOConnection::_findvers($arr['description']); 130 $this->version = $arr; 131 return $arr; 132 } 133 134 function IfNull( $field, $ifNull ) 135 { 136 return " coalesce($field, $ifNull) "; 137 } 138 139 // get the last id - never tested 140 function pg_insert_id($tablename,$fieldname) 141 { 142 $result=pg_exec($this->_connectionID, "SELECT last_value FROM $tablename}_$fieldname}_seq"); 143 if ($result) { 144 $arr = @pg_fetch_row($result,0); 145 pg_freeresult($result); 146 if (isset($arr[0])) return $arr[0]; 147 } 148 return false; 149 } 150 151 /* Warning from http://www.php.net/manual/function.pg-getlastoid.php: 152 Using a OID as a unique identifier is not generally wise. 153 Unless you are very careful, you might end up with a tuple having 154 a different OID if a database must be reloaded. */ 155 function _insertid($table,$column) 156 { 157 if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false; 158 $oid = pg_getlastoid($this->_resultid); 159 160 if ($oid === false && $table && $column) // table might not use oid's, default for 8.1+ 161 { 162 // try the standard sequence name first, due to table renames etc. this might not be the correct one 163 if (!($ret = $this->GetOne($sql='SELECT currval('.$this->qstr($table.'_'.$column.'_seq').')'))) { 164 // now we read the sequence name from the database itself, that is a lot slower! 165 $cols = $this->MetaColumns($table); 166 $fld = $cols[strtoupper($column)]; 167 if ($fld->primary_key && $fld->has_default && 168 preg_match("/nextval\('([^']+)'::text\)/",$fld->default_value,$matches)) { 169 $ret = $this->GetOne($sql='SELECT currval('.$this->qstr($matches[1]).')'); 170 } 171 } 172 return $ret; 173 } 174 // to really return the id, we need the table and column-name, else we can only return the oid != id 175 return empty($table) || empty($column) ? $oid : $this->GetOne("SELECT $column FROM $table WHERE oid=".(int)$oid); 176 } 177 178 // I get this error with PHP before 4.0.6 - jlim 179 // Warning: This compilation does not support pg_cmdtuples() in d:/inetpub/wwwroot/php/adodb/adodb-postgres.inc.php on line 44 180 function _affectedrows() 181 { 182 if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false; 183 return pg_cmdtuples($this->_resultid); 184 } 185 186 187 // returns true/false 188 function BeginTrans() 189 { 190 if ($this->transOff) return true; 191 $this->transCnt += 1; 192 return @pg_Exec($this->_connectionID, "begin"); 193 } 194 195 function RowLock($tables,$where,$flds='1 as ignore') 196 { 197 if (!$this->transCnt) $this->BeginTrans(); 198 return $this->GetOne("select $flds from $tables where $where for update"); 199 } 200 201 // returns true/false. 202 function CommitTrans($ok=true) 203 { 204 if ($this->transOff) return true; 205 if (!$ok) return $this->RollbackTrans(); 206 207 $this->transCnt -= 1; 208 return @pg_Exec($this->_connectionID, "commit"); 209 } 210 211 // returns true/false 212 function RollbackTrans() 213 { 214 if ($this->transOff) return true; 215 $this->transCnt -= 1; 216 return @pg_Exec($this->_connectionID, "rollback"); 217 } 218 219 function &MetaTables($ttype=false,$showSchema=false,$mask=false) 220 { 221 $info = $this->ServerInfo(); 222 if ($info['version'] >= 7.3) { 223 $this->metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' 224 and schemaname not in ( 'pg_catalog','information_schema') 225 union 226 select viewname,'V' from pg_views where viewname not like 'pg\_%' and schemaname not in ( 'pg_catalog','information_schema') "; 227 } 228 if ($mask) { 229 $save = $this->metaTablesSQL; 230 $mask = $this->qstr(strtolower($mask)); 231 if ($info['version']>=7.3) 232 $this->metaTablesSQL = " 233 select tablename,'T' from pg_tables where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema') 234 union 235 select viewname,'V' from pg_views where viewname like $mask and schemaname not in ( 'pg_catalog','information_schema') "; 236 else 237 $this->metaTablesSQL = " 238 select tablename,'T' from pg_tables where tablename like $mask 239 union 240 select viewname,'V' from pg_views where viewname like $mask"; 241 } 242 $ret =& ADOConnection::MetaTables($ttype,$showSchema); 243 244 if ($mask) { 245 $this->metaTablesSQL = $save; 246 } 247 return $ret; 248 } 249 250 /* 251 // if magic quotes disabled, use pg_escape_string() 252 function qstr($s,$magic_quotes=false) 253 { 254 if (!$magic_quotes) { 255 if (ADODB_PHPVER >= 0x4200) { 256 return "'".pg_escape_string($s)."'"; 257 } 258 if ($this->replaceQuote[0] == '\\'){ 259 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); 260 } 261 return "'".str_replace("'",$this->replaceQuote,$s)."'"; 262 } 263 264 // undo magic quotes for " 265 $s = str_replace('\\"','"',$s); 266 return "'$s'"; 267 } 268 */ 269 270 271 // Format date column in sql string given an input format that understands Y M D 272 function SQLDate($fmt, $col=false) 273 { 274 if (!$col) $col = $this->sysTimeStamp; 275 $s = 'TO_CHAR('.$col.",'"; 276 277 $len = strlen($fmt); 278 for ($i=0; $i < $len; $i++) { 279 $ch = $fmt[$i]; 280 switch($ch) { 281 case 'Y': 282 case 'y': 283 $s .= 'YYYY'; 284 break; 285 case 'Q': 286 case 'q': 287 $s .= 'Q'; 288 break; 289 290 case 'M': 291 $s .= 'Mon'; 292 break; 293 294 case 'm': 295 $s .= 'MM'; 296 break; 297 case 'D': 298 case 'd': 299 $s .= 'DD'; 300 break; 301 302 case 'H': 303 $s.= 'HH24'; 304 break; 305 306 case 'h': 307 $s .= 'HH'; 308 break; 309 310 case 'i': 311 $s .= 'MI'; 312 break; 313 314 case 's': 315 $s .= 'SS'; 316 break; 317 318 case 'a': 319 case 'A': 320 $s .= 'AM'; 321 break; 322 323 case 'w': 324 $s .= 'D'; 325 break; 326 327 case 'l': 328 $s .= 'DAY'; 329 break; 330 331 default: 332 // handle escape characters... 333 if ($ch == '\\') { 334 $i++; 335 $ch = substr($fmt,$i,1); 336 } 337 if (strpos('-/.:;, ',$ch) !== false) $s .= $ch; 338 else $s .= '"'.$ch.'"'; 339 340 } 341 } 342 return $s. "')"; 343 } 344 345 346 347 /* 348 * Load a Large Object from a file 349 * - the procedure stores the object id in the table and imports the object using 350 * postgres proprietary blob handling routines 351 * 352 * contributed by Mattia Rossi mattia@technologist.com 353 * modified for safe mode by juraj chlebec 354 */ 355 function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') 356 { 357 pg_exec ($this->_connectionID, "begin"); 358 359 $fd = fopen($path,'r'); 360 $contents = fread($fd,filesize($path)); 361 fclose($fd); 362 363 $oid = pg_lo_create($this->_connectionID); 364 $handle = pg_lo_open($this->_connectionID, $oid, 'w'); 365 pg_lo_write($handle, $contents); 366 pg_lo_close($handle); 367 368 // $oid = pg_lo_import ($path); 369 pg_exec($this->_connectionID, "commit"); 370 $rs = ADOConnection::UpdateBlob($table,$column,$oid,$where,$blobtype); 371 $rez = !empty($rs); 372 return $rez; 373 } 374 375 /* 376 Hueristic - not guaranteed to work. 377 */ 378 function GuessOID($oid) 379 { 380 if (strlen($oid)>16) return false; 381 return is_numeric($oid); 382 } 383 384 /* 385 * If an OID is detected, then we use pg_lo_* to open the oid file and read the 386 * real blob from the db using the oid supplied as a parameter. If you are storing 387 * blobs using bytea, we autodetect and process it so this function is not needed. 388 * 389 * contributed by Mattia Rossi mattia@technologist.com 390 * 391 * see http://www.postgresql.org/idocs/index.php?largeobjects.html 392 * 393 * Since adodb 4.54, this returns the blob, instead of sending it to stdout. Also 394 * added maxsize parameter, which defaults to $db->maxblobsize if not defined. 395 */ 396 function BlobDecode($blob,$maxsize=false,$hastrans=true) 397 { 398 if (!$this->GuessOID($blob)) return $blob; 399 400 if ($hastrans) @pg_exec($this->_connectionID,"begin"); 401 $fd = @pg_lo_open($this->_connectionID,$blob,"r"); 402 if ($fd === false) { 403 if ($hastrans) @pg_exec($this->_connectionID,"commit"); 404 return $blob; 405 } 406 if (!$maxsize) $maxsize = $this->maxblobsize; 407 $realblob = @pg_loread($fd,$maxsize); 408 @pg_loclose($fd); 409 if ($hastrans) @pg_exec($this->_connectionID,"commit"); 410 return $realblob; 411 } 412 413 /* 414 See http://www.postgresql.org/idocs/index.php?datatype-binary.html 415 416 NOTE: SQL string literals (input strings) must be preceded with two backslashes 417 due to the fact that they must pass through two parsers in the PostgreSQL 418 backend. 419 */ 420 function BlobEncode($blob) 421 { 422 if (ADODB_PHPVER >= 0x4200) return pg_escape_bytea($blob); 423 424 /*92=backslash, 0=null, 39=single-quote*/ 425 $badch = array(chr(92),chr(0),chr(39)); # \ null ' 426 $fixch = array('\\\\134','\\\\000','\\\\047'); 427 return adodb_str_replace($badch,$fixch,$blob); 428 429 // note that there is a pg_escape_bytea function only for php 4.2.0 or later 430 } 431 432 // assumes bytea for blob, and varchar for clob 433 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') 434 { 435 436 if ($blobtype == 'CLOB') { 437 return $this->Execute("UPDATE $table SET $column=" . $this->qstr($val) . " WHERE $where"); 438 } 439 // do not use bind params which uses qstr(), as blobencode() already quotes data 440 return $this->Execute("UPDATE $table SET $column='".$this->BlobEncode($val)."'::bytea WHERE $where"); 441 } 442 443 function OffsetDate($dayFraction,$date=false) 444 { 445 if (!$date) $date = $this->sysDate; 446 return "($date+interval'$dayFraction days')"; 447 } 448 449 450 // for schema support, pass in the $table param "$schema.$tabname". 451 // converts field names to lowercase, $upper is ignored 452 function &MetaColumns($table,$normalize=true) 453 { 454 global $ADODB_FETCH_MODE; 455 456 $schema = false; 457 $false = false; 458 $this->_findschema($table,$schema); 459 460 if ($normalize) $table = strtolower($table); 461 462 $save = $ADODB_FETCH_MODE; 463 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 464 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); 465 466 if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema)); 467 else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table)); 468 if (isset($savem)) $this->SetFetchMode($savem); 469 $ADODB_FETCH_MODE = $save; 470 471 if ($rs === false) { 472 return $false; 473 } 474 if (!empty($this->metaKeySQL)) { 475 // If we want the primary keys, we have to issue a separate query 476 // Of course, a modified version of the metaColumnsSQL query using a 477 // LEFT JOIN would have been much more elegant, but postgres does 478 // not support OUTER JOINS. So here is the clumsy way. 479 480 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; 481 482 $rskey = $this->Execute(sprintf($this->metaKeySQL,($table))); 483 // fetch all result in once for performance. 484 $keys =& $rskey->GetArray(); 485 if (isset($savem)) $this->SetFetchMode($savem); 486 $ADODB_FETCH_MODE = $save; 487 488 $rskey->Close(); 489 unset($rskey); 490 } 491 492 $rsdefa = array(); 493 if (!empty($this->metaDefaultsSQL)) { 494 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; 495 $sql = sprintf($this->metaDefaultsSQL, ($table)); 496 $rsdef = $this->Execute($sql); 497 if (isset($savem)) $this->SetFetchMode($savem); 498 $ADODB_FETCH_MODE = $save; 499 500 if ($rsdef) { 501 while (!$rsdef->EOF) { 502 $num = $rsdef->fields['num']; 503 $s = $rsdef->fields['def']; 504 if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */ 505 $s = substr($s, 1); 506 $s = substr($s, 0, strlen($s) - 1); 507 } 508 509 $rsdefa[$num] = $s; 510 $rsdef->MoveNext(); 511 } 512 } else { 513 ADOConnection::outp( "==> SQL => " . $sql); 514 } 515 unset($rsdef); 516 } 517 518 $retarr = array(); 519 while (!$rs->EOF) { 520 $fld = new ADOFieldObject(); 521 $fld->name = $rs->fields[0]; 522 $fld->type = $rs->fields[1]; 523 $fld->max_length = $rs->fields[2]; 524 if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4; 525 if ($fld->max_length <= 0) $fld->max_length = -1; 526 if ($fld->type == 'numeric') { 527 $fld->scale = $fld->max_length & 0xFFFF; 528 $fld->max_length >>= 16; 529 } 530 // dannym 531 // 5 hasdefault; 6 num-of-column 532 $fld->has_default = ($rs->fields[5] == 't'); 533 if ($fld->has_default) { 534 $fld->default_value = $rsdefa[$rs->fields[6]]; 535 } 536 537 //Freek 538 if ($rs->fields[4] == 't') { 539 $fld->not_null = true; 540 } 541 542 // Freek 543 if (is_array($keys)) { 544 foreach($keys as $key) { 545 if ($fld->name == $key['column_name'] AND $key['primary_key'] == 't') 546 $fld->primary_key = true; 547 if ($fld->name == $key['column_name'] AND $key['unique_key'] == 't') 548 $fld->unique = true; // What name is more compatible? 549 } 550 } 551 552 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; 553 else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld; 554 555 $rs->MoveNext(); 556 } 557 $rs->Close(); 558 if (empty($retarr)) 559 return $false; 560 else 561 return $retarr; 562 563 } 564 565 function &MetaIndexes ($table, $primary = FALSE) 566 { 567 global $ADODB_FETCH_MODE; 568 569 $schema = false; 570 $this->_findschema($table,$schema); 571 572 if ($schema) { // requires pgsql 7.3+ - pg_namespace used. 573 $sql = ' 574 SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" 575 FROM pg_catalog.pg_class c 576 JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid 577 JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid 578 ,pg_namespace n 579 WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\')) and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\' AND i.indisprimary=false'; 580 } else { 581 $sql = ' 582 SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" 583 FROM pg_catalog.pg_class c 584 JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid 585 JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid 586 WHERE c2.relname=\'%s\' or c2.relname=lower(\'%s\')'; 587 } 588 589 if ($primary == FALSE) { 590 $sql .= ' AND i.indisprimary=false;'; 591 } 592 593 $save = $ADODB_FETCH_MODE; 594 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 595 if ($this->fetchMode !== FALSE) { 596 $savem = $this->SetFetchMode(FALSE); 597 } 598 599 $rs = $this->Execute(sprintf($sql,$table,$table,$schema)); 600 if (isset($savem)) { 601 $this->SetFetchMode($savem); 602 } 603 $ADODB_FETCH_MODE = $save; 604 605 if (!is_object($rs)) { 606 $false = false; 607 return $false; 608 } 609 610 $col_names = $this->MetaColumnNames($table,true); 611 $indexes = array(); 612 while ($row = $rs->FetchRow()) { 613 $columns = array(); 614 foreach (explode(' ', $row[2]) as $col) { 615 $columns[] = $col_names[$col - 1]; 616 } 617 618 $indexes[$row[0]] = array( 619 'unique' => ($row[1] == 't'), 620 'columns' => $columns 621 ); 622 } 623 return $indexes; 624 } 625 626 // returns true or false 627 // 628 // examples: 629 // $db->Connect("host=host1 user=user1 password=secret port=4341"); 630 // $db->Connect('host1','user1','secret'); 631 function _connect($str,$user='',$pwd='',$db='',$ctype=0) 632 { 633 634 if (!function_exists('pg_pconnect')) return null; 635 636 $this->_errorMsg = false; 637 638 if ($user || $pwd || $db) { 639 $user = adodb_addslashes($user); 640 $pwd = adodb_addslashes($pwd); 641 if (strlen($db) == 0) $db = 'template1'; 642 $db = adodb_addslashes($db); 643 if ($str) { 644 $host = split(":", $str); 645 if ($host[0]) $str = "host=".adodb_addslashes($host[0]); 646 else $str = 'host=localhost'; 647 if (isset($host[1])) $str .= " port=$host[1]"; 648 else if (!empty($this->port)) $str .= " port=".$this->port; 649 } 650 if ($user) $str .= " user=".$user; 651 if ($pwd) $str .= " password=".$pwd; 652 if ($db) $str .= " dbname=".$db; 653 } 654 655 //if ($user) $linea = "user=$user host=$linea password=$pwd dbname=$db port=5432"; 656 657 if ($ctype === 1) { // persistent 658 $this->_connectionID = pg_pconnect($str); 659 } else { 660 if ($ctype === -1) { // nconnect, we trick pgsql ext by changing the connection str 661 static $ncnt; 662 663 if (empty($ncnt)) $ncnt = 1; 664 else $ncnt += 1; 665 666 $str .= str_repeat(' ',$ncnt); 667 } 668 $this->_connectionID = pg_connect($str); 669 } 670 if ($this->_connectionID === false) return false; 671 $this->Execute("set datestyle='ISO'"); 672 return true; 673 } 674 675 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) 676 { 677 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName,-1); 678 } 679 680 // returns true or false 681 // 682 // examples: 683 // $db->PConnect("host=host1 user=user1 password=secret port=4341"); 684 // $db->PConnect('host1','user1','secret'); 685 function _pconnect($str,$user='',$pwd='',$db='') 686 { 687 return $this->_connect($str,$user,$pwd,$db,1); 688 } 689 690 691 // returns queryID or false 692 function _query($sql,$inputarr) 693 { 694 695 if ($inputarr) { 696 /* 697 It appears that PREPARE/EXECUTE is slower for many queries. 698 699 For query executed 1000 times: 700 "select id,firstname,lastname from adoxyz 701 where firstname not like ? and lastname not like ? and id = ?" 702 703 with plan = 1.51861286163 secs 704 no plan = 1.26903700829 secs 705 706 707 708 */ 709 $plan = 'P'.md5($sql); 710 711 $execp = ''; 712 foreach($inputarr as $v) { 713 if ($execp) $execp .= ','; 714 if (is_string($v)) { 715 if (strncmp($v,"'",1) !== 0) $execp .= $this->qstr($v); 716 } else { 717 $execp .= $v; 718 } 719 } 720 721 if ($execp) $exsql = "EXECUTE $plan ($execp)"; 722 else $exsql = "EXECUTE $plan"; 723 724 $rez = @pg_exec($this->_connectionID,$exsql); 725 if (!$rez) { 726 # Perhaps plan does not exist? Prepare/compile plan. 727 $params = ''; 728 foreach($inputarr as $v) { 729 if ($params) $params .= ','; 730 if (is_string($v)) { 731 $params .= 'VARCHAR'; 732 } else if (is_integer($v)) { 733 $params .= 'INTEGER'; 734 } else { 735 $params .= "REAL"; 736 } 737 } 738 $sqlarr = explode('?',$sql); 739 //print_r($sqlarr); 740 $sql = ''; 741 $i = 1; 742 foreach($sqlarr as $v) { 743 $sql .= $v.' $'.$i; 744 $i++; 745 } 746 $s = "PREPARE $plan ($params) AS ".substr($sql,0,strlen($sql)-2); 747 //adodb_pr($s); 748 pg_exec($this->_connectionID,$s); 749 echo $this->ErrorMsg(); 750 } 751 752 $rez = pg_exec($this->_connectionID,$exsql); 753 } else { 754 $this->_errorMsg = false; 755 //adodb_backtrace(); 756 $rez = pg_exec($this->_connectionID,$sql); 757 } 758 // check if no data returned, then no need to create real recordset 759 if ($rez && pg_numfields($rez) <= 0) { 760 if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') { 761 pg_freeresult($this->_resultid); 762 } 763 $this->_resultid = $rez; 764 return true; 765 } 766 767 return $rez; 768 } 769 770 771 /* Returns: the last error message from previous database operation */ 772 function ErrorMsg() 773 { 774 if ($this->_errorMsg !== false) return $this->_errorMsg; 775 if (ADODB_PHPVER >= 0x4300) { 776 if (!empty($this->_resultid)) { 777 $this->_errorMsg = @pg_result_error($this->_resultid); 778 if ($this->_errorMsg) return $this->_errorMsg; 779 } 780 781 if (!empty($this->_connectionID)) { 782 $this->_errorMsg = @pg_last_error($this->_connectionID); 783 } else $this->_errorMsg = @pg_last_error(); 784 } else { 785 if (empty($this->_connectionID)) $this->_errorMsg = @pg_errormessage(); 786 else $this->_errorMsg = @pg_errormessage($this->_connectionID); 787 } 788 return $this->_errorMsg; 789 } 790 791 function ErrorNo() 792 { 793 $e = $this->ErrorMsg(); 794 if (strlen($e)) { 795 return ADOConnection::MetaError($e); 796 } 797 return 0; 798 } 799 800 // returns true or false 801 function _close() 802 { 803 if ($this->transCnt) $this->RollbackTrans(); 804 if ($this->_resultid) { 805 @pg_freeresult($this->_resultid); 806 $this->_resultid = false; 807 } 808 @pg_close($this->_connectionID); 809 $this->_connectionID = false; 810 return true; 811 } 812 813 814 /* 815 * Maximum size of C field 816 */ 817 function CharMax() 818 { 819 return 1000000000; // should be 1 Gb? 820 } 821 822 /* 823 * Maximum size of X field 824 */ 825 function TextMax() 826 { 827 return 1000000000; // should be 1 Gb? 828 } 829 830 831 } 832 833 /*-------------------------------------------------------------------------------------- 834 Class Name: Recordset 835 --------------------------------------------------------------------------------------*/ 836 837 class ADORecordSet_postgres64 extends ADORecordSet{ 838 var $_blobArr; 839 var $databaseType = "postgres64"; 840 var $canSeek = true; 841 function ADORecordSet_postgres64($queryID,$mode=false) 842 { 843 if ($mode === false) { 844 global $ADODB_FETCH_MODE; 845 $mode = $ADODB_FETCH_MODE; 846 } 847 switch ($mode) 848 { 849 case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break; 850 case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break; 851 852 case ADODB_FETCH_DEFAULT: 853 case ADODB_FETCH_BOTH: 854 default: $this->fetchMode = PGSQL_BOTH; break; 855 } 856 $this->adodbFetchMode = $mode; 857 $this->ADORecordSet($queryID); 858 } 859 860 function &GetRowAssoc($upper=true) 861 { 862 if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields; 863 $row =& ADORecordSet::GetRowAssoc($upper); 864 return $row; 865 } 866 867 function _initrs() 868 { 869 global $ADODB_COUNTRECS; 870 $qid = $this->_queryID; 871 $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($qid):-1; 872 $this->_numOfFields = @pg_numfields($qid); 873 874 // cache types for blob decode check 875 // apparently pg_fieldtype actually performs an sql query on the database to get the type. 876 if (empty($this->connection->noBlobs)) 877 for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { 878 if (pg_fieldtype($qid,$i) == 'bytea') { 879 $this->_blobArr[$i] = pg_fieldname($qid,$i); 880 } 881 } 882 } 883 884 /* Use associative array to get fields array */ 885 function Fields($colname) 886 { 887 if ($this->fetchMode != PGSQL_NUM) return @$this->fields[$colname]; 888 889 if (!$this->bind) { 890 $this->bind = array(); 891 for ($i=0; $i < $this->_numOfFields; $i++) { 892 $o = $this->FetchField($i); 893 $this->bind[strtoupper($o->name)] = $i; 894 } 895 } 896 return $this->fields[$this->bind[strtoupper($colname)]]; 897 } 898 899 function &FetchField($off = 0) 900 { 901 // offsets begin at 0 902 903 $o= new ADOFieldObject(); 904 $o->name = @pg_fieldname($this->_queryID,$off); 905 $o->type = @pg_fieldtype($this->_queryID,$off); 906 $o->max_length = @pg_fieldsize($this->_queryID,$off); 907 return $o; 908 } 909 910 function _seek($row) 911 { 912 return @pg_fetch_row($this->_queryID,$row); 913 } 914 915 function _decode($blob) 916 { 917 eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";'); 918 return $realblob; 919 } 920 921 function _fixblobs() 922 { 923 if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) { 924 foreach($this->_blobArr as $k => $v) { 925 $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]); 926 } 927 } 928 if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) { 929 foreach($this->_blobArr as $k => $v) { 930 $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]); 931 } 932 } 933 } 934 935 // 10% speedup to move MoveNext to child class 936 function MoveNext() 937 { 938 if (!$this->EOF) { 939 $this->_currentRow++; 940 if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) { 941 $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode); 942 if (is_array($this->fields) && $this->fields) { 943 if (isset($this->_blobArr)) $this->_fixblobs(); 944 return true; 945 } 946 } 947 $this->fields = false; 948 $this->EOF = true; 949 } 950 return false; 951 } 952 953 function _fetch() 954 { 955 956 if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0) 957 return false; 958 959 $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode); 960 961 if ($this->fields && isset($this->_blobArr)) $this->_fixblobs(); 962 963 return (is_array($this->fields)); 964 } 965 966 function _close() 967 { 968 return @pg_freeresult($this->_queryID); 969 } 970 971 function MetaType($t,$len=-1,$fieldobj=false) 972 { 973 if (is_object($t)) { 974 $fieldobj = $t; 975 $t = $fieldobj->type; 976 $len = $fieldobj->max_length; 977 } 978 switch (strtoupper($t)) { 979 case 'MONEY': // stupid, postgres expects money to be a string 980 case 'INTERVAL': 981 case 'CHAR': 982 case 'CHARACTER': 983 case 'VARCHAR': 984 case 'NAME': 985 case 'BPCHAR': 986 case '_VARCHAR': 987 case 'INET': 988 if ($len <= $this->blobSize) return 'C'; 989 990 case 'TEXT': 991 return 'X'; 992 993 case 'IMAGE': // user defined type 994 case 'BLOB': // user defined type 995 case 'BIT': // This is a bit string, not a single bit, so don't return 'L' 996 case 'VARBIT': 997 case 'BYTEA': 998 return 'B'; 999 1000 case 'BOOL': 1001 case 'BOOLEAN': 1002 return 'L'; 1003 1004 case 'DATE': 1005 return 'D'; 1006 1007 case 'TIME': 1008 case 'DATETIME': 1009 case 'TIMESTAMP': 1010 case 'TIMESTAMPTZ': 1011 return 'T'; 1012 1013 case 'SMALLINT': 1014 case 'BIGINT': 1015 case 'INTEGER': 1016 case 'INT8': 1017 case 'INT4': 1018 case 'INT2': 1019 if (isset($fieldobj) && 1020 empty($fieldobj->primary_key) && empty($fieldobj->unique)) return 'I'; 1021 1022 case 'OID': 1023 case 'SERIAL': 1024 return 'R'; 1025 1026 default: 1027 return 'N'; 1028 } 1029 } 1030 1031 } 1032 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |