eZ Publish  [4.0]
ezpostgresqldb.php
Go to the documentation of this file.
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 ?>