2011-04-12 17:07:01 +00:00
|
|
|
<?php
|
|
|
|
|
/**
|
|
|
|
|
* IBM_DB2-specific installer.
|
|
|
|
|
*
|
2012-05-06 05:50:15 +00:00
|
|
|
* 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
|
|
|
|
|
*
|
2011-04-12 17:07:01 +00:00
|
|
|
* @file
|
|
|
|
|
* @ingroup Deployment
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Class for setting up the MediaWiki database using IBM_DB2.
|
|
|
|
|
*
|
|
|
|
|
* @ingroup Deployment
|
|
|
|
|
* @since 1.17
|
|
|
|
|
*/
|
|
|
|
|
class Ibm_db2Installer extends DatabaseInstaller {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected $globalNames = array(
|
|
|
|
|
'wgDBserver',
|
|
|
|
|
'wgDBport',
|
|
|
|
|
'wgDBname',
|
|
|
|
|
'wgDBuser',
|
|
|
|
|
'wgDBpassword',
|
|
|
|
|
'wgDBmwschema',
|
|
|
|
|
);
|
|
|
|
|
|
PostgreSQL install fixes:
* Made PG throw a DBQueryError when it gets a query error, instead of DBUnexpectedError. Apparently this mistake goes back to r14625, when exceptions were first introduced. Did it by removing reportQueryError(), the DatabaseBase version works fine.
* Fixed several places where there was an attempt to check for a query error by checking if the result of query() was false. This never worked. Used try/catch instead.
* Made the DBConnectionError messages go on one line so that they don't mess up the formatting in the installer.
* In DatabasePostgres::selectDB(), only disconnect and reconnect if the DB name is actually changing.
* Made DatabasePostgres::schemaExists() less weird and scary.
* Added DatabasePostgres::roleExists() for use by the installer.
* Removed the PostgreSQL-specific hack to make _InstallUser have a default other than "root". Made _InstallUser into a proper DBMS-specific internal variable instead, since every DBMS we support so far needs a different default.
* Removed the $dbName parameters from openConnection/getConnection, and got rid of $this->useAdmin. Implemented a more sophisticated caching scheme instead. Partial revert of r89389 and r81440.
* When connecting as the install user before DB creation, and when testing the web user's credentials, try a few different database names and use whichever one works.
* Instead of connecting as the web user to create tables, I used SET ROLE. It seems cleaner and more like what the other DBMSes do during installation. "SET ROLE wikiuser" requires the same privileges as "CREATE SCHEMA ... AUTHORIZATION wikiuser", so it's unlikely to break anything.
* In the area of web account creation, fixed various minor logic errors and introduced more informative error messages at the submit stage, pre-install. Show a helpful error message if the web user exists already and the install user can't do the relevant SET ROLE.
* Split schema creation out to a separate install step.
* When creating an account as a non-superuser, add the administrative account to the new account's group. This is necessary to avoid a fatal error during installation (bug 28845).
* Removed code which alters an existing web user to have appropriate search paths and permissions. This may break other apps and is not necessary. As in other DBMSes, If the web user exists, it is the responsibility of the sysadmin to ensure that it has appropriate permissions.
* Rewrote setupPLpgSQL() to use the query builder functions.
2011-06-10 11:32:57 +00:00
|
|
|
protected $internalDefaults = array(
|
|
|
|
|
'_InstallUser' => 'db2admin'
|
|
|
|
|
);
|
|
|
|
|
|
2011-04-12 17:07:01 +00:00
|
|
|
/**
|
|
|
|
|
* Get the DB2 database extension name
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public function getName(){
|
|
|
|
|
return 'ibm_db2';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine whether the DB2 database extension is currently available in PHP
|
|
|
|
|
* @return boolean
|
|
|
|
|
*/
|
|
|
|
|
public function isCompiled() {
|
|
|
|
|
return self::checkExtension( 'ibm_db2' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Generate a connection form for a DB2 database
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public function getConnectForm() {
|
|
|
|
|
return
|
|
|
|
|
$this->getTextBox( 'wgDBserver', 'config-db-host', array(), $this->parent->getHelpBox( 'config-db-host-help' ) ) .
|
|
|
|
|
$this->getTextBox( 'wgDBport', 'config-db-port', array(), $this->parent->getHelpBox( 'config-db-port' ) ) .
|
|
|
|
|
Html::openElement( 'fieldset' ) .
|
|
|
|
|
Html::element( 'legend', array(), wfMsg( 'config-db-wiki-settings' ) ) .
|
|
|
|
|
$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' ) .
|
|
|
|
|
$this->getInstallUserBox();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validate and then execute the connection form for a DB2 database
|
|
|
|
|
* @return Status
|
|
|
|
|
*/
|
|
|
|
|
public function submitConnectForm() {
|
|
|
|
|
// Get variables from the request
|
2011-05-20 18:20:16 +00:00
|
|
|
$newValues = $this->setVarsFromRequest(
|
|
|
|
|
array( 'wgDBserver', 'wgDBport', 'wgDBname',
|
2011-04-12 17:07:01 +00:00
|
|
|
'wgDBmwschema', 'wgDBuser', 'wgDBpassword' ) );
|
|
|
|
|
|
|
|
|
|
// Validate them
|
|
|
|
|
$status = Status::newGood();
|
|
|
|
|
if ( !strlen( $newValues['wgDBname'] ) ) {
|
|
|
|
|
$status->fatal( 'config-missing-db-name' );
|
|
|
|
|
} elseif ( !preg_match( '/^[a-zA-Z0-9_]+$/', $newValues['wgDBname'] ) ) {
|
|
|
|
|
$status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] );
|
|
|
|
|
}
|
|
|
|
|
if ( !strlen( $newValues['wgDBmwschema'] ) ) {
|
|
|
|
|
$status->fatal( 'config-invalid-schema' );
|
|
|
|
|
}
|
|
|
|
|
elseif ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBmwschema'] ) ) {
|
|
|
|
|
$status->fatal( 'config-invalid-schema', $newValues['wgDBmwschema'] );
|
|
|
|
|
}
|
2011-04-12 17:18:35 +00:00
|
|
|
if ( !strlen( $newValues['wgDBport'] ) ) {
|
2011-04-12 17:07:01 +00:00
|
|
|
$status->fatal( 'config-invalid-port' );
|
|
|
|
|
}
|
|
|
|
|
elseif ( !preg_match( '/^[0-9_]*$/', $newValues['wgDBport'] ) ) {
|
|
|
|
|
$status->fatal( 'config-invalid-port', $newValues['wgDBport'] );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Submit user box
|
|
|
|
|
if ( $status->isOK() ) {
|
|
|
|
|
$status->merge( $this->submitInstallUserBox() );
|
|
|
|
|
}
|
|
|
|
|
if ( !$status->isOK() ) {
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-12 17:18:35 +00:00
|
|
|
global $wgDBport;
|
|
|
|
|
$wgDBport = $newValues['wgDBport'];
|
2011-04-12 17:07:01 +00:00
|
|
|
|
|
|
|
|
// Try to connect
|
|
|
|
|
$status->merge( $this->getConnection() );
|
|
|
|
|
if ( !$status->isOK() ) {
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->parent->setVar( 'wgDBuser', $this->getVar( '_InstallUser' ) );
|
|
|
|
|
$this->parent->setVar( 'wgDBpassword', $this->getVar( '_InstallPassword' ) );
|
|
|
|
|
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Open a DB2 database connection
|
|
|
|
|
* @return Status
|
|
|
|
|
*/
|
PostgreSQL install fixes:
* Made PG throw a DBQueryError when it gets a query error, instead of DBUnexpectedError. Apparently this mistake goes back to r14625, when exceptions were first introduced. Did it by removing reportQueryError(), the DatabaseBase version works fine.
* Fixed several places where there was an attempt to check for a query error by checking if the result of query() was false. This never worked. Used try/catch instead.
* Made the DBConnectionError messages go on one line so that they don't mess up the formatting in the installer.
* In DatabasePostgres::selectDB(), only disconnect and reconnect if the DB name is actually changing.
* Made DatabasePostgres::schemaExists() less weird and scary.
* Added DatabasePostgres::roleExists() for use by the installer.
* Removed the PostgreSQL-specific hack to make _InstallUser have a default other than "root". Made _InstallUser into a proper DBMS-specific internal variable instead, since every DBMS we support so far needs a different default.
* Removed the $dbName parameters from openConnection/getConnection, and got rid of $this->useAdmin. Implemented a more sophisticated caching scheme instead. Partial revert of r89389 and r81440.
* When connecting as the install user before DB creation, and when testing the web user's credentials, try a few different database names and use whichever one works.
* Instead of connecting as the web user to create tables, I used SET ROLE. It seems cleaner and more like what the other DBMSes do during installation. "SET ROLE wikiuser" requires the same privileges as "CREATE SCHEMA ... AUTHORIZATION wikiuser", so it's unlikely to break anything.
* In the area of web account creation, fixed various minor logic errors and introduced more informative error messages at the submit stage, pre-install. Show a helpful error message if the web user exists already and the install user can't do the relevant SET ROLE.
* Split schema creation out to a separate install step.
* When creating an account as a non-superuser, add the administrative account to the new account's group. This is necessary to avoid a fatal error during installation (bug 28845).
* Removed code which alters an existing web user to have appropriate search paths and permissions. This may break other apps and is not necessary. As in other DBMSes, If the web user exists, it is the responsibility of the sysadmin to ensure that it has appropriate permissions.
* Rewrote setupPLpgSQL() to use the query builder functions.
2011-06-10 11:32:57 +00:00
|
|
|
public function openConnection() {
|
2011-04-12 17:07:01 +00:00
|
|
|
$status = Status::newGood();
|
|
|
|
|
try {
|
|
|
|
|
$db = new DatabaseIbm_db2(
|
|
|
|
|
$this->getVar( 'wgDBserver' ),
|
|
|
|
|
$this->getVar( '_InstallUser' ),
|
|
|
|
|
$this->getVar( '_InstallPassword' ),
|
|
|
|
|
$this->getVar( 'wgDBname' ),
|
|
|
|
|
0,
|
|
|
|
|
$this->getVar( 'wgDBmwschema' )
|
|
|
|
|
);
|
|
|
|
|
$status->value = $db;
|
|
|
|
|
} catch ( DBConnectionError $e ) {
|
|
|
|
|
$status->fatal( 'config-connection-error', $e->getMessage() );
|
|
|
|
|
}
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a DB2 database for MediaWiki
|
|
|
|
|
* @return Status
|
|
|
|
|
*/
|
|
|
|
|
public function setupDatabase() {
|
|
|
|
|
$status = $this->getConnection();
|
|
|
|
|
if ( !$status->isOK() ) {
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
2011-10-18 17:26:09 +00:00
|
|
|
/**
|
|
|
|
|
* @var $conn DatabaseBase
|
|
|
|
|
*/
|
2011-04-12 17:07:01 +00:00
|
|
|
$conn = $status->value;
|
|
|
|
|
$dbName = $this->getVar( 'wgDBname' );
|
|
|
|
|
if( !$conn->selectDB( $dbName ) ) {
|
|
|
|
|
$conn->query( "CREATE DATABASE "
|
2011-05-20 18:20:16 +00:00
|
|
|
. $conn->addIdentifierQuotes( $dbName )
|
2011-04-12 17:07:01 +00:00
|
|
|
. " AUTOMATIC STORAGE YES"
|
|
|
|
|
. " USING CODESET UTF-8 TERRITORY US COLLATE USING SYSTEM"
|
|
|
|
|
. " PAGESIZE 32768", __METHOD__ );
|
|
|
|
|
$conn->selectDB( $dbName );
|
|
|
|
|
}
|
|
|
|
|
$this->setupSchemaVars();
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create tables from scratch.
|
|
|
|
|
* First check if pagesize >= 32k.
|
|
|
|
|
*
|
|
|
|
|
* @return Status
|
|
|
|
|
*/
|
|
|
|
|
public function createTables() {
|
|
|
|
|
$status = $this->getConnection();
|
|
|
|
|
if ( !$status->isOK() ) {
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
$this->db->selectDB( $this->getVar( 'wgDBname' ) );
|
|
|
|
|
|
|
|
|
|
if( $this->db->tableExists( 'user' ) ) {
|
|
|
|
|
$status->warning( 'config-install-tables-exist' );
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check for pagesize */
|
|
|
|
|
$status = $this->checkPageSize();
|
|
|
|
|
if ( !$status->isOK() ) {
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->db->setFlag( DBO_DDLMODE ); // For Oracle's handling of schema files
|
|
|
|
|
$this->db->begin( __METHOD__ );
|
|
|
|
|
|
2011-06-20 07:16:09 +00:00
|
|
|
$error = $this->db->sourceFile( $this->db->getSchemaPath() );
|
2011-04-12 17:07:01 +00:00
|
|
|
if( $error !== true ) {
|
|
|
|
|
$this->db->reportQueryError( $error, 0, '', __METHOD__ );
|
|
|
|
|
$this->db->rollback( __METHOD__ );
|
|
|
|
|
$status->fatal( 'config-install-tables-failed', $error );
|
|
|
|
|
} else {
|
|
|
|
|
$this->db->commit( __METHOD__ );
|
|
|
|
|
}
|
|
|
|
|
// Resume normal operations
|
|
|
|
|
if( $status->isOk() ) {
|
|
|
|
|
$this->enableLB();
|
|
|
|
|
}
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if database has a tablspace with pagesize >= 32k.
|
|
|
|
|
*
|
|
|
|
|
* @return Status
|
|
|
|
|
*/
|
|
|
|
|
public function checkPageSize() {
|
|
|
|
|
$status = $this->getConnection();
|
|
|
|
|
if ( !$status->isOK() ) {
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
$this->db->selectDB( $this->getVar( 'wgDBname' ) );
|
|
|
|
|
|
|
|
|
|
try {
|
2011-12-16 21:17:20 +00:00
|
|
|
$result = $this->db->query( 'SELECT PAGESIZE FROM SYSCAT.TABLESPACES FOR READ ONLY' );
|
2011-04-12 17:07:01 +00:00
|
|
|
if( $result == false ) {
|
|
|
|
|
$status->fatal( 'config-connection-error', '' );
|
2011-10-16 03:27:12 +00:00
|
|
|
} else {
|
|
|
|
|
$row = $this->db->fetchRow( $result );
|
|
|
|
|
while ( $row ) {
|
2011-04-12 17:07:01 +00:00
|
|
|
if( $row[0] >= 32768 ) {
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
2011-10-16 03:27:12 +00:00
|
|
|
$row = $this->db->fetchRow( $result );
|
2011-04-12 17:07:01 +00:00
|
|
|
}
|
|
|
|
|
$status->fatal( 'config-ibm_db2-low-db-pagesize', '' );
|
|
|
|
|
}
|
|
|
|
|
} catch ( DBUnexpectedError $e ) {
|
|
|
|
|
$status->fatal( 'config-connection-error', $e->getMessage() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Generate the code to store the DB2-specific settings defined by the configuration form
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public function getLocalSettings() {
|
|
|
|
|
$schema = LocalSettingsGenerator::escapePhpString( $this->getVar( 'wgDBmwschema' ) );
|
|
|
|
|
$port = LocalSettingsGenerator::escapePhpString( $this->getVar( 'wgDBport' ) );
|
|
|
|
|
return
|
|
|
|
|
"# IBM_DB2 specific settings
|
|
|
|
|
\$wgDBmwschema = \"{$schema}\";
|
|
|
|
|
\$wgDBport = \"{$port}\";";
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-16 21:17:20 +00:00
|
|
|
public function __construct( $parent ) {
|
|
|
|
|
parent::__construct( $parent );
|
2011-04-12 17:07:01 +00:00
|
|
|
}
|
PostgreSQL install fixes:
* Made PG throw a DBQueryError when it gets a query error, instead of DBUnexpectedError. Apparently this mistake goes back to r14625, when exceptions were first introduced. Did it by removing reportQueryError(), the DatabaseBase version works fine.
* Fixed several places where there was an attempt to check for a query error by checking if the result of query() was false. This never worked. Used try/catch instead.
* Made the DBConnectionError messages go on one line so that they don't mess up the formatting in the installer.
* In DatabasePostgres::selectDB(), only disconnect and reconnect if the DB name is actually changing.
* Made DatabasePostgres::schemaExists() less weird and scary.
* Added DatabasePostgres::roleExists() for use by the installer.
* Removed the PostgreSQL-specific hack to make _InstallUser have a default other than "root". Made _InstallUser into a proper DBMS-specific internal variable instead, since every DBMS we support so far needs a different default.
* Removed the $dbName parameters from openConnection/getConnection, and got rid of $this->useAdmin. Implemented a more sophisticated caching scheme instead. Partial revert of r89389 and r81440.
* When connecting as the install user before DB creation, and when testing the web user's credentials, try a few different database names and use whichever one works.
* Instead of connecting as the web user to create tables, I used SET ROLE. It seems cleaner and more like what the other DBMSes do during installation. "SET ROLE wikiuser" requires the same privileges as "CREATE SCHEMA ... AUTHORIZATION wikiuser", so it's unlikely to break anything.
* In the area of web account creation, fixed various minor logic errors and introduced more informative error messages at the submit stage, pre-install. Show a helpful error message if the web user exists already and the install user can't do the relevant SET ROLE.
* Split schema creation out to a separate install step.
* When creating an account as a non-superuser, add the administrative account to the new account's group. This is necessary to avoid a fatal error during installation (bug 28845).
* Removed code which alters an existing web user to have appropriate search paths and permissions. This may break other apps and is not necessary. As in other DBMSes, If the web user exists, it is the responsibility of the sysadmin to ensure that it has appropriate permissions.
* Rewrote setupPLpgSQL() to use the query builder functions.
2011-06-10 11:32:57 +00:00
|
|
|
}
|