|
eZ Publish
[4.0]
|
00001 <?php 00002 // 00003 // $Id$ 00004 // 00005 // Definition of eZPostgreSQLLDB class 00006 // 00007 // Created on: <25-Feb-2002 14:08:32 bf> 00008 // 00009 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00010 // SOFTWARE NAME: eZ Publish 00011 // SOFTWARE RELEASE: 4.0.x 00012 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS 00013 // SOFTWARE LICENSE: GNU General Public License v2.0 00014 // NOTICE: > 00015 // This program is free software; you can redistribute it and/or 00016 // modify it under the terms of version 2.0 of the GNU General 00017 // Public License as published by the Free Software Foundation. 00018 // 00019 // This program is distributed in the hope that it will be useful, 00020 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00022 // GNU General Public License for more details. 00023 // 00024 // You should have received a copy of version 2.0 of the GNU General 00025 // Public License along with this program; if not, write to the Free 00026 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 00027 // MA 02110-1301, USA. 00028 // 00029 // 00030 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00031 // 00032 00033 /*! 00034 \class eZPostgreSQLDB ezpostgresqldb.php 00035 \ingroup eZDB 00036 \brief The eZPostgreSQLDB class provides PostgreSQL database functions. 00037 00038 eZPostgreSQLDB implementes PostgreSQLDB specific database code. 00039 00040 \sa eZDB 00041 */ 00042 00043 require_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 Creates a new eZPostgreSQLDB object and connects to the database. 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' => eZDBInterface::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 $port = $this->Port; 00073 $db = $this->DB; 00074 $user = $this->User; 00075 $password = $this->Password; 00076 00077 $connectParams = array(); 00078 if ( $server !== false and $server !== null ) 00079 $connectParams[] = "host='$server'"; 00080 if ( $db !== false and $db !== null ) 00081 $connectParams[] = "dbname='$db'"; 00082 if ( $user !== false and $user !== null ) 00083 $connectParams[] = "user='$user'"; 00084 if ( $password !== false and $password !== null ) 00085 $connectParams[] = "password='$password'"; 00086 if ( $port ) 00087 $connectParams[] = "port='$port'"; 00088 00089 $connectString = implode( " ", $connectParams ); 00090 00091 if ( $ini->variable( "DatabaseSettings", "UsePersistentConnection" ) == "enabled" && function_exists( "pg_pconnect" )) 00092 { 00093 eZDebugSetting::writeDebug( 'kernel-db-postgresql', $ini->variable( "DatabaseSettings", "UsePersistentConnection" ), "using persistent connection" ); 00094 $this->DBConnection = pg_pconnect( $connectString ); 00095 $maxAttempts = $this->connectRetryCount(); 00096 $waitTime = $this->connectRetryWaitTime(); 00097 $numAttempts = 1; 00098 while ( $this->DBConnection == false and $numAttempts <= $maxAttempts ) 00099 { 00100 sleep( $waitTime ); 00101 $this->DBConnection = pg_pconnect( $connectString ); 00102 $numAttempts++; 00103 } 00104 if ( $this->DBConnection ) 00105 $this->IsConnected = true; 00106 // add error checking 00107 // eZDebug::writeError( "Error: could not connect to database." . pg_last_error( $this->DBConnection ), "eZPostgreSQLDB" ); 00108 } 00109 else if ( function_exists( "pg_connect" ) ) 00110 { 00111 eZDebugSetting::writeDebug( 'kernel-db-postgresql', "using real connection", "using real connection" ); 00112 $this->DBConnection = pg_connect( $connectString ); 00113 $maxAttempts = $this->connectRetryCount(); 00114 $waitTime = $this->connectRetryWaitTime(); 00115 $numAttempts = 1; 00116 while ( $this->DBConnection == false and $numAttempts <= $maxAttempts ) 00117 { 00118 sleep( $waitTime ); 00119 $this->DBConnection = pg_connect( $connectString ); 00120 $numAttempts++; 00121 } 00122 if ( $this->DBConnection ) 00123 $this->IsConnected = true; 00124 } 00125 else 00126 { 00127 $this->IsConnected = false; 00128 eZDebug::writeError( "PostgreSQL support not compiled into PHP, contact your system administrator", "eZPostgreSQLDB" ); 00129 00130 } 00131 } 00132 00133 /*! 00134 \reimp 00135 */ 00136 function databaseName() 00137 { 00138 return 'postgresql'; 00139 } 00140 00141 /*! 00142 \reimp 00143 */ 00144 function bindingType( ) 00145 { 00146 return eZDBInterface::BINDING_NO; 00147 } 00148 00149 /*! 00150 \reimp 00151 */ 00152 function bindVariable( $value, $fieldDef = false ) 00153 { 00154 return $value; 00155 } 00156 00157 /*! 00158 \reimp 00159 */ 00160 function query( $sql, $server = false ) 00161 { 00162 if ( $this->isConnected() ) 00163 { 00164 if ( $this->OutputSQL ) 00165 { 00166 eZDebug::accumulatorStart( 'postgresql_query', 'postgresql_total', 'Postgresql_queries' ); 00167 $this->startTimer(); 00168 00169 } 00170 $result = pg_query( $this->DBConnection, $sql ); 00171 if ( $this->OutputSQL ) 00172 { 00173 $this->endTimer(); 00174 00175 if ($this->timeTaken() > $this->SlowSQLTimeout) 00176 { 00177 eZDebug::instance(); 00178 eZDebug::accumulatorStop( 'postgresql_query' ); 00179 $this->reportQuery( 'eZPostgreSQLDB', $sql, false, $this->timeTaken() ); 00180 } 00181 } 00182 00183 if ( !$result ) 00184 { 00185 eZDebug::writeError( "Error: error executing query: $sql " . pg_last_error( $this->DBConnection ), "eZPostgreSQLDB" ); 00186 $this->setError(); 00187 00188 $this->reportError(); 00189 } 00190 } 00191 else 00192 $result = false; 00193 return $result; 00194 } 00195 00196 00197 /*! 00198 \reimp 00199 */ 00200 function arrayQuery( $sql, $params = array(), $server = false ) 00201 { 00202 $retArray = array(); 00203 if ( $this->isConnected() ) 00204 { 00205 $limit = -1; 00206 $offset = 0; 00207 // check for array parameters 00208 if ( is_array( $params ) ) 00209 { 00210 // $params = $min; 00211 00212 00213 $column = false; 00214 if ( isset( $params["limit"] ) and is_numeric( $params["limit"] ) ) 00215 { 00216 $limit = $params["limit"]; 00217 } 00218 00219 if ( isset( $params["offset"] ) and is_numeric( $params["offset"] ) ) 00220 { 00221 $offset = $params["offset"]; 00222 } 00223 if ( isset( $params["column"] ) and ( is_numeric( $params["column"] ) or is_string( $params["column"] ) ) ) 00224 $column = $params["column"]; 00225 } 00226 00227 if ( $limit != -1 ) 00228 { 00229 $sql .= "\nLIMIT $limit"; 00230 } 00231 if ( $offset > 0 ) 00232 { 00233 if ( $limit == -1 ) 00234 $sql .= "\n"; 00235 else 00236 $sql .= " "; 00237 $sql .= "OFFSET $offset"; 00238 } 00239 $result = $this->query( $sql ); 00240 00241 if ( $result == false ) 00242 { 00243 return false; 00244 } 00245 00246 if ( pg_numrows( $result ) > 0 ) 00247 { 00248 if ( !is_string( $column ) ) 00249 { 00250 for($i = 0; $i < pg_numrows($result); $i++) 00251 { 00252 $retArray[$i + $offset] = pg_fetch_array( $result, $i, PGSQL_ASSOC ); 00253 } 00254 } 00255 else 00256 { 00257 for ($i = 0; $i < pg_numrows( $result ); $i++ ) 00258 { 00259 $tmp_row = pg_fetch_array( $result, $i, PGSQL_ASSOC ); 00260 $retArray[$i + $offset] =& $tmp_row[$column]; 00261 } 00262 } 00263 } 00264 pg_free_result( $result ); 00265 } 00266 return $retArray; 00267 } 00268 00269 /*! 00270 \private 00271 */ 00272 function subString( $string, $from, $len = null ) 00273 { 00274 if ( $len == null ) 00275 { 00276 return " substring( $string from $from ) "; 00277 }else 00278 { 00279 return " substring( $string from $from for $len ) "; 00280 } 00281 00282 } 00283 00284 function concatString( $strings = array() ) 00285 { 00286 $str = implode( " || " , $strings ); 00287 return " $str "; 00288 } 00289 00290 function md5( $str ) 00291 { 00292 return " encode(digest( $str, 'md5' ), 'hex' ) "; 00293 } 00294 00295 /*! 00296 \reimp 00297 */ 00298 function supportedRelationTypeMask() 00299 { 00300 return ( eZDBInterface::RELATION_TABLE_BIT | 00301 eZDBInterface::RELATION_SEQUENCE_BIT | 00302 eZDBInterface::RELATION_TRIGGER_BIT | 00303 eZDBInterface::RELATION_VIEW_BIT | 00304 eZDBInterface::RELATION_INDEX_BIT ); 00305 } 00306 00307 /*! 00308 \reimp 00309 */ 00310 function supportedRelationTypes() 00311 { 00312 return array( eZDBInterface::RELATION_TABLE, 00313 eZDBInterface::RELATION_SEQUENCE, 00314 eZDBInterface::RELATION_TRIGGER, 00315 eZDBInterface::RELATION_VIEW, 00316 eZDBInterface::RELATION_INDEX ); 00317 } 00318 00319 /*! 00320 \private 00321 */ 00322 function relationKind( $relationType ) 00323 { 00324 $kind = array( eZDBInterface::RELATION_TABLE => 'r', 00325 eZDBInterface::RELATION_SEQUENCE => 'S', 00326 eZDBInterface::RELATION_TRIGGER => 't', 00327 eZDBInterface::RELATION_VIEW => 'v', 00328 eZDBInterface::RELATION_INDEX => 'i' ); 00329 if ( !isset( $kind[$relationType] ) ) 00330 return false; 00331 return $kind[$relationType]; 00332 } 00333 00334 /*! 00335 \reimp 00336 */ 00337 function relationCounts( $relationMask ) 00338 { 00339 $relationTypes = $this->supportedRelationTypes(); 00340 $relationKinds = array(); 00341 foreach ( $relationTypes as $relationType ) 00342 { 00343 $relationBit = ( 1 << $relationType ); 00344 if ( $relationMask & $relationBit ) 00345 { 00346 $relationKind = $this->relationKind( $relationType ); 00347 if ( $relationKind ) 00348 $relationKinds[] = $relationKind; 00349 } 00350 } 00351 if ( count( $relationKinds ) == 0 ) 00352 return 0; 00353 $count = false; 00354 $relkindText = ''; 00355 $i = 0; 00356 foreach ( $relationKinds as $relationKind ) 00357 { 00358 if ( $i > 0 ) 00359 $relkindText .= ' OR '; 00360 $relkindText .= "relkind='$relationKind'"; 00361 $i++; 00362 } 00363 if ( $this->isConnected() ) 00364 { 00365 $sql = "SELECT COUNT( relname ) as count 00366 FROM pg_catalog.pg_class c 00367 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 00368 WHERE ( $relkindText ) 00369 AND c.relname !~ '^pg_' 00370 AND pg_catalog.pg_table_is_visible(c.oid)"; 00371 $array = $this->arrayQuery( $sql, array( 'column' => 'count' ) ); 00372 $count = $array[0]; 00373 } 00374 return $count; 00375 } 00376 00377 /*! 00378 \reimp 00379 */ 00380 function relationCount( $relationType = eZDBInterface::RELATION_TABLE ) 00381 { 00382 $count = false; 00383 $relationKind = $this->relationKind( $relationType ); 00384 if ( !$relationKind ) 00385 { 00386 eZDebug::writeError( "Unsupported relation type '$relationType'", 'eZPostgreSQLDB::relationCount' ); 00387 return false; 00388 } 00389 00390 if ( $this->isConnected() ) 00391 { 00392 $sql = "SELECT COUNT( relname ) as count 00393 FROM pg_catalog.pg_class c 00394 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 00395 WHERE c.relkind = '$relationKind' 00396 AND c.relname !~ '^pg_' 00397 AND pg_catalog.pg_table_is_visible(c.oid)"; 00398 $array = $this->arrayQuery( $sql, array( 'column' => 'count' ) ); 00399 $count = $array[0]; 00400 } 00401 return $count; 00402 } 00403 00404 /*! 00405 \reimp 00406 */ 00407 function relationList( $relationType = eZDBInterface::RELATION_TABLE ) 00408 { 00409 $count = false; 00410 $relationKind = $this->relationKind( $relationType ); 00411 if ( !$relationKind ) 00412 { 00413 eZDebug::writeError( "Unsupported relation type '$relationType'", 'eZPostgreSQLDB::relationList' ); 00414 return false; 00415 } 00416 00417 $array = array(); 00418 if ( $this->isConnected() ) 00419 { 00420 $sql = "SELECT relname 00421 FROM pg_catalog.pg_class c 00422 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 00423 WHERE c.relkind = '$relationKind' 00424 AND c.relname !~ '^pg_' 00425 AND pg_catalog.pg_table_is_visible( c.oid )"; 00426 $array = $this->arrayQuery( $sql, array( 'column' => 'relname' ) ); 00427 } 00428 return $array; 00429 } 00430 00431 /*! 00432 \reimp 00433 */ 00434 function eZTableList( $server = eZDBInterface::SERVER_MASTER ) 00435 { 00436 $array = array(); 00437 if ( $this->isConnected() ) 00438 { 00439 foreach ( array( eZDBInterface::RELATION_TABLE, eZDBInterface::RELATION_SEQUENCE ) as $relationType ) 00440 { 00441 $sql = "SELECT relname FROM pg_class WHERE relkind='" . $this->relationKind( $relationType ) . "' AND relname like 'ez%'"; 00442 foreach ( $this->arrayQuery( $sql, array( 'column' => 'relname' ) ) as $result ) 00443 { 00444 $array[$result] = $relationType; 00445 } 00446 } 00447 } 00448 return $array; 00449 } 00450 00451 /*! 00452 \reimp 00453 */ 00454 function relationMatchRegexp( $relationType ) 00455 { 00456 return "#^(ez|tmp_notification_rule_s)#"; 00457 } 00458 00459 /*! 00460 \reimp 00461 */ 00462 function removeRelation( $relationName, $relationType ) 00463 { 00464 $relationTypeName = $this->relationName( $relationType ); 00465 if ( !$relationTypeName ) 00466 { 00467 eZDebug::writeError( "Unsupported relation type '$relationType'", 'eZPostgreSQLDB::removeRelation' ); 00468 return false; 00469 } 00470 00471 if ( $this->isConnected() ) 00472 { 00473 $sql = "DROP $relationTypeName $relationName"; 00474 return $this->query( $sql ); 00475 } 00476 return false; 00477 } 00478 00479 /*! 00480 \reimp 00481 */ 00482 function lock( $table ) 00483 { 00484 $this->begin(); 00485 if ( $this->isConnected() ) 00486 { 00487 if ( is_array( $table ) ) 00488 { 00489 $lockQuery = "LOCK TABLE"; 00490 $first = true; 00491 foreach( array_keys( $table ) as $tableKey ) 00492 { 00493 if ( $first == true ) 00494 $first = false; 00495 else 00496 $lockQuery .= ","; 00497 $lockQuery .= " " . $table[$tableKey]['table']; 00498 } 00499 $this->query( $lockQuery ); 00500 } 00501 else 00502 { 00503 $this->query( "LOCK TABLE $table" ); 00504 } 00505 } 00506 } 00507 00508 /*! 00509 \reimp 00510 */ 00511 function unlock() 00512 { 00513 $this->commit(); 00514 } 00515 00516 /*! 00517 \reimp 00518 The query to start the transaction. 00519 */ 00520 function beginQuery() 00521 { 00522 return $this->query("BEGIN WORK"); 00523 } 00524 00525 /*! 00526 \reimp 00527 The query to commit the transaction. 00528 */ 00529 function commitQuery() 00530 { 00531 return $this->query( "COMMIT WORK" ); 00532 } 00533 00534 /*! 00535 \reimp 00536 The query to cancel the transaction. 00537 */ 00538 function rollbackQuery() 00539 { 00540 return $this->query( "ROLLBACK WORK" ); 00541 } 00542 00543 /** 00544 * Returns the last serial ID generated with an auto increment field. 00545 * 00546 * In this case that means the current value of the sequence assigned 00547 * <var>$table</var> 00548 * 00549 * @param string $table 00550 * @param string $column 00551 * @return int The most recent value for the sequence 00552 */ 00553 function lastSerialID( $table = false, $column = 'id' ) 00554 { 00555 if ( $this->isConnected() ) 00556 { 00557 $sql = "SELECT currval( '" . $table . "_s')"; 00558 $result = pg_query( $this->DBConnection, $sql ); 00559 if ( !$result ) 00560 { 00561 eZDebug::writeError( "Error: error executing query: $sql " . pg_last_error( $this->DBConnection ), "eZPostgreSQLDB" ); 00562 } 00563 00564 if ( $result ) 00565 { 00566 $array = pg_fetch_row( $result, 0 ); 00567 $id = (int)$array[0]; 00568 } 00569 } 00570 return $id; 00571 } 00572 00573 /*! 00574 \reimp 00575 */ 00576 function setError( ) 00577 { 00578 if ( $this->DBConnection ) 00579 { 00580 00581 $this->ErrorMessage = pg_last_error( $this->DBConnection ); 00582 if ( $this->ErrorMessage != '' ) 00583 { 00584 $this->ErrorNumber = 1; 00585 } 00586 else 00587 { 00588 $this->ErrorNumber = 0; 00589 } 00590 00591 } 00592 } 00593 00594 /*! 00595 \reimp 00596 */ 00597 function escapeString( $str ) 00598 { 00599 $str = str_replace("\0", '', $str); 00600 $str = pg_escape_string( $str ); 00601 return $str; 00602 } 00603 00604 /*! 00605 \reimp 00606 */ 00607 function close() 00608 { 00609 pg_close( $this->DBConnection ); 00610 } 00611 00612 /*! 00613 \reimp 00614 */ 00615 function isCharsetSupported( $charset ) 00616 { 00617 return true; 00618 } 00619 00620 /*! 00621 \reimp 00622 */ 00623 function databaseServerVersion() 00624 { 00625 if ( $this->isConnected() ) 00626 { 00627 $sql = "SELECT version()"; 00628 $result = pg_query( $this->DBConnection, $sql ); 00629 if ( !$result ) 00630 { 00631 eZDebug::writeError( "Error: error executing query: $sql " . pg_last_error( $this->DBConnection ), "eZPostgreSQLDB" ); 00632 } 00633 00634 if ( $result ) 00635 { 00636 $array = pg_fetch_row( $result, 0 ); 00637 $versionText = $array[0]; 00638 } 00639 list( $dbType, $versionInfo ) = split( " ", $versionText ); 00640 $versionArray = explode( '.', $versionInfo ); 00641 return array( 'string' => $versionInfo, 00642 'values' => $versionArray ); 00643 } 00644 return false; 00645 } 00646 00647 /*! 00648 Sets PostgreSQL sequence values to the maximum values used in the corresponding columns. 00649 */ 00650 function correctSequenceValues() 00651 { 00652 if ( $this->isConnected() ) 00653 { 00654 $rows = $this->arrayQuery( "SELECT pg_class.relname AS table, pg_attribute.attname AS column 00655 FROM pg_class,pg_attribute,pg_attrdef 00656 WHERE pg_attrdef.adsrc LIKE 'nextval(%' 00657 AND pg_attrdef.adrelid=pg_attribute.attrelid 00658 AND pg_attrdef.adnum=pg_attribute.attnum 00659 AND pg_attribute.attrelid=pg_class.oid" ); 00660 foreach ( $rows as $row ) 00661 { 00662 $this->query( "SELECT setval('".$row['table']."_s', max(".$row['column'].")) from ".$row['table'] ); 00663 } 00664 return true; 00665 } 00666 return false; 00667 } 00668 00669 /// \privatesection 00670 00671 } 00672 00673 ?>