Merge "(bug 43560) Initial input focus on Special:ListUsers isn't set"
[lhc/web/wiklou.git] / includes / installer / PostgresInstaller.php
index 501f673..882ec53 100644 (file)
@@ -2,6 +2,21 @@
 /**
  * PostgreSQL-specific installer.
  *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @file
  * @ingroup Deployment
  */
@@ -45,7 +60,7 @@ class PostgresInstaller extends DatabaseInstaller {
                        $this->getTextBox( 'wgDBserver', 'config-db-host', array(), $this->parent->getHelpBox( 'config-db-host-help' ) ) .
                        $this->getTextBox( 'wgDBport', 'config-db-port' ) .
                        Html::openElement( 'fieldset' ) .
-                       Html::element( 'legend', array(), wfMsg( 'config-db-wiki-settings' ) ) .
+                       Html::element( 'legend', array(), wfMessage( 'config-db-wiki-settings' )->text() ) .
                        $this->getTextBox( 'wgDBname', 'config-db-name', array(), $this->parent->getHelpBox( 'config-db-name-help' ) ) .
                        $this->getTextBox( 'wgDBmwschema', 'config-db-schema', array(), $this->parent->getHelpBox( 'config-db-schema-help' ) ) .
                        Html::closeElement( 'fieldset' ) .
@@ -80,6 +95,9 @@ class PostgresInstaller extends DatabaseInstaller {
                if ( !$status->isOK() ) {
                        return $status;
                }
+               /**
+                * @var $conn DatabaseBase
+                */
                $conn = $status->value;
 
                // Check version
@@ -107,9 +125,9 @@ class PostgresInstaller extends DatabaseInstaller {
 
        /**
         * Open a PG connection with given parameters
-        * @param $user User name
-        * @param $password Password
-        * @param $dbName Database name
+        * @param $user string User name
+        * @param $password string Password
+        * @param $dbName string Database name
         * @return Status
         */
        protected function openConnectionWithParams( $user, $password, $dbName ) {
@@ -129,7 +147,7 @@ class PostgresInstaller extends DatabaseInstaller {
 
        /**
         * Get a special type of connection
-        * @param $type See openPgConnection() for details.
+        * @param $type string See openPgConnection() for details.
         * @return Status
         */
        protected function getPgConnection( $type ) {
@@ -139,9 +157,12 @@ class PostgresInstaller extends DatabaseInstaller {
                $status = $this->openPgConnection( $type );
 
                if ( $status->isOK() ) {
+                       /**
+                        * @var $conn DatabaseBase
+                        */
                        $conn = $status->value;
                        $conn->clearFlag( DBO_TRX );
-                       $conn->commit();
+                       $conn->commit( __METHOD__ );
                        $this->pgConns[$type] = $conn;
                }
                return $status;
@@ -151,41 +172,45 @@ class PostgresInstaller extends DatabaseInstaller {
         * Get a connection of a specific PostgreSQL-specific type. Connections
         * of a given type are cached.
         *
-        * PostgreSQL lacks cross-database operations, so after the new database is 
-        * created, you need to make a separate connection to connect to that 
-        * database and add tables to it. 
+        * PostgreSQL lacks cross-database operations, so after the new database is
+        * created, you need to make a separate connection to connect to that
+        * database and add tables to it.
         *
-        * New tables are owned by the user that creates them, and MediaWiki's 
-        * PostgreSQL support has always assumed that the table owner will be 
-        * $wgDBuser. So before we create new tables, we either need to either 
-        * connect as the other user or to execute a SET ROLE command. Using a 
-        * separate connection for this allows us to avoid accidental cross-module 
+        * New tables are owned by the user that creates them, and MediaWiki's
+        * PostgreSQL support has always assumed that the table owner will be
+        * $wgDBuser. So before we create new tables, we either need to either
+        * connect as the other user or to execute a SET ROLE command. Using a
+        * separate connection for this allows us to avoid accidental cross-module
         * dependencies.
         *
-        * @param $type The type of connection to get:
+        * @param $type string The type of connection to get:
         *    - create-db:     A connection for creating DBs, suitable for pre-
         *                     installation.
-        *    - create-schema: A connection to the new DB, for creating schemas and 
+        *    - create-schema: A connection to the new DB, for creating schemas and
         *                     other similar objects in the new DB.
         *    - create-tables: A connection with a role suitable for creating tables.
         *
-        * @return A Status object. On success, a connection object will be in the 
+        * @throws MWException
+        * @return Status object. On success, a connection object will be in the
         *   value member.
         */
        protected function openPgConnection( $type ) {
                switch ( $type ) {
                        case 'create-db':
                                return $this->openConnectionToAnyDB(
-                                       $this->getVar( '_InstallUser' ), 
+                                       $this->getVar( '_InstallUser' ),
                                        $this->getVar( '_InstallPassword' ) );
                        case 'create-schema':
-                               return $this->openConnectionWithParams( 
+                               return $this->openConnectionWithParams(
                                        $this->getVar( '_InstallUser' ),
                                        $this->getVar( '_InstallPassword' ),
                                        $this->getVar( 'wgDBname' ) );
                        case 'create-tables':
                                $status = $this->openPgConnection( 'create-schema' );
                                if ( $status->isOK() ) {
+                                       /**
+                                        * @var $conn DatabaseBase
+                                        */
                                        $conn = $status->value;
                                        $safeRole = $conn->addIdentifierQuotes( $this->getVar( 'wgDBuser' ) );
                                        $conn->query( "SET ROLE $safeRole" );
@@ -204,6 +229,7 @@ class PostgresInstaller extends DatabaseInstaller {
                if ( !in_array( $this->getVar( 'wgDBname' ), $dbs ) ) {
                        array_unshift( $dbs, $this->getVar( 'wgDBname' ) );
                }
+               $conn = false;
                $status = Status::newGood();
                foreach ( $dbs as $db ) {
                        try {
@@ -233,10 +259,13 @@ class PostgresInstaller extends DatabaseInstaller {
                if ( !$status->isOK() ) {
                        return false;
                }
+               /**
+                * @var $conn DatabaseBase
+                */
                $conn = $status->value;
                $superuser = $this->getVar( '_InstallUser' );
 
-               $row = $conn->selectRow( '"pg_catalog"."pg_roles"', '*', 
+               $row = $conn->selectRow( '"pg_catalog"."pg_roles"', '*',
                        array( 'rolname' => $superuser ), __METHOD__ );
                return $row;
        }
@@ -254,7 +283,7 @@ class PostgresInstaller extends DatabaseInstaller {
                if ( !$perms ) {
                        return false;
                }
-               return $perms->rolsuper === 't';                
+               return $perms->rolsuper === 't';
        }
 
        public function getSettingsForm() {
@@ -276,7 +305,9 @@ class PostgresInstaller extends DatabaseInstaller {
 
                $same = $this->getVar( 'wgDBuser' ) === $this->getVar( '_InstallUser' );
 
-               if ( !$same ) {
+               if ( $same ) {
+                       $exists = true;
+               } else {
                        // Check if the web user exists
                        // Connect to the database with the install user
                        $status = $this->getPgConnection( 'create-db' );
@@ -309,17 +340,17 @@ class PostgresInstaller extends DatabaseInstaller {
                }
 
                // Existing web account. Test the connection.
-               $status = $this->openConnectionToAnyDB( 
+               $status = $this->openConnectionToAnyDB(
                        $this->getVar( 'wgDBuser' ),
                        $this->getVar( 'wgDBpassword' ) );
                if ( !$status->isOK() ) {
                        return $status;
                }
 
-               // The web user is conventionally the table owner in PostgreSQL 
-               // installations. Make sure the install user is able to create 
+               // The web user is conventionally the table owner in PostgreSQL
+               // installations. Make sure the install user is able to create
                // objects on behalf of the web user.
-               if ( $this->canCreateObjectsForWebUser() ) {
+               if ( $same || $this->canCreateObjectsForWebUser() ) {
                        return Status::newGood();
                } else {
                        return Status::newFatal( 'config-pg-not-in-role' );
@@ -329,6 +360,7 @@ class PostgresInstaller extends DatabaseInstaller {
        /**
         * Returns true if the install user is able to create objects owned
         * by the web user, false otherwise.
+        * @return bool
         */
        protected function canCreateObjectsForWebUser() {
                if ( $this->isSuperUser() ) {
@@ -350,10 +382,11 @@ class PostgresInstaller extends DatabaseInstaller {
 
        /**
         * Recursive helper for canCreateObjectsForWebUser().
-        * @param $conn Database object
-        * @param $targetMember Role ID of the member to look for
-        * @param $group Role ID of the group to look for
-        * @param $maxDepth Maximum recursive search depth
+        * @param $conn DatabaseBase object
+        * @param $targetMember int Role ID of the member to look for
+        * @param $group int Role ID of the group to look for
+        * @param $maxDepth int Maximum recursive search depth
+        * @return bool
         */
        protected function isRoleMember( $conn, $targetMember, $group, $maxDepth ) {
                if ( $targetMember === $group ) {
@@ -381,6 +414,10 @@ class PostgresInstaller extends DatabaseInstaller {
        }
 
        public function preInstall() {
+               $createDbAccount = array(
+                       'name' => 'user',
+                       'callback' => array( $this, 'setupUser' ),
+               );
                $commitCB = array(
                        'name' => 'pg-commit',
                        'callback' => array( $this, 'commitChanges' ),
@@ -393,15 +430,13 @@ class PostgresInstaller extends DatabaseInstaller {
                        'name' => 'schema',
                        'callback' => array( $this, 'setupSchema' )
                );
+
+               if( $this->getVar( '_CreateDBAccount' ) ) {
+                       $this->parent->addInstallStep( $createDbAccount, 'database' );
+               }
                $this->parent->addInstallStep( $commitCB, 'interwiki' );
                $this->parent->addInstallStep( $plpgCB, 'database' );
                $this->parent->addInstallStep( $schemaCB, 'database' );
-               if( $this->getVar( '_CreateDBAccount' ) ) {
-                       $this->parent->addInstallStep( array(
-                               'name' => 'user',
-                               'callback' => array( $this, 'setupUser' ),
-                       ) );
-               }
        }
 
        function setupDatabase() {
@@ -412,10 +447,6 @@ class PostgresInstaller extends DatabaseInstaller {
                $conn = $status->value;
 
                $dbName = $this->getVar( 'wgDBname' );
-               $schema = $this->getVar( 'wgDBmwschema' );
-               $user = $this->getVar( 'wgDBuser' );
-               $safeschema = $conn->addIdentifierQuotes( $schema );
-               $safeuser = $conn->addIdentifierQuotes( $user );
 
                $exists = $conn->selectField( '"pg_catalog"."pg_database"', '1',
                        array( 'datname' => $dbName ), __METHOD__ );
@@ -442,24 +473,18 @@ class PostgresInstaller extends DatabaseInstaller {
                        try {
                                $conn->query( "CREATE SCHEMA $safeschema AUTHORIZATION $safeuser" );
                        } catch ( DBQueryError $e ) {
-                               return Status::newFatal( 'config-install-pg-schema-failed', 
+                               return Status::newFatal( 'config-install-pg-schema-failed',
                                        $this->getVar( '_InstallUser' ), $schema );
                        }
                }
 
-               // If we created a user, alter it now to search the new schema by default
-               if ( $this->getVar( '_CreateDBAccount' ) ) {
-                       $conn->query( "ALTER ROLE $safeuser SET search_path = $safeschema, public", 
-                               __METHOD__ );
-               }
-
                // Select the new schema in the current connection
-               $conn->query( "SET search_path = $safeschema" );
+               $conn->determineCoreSchema( $schema );
                return Status::newGood();
        }
 
        function commitChanges() {
-               $this->db->query( 'COMMIT' );
+               $this->db->commit( __METHOD__ );
                return Status::newGood();
        }
 
@@ -474,10 +499,8 @@ class PostgresInstaller extends DatabaseInstaller {
                }
                $conn = $status->value;
 
-               $schema = $this->getVar( 'wgDBmwschema' );
                $safeuser = $conn->addIdentifierQuotes( $this->getVar( 'wgDBuser' ) );
                $safepass = $conn->addQuotes( $this->getVar( 'wgDBpassword' ) );
-               $safeschema = $conn->addIdentifierQuotes( $schema );
 
                // Check if the user already exists
                $userExists = $conn->roleExists( $this->getVar( 'wgDBuser' ) );
@@ -485,8 +508,8 @@ class PostgresInstaller extends DatabaseInstaller {
                        // Create the user
                        try {
                                $sql = "CREATE ROLE $safeuser NOCREATEDB LOGIN PASSWORD $safepass";
-                               
-                               // If the install user is not a superuser, we need to make the install 
+
+                               // If the install user is not a superuser, we need to make the install
                                // user a member of the new user's group, so that the install user will
                                // be able to create a schema and other objects on behalf of the new user.
                                if ( !$this->isSuperUser() ) {
@@ -495,7 +518,7 @@ class PostgresInstaller extends DatabaseInstaller {
 
                                $conn->query( $sql, __METHOD__ );
                        } catch ( DBQueryError $e ) {
-                               return Status::newFatal( 'config-install-user-create-failed', 
+                               return Status::newFatal( 'config-install-user-create-failed',
                                        $this->getVar( 'wgDBuser' ), $e->getMessage() );
                        }
                }
@@ -528,10 +551,15 @@ class PostgresInstaller extends DatabaseInstaller {
                if ( !$status->isOK() ) {
                        return $status;
                }
+
+               /**
+                * @var $conn DatabaseBase
+                */
                $conn = $status->value;
 
-               if( $conn->tableExists( 'user' ) ) {
+               if( $conn->tableExists( 'archive' ) ) {
                        $status->warning( 'config-install-tables-exist' );
+                       $this->enableLB();
                        return $status;
                }
 
@@ -541,7 +569,7 @@ class PostgresInstaller extends DatabaseInstaller {
                        $status->fatal( 'config-install-pg-schema-not-exist' );
                        return $status;
                }
-               $error = $conn->sourceFile( $conn->getSchema() );
+               $error = $conn->sourceFile( $conn->getSchemaPath() );
                if( $error !== true ) {
                        $conn->reportQueryError( $error, 0, '', __METHOD__ );
                        $conn->rollback( __METHOD__ );
@@ -557,12 +585,15 @@ class PostgresInstaller extends DatabaseInstaller {
        }
 
        public function setupPLpgSQL() {
-               // Connect as the install user, since it owns the database and so is 
+               // Connect as the install user, since it owns the database and so is
                // the user that needs to run "CREATE LANGAUGE"
                $status = $this->getPgConnection( 'create-schema' );
                if ( !$status->isOK() ) {
                        return $status;
                }
+               /**
+                * @var $conn DatabaseBase
+                */
                $conn = $status->value;
 
                $exists = $conn->selectField( '"pg_catalog"."pg_language"', 1,
@@ -572,7 +603,7 @@ class PostgresInstaller extends DatabaseInstaller {
                        return Status::newGood();
                }
 
-               // plpgsql is not installed, but if we have a pg_pltemplate table, we 
+               // plpgsql is not installed, but if we have a pg_pltemplate table, we
                // should be able to create it
                $exists = $conn->selectField(
                        array( '"pg_catalog"."pg_class"', '"pg_catalog"."pg_namespace"' ),