00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 include_once( "lib/ezutils/classes/ezdebug.php" );
00044 include_once( "lib/ezutils/classes/ezini.php" );
00045 include_once( "lib/ezdb/classes/ezdbinterface.php" );
00046
00047 class eZPostgreSQLDB extends eZDBInterface
00048 {
00049
00050
00051
00052 function eZPostgreSQLDB( $parameters )
00053 {
00054 $this->eZDBInterface( $parameters );
00055
00056 if ( !extension_loaded( 'pgsql' ) )
00057 {
00058 if ( function_exists( 'eZAppendWarningItem' ) )
00059 {
00060 eZAppendWarningItem( array( 'error' => array( 'type' => 'ezdb',
00061 'number' => EZ_DB_ERROR_MISSING_EXTENSION ),
00062 'text' => 'PostgreSQL extension was not found, the DB handler will not be initialized.' ) );
00063 $this->IsConnected = false;
00064 }
00065 eZDebug::writeWarning( 'PostgreSQL extension was not found, the DB handler will not be initialized.', 'eZPostgreSQLDB' );
00066 return;
00067 }
00068
00069 $ini =& eZINI::instance();
00070
00071 $server = $this->Server;
00072 $db = $this->DB;
00073 $user = $this->User;
00074 $password = $this->Password;
00075
00076 $connectParams = array();
00077 if ( $server !== false and $server !== null )
00078 $connectParams[] = "host='$server'";
00079 if ( $db !== false and $db !== null )
00080 $connectParams[] = "dbname='$db'";
00081 if ( $user !== false and $user !== null )
00082 $connectParams[] = "user='$user'";
00083 if ( $password !== false and $password !== null )
00084 $connectParams[] = "password='$password'";
00085 $connectString = implode( " ", $connectParams );
00086
00087 if ( $ini->variable( "DatabaseSettings", "UsePersistentConnection" ) == "enabled" && function_exists( "pg_pconnect" ))
00088 {
00089 eZDebugSetting::writeDebug( 'kernel-db-postgresql', $ini->variable( "DatabaseSettings", "UsePersistentConnection" ), "using persistent connection" );
00090 $this->DBConnection = pg_pconnect( $connectString );
00091 $maxAttempts = $this->connectRetryCount();
00092 $waitTime = $this->connectRetryWaitTime();
00093 $numAttempts = 1;
00094 while ( $this->DBConnection == false and $numAttempts <= $maxAttempts )
00095 {
00096 sleep( $waitTime );
00097 $this->DBConnection = pg_pconnect( $connectString );
00098 $numAttempts++;
00099 }
00100 if ( $this->DBConnection )
00101 $this->IsConnected = true;
00102 }
00103 else if ( function_exists( "pg_connect" ) )
00104 {
00105 eZDebugSetting::writeDebug( 'kernel-db-postgresql', "using real connection", "using real connection" );
00106 $this->DBConnection = pg_connect( $connectString );
00107 $maxAttempts = $this->connectRetryCount();
00108 $waitTime = $this->connectRetryWaitTime();
00109 $numAttempts = 1;
00110 while ( $this->DBConnection == false and $numAttempts <= $maxAttempts )
00111 {
00112 sleep( $waitTime );
00113 $this->DBConnection = pg_connect( $connectString );
00114 $numAttempts++;
00115 }
00116 if ( $this->DBConnection )
00117 $this->IsConnected = true;
00118 }
00119 else
00120 {
00121 $this->IsConnected = false;
00122 eZDebug::writeError( "PostgreSQL support not compiled into PHP, contact your system administrator", "eZPostgreSQLDB" );
00123
00124 }
00125 }
00126
00127
00128
00129
00130 function databaseName()
00131 {
00132 return 'postgresql';
00133 }
00134
00135
00136
00137
00138 function bindingType( )
00139 {
00140 return EZ_DB_BINDING_NO;
00141 }
00142
00143
00144
00145
00146 function bindVariable( &$value, $fieldDef = false )
00147 {
00148 return $value;
00149 }
00150
00151
00152
00153
00154 function query( $sql, $server = false )
00155 {
00156 if ( $this->isConnected() )
00157 {
00158 if ( $this->OutputSQL )
00159 {
00160 eZDebug::accumulatorStart( 'postgresql_query', 'postgresql_total', 'Postgresql_queries' );
00161 $this->startTimer();
00162
00163 }
00164 $result = pg_exec( $this->DBConnection, $sql );
00165 if ( $this->OutputSQL )
00166 {
00167 $this->endTimer();
00168
00169 if ($this->timeTaken() > $this->SlowSQLTimeout)
00170 {
00171 eZDebug::accumulatorStop( 'postgresql_query' );
00172 $this->reportQuery( 'eZPostgreSQLDB', $sql, false, $this->timeTaken() );
00173 }
00174 }
00175
00176 if ( !$result )
00177 {
00178 eZDebug::writeError( "Error: error executing query: $sql " . pg_errormessage ( $this->DBConnection ), "eZPostgreSQLDB" );
00179 $this->setError();
00180
00181 $this->reportError();
00182 }
00183 }
00184 else
00185 $result = false;
00186 return $result;
00187 }
00188
00189
00190
00191
00192
00193 function arrayQuery( $sql, $params = array(), $server = false )
00194 {
00195 $retArray = array();
00196 if ( $this->isConnected() )
00197 {
00198 $limit = -1;
00199 $offset = 0;
00200
00201 if ( is_array( $params ) )
00202 {
00203 $column = false;
00204 if ( isset( $params["limit"] ) and is_numeric( $params["limit"] ) )
00205 {
00206 $limit = $params["limit"];
00207 }
00208 if ( isset( $params["offset"] ) and is_numeric( $params["offset"] ) )
00209 {
00210 $offset = $params["offset"];
00211 }
00212 if ( isset( $params["column"] ) and ( is_numeric( $params["column"] ) or is_string( $params["column"] ) ) )
00213 {
00214 $column = $params["column"];
00215 }
00216 }
00217
00218 if ( $limit != -1 )
00219 {
00220 $sql .= "\nLIMIT $limit";
00221 }
00222 if ( $offset > 0 )
00223 {
00224 if ( $limit == -1 )
00225 $sql .= "\n";
00226 else
00227 $sql .= " ";
00228 $sql .= "OFFSET $offset";
00229 }
00230 $result = $this->query( $sql );
00231
00232 if ( $result == false )
00233 {
00234 return false;
00235 }
00236
00237 if ( pg_numrows( $result ) > 0 )
00238 {
00239 if ( !is_string( $column ) )
00240 {
00241 for($i = 0; $i < pg_numrows($result); $i++)
00242 {
00243 $retArray[$i + $offset] = pg_fetch_array ( $result, $i, PGSQL_ASSOC );
00244 }
00245 }
00246 else
00247 {
00248 for ($i = 0; $i < pg_numrows( $result ); $i++ )
00249 {
00250 $tmp_row = pg_fetch_array ( $result, $i, PGSQL_ASSOC );
00251 $retArray[$i + $offset] =& $tmp_row[$column];
00252 }
00253 }
00254 }
00255 pg_freeresult( $result );
00256 }
00257 return $retArray;
00258 }
00259
00260
00261
00262
00263 function subString( $string, $from, $len = null )
00264 {
00265 if ( $len == null )
00266 {
00267 return " substring( $string from $from ) ";
00268 }
00269 else
00270 {
00271 return " substring( $string from $from for $len ) ";
00272 }
00273
00274 }
00275
00276 function concatString( $strings = array() )
00277 {
00278 $str = implode( " || " , $strings );
00279 return " $str ";
00280 }
00281
00282 function md5( $str )
00283 {
00284 return " encode(digest( $str, 'md5' ), 'hex' ) ";
00285 }
00286
00287
00288
00289
00290 function supportedRelationTypeMask()
00291 {
00292 return ( EZ_DB_RELATION_TABLE_BIT |
00293 EZ_DB_RELATION_SEQUENCE_BIT |
00294 EZ_DB_RELATION_TRIGGER_BIT |
00295 EZ_DB_RELATION_VIEW_BIT |
00296 EZ_DB_RELATION_INDEX_BIT );
00297 }
00298
00299
00300
00301
00302 function supportedRelationTypes()
00303 {
00304 return array( EZ_DB_RELATION_TABLE,
00305 EZ_DB_RELATION_SEQUENCE,
00306 EZ_DB_RELATION_TRIGGER,
00307 EZ_DB_RELATION_VIEW,
00308 EZ_DB_RELATION_INDEX );
00309 }
00310
00311
00312
00313
00314 function relationKind( $relationType )
00315 {
00316 $kind = array( EZ_DB_RELATION_TABLE => 'r',
00317 EZ_DB_RELATION_SEQUENCE => 'S',
00318 EZ_DB_RELATION_TRIGGER => 't',
00319 EZ_DB_RELATION_VIEW => 'v',
00320 EZ_DB_RELATION_INDEX => 'i' );
00321 if ( !isset( $kind[$relationType] ) )
00322 return false;
00323 return $kind[$relationType];
00324 }
00325
00326
00327
00328
00329 function relationCounts( $relationMask )
00330 {
00331 $relationTypes = $this->supportedRelationTypes();
00332 $relationKinds = array();
00333 foreach ( $relationTypes as $relationType )
00334 {
00335 $relationBit = ( 1 << $relationType );
00336 if ( $relationMask & $relationBit )
00337 {
00338 $relationKind = $this->relationKind( $relationType );
00339 if ( $relationKind )
00340 $relationKinds[] = $relationKind;
00341 }
00342 }
00343 if ( count( $relationKinds ) == 0 )
00344 return 0;
00345 $count = false;
00346 $relkindText = '';
00347 $i = 0;
00348 foreach ( $relationKinds as $relationKind )
00349 {
00350 if ( $i > 0 )
00351 $relkindText .= ' OR ';
00352 $relkindText .= "relkind='$relationKind'";
00353 $i++;
00354 }
00355 if ( $this->isConnected() )
00356 {
00357 $sql = "SELECT COUNT( relname ) as count FROM pg_class WHERE ( $relkindText ) AND NOT relname~'pg_.*'";
00358 $array = $this->arrayQuery( $sql, array( 'column' => 'count' ) );
00359 $count = $array[0];
00360 }
00361 return $count;
00362 }
00363
00364
00365
00366
00367 function relationCount( $relationType = EZ_DB_RELATION_TABLE )
00368 {
00369 $count = false;
00370 $relationKind = $this->relationKind( $relationType );
00371 if ( !$relationKind )
00372 {
00373 eZDebug::writeError( "Unsupported relation type '$relationType'", 'eZPostgreSQLDB::relationCount' );
00374 return false;
00375 }
00376
00377 if ( $this->isConnected() )
00378 {
00379 $sql = "SELECT COUNT( relname ) as count FROM pg_class WHERE relkind='$relationKind' AND NOT relname~'pg_.*'";
00380 $array = $this->arrayQuery( $sql, array( 'column' => 'count' ) );
00381 $count = $array[0];
00382 }
00383 return $count;
00384 }
00385
00386
00387
00388
00389 function relationList( $relationType = EZ_DB_RELATION_TABLE )
00390 {
00391 $count = false;
00392 $relationKind = $this->relationKind( $relationType );
00393 if ( !$relationKind )
00394 {
00395 eZDebug::writeError( "Unsupported relation type '$relationType'", 'eZPostgreSQLDB::relationList' );
00396 return false;
00397 }
00398
00399 $array = array();
00400 if ( $this->isConnected() )
00401 {
00402 $sql = "SELECT relname FROM pg_class WHERE relkind='$relationKind' AND NOT relname~'pg_.*'";
00403 $array = $this->arrayQuery( $sql, array( 'column' => 'relname' ) );
00404 }
00405 return $array;
00406 }
00407
00408
00409
00410
00411 function eZTableList( $server = EZ_DB_SERVER_MASTER )
00412 {
00413 $array = array();
00414 if ( $this->isConnected() )
00415 {
00416 foreach ( array( EZ_DB_RELATION_TABLE, EZ_DB_RELATION_SEQUENCE ) as $relationType )
00417 {
00418 $sql = "SELECT relname FROM pg_class WHERE relkind='" . $this->relationKind( $relationType ) . "' AND relname like 'ez%'";
00419 foreach ( $this->arrayQuery( $sql, array( 'column' => 'relname' ) ) as $result )
00420 {
00421 $array[$result] = $relationType;
00422 }
00423 }
00424 }
00425 return $array;
00426 }
00427
00428
00429
00430
00431 function relationMatchRegexp( $relationType )
00432 {
00433 return "#^(ez|tmp_notification_rule_s)#";
00434 }
00435
00436
00437
00438
00439 function removeRelation( $relationName, $relationType )
00440 {
00441 $relationTypeName = $this->relationName( $relationType );
00442 if ( !$relationTypeName )
00443 {
00444 eZDebug::writeError( "Unsupported relation type '$relationType'", 'eZPostgreSQLDB::removeRelation' );
00445 return false;
00446 }
00447
00448 if ( $this->isConnected() )
00449 {
00450 $sql = "DROP $relationTypeName $relationName";
00451 return $this->query( $sql );
00452 }
00453 return false;
00454 }
00455
00456
00457
00458
00459 function lock( $table )
00460 {
00461 $this->begin();
00462 if ( $this->isConnected() )
00463 {
00464 if ( is_array( $table ) )
00465 {
00466 $lockQuery = "LOCK TABLE";
00467 $first = true;
00468 foreach( array_keys( $table ) as $tableKey )
00469 {
00470 if ( $first == true )
00471 $first = false;
00472 else
00473 $lockQuery .= ",";
00474 $lockQuery .= " " . $table[$tableKey]['table'];
00475 }
00476 $this->query( $lockQuery );
00477 }
00478 else
00479 {
00480 $this->query( "LOCK TABLE $table" );
00481 }
00482 }
00483 }
00484
00485
00486
00487
00488 function unlock()
00489 {
00490 $this->commit();
00491 }
00492
00493
00494
00495
00496
00497 function beginQuery()
00498 {
00499 return $this->query("BEGIN WORK");
00500 }
00501
00502
00503
00504
00505
00506 function commitQuery()
00507 {
00508 return $this->query( "COMMIT WORK" );
00509 }
00510
00511
00512
00513
00514
00515 function rollbackQuery()
00516 {
00517 return $this->query( "ROLLBACK WORK" );
00518 }
00519
00520
00521
00522
00523 function lastSerialID( $table, $column = 'id' )
00524 {
00525 if ( $this->isConnected() )
00526 {
00527 $sql = "SELECT currval( '" . $table . "_s')";
00528 $result = pg_exec( $this->DBConnection, $sql );
00529 if ( !$result )
00530 {
00531 eZDebug::writeError( "Error: error executing query: $sql " . pg_errormessage( $this->DBConnection ), "eZPostgreSQLDB" );
00532 }
00533
00534 if ( $result )
00535 {
00536 $array = pg_fetch_row( $result, 0 );
00537 $id = $array[0];
00538 }
00539 }
00540 return $id;
00541 }
00542
00543
00544
00545
00546 function setError( )
00547 {
00548 if ( $this->DBConnection )
00549 {
00550
00551 $this->ErrorMessage = pg_errormessage ( $this->DBConnection );
00552 if ( $this->ErrorMessage != '' )
00553 {
00554 $this->ErrorNumber = 1;
00555 }
00556 else
00557 {
00558 $this->ErrorNumber = 0;
00559 }
00560
00561 }
00562 }
00563
00564
00565
00566
00567 function escapeString( $str )
00568 {
00569 $str = str_replace("\0", '', $str);
00570 $str = pg_escape_string( $str );
00571 return $str;
00572 }
00573
00574
00575
00576
00577 function close()
00578 {
00579 pg_close();
00580 }
00581
00582
00583
00584
00585 function isCharsetSupported( $charset )
00586 {
00587 return true;
00588 }
00589
00590
00591
00592
00593 function databaseServerVersion()
00594 {
00595 if ( $this->isConnected() )
00596 {
00597 $sql = "SELECT version()";
00598 $result = pg_exec( $this->DBConnection, $sql );
00599 if ( !$result )
00600 {
00601 eZDebug::writeError( "Error: error executing query: $sql " . pg_errormessage( $this->DBConnection ), "eZPostgreSQLDB" );
00602 }
00603
00604 if ( $result )
00605 {
00606 $array = pg_fetch_row( $result, 0 );
00607 $versionText = $array[0];
00608 }
00609 list( $dbType, $versionInfo ) = split( " ", $versionText );
00610 $versionArray = explode( '.', $versionInfo );
00611 return array( 'string' => $versionInfo,
00612 'values' => $versionArray );
00613 }
00614 return false;
00615 }
00616
00617
00618
00619
00620 function correctSequenceValues()
00621 {
00622 if ( $this->isConnected() )
00623 {
00624 $rows = $this->arrayQuery( "SELECT pg_class.relname AS table, pg_attribute.attname AS column
00625 FROM pg_class,pg_attribute,pg_attrdef
00626 WHERE pg_attrdef.adsrc LIKE 'nextval(%'
00627 AND pg_attrdef.adrelid=pg_attribute.attrelid
00628 AND pg_attrdef.adnum=pg_attribute.attnum
00629 AND pg_attribute.attrelid=pg_class.oid" );
00630 foreach ( $rows as $row )
00631 {
00632 $this->query( "SELECT setval('".$row['table']."_s', max(".$row['column'].")) from ".$row['table'] );
00633 }
00634 return true;
00635 }
00636 return false;
00637 }
00638
00639
00640
00641 }
00642
00643 ?>