52 '_InstallUser' =>
'postgres',
74 $this->parent->getHelpBox(
'config-db-host-help' )
76 $this->
getTextBox(
'wgDBport',
'config-db-port' ) .
78 Html::openElement(
'fieldset' ) .
79 Html::element(
'legend', [],
wfMessage(
'config-db-wiki-settings' )->text() ) .
84 $this->parent->getHelpBox(
'config-db-name-help' )
90 $this->parent->getHelpBox(
'config-db-schema-help' )
92 Html::closeElement(
'fieldset' ) .
107 $status = Status::newGood();
108 if ( !strlen( $newValues[
'wgDBname'] ) ) {
109 $status->fatal(
'config-missing-db-name' );
110 } elseif ( !preg_match(
'/^[a-zA-Z0-9_]+$/', $newValues[
'wgDBname'] ) ) {
111 $status->fatal(
'config-invalid-db-name', $newValues[
'wgDBname'] );
113 if ( !preg_match(
'/^[a-zA-Z0-9_]*$/', $newValues[
'wgDBmwschema'] ) ) {
114 $status->fatal(
'config-invalid-schema', $newValues[
'wgDBmwschema'] );
118 if ( $status->isOK() ) {
121 if ( !$status->isOK() ) {
126 if ( !$status->isOK() ) {
132 $conn = $status->value;
135 $status = static::meetsMinimumRequirement( $conn );
136 if ( !$status->isOK() ) {
140 $this->
setVar(
'wgDBuser', $this->
getVar(
'_InstallUser' ) );
141 $this->
setVar(
'wgDBpassword', $this->
getVar(
'_InstallPassword' ) );
143 return Status::newGood();
148 if ( $status->isOK() ) {
149 $this->db = $status->value;
168 $status = Status::newGood();
170 $db = MediaWikiServices::getInstance()->getDatabaseFactory()->create(
'postgres', [
171 'host' => $this->
getVar(
'wgDBserver' ),
172 'port' => $this->
getVar(
'wgDBport' ),
174 'password' => $password,
175 'ssl' => $this->
getVar(
'wgDBssl' ),
179 $status->value =
$db;
181 $status->fatal(
'config-connection-error', $e->getMessage() );
193 if ( isset( $this->pgConns[$type] ) ) {
194 return Status::newGood( $this->pgConns[$type] );
198 if ( $status->isOK() ) {
202 $conn = $status->value;
204 $conn->commit( __METHOD__ );
205 $this->pgConns[$type] = $conn;
240 $this->
getVar(
'_InstallUser' ),
241 $this->
getVar(
'_InstallPassword' ) );
242 case 'create-schema':
244 $this->
getVar(
'_InstallUser' ),
245 $this->
getVar(
'_InstallPassword' ),
246 $this->
getVar(
'wgDBname' ),
247 $this->
getVar(
'wgDBmwschema' ) );
248 case 'create-tables':
250 if ( $status->isOK() ) {
254 $conn = $status->value;
255 $safeRole = $conn->addIdentifierQuotes( $this->
getVar(
'wgDBuser' ) );
256 $conn->query(
"SET ROLE $safeRole", __METHOD__ );
261 throw new MWException(
"Invalid special connection type: \"$type\"" );
270 if ( !in_array( $this->
getVar(
'wgDBname' ), $dbs ) ) {
271 array_unshift( $dbs, $this->
getVar(
'wgDBname' ) );
274 $status = Status::newGood();
275 foreach ( $dbs as
$db ) {
278 'host' => $this->
getVar(
'wgDBserver' ),
279 'port' => $this->
getVar(
'wgDBport' ),
281 'password' => $password,
282 'ssl' => $this->
getVar(
'wgDBssl' ),
288 $status->fatal(
'config-pg-test-error',
$db,
289 $error->getMessage() );
291 if ( $conn !==
false ) {
295 if ( $conn !==
false ) {
296 return Status::newGood( $conn );
304 if ( !$status->isOK() ) {
310 $conn = $status->value;
311 $superuser = $this->
getVar(
'_InstallUser' );
313 $row = $conn->selectRow(
'"pg_catalog"."pg_roles"',
'*',
314 [
'rolname' => $superuser ], __METHOD__ );
321 return $perms && ( $perms->rolsuper ===
't' || $perms->rolcreaterole ===
't' );
326 return $perms && $perms->rolsuper ===
't';
331 $noCreateMsg =
false;
333 $noCreateMsg =
'config-db-web-no-create-privs';
342 if ( !$status->isOK() ) {
346 $same = $this->
getVar(
'wgDBuser' ) === $this->
getVar(
'_InstallUser' );
354 if ( !$status->isOK() ) {
358 $exists = $status->value->roleExists( $this->
getVar(
'wgDBuser' ) );
363 $create = $this->
getVar(
'_CreateDBAccount' );
365 $this->
setVar(
'_CreateDBAccount',
false );
369 if ( !$create && !$exists ) {
371 $msg =
'config-install-user-missing-create';
373 $msg =
'config-install-user-missing';
376 return Status::newFatal( $msg, $this->
getVar(
'wgDBuser' ) );
381 return Status::newGood();
386 $this->
getVar(
'wgDBuser' ),
387 $this->
getVar(
'wgDBpassword' ) );
388 if ( !$status->isOK() ) {
396 return Status::newGood();
398 return Status::newFatal(
'config-pg-not-in-role' );
413 if ( !$status->isOK() ) {
416 $conn = $status->value;
417 $installerId = $conn->selectField(
'"pg_catalog"."pg_roles"',
'oid',
418 [
'rolname' => $this->
getVar(
'_InstallUser' ) ], __METHOD__ );
419 $webId = $conn->selectField(
'"pg_catalog"."pg_roles"',
'oid',
420 [
'rolname' => $this->
getVar(
'wgDBuser' ) ], __METHOD__ );
422 return $this->
isRoleMember( $conn, $installerId, $webId, $this->maxRoleSearchDepth );
433 protected function isRoleMember( $conn, $targetMember, $group, $maxDepth ) {
434 if ( $targetMember === $group ) {
439 $res = $conn->select(
'"pg_catalog"."pg_auth_members"', [
'member' ],
440 [
'roleid' => $group ], __METHOD__ );
441 foreach ( $res as $row ) {
442 if ( $row->member == $targetMember ) {
448 if ( $maxDepth > 0 &&
449 $this->
isRoleMember( $conn, $targetMember, $row->member, $maxDepth - 1 )
462 'callback' => [ $this,
'setupUser' ],
465 'name' =>
'pg-commit',
466 'callback' => [ $this,
'commitChanges' ],
469 'name' =>
'pg-plpgsql',
470 'callback' => [ $this,
'setupPLpgSQL' ],
474 'callback' => [ $this,
'setupSchema' ]
477 if ( $this->
getVar(
'_CreateDBAccount' ) ) {
478 $this->parent->addInstallStep( $createDbAccount,
'database' );
480 $this->parent->addInstallStep( $commitCB,
'interwiki' );
481 $this->parent->addInstallStep( $plpgCB,
'database' );
482 $this->parent->addInstallStep( $schemaCB,
'database' );
487 if ( !$status->isOK() ) {
490 $conn = $status->value;
492 $dbName = $this->
getVar(
'wgDBname' );
494 $exists = (bool)$conn->selectField(
'"pg_catalog"."pg_database"',
'1',
495 [
'datname' => $dbName ], __METHOD__ );
497 $safedb = $conn->addIdentifierQuotes( $dbName );
498 $conn->query(
"CREATE DATABASE $safedb", __METHOD__ );
501 return Status::newGood();
507 if ( !$status->isOK() ) {
511 $conn = $status->value;
512 '@phan-var DatabasePostgres $conn';
515 $schema = $this->
getVar(
'wgDBmwschema' );
516 $safeschema = $conn->addIdentifierQuotes( $schema );
517 $safeuser = $conn->addIdentifierQuotes( $this->
getVar(
'wgDBuser' ) );
518 if ( !$conn->schemaExists( $schema ) ) {
520 $conn->query(
"CREATE SCHEMA $safeschema AUTHORIZATION $safeuser", __METHOD__ );
522 return Status::newFatal(
'config-install-pg-schema-failed',
523 $this->
getVar(
'_InstallUser' ), $schema );
528 $conn->determineCoreSchema( $schema );
530 return Status::newGood();
534 $this->db->commit( __METHOD__ );
536 return Status::newGood();
540 if ( !$this->
getVar(
'_CreateDBAccount' ) ) {
541 return Status::newGood();
545 if ( !$status->isOK() ) {
549 $conn = $status->value;
550 '@phan-var DatabasePostgres $conn';
552 $safeuser = $conn->addIdentifierQuotes( $this->
getVar(
'wgDBuser' ) );
553 $safepass = $conn->addQuotes( $this->
getVar(
'wgDBpassword' ) );
556 $userExists = $conn->roleExists( $this->
getVar(
'wgDBuser' ) );
557 if ( !$userExists ) {
560 $sql =
"CREATE ROLE $safeuser NOCREATEDB LOGIN PASSWORD $safepass";
566 $sql .=
' ROLE' . $conn->addIdentifierQuotes( $this->
getVar(
'_InstallUser' ) );
569 $conn->query( $sql, __METHOD__ );
571 return Status::newFatal(
'config-install-user-create-failed',
572 $this->
getVar(
'wgDBuser' ), $e->getMessage() );
576 return Status::newGood();
580 $port = $this->
getVar(
'wgDBport' );
581 $useSsl = $this->
getVar(
'wgDBssl' ) ?
'true' :
'false';
582 $schema = $this->
getVar(
'wgDBmwschema' );
584 return "# Postgres specific settings
585 \$wgDBport = \"{$port}\";
586 \$wgDBssl = {$useSsl};
587 \$wgDBmwschema = \"{$schema}\";";
593 # Normal user and password are selected after this step, so for now
594 # just copy these two
596 $wgDBpassword = $this->
getVar(
'_InstallPassword' );
600 $schema = $this->
getVar(
'wgDBmwschema' );
603 if ( !$status->isOK() ) {
608 $conn = $status->value;
609 '@phan-var DatabasePostgres $conn';
611 if ( $conn->tableExists(
'archive', __METHOD__ ) ) {
612 $status->warning(
'config-install-tables-exist' );
618 $conn->begin( __METHOD__ );
620 if ( !$conn->schemaExists( $schema ) ) {
621 $status->fatal(
'config-install-pg-schema-not-exist' );
627 if ( $error !==
true ) {
628 $conn->reportQueryError( $error, 0,
'', __METHOD__ );
629 $conn->rollback( __METHOD__ );
630 $status->fatal(
'config-install-tables-failed', $error );
633 if ( $error !==
true ) {
634 $conn->reportQueryError( $error, 0,
'', __METHOD__ );
635 $conn->rollback( __METHOD__ );
636 $status->fatal(
'config-install-tables-manual-failed', $error );
638 $conn->commit( __METHOD__ );
642 if ( $status->isOK() ) {
651 return Status::newGood();
657 return array_merge( parent::getGlobalDefaults(), [
658 'wgDBmwschema' =>
'mediawiki',
666 if ( !$status->isOK() ) {
672 $conn = $status->value;
674 $exists = (bool)$conn->selectField(
'"pg_catalog"."pg_language"',
'1',
675 [
'lanname' =>
'plpgsql' ], __METHOD__ );
678 return Status::newGood();
683 $exists = (bool)$conn->selectField(
684 [
'"pg_catalog"."pg_class"',
'"pg_catalog"."pg_namespace"' ],
687 'pg_namespace.oid=relnamespace',
688 'nspname' =>
'pg_catalog',
689 'relname' =>
'pg_pltemplate',
694 $conn->query(
'CREATE LANGUAGE plpgsql', __METHOD__ );
696 return Status::newFatal(
'config-pg-no-plpgsql', $this->
getVar(
'wgDBname' ) );
699 return Status::newFatal(
'config-pg-no-plpgsql', $this->
getVar(
'wgDBname' ) );
702 return Status::newGood();
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Base class for DBMS-specific installation helper classes.
getWebUserBox( $noCreateMsg=false)
Get a standard web-user fieldset.
submitWebUserBox()
Submit the form from getWebUserBox().
static checkExtension( $name)
Convenience function.
enableLB()
Set up LBFactory so that wfGetDB() etc.
Database $db
The database connection.
getGeneratedSchemaPath( $db)
Return a path to the DBMS-specific automatically generated schema file.
setVarsFromRequest( $varNames)
Convenience function to set variables based on form data.
getCheckBox( $var, $label, $attribs=[], $helpData="")
Get a labelled checkbox to configure a local boolean variable.
getSchemaPath( $db)
Return a path to the DBMS-specific schema file, otherwise default to tables.sql.
getVar( $var, $default=null)
Get a variable, taking local defaults into account.
getTextBox( $var, $label, $attribs=[], $helpData="")
Get a labelled text box to configure a local variable.
setVar( $name, $value)
Convenience alias for $this->parent->setVar()
submitInstallUserBox()
Submit a standard install user fieldset.
getInstallUserBox()
Get a standard install-user fieldset.
Class for setting up the MediaWiki database using Postgres.
getConnection()
Connect to the database using the administrative user/password currently defined in the session.
getPgConnection( $type)
Get a special type of connection.
openConnectionToAnyDB( $user, $password)
getName()
Return the internal name, e.g.
openConnectionWithParams( $user, $password, $dbName, $schema)
Open a PG connection with given parameters.
preUpgrade()
Allow DB installers a chance to make checks before upgrade.
setupDatabase()
Create the database and return a Status object indicating success or failure.
getGlobalDefaults()
Get a name=>value map of MW configuration globals for the default values.
createManualTables()
Create database tables from scratch.
createTables()
Create database tables from scratch from the automatically generated file.
getConnectForm()
Get HTML for a web form that configures this database.
submitSettingsForm()
Set variables based on the request array, assuming it was submitted via the form return by getSetting...
static $notMinimumVersionMessage
preInstall()
Allow DB installers a chance to make last-minute changes before installation occurs.
openConnection()
Open a connection to the database using the administrative user/password currently defined in the ses...
getInstallUserPermissions()
isRoleMember( $conn, $targetMember, $group, $maxDepth)
Recursive helper for canCreateObjectsForWebUser().
canCreateObjectsForWebUser()
Returns true if the install user is able to create objects owned by the web user, false otherwise.
getSettingsForm()
Get HTML for a web form that retrieves settings used for installation.
getLocalSettings()
Get the DBMS-specific options for LocalSettings.php generation.
openPgConnection( $type)
Get a connection of a specific PostgreSQL-specific type.
submitConnectForm()
Set variables based on the request array, assuming it was submitted via the form returned by getConne...
Postgres database abstraction layer.
$wgDBuser
Config variable stub for the DBuser setting, for use by phpdoc and IDEs.
$wgDBpassword
Config variable stub for the DBpassword setting, for use by phpdoc and IDEs.