| [ Index ] |
|
Code source de vtiger CRM 5.0.2 |
1 <?php 2 /* 3 V4.90 8 June 2006 (c) 2000-2006 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 H: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 // to really return the id, we need the table and column-name, else we can only return the oid != id 160 return empty($table) || empty($column) ? $oid : $this->GetOne("SELECT $column FROM $table WHERE oid=".(int)$oid); 161 } 162 163 // I get this error with PHP before 4.0.6 - jlim 164 // Warning: This compilation does not support pg_cmdtuples() in adodb-postgres.inc.php on line 44 165 function _affectedrows() 166 { 167 if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false; 168 return pg_cmdtuples($this->_resultid); 169 } 170 171 172 function SetTransactionMode( $transaction_mode ) 173 { 174 if (empty($transaction_mode)) { 175 $transaction_mode = 'ISOLATION LEVEL SERIALIZABLE'; 176 } 177 if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; 178 $this->_transmode = $transaction_mode; 179 return( @pg_Exec($this->_connectionID, "SET SESSION TRANSACTION ".$transaction_mode)); 180 } 181 182 function BeginTrans() 183 { 184 if ($this->transOff) return true; 185 $this->transCnt += 1; 186 if( $this->SetTransactionMode($this->_transmode)) 187 return @pg_Exec($this->_connectionID, "begin"); 188 else 189 return(0); 190 } 191 192 function RowLock($tables,$where,$flds='1 as ignore') 193 { 194 if (!$this->transCnt) $this->BeginTrans(); 195 return $this->GetOne("select $flds from $tables where $where for update"); 196 } 197 198 // returns true/false. 199 function CommitTrans($ok=true) 200 { 201 if ($this->transOff) return true; 202 if (!$ok) return $this->RollbackTrans(); 203 204 $this->transCnt -= 1; 205 return @pg_Exec($this->_connectionID, "commit"); 206 } 207 208 // returns true/false 209 function RollbackTrans() 210 { 211 if ($this->transOff) return true; 212 $this->transCnt -= 1; 213 return @pg_Exec($this->_connectionID, "rollback"); 214 } 215 216 function &MetaTables($ttype=false,$showSchema=false,$mask=false) 217 { 218 $info = $this->ServerInfo(); 219 if ($info['version'] >= 7.3) { 220 $this->metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' 221 and schemaname not in ( 'pg_catalog','information_schema') 222 union 223 select viewname,'V' from pg_views where viewname not like 'pg\_%' and schemaname not in ( 'pg_catalog','information_schema') "; 224 } 225 if ($mask) { 226 $save = $this->metaTablesSQL; 227 $mask = $this->qstr(strtolower($mask)); 228 if ($info['version']>=7.3) 229 $this->metaTablesSQL = " 230 select tablename,'T' from pg_tables where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema') 231 union 232 select viewname,'V' from pg_views where viewname like $mask and schemaname not in ( 'pg_catalog','information_schema') "; 233 else 234 $this->metaTablesSQL = " 235 select tablename,'T' from pg_tables where tablename like $mask 236 union 237 select viewname,'V' from pg_views where viewname like $mask"; 238 } 239 $ret =& ADOConnection::MetaTables($ttype,$showSchema); 240 241 if ($mask) { 242 $this->metaTablesSQL = $save; 243 } 244 return $ret; 245 } 246 247 248 // if magic quotes disabled, use pg_escape_string() 249 function qstr($s,$magic_quotes=false) 250 { 251 if (!$magic_quotes) { 252 if (ADODB_PHPVER >= 0x4200) { 253 return "'".pg_escape_string($s)."'"; 254 } 255 if ($this->replaceQuote[0] == '\\'){ 256 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\\000"),$s); 257 } 258 return "'".str_replace("'",$this->replaceQuote,$s)."'"; 259 } 260 261 // undo magic quotes for " 262 $s = str_replace('\\"','"',$s); 263 return "'$s'"; 264 } 265 266 267 268 // Format date column in sql string given an input format that understands Y M D 269 function SQLDate($fmt, $col=false) 270 { 271 if (!$col) $col = $this->sysTimeStamp; 272 $s = 'TO_CHAR('.$col.",'"; 273 274 $len = strlen($fmt); 275 for ($i=0; $i < $len; $i++) { 276 $ch = $fmt[$i]; 277 switch($ch) { 278 case 'Y': 279 case 'y': 280 $s .= 'YYYY'; 281 break; 282 case 'Q': 283 case 'q': 284 $s .= 'Q'; 285 break; 286 287 case 'M': 288 $s .= 'Mon'; 289 break; 290 291 case 'm': 292 $s .= 'MM'; 293 break; 294 case 'D': 295 case 'd': 296 $s .= 'DD'; 297 break; 298 299 case 'H': 300 $s.= 'HH24'; 301 break; 302 303 case 'h': 304 $s .= 'HH'; 305 break; 306 307 case 'i': 308 $s .= 'MI'; 309 break; 310 311 case 's': 312 $s .= 'SS'; 313 break; 314 315 case 'a': 316 case 'A': 317 $s .= 'AM'; 318 break; 319 320 case 'w': 321 $s .= 'D'; 322 break; 323 324 case 'l': 325 $s .= 'DAY'; 326 break; 327 328 case 'W': 329 $s .= 'WW'; 330 break; 331 332 default: 333 // handle escape characters... 334 if ($ch == '\\') { 335 $i++; 336 $ch = substr($fmt,$i,1); 337 } 338 if (strpos('-/.:;, ',$ch) !== false) $s .= $ch; 339 else $s .= '"'.$ch.'"'; 340 341 } 342 } 343 return $s. "')"; 344 } 345 346 347 348 /* 349 * Load a Large Object from a file 350 * - the procedure stores the object id in the table and imports the object using 351 * postgres proprietary blob handling routines 352 * 353 * contributed by Mattia Rossi mattia@technologist.com 354 * modified for safe mode by juraj chlebec 355 */ 356 function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') 357 { 358 pg_exec ($this->_connectionID, "begin"); 359 360 $fd = fopen($path,'r'); 361 $contents = fread($fd,filesize($path)); 362 fclose($fd); 363 364 $oid = pg_lo_create($this->_connectionID); 365 $handle = pg_lo_open($this->_connectionID, $oid, 'w'); 366 pg_lo_write($handle, $contents); 367 pg_lo_close($handle); 368 369 // $oid = pg_lo_import ($path); 370 pg_exec($this->_connectionID, "commit"); 371 $rs = ADOConnection::UpdateBlob($table,$column,$oid,$where,$blobtype); 372 $rez = !empty($rs); 373 return $rez; 374 } 375 376 /* 377 * Deletes/Unlinks a Blob from the database, otherwise it 378 * will be left behind 379 * 380 * Returns TRUE on success or FALSE on failure. 381 * 382 * contributed by Todd Rogers todd#windfox.net 383 */ 384 function BlobDelete( $blob ) 385 { 386 pg_exec ($this->_connectionID, "begin"); 387 $result = @pg_lo_unlink($blob); 388 pg_exec ($this->_connectionID, "commit"); 389 return( $result ); 390 } 391 392 /* 393 Hueristic - not guaranteed to work. 394 */ 395 function GuessOID($oid) 396 { 397 if (strlen($oid)>16) return false; 398 return is_numeric($oid); 399 } 400 401 /* 402 * If an OID is detected, then we use pg_lo_* to open the oid file and read the 403 * real blob from the db using the oid supplied as a parameter. If you are storing 404 * blobs using bytea, we autodetect and process it so this function is not needed. 405 * 406 * contributed by Mattia Rossi mattia@technologist.com 407 * 408 * see http://www.postgresql.org/idocs/index.php?largeobjects.html 409 * 410 * Since adodb 4.54, this returns the blob, instead of sending it to stdout. Also 411 * added maxsize parameter, which defaults to $db->maxblobsize if not defined. 412 */ 413 function BlobDecode($blob,$maxsize=false,$hastrans=true) 414 { 415 if (!$this->GuessOID($blob)) return $blob; 416 417 if ($hastrans) @pg_exec($this->_connectionID,"begin"); 418 $fd = @pg_lo_open($this->_connectionID,$blob,"r"); 419 if ($fd === false) { 420 if ($hastrans) @pg_exec($this->_connectionID,"commit"); 421 return $blob; 422 } 423 if (!$maxsize) $maxsize = $this->maxblobsize; 424 $realblob = @pg_loread($fd,$maxsize); 425 @pg_loclose($fd); 426 if ($hastrans) @pg_exec($this->_connectionID,"commit"); 427 return $realblob; 428 } 429 430 /* 431 See http://www.postgresql.org/idocs/index.php?datatype-binary.html 432 433 NOTE: SQL string literals (input strings) must be preceded with two backslashes 434 due to the fact that they must pass through two parsers in the PostgreSQL 435 backend. 436 */ 437 function BlobEncode($blob) 438 { 439 if (ADODB_PHPVER >= 0x4200) return pg_escape_bytea($blob); 440 441 /*92=backslash, 0=null, 39=single-quote*/ 442 $badch = array(chr(92),chr(0),chr(39)); # \ null ' 443 $fixch = array('\\\\134','\\\\000','\\\\047'); 444 return adodb_str_replace($badch,$fixch,$blob); 445 446 // note that there is a pg_escape_bytea function only for php 4.2.0 or later 447 } 448 449 // assumes bytea for blob, and varchar for clob 450 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') 451 { 452 453 if ($blobtype == 'CLOB') { 454 return $this->Execute("UPDATE $table SET $column=" . $this->qstr($val) . " WHERE $where"); 455 } 456 // do not use bind params which uses qstr(), as blobencode() already quotes data 457 return $this->Execute("UPDATE $table SET $column='".$this->BlobEncode($val)."'::bytea WHERE $where"); 458 } 459 460 function OffsetDate($dayFraction,$date=false) 461 { 462 if (!$date) $date = $this->sysDate; 463 else if (strncmp($date,"'",1) == 0) { 464 $len = strlen($date); 465 if (10 <= $len && $len <= 12) $date = 'date '.$date; 466 else $date = 'timestamp '.$date; 467 } 468 return "($date+interval'$dayFraction days')"; 469 } 470 471 472 // for schema support, pass in the $table param "$schema.$tabname". 473 // converts field names to lowercase, $upper is ignored 474 // see http://phplens.com/lens/lensforum/msgs.php?id=14018 for more info 475 function &MetaColumns($table,$normalize=true) 476 { 477 global $ADODB_FETCH_MODE; 478 479 $schema = false; 480 $false = false; 481 $this->_findschema($table,$schema); 482 483 if ($normalize) $table = strtolower($table); 484 485 $save = $ADODB_FETCH_MODE; 486 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 487 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); 488 489 if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema)); 490 else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table)); 491 if (isset($savem)) $this->SetFetchMode($savem); 492 $ADODB_FETCH_MODE = $save; 493 494 if ($rs === false) { 495 return $false; 496 } 497 if (!empty($this->metaKeySQL)) { 498 // If we want the primary keys, we have to issue a separate query 499 // Of course, a modified version of the metaColumnsSQL query using a 500 // LEFT JOIN would have been much more elegant, but postgres does 501 // not support OUTER JOINS. So here is the clumsy way. 502 503 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; 504 505 $rskey = $this->Execute(sprintf($this->metaKeySQL,($table))); 506 // fetch all result in once for performance. 507 $keys =& $rskey->GetArray(); 508 if (isset($savem)) $this->SetFetchMode($savem); 509 $ADODB_FETCH_MODE = $save; 510 511 $rskey->Close(); 512 unset($rskey); 513 } 514 515 $rsdefa = array(); 516 if (!empty($this->metaDefaultsSQL)) { 517 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; 518 $sql = sprintf($this->metaDefaultsSQL, ($table)); 519 $rsdef = $this->Execute($sql); 520 if (isset($savem)) $this->SetFetchMode($savem); 521 $ADODB_FETCH_MODE = $save; 522 523 if ($rsdef) { 524 while (!$rsdef->EOF) { 525 $num = $rsdef->fields['num']; 526 $s = $rsdef->fields['def']; 527 if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */ 528 $s = substr($s, 1); 529 $s = substr($s, 0, strlen($s) - 1); 530 } 531 532 $rsdefa[$num] = $s; 533 $rsdef->MoveNext(); 534 } 535 } else { 536 ADOConnection::outp( "==> SQL => " . $sql); 537 } 538 unset($rsdef); 539 } 540 541 $retarr = array(); 542 while (!$rs->EOF) { 543 $fld = new ADOFieldObject(); 544 $fld->name = $rs->fields[0]; 545 $fld->type = $rs->fields[1]; 546 $fld->max_length = $rs->fields[2]; 547 $fld->attnum = $rs->fields[6]; 548 549 if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4; 550 if ($fld->max_length <= 0) $fld->max_length = -1; 551 if ($fld->type == 'numeric') { 552 $fld->scale = $fld->max_length & 0xFFFF; 553 $fld->max_length >>= 16; 554 } 555 // dannym 556 // 5 hasdefault; 6 num-of-column 557 $fld->has_default = ($rs->fields[5] == 't'); 558 if ($fld->has_default) { 559 $fld->default_value = $rsdefa[$rs->fields[6]]; 560 } 561 562 //Freek 563 $fld->not_null = $rs->fields[4] == 't'; 564 565 566 // Freek 567 if (is_array($keys)) { 568 foreach($keys as $key) { 569 if ($fld->name == $key['column_name'] AND $key['primary_key'] == 't') 570 $fld->primary_key = true; 571 if ($fld->name == $key['column_name'] AND $key['unique_key'] == 't') 572 $fld->unique = true; // What name is more compatible? 573 } 574 } 575 576 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; 577 else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld; 578 579 $rs->MoveNext(); 580 } 581 $rs->Close(); 582 if (empty($retarr)) 583 return $false; 584 else 585 return $retarr; 586 587 } 588 589 function &MetaIndexes ($table, $primary = FALSE) 590 { 591 global $ADODB_FETCH_MODE; 592 593 $schema = false; 594 $this->_findschema($table,$schema); 595 596 if ($schema) { // requires pgsql 7.3+ - pg_namespace used. 597 $sql = ' 598 SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" 599 FROM pg_catalog.pg_class c 600 JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid 601 JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid 602 ,pg_namespace n 603 WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\')) and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\''; 604 } else { 605 $sql = ' 606 SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" 607 FROM pg_catalog.pg_class c 608 JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid 609 JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid 610 WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))'; 611 } 612 613 if ($primary == FALSE) { 614 $sql .= ' AND i.indisprimary=false;'; 615 } 616 617 $save = $ADODB_FETCH_MODE; 618 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 619 if ($this->fetchMode !== FALSE) { 620 $savem = $this->SetFetchMode(FALSE); 621 } 622 623 $rs = $this->Execute(sprintf($sql,$table,$table,$schema)); 624 if (isset($savem)) { 625 $this->SetFetchMode($savem); 626 } 627 $ADODB_FETCH_MODE = $save; 628 629 if (!is_object($rs)) { 630 $false = false; 631 return $false; 632 } 633 634 $col_names = $this->MetaColumnNames($table,true,true); 635 //3rd param is use attnum, 636 // see http://sourceforge.net/tracker/index.php?func=detail&aid=1451245&group_id=42718&atid=433976 637 $indexes = array(); 638 while ($row = $rs->FetchRow()) { 639 $columns = array(); 640 foreach (explode(' ', $row[2]) as $col) { 641 $columns[] = $col_names[$col]; 642 } 643 644 $indexes[$row[0]] = array( 645 'unique' => ($row[1] == 't'), 646 'columns' => $columns 647 ); 648 } 649 return $indexes; 650 } 651 652 // returns true or false 653 // 654 // examples: 655 // $db->Connect("host=host1 user=user1 password=secret port=4341"); 656 // $db->Connect('host1','user1','secret'); 657 function _connect($str,$user='',$pwd='',$db='',$ctype=0) 658 { 659 660 if (!function_exists('pg_connect')) return null; 661 662 $this->_errorMsg = false; 663 664 if ($user || $pwd || $db) { 665 $user = adodb_addslashes($user); 666 $pwd = adodb_addslashes($pwd); 667 if (strlen($db) == 0) $db = 'template1'; 668 $db = adodb_addslashes($db); 669 if ($str) { 670 $host = split(":", $str); 671 if ($host[0]) $str = "host=".adodb_addslashes($host[0]); 672 else $str = 'host=localhost'; 673 if (isset($host[1])) $str .= " port=$host[1]"; 674 else if (!empty($this->port)) $str .= " port=".$this->port; 675 } 676 if ($user) $str .= " user=".$user; 677 if ($pwd) $str .= " password=".$pwd; 678 if ($db) $str .= " dbname=".$db; 679 } 680 681 //if ($user) $linea = "user=$user host=$linea password=$pwd dbname=$db port=5432"; 682 683 if ($ctype === 1) { // persistent 684 $this->_connectionID = pg_pconnect($str); 685 } else { 686 if ($ctype === -1) { // nconnect, we trick pgsql ext by changing the connection str 687 static $ncnt; 688 689 if (empty($ncnt)) $ncnt = 1; 690 else $ncnt += 1; 691 692 $str .= str_repeat(' ',$ncnt); 693 } 694 $this->_connectionID = pg_connect($str); 695 } 696 if ($this->_connectionID === false) return false; 697 $this->Execute("set datestyle='ISO'"); 698 return true; 699 } 700 701 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) 702 { 703 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName,-1); 704 } 705 706 // returns true or false 707 // 708 // examples: 709 // $db->PConnect("host=host1 user=user1 password=secret port=4341"); 710 // $db->PConnect('host1','user1','secret'); 711 function _pconnect($str,$user='',$pwd='',$db='') 712 { 713 return $this->_connect($str,$user,$pwd,$db,1); 714 } 715 716 717 // returns queryID or false 718 function _query($sql,$inputarr) 719 { 720 $this->_errorMsg = false; 721 if ($inputarr) { 722 /* 723 It appears that PREPARE/EXECUTE is slower for many queries. 724 725 For query executed 1000 times: 726 "select id,firstname,lastname from adoxyz 727 where firstname not like ? and lastname not like ? and id = ?" 728 729 with plan = 1.51861286163 secs 730 no plan = 1.26903700829 secs 731 732 733 734 */ 735 $plan = 'P'.md5($sql); 736 737 $execp = ''; 738 foreach($inputarr as $v) { 739 if ($execp) $execp .= ','; 740 if (is_string($v)) { 741 if (strncmp($v,"'",1) !== 0) $execp .= $this->qstr($v); 742 } else { 743 $execp .= $v; 744 } 745 } 746 747 if ($execp) $exsql = "EXECUTE $plan ($execp)"; 748 else $exsql = "EXECUTE $plan"; 749 750 751 $rez = @pg_exec($this->_connectionID,$exsql); 752 if (!$rez) { 753 # Perhaps plan does not exist? Prepare/compile plan. 754 $params = ''; 755 foreach($inputarr as $v) { 756 if ($params) $params .= ','; 757 if (is_string($v)) { 758 $params .= 'VARCHAR'; 759 } else if (is_integer($v)) { 760 $params .= 'INTEGER'; 761 } else { 762 $params .= "REAL"; 763 } 764 } 765 $sqlarr = explode('?',$sql); 766 //print_r($sqlarr); 767 $sql = ''; 768 $i = 1; 769 foreach($sqlarr as $v) { 770 $sql .= $v.' $'.$i; 771 $i++; 772 } 773 $s = "PREPARE $plan ($params) AS ".substr($sql,0,strlen($sql)-2); 774 //adodb_pr($s); 775 pg_exec($this->_connectionID,$s); 776 //echo $this->ErrorMsg(); 777 } 778 779 $rez = pg_exec($this->_connectionID,$exsql); 780 } else { 781 //adodb_backtrace(); 782 $rez = pg_exec($this->_connectionID,$sql); 783 } 784 // check if no data returned, then no need to create real recordset 785 if ($rez && pg_numfields($rez) <= 0) { 786 if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') { 787 pg_freeresult($this->_resultid); 788 } 789 $this->_resultid = $rez; 790 return true; 791 } 792 793 return $rez; 794 } 795 796 function _errconnect() 797 { 798 if (defined('DB_ERROR_CONNECT_FAILED')) return DB_ERROR_CONNECT_FAILED; 799 else return 'Database connection failed'; 800 } 801 802 /* Returns: the last error message from previous database operation */ 803 function ErrorMsg() 804 { 805 if ($this->_errorMsg !== false) return $this->_errorMsg; 806 if (ADODB_PHPVER >= 0x4300) { 807 if (!empty($this->_resultid)) { 808 $this->_errorMsg = @pg_result_error($this->_resultid); 809 if ($this->_errorMsg) return $this->_errorMsg; 810 } 811 812 if (!empty($this->_connectionID)) { 813 $this->_errorMsg = @pg_last_error($this->_connectionID); 814 } else $this->_errorMsg = $this->_errconnect(); 815 } else { 816 if (empty($this->_connectionID)) $this->_errconnect(); 817 else $this->_errorMsg = @pg_errormessage($this->_connectionID); 818 } 819 return $this->_errorMsg; 820 } 821 822 function ErrorNo() 823 { 824 $e = $this->ErrorMsg(); 825 if (strlen($e)) { 826 return ADOConnection::MetaError($e); 827 } 828 return 0; 829 } 830 831 // returns true or false 832 function _close() 833 { 834 if ($this->transCnt) $this->RollbackTrans(); 835 if ($this->_resultid) { 836 @pg_freeresult($this->_resultid); 837 $this->_resultid = false; 838 } 839 @pg_close($this->_connectionID); 840 $this->_connectionID = false; 841 return true; 842 } 843 844 845 /* 846 * Maximum size of C field 847 */ 848 function CharMax() 849 { 850 return 1000000000; // should be 1 Gb? 851 } 852 853 /* 854 * Maximum size of X field 855 */ 856 function TextMax() 857 { 858 return 1000000000; // should be 1 Gb? 859 } 860 861 862 } 863 864 /*-------------------------------------------------------------------------------------- 865 Class Name: Recordset 866 --------------------------------------------------------------------------------------*/ 867 868 class ADORecordSet_postgres64 extends ADORecordSet{ 869 var $_blobArr; 870 var $databaseType = "postgres64"; 871 var $canSeek = true; 872 function ADORecordSet_postgres64($queryID,$mode=false) 873 { 874 if ($mode === false) { 875 global $ADODB_FETCH_MODE; 876 $mode = $ADODB_FETCH_MODE; 877 } 878 switch ($mode) 879 { 880 case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break; 881 case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break; 882 883 case ADODB_FETCH_DEFAULT: 884 case ADODB_FETCH_BOTH: 885 default: $this->fetchMode = PGSQL_BOTH; break; 886 } 887 $this->adodbFetchMode = $mode; 888 $this->ADORecordSet($queryID); 889 } 890 891 function &GetRowAssoc($upper=true) 892 { 893 if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields; 894 $row =& ADORecordSet::GetRowAssoc($upper); 895 return $row; 896 } 897 898 function _initrs() 899 { 900 global $ADODB_COUNTRECS; 901 $qid = $this->_queryID; 902 $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($qid):-1; 903 $this->_numOfFields = @pg_numfields($qid); 904 905 // cache types for blob decode check 906 // apparently pg_fieldtype actually performs an sql query on the database to get the type. 907 if (empty($this->connection->noBlobs)) 908 for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { 909 if (pg_fieldtype($qid,$i) == 'bytea') { 910 $this->_blobArr[$i] = pg_fieldname($qid,$i); 911 } 912 } 913 } 914 915 /* Use associative array to get fields array */ 916 function Fields($colname) 917 { 918 if ($this->fetchMode != PGSQL_NUM) return @$this->fields[$colname]; 919 920 if (!$this->bind) { 921 $this->bind = array(); 922 for ($i=0; $i < $this->_numOfFields; $i++) { 923 $o = $this->FetchField($i); 924 $this->bind[strtoupper($o->name)] = $i; 925 } 926 } 927 return $this->fields[$this->bind[strtoupper($colname)]]; 928 } 929 930 function &FetchField($off = 0) 931 { 932 // offsets begin at 0 933 934 $o= new ADOFieldObject(); 935 $o->name = @pg_fieldname($this->_queryID,$off); 936 $o->type = @pg_fieldtype($this->_queryID,$off); 937 $o->max_length = @pg_fieldsize($this->_queryID,$off); 938 return $o; 939 } 940 941 function _seek($row) 942 { 943 return @pg_fetch_row($this->_queryID,$row); 944 } 945 946 function _decode($blob) 947 { 948 eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";'); 949 return $realblob; 950 } 951 952 function _fixblobs() 953 { 954 if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) { 955 foreach($this->_blobArr as $k => $v) { 956 $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]); 957 } 958 } 959 if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) { 960 foreach($this->_blobArr as $k => $v) { 961 $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]); 962 } 963 } 964 } 965 966 // 10% speedup to move MoveNext to child class 967 function MoveNext() 968 { 969 if (!$this->EOF) { 970 $this->_currentRow++; 971 if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) { 972 $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode); 973 if (is_array($this->fields) && $this->fields) { 974 if (isset($this->_blobArr)) $this->_fixblobs(); 975 return true; 976 } 977 } 978 $this->fields = false; 979 $this->EOF = true; 980 } 981 return false; 982 } 983 984 function _fetch() 985 { 986 987 if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0) 988 return false; 989 990 $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode); 991 992 if ($this->fields && isset($this->_blobArr)) $this->_fixblobs(); 993 994 return (is_array($this->fields)); 995 } 996 997 function _close() 998 { 999 return @pg_freeresult($this->_queryID); 1000 } 1001 1002 function MetaType($t,$len=-1,$fieldobj=false) 1003 { 1004 if (is_object($t)) { 1005 $fieldobj = $t; 1006 $t = $fieldobj->type; 1007 $len = $fieldobj->max_length; 1008 } 1009 switch (strtoupper($t)) { 1010 case 'MONEY': // stupid, postgres expects money to be a string 1011 case 'INTERVAL': 1012 case 'CHAR': 1013 case 'CHARACTER': 1014 case 'VARCHAR': 1015 case 'NAME': 1016 case 'BPCHAR': 1017 case '_VARCHAR': 1018 case 'INET': 1019 case 'MACADDR': 1020 if ($len <= $this->blobSize) return 'C'; 1021 1022 case 'TEXT': 1023 return 'X'; 1024 1025 case 'IMAGE': // user defined type 1026 case 'BLOB': // user defined type 1027 case 'BIT': // This is a bit string, not a single bit, so don't return 'L' 1028 case 'VARBIT': 1029 case 'BYTEA': 1030 return 'B'; 1031 1032 case 'BOOL': 1033 case 'BOOLEAN': 1034 return 'L'; 1035 1036 case 'DATE': 1037 return 'D'; 1038 1039 1040 case 'TIMESTAMP WITHOUT TIME ZONE': 1041 case 'TIME': 1042 case 'DATETIME': 1043 case 'TIMESTAMP': 1044 case 'TIMESTAMPTZ': 1045 return 'T'; 1046 1047 case 'SMALLINT': 1048 case 'BIGINT': 1049 case 'INTEGER': 1050 case 'INT8': 1051 case 'INT4': 1052 case 'INT2': 1053 if (isset($fieldobj) && 1054 empty($fieldobj->primary_key) && empty($fieldobj->unique)) return 'I'; 1055 1056 case 'OID': 1057 case 'SERIAL': 1058 return 'R'; 1059 1060 default: 1061 return 'N'; 1062 } 1063 } 1064 1065 } 1066 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Feb 25 10:22:19 2007 | par Balluche grâce à PHPXref 0.7 |