Move MySQL-specific fakeMaster/fakeSlave stuff to DatabaseMysqlBase
[lhc/web/wiklou.git] / includes / db / DatabasePostgres.php
index 21a7bcf..83d8cae 100644 (file)
@@ -26,9 +26,9 @@ class PostgresField implements Field {
                $has_default, $default;
 
        /**
-        * @param $db DatabaseBase
-        * @param  $table
-        * @param  $field
+        * @param DatabaseBase $db
+        * @param string $table
+        * @param string $field
         * @return null|PostgresField
         */
        static function fromText( $db, $table, $field ) {
@@ -216,13 +216,15 @@ class PostgresTransactionState {
  * @since 1.19
  */
 class SavepointPostgres {
-       /**
-        * Establish a savepoint within a transaction
-        */
+       /** @var DatabaseBase Establish a savepoint within a transaction */
        protected $dbw;
        protected $id;
        protected $didbegin;
 
+       /**
+        * @param DatabaseBase $dbw
+        * @param $id
+        */
        public function __construct( $dbw, $id ) {
                $this->dbw = $dbw;
                $this->id = $id;
@@ -362,7 +364,7 @@ class DatabasePostgres extends DatabaseBase {
         * @param string $user
         * @param string $password
         * @param string $dbName
-        * @throws DBConnectionError
+        * @throws DBConnectionError|Exception
         * @return DatabaseBase|null
         */
        function open( $server, $user, $password, $dbName ) {
@@ -379,7 +381,7 @@ class DatabasePostgres extends DatabaseBase {
                global $wgDBport;
 
                if ( !strlen( $user ) ) { # e.g. the class is being loaded
-                       return;
+                       return null;
                }
 
                $this->mServer = $server;
@@ -450,7 +452,8 @@ class DatabasePostgres extends DatabaseBase {
        /**
         * Postgres doesn't support selectDB in the same way MySQL does. So if the
         * DB name doesn't match the open connection, open a new one
-        * @return
+        * @param string $db
+        * @return bool
         */
        function selectDB( $db ) {
                if ( $this->mDBname !== $db ) {
@@ -536,6 +539,10 @@ class DatabasePostgres extends DatabaseBase {
                return $this->query( $sql, $fname, true );
        }
 
+       /**
+        * @param stdClass|ResultWrapper $res
+        * @throws DBUnexpectedError
+        */
        function freeResult( $res ) {
                if ( $res instanceof ResultWrapper ) {
                        $res = $res->result;
@@ -548,6 +555,11 @@ class DatabasePostgres extends DatabaseBase {
                }
        }
 
+       /**
+        * @param ResultWrapper|stdClass $res
+        * @return stdClass
+        * @throws DBUnexpectedError
+        */
        function fetchObject( $res ) {
                if ( $res instanceof ResultWrapper ) {
                        $res = $res->result;
@@ -629,6 +641,11 @@ class DatabasePostgres extends DatabaseBase {
                return $this->mInsertId;
        }
 
+       /**
+        * @param mixed $res
+        * @param int $row
+        * @return bool
+        */
        function dataSeek( $res, $row ) {
                if ( $res instanceof ResultWrapper ) {
                        $res = $res->result;
@@ -675,6 +692,12 @@ class DatabasePostgres extends DatabaseBase {
         * This is not necessarily an accurate estimate, so use sparingly
         * Returns -1 if count cannot be found
         * Takes same arguments as Database::select()
+        *
+        * @param string $table
+        * @param string $vars
+        * @param string $conds
+        * @param string $fname
+        * @param array $options
         * @return int
         */
        function estimateRowCount( $table, $vars = '*', $conds = '',
@@ -697,6 +720,10 @@ class DatabasePostgres extends DatabaseBase {
        /**
         * Returns information about an index
         * If errors are explicitly ignored, returns NULL on failure
+        *
+        * @param string $table
+        * @param string $index
+        * @param string $fname
         * @return bool|null
         */
        function indexInfo( $table, $index, $fname = __METHOD__ ) {
@@ -718,7 +745,9 @@ class DatabasePostgres extends DatabaseBase {
         * Returns is of attributes used in index
         *
         * @since 1.19
-        * @return Array
+        * @param string $index
+        * @param bool|string $schema
+        * @return array
         */
        function indexAttributes( $index, $schema = false ) {
                if ( $schema === false ) {
@@ -790,17 +819,39 @@ __INDEXATTR__;
                return $res->numRows() > 0;
        }
 
+       /**
+        * Change the FOR UPDATE option as necessary based on the join conditions. Then pass
+        * to the parent function to get the actual SQL text.
+        *
+        * In Postgres when using FOR UPDATE, only the main table and tables that are inner joined
+        * can be locked. That means tables in an outer join cannot be FOR UPDATE locked. Trying to do
+        * so causes a DB error. This wrapper checks which tables can be locked and adjusts it accordingly.
+        */
+       function selectSQLText( $table, $vars, $conds = '', $fname = __METHOD__, $options = array(), $join_conds = array() ) {
+               $forUpdateKey = array_search( 'FOR UPDATE', $options );
+               if ( $forUpdateKey !== false && $join_conds ) {
+                       unset( $options[$forUpdateKey] );
+
+                       foreach ( $join_conds as $table => $join_cond ) {
+                               if ( 0 === preg_match( '/^(?:LEFT|RIGHT|FULL)(?: OUTER)? JOIN$/i', $join_cond[0] ) ) {
+                                       $options['FOR UPDATE'][] = $table;
+                               }
+                       }
+               }
+
+               return parent::selectSQLText( $table, $vars, $conds, $fname, $options, $join_conds );
+       }
+
        /**
         * INSERT wrapper, inserts an array into a table
         *
         * $args may be a single associative array, or an array of these with numeric keys,
         * for multi-row insert (Postgres version 8.2 and above only).
         *
-        * @param $table   String: Name of the table to insert to.
-        * @param $args    Array: Items to insert into the table.
-        * @param $fname   String: Name of the function, for profiling
-        * @param string $options or Array. Valid options: IGNORE
-        *
+        * @param string $table Name of the table to insert to.
+        * @param array $args Items to insert into the table.
+        * @param string $fname Name of the function, for profiling
+        * @param array|string $options String or array. Valid options: IGNORE
         * @return bool Success of insert operation. IGNORE always returns true.
         */
        function insert( $table, $args, $fname = __METHOD__, $options = array() ) {
@@ -919,6 +970,14 @@ __INDEXATTR__;
         * $conds may be "*" to copy the whole table
         * srcTable may be an array of tables.
         * @todo FIXME: Implement this a little better (seperate select/insert)?
+        *
+        * @param string $destTable
+        * @param array|string $srcTable
+        * @param array $varMap
+        * @param array $conds
+        * @param string $fname
+        * @param array $insertOptions
+        * @param array $selectOptions
         * @return bool
         */
        function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = __METHOD__,
@@ -1019,7 +1078,7 @@ __INDEXATTR__;
         * Return the current value of a sequence. Assumes it has been nextval'ed in this session.
         *
         * @param string $seqName
-        * @return
+        * @return int
         */
        function currentSequenceValue( $seqName ) {
                $safeseq = str_replace( "'", "''", $seqName );
@@ -1096,10 +1155,10 @@ __INDEXATTR__;
         * This should really be handled by PHP PostgreSQL module
         *
         * @since 1.19
-        * @param $text   string: postgreql array returned in a text form like {a,b}
-        * @param $output string
-        * @param $limit  int
-        * @param $offset int
+        * @param string $text Postgreql array returned in a text form like {a,b}
+        * @param string $output
+        * @param int $limit
+        * @param int $offset
         * @return string
         */
        function pg_array_parse( $text, &$output, $limit = false, $offset = 1 ) {
@@ -1137,10 +1196,10 @@ __INDEXATTR__;
        }
 
        /**
-        * @return string wikitext of a link to the server software's web site
+        * @return string Wikitext of a link to the server software's web site
         */
        public function getSoftwareLink() {
-               return '[http://www.postgresql.org/ PostgreSQL]';
+               return '[{{int:version-db-postgres-url}} PostgreSQL]';
        }
 
        /**
@@ -1184,7 +1243,7 @@ __INDEXATTR__;
         * Needs transaction
         *
         * @since 1.19
-        * @return array how to search for table names schemas for the current user
+        * @return array How to search for table names schemas for the current user
         */
        function getSearchPath() {
                $res = $this->query( "SHOW search_path", __METHOD__ );
@@ -1217,14 +1276,15 @@ __INDEXATTR__;
         * This will be also called by the installer after the schema is created
         *
         * @since 1.19
-        * @param $desired_schema string
+        *
+        * @param string $desiredSchema
         */
-       function determineCoreSchema( $desired_schema ) {
+       function determineCoreSchema( $desiredSchema ) {
                $this->begin( __METHOD__ );
-               if ( $this->schemaExists( $desired_schema ) ) {
-                       if ( in_array( $desired_schema, $this->getSchemas() ) ) {
-                               $this->mCoreSchema = $desired_schema;
-                               wfDebug( "Schema \"" . $desired_schema . "\" already in the search path\n" );
+               if ( $this->schemaExists( $desiredSchema ) ) {
+                       if ( in_array( $desiredSchema, $this->getSchemas() ) ) {
+                               $this->mCoreSchema = $desiredSchema;
+                               wfDebug( "Schema \"" . $desiredSchema . "\" already in the search path\n" );
                        } else {
                                /**
                                 * Prepend our schema (e.g. 'mediawiki') in front
@@ -1233,14 +1293,14 @@ __INDEXATTR__;
                                 */
                                $search_path = $this->getSearchPath();
                                array_unshift( $search_path,
-                                       $this->addIdentifierQuotes( $desired_schema ) );
+                                       $this->addIdentifierQuotes( $desiredSchema ) );
                                $this->setSearchPath( $search_path );
-                               $this->mCoreSchema = $desired_schema;
-                               wfDebug( "Schema \"" . $desired_schema . "\" added to the search path\n" );
+                               $this->mCoreSchema = $desiredSchema;
+                               wfDebug( "Schema \"" . $desiredSchema . "\" added to the search path\n" );
                        }
                } else {
                        $this->mCoreSchema = $this->getCurrentSchema();
-                       wfDebug( "Schema \"" . $desired_schema . "\" not found, using current \"" .
+                       wfDebug( "Schema \"" . $desiredSchema . "\" not found, using current \"" .
                                $this->mCoreSchema . "\"\n" );
                }
                /* Commit SET otherwise it will be rollbacked on error or IGNORE SELECT */
@@ -1281,6 +1341,9 @@ __INDEXATTR__;
        /**
         * Query whether a given relation exists (in the given schema, or the
         * default mw one if not given)
+        * @param string $table
+        * @param array|string $types
+        * @param bool|string $schema
         * @return bool
         */
        function relationExists( $table, $types, $schema = false ) {
@@ -1305,6 +1368,9 @@ __INDEXATTR__;
        /**
         * For backward compatibility, this function checks both tables and
         * views.
+        * @param string $table
+        * @param string $fname
+        * @param bool|string $schema
         * @return bool
         */
        function tableExists( $table, $fname = __METHOD__, $schema = false ) {
@@ -1368,6 +1434,7 @@ SQL;
 
        /**
         * Query whether a given schema exists. Returns true if it does, false if it doesn't.
+        * @param string $schema
         * @return bool
         */
        function schemaExists( $schema ) {
@@ -1379,6 +1446,7 @@ SQL;
 
        /**
         * Returns true if a given role (i.e. user) exists, false otherwise.
+        * @param string $roleName
         * @return bool
         */
        function roleExists( $roleName ) {
@@ -1394,6 +1462,8 @@ SQL;
 
        /**
         * pg_field_type() wrapper
+        * @param ResultWrapper|resource $res ResultWrapper or PostgreSQL query result resource
+        * @param int $index Field number, starting from 0
         * @return string
         */
        function fieldType( $res, $index ) {
@@ -1405,7 +1475,7 @@ SQL;
        }
 
        /**
-        * @param $b
+        * @param string $b
         * @return Blob
         */
        function encodeBlob( $b ) {
@@ -1425,7 +1495,7 @@ SQL;
        }
 
        /**
-        * @param $s null|bool|Blob
+        * @param null|bool|Blob $s
         * @return int|string
         */
        function addQuotes( $s ) {
@@ -1444,10 +1514,7 @@ SQL;
         * Postgres specific version of replaceVars.
         * Calls the parent version in Database.php
         *
-        * @private
-        *
         * @param string $ins SQL string, read from a stream (usually tables.sql)
-        *
         * @return string SQL string
         */
        protected function replaceVars( $ins ) {
@@ -1468,10 +1535,8 @@ SQL;
        /**
         * Various select options
         *
-        * @private
-        *
         * @param array $options an associative array of options to be turned into
-        *              an SQL query, valid keys are listed in the function.
+        *   an SQL query, valid keys are listed in the function.
         * @return array
         */
        function makeSelectOptions( $options ) {
@@ -1495,9 +1560,12 @@ SQL;
                //              : false );
                //}
 
-               if ( isset( $noKeyOptions['FOR UPDATE'] ) ) {
+               if ( isset( $options['FOR UPDATE'] ) ) {
+                       $postLimitTail .= ' FOR UPDATE OF ' . implode( ', ', $options['FOR UPDATE'] );
+               } else if ( isset( $noKeyOptions['FOR UPDATE'] ) ) {
                        $postLimitTail .= ' FOR UPDATE';
                }
+
                if ( isset( $noKeyOptions['DISTINCT'] ) || isset( $noKeyOptions['DISTINCTROW'] ) ) {
                        $startOpts .= 'DISTINCT';
                }
@@ -1505,9 +1573,6 @@ SQL;
                return array( $startOpts, $useIndex, $preLimitTail, $postLimitTail );
        }
 
-       function setFakeMaster( $enabled = true ) {
-       }
-
        function getDBname() {
                return $this->mDBname;
        }
@@ -1549,9 +1614,9 @@ SQL;
         * Check to see if a named lock is available. This is non-blocking.
         * See http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
         *
-        * @param string $lockName name of lock to poll
-        * @param string $method name of method calling us
-        * @return Boolean
+        * @param string $lockName Name of lock to poll
+        * @param string $method Name of method calling us
+        * @return bool
         * @since 1.20
         */
        public function lockIsFree( $lockName, $method ) {
@@ -1565,9 +1630,9 @@ SQL;
 
        /**
         * See http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
-        * @param $lockName string
-        * @param $method string
-        * @param $timeout int
+        * @param string $lockName
+        * @param string $method
+        * @param int $timeout
         * @return bool
         */
        public function lock( $lockName, $method, $timeout = 5 ) {
@@ -1590,8 +1655,8 @@ SQL;
        /**
         * See http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKSFROM
         * PG DOCS: http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
-        * @param $lockName string
-        * @param $method string
+        * @param string $lockName
+        * @param string $method
         * @return bool
         */
        public function unlock( $lockName, $method ) {