Index: branches/REL1_17/phase3/maintenance/oracle/archives/patch_16_17_schema_changes.sql |
— | — | @@ -31,7 +31,8 @@ |
32 | 32 | ALTER TABLE &mw_prefix.image MODIFY img_bits DEFAULT 0 NOT NULL; |
33 | 33 | ALTER TABLE &mw_prefix.image MODIFY img_user DEFAULT 0 NOT NULL; |
34 | 34 | |
35 | | -ALTER TABLE &mw_prefix.interwiki ADD iw_api BLOB NOT NULL; |
| 35 | +ALTER TABLE &mw_prefix.interwiki ADD iw_api BLOB DEFAULT EMPTY_BLOB(); |
| 36 | +ALTER TABLE &mw_prefix.interwiki MODIFY iw_api DEFAULT NULL NOT NULL; |
36 | 37 | ALTER TABLE &mw_prefix.interwiki ADD iw_wikiid VARCHAR2(64); |
37 | 38 | |
38 | 39 | ALTER TABLE &mw_prefix.ipblocks MODIFY ipb_user DEFAULT 0 NOT NULL; |
Index: branches/REL1_17/phase3/maintenance/oracle/tables.sql |
— | — | @@ -803,7 +803,6 @@ |
804 | 804 | FROM user_triggers |
805 | 805 | WHERE table_name = p_oldprefix || p_tabname) LOOP |
806 | 806 | l_temp_ei_sql := SUBSTR(rc.ddlvc2, 1, INSTR(rc.ddlvc2, 'ALTER ') - 1); |
807 | | - dbms_output.put_line(l_temp_ei_sql); |
808 | 807 | EXECUTE IMMEDIATE l_temp_ei_sql; |
809 | 808 | END LOOP; |
810 | 809 | END; |
Index: branches/REL1_17/phase3/includes/db/DatabaseOracle.php |
— | — | @@ -7,21 +7,6 @@ |
8 | 8 | */ |
9 | 9 | |
10 | 10 | /** |
11 | | - * @ingroup Database |
12 | | - */ |
13 | | -class ORABlob { |
14 | | - var $mData; |
15 | | - |
16 | | - function __construct( $data ) { |
17 | | - $this->mData = $data; |
18 | | - } |
19 | | - |
20 | | - function getData() { |
21 | | - return $this->mData; |
22 | | - } |
23 | | -} |
24 | | - |
25 | | -/** |
26 | 11 | * The oci8 extension is fairly weak and doesn't support oci_num_rows, among |
27 | 12 | * other things. We use a wrapper class to handle that and other |
28 | 13 | * Oracle-specific bits, like converting column names back to lowercase. |
— | — | @@ -496,7 +481,7 @@ |
497 | 482 | } |
498 | 483 | |
499 | 484 | if ( $val === null ) { |
500 | | - if ( $col_info != false && $col_info->nullable() == 0 && $col_info->defaultValue() != null ) { |
| 485 | + if ( $col_info != false && $col_info->isNullable() == 0 && $col_info->defaultValue() != null ) { |
501 | 486 | $bind .= 'DEFAULT'; |
502 | 487 | } else { |
503 | 488 | $bind .= 'NULL'; |
— | — | @@ -862,6 +847,37 @@ |
863 | 848 | return $this->doQuery( 'BEGIN DUPLICATE_TABLE(\'' . $tabName . '\', \'' . $oldPrefix . '\', \'' . strtoupper( $wgDBprefix ) . '\', ' . $temporary . '); END;' ); |
864 | 849 | } |
865 | 850 | |
| 851 | + function listTables( $prefix = null, $fname = 'DatabaseOracle::listTables' ) { |
| 852 | + $listWhere = ''; |
| 853 | + if (!empty($prefix)) { |
| 854 | + $listWhere = ' AND table_name LIKE \''.strtoupper($prefix).'%\''; |
| 855 | + } |
| 856 | + |
| 857 | + $result = $this->doQuery( "SELECT table_name FROM user_tables WHERE table_name NOT LIKE '%!_IDX$_' ESCAPE '!' $listWhere" ); |
| 858 | + |
| 859 | + // dirty code ... i know |
| 860 | + $endArray = array(); |
| 861 | + $endArray[] = $prefix.'MWUSER'; |
| 862 | + $endArray[] = $prefix.'PAGE'; |
| 863 | + $endArray[] = $prefix.'IMAGE'; |
| 864 | + $fixedOrderTabs = $endArray; |
| 865 | + while (($row = $result->fetchRow()) !== false) { |
| 866 | + if (!in_array($row['table_name'], $fixedOrderTabs)) |
| 867 | + $endArray[] = $row['table_name']; |
| 868 | + } |
| 869 | + |
| 870 | + return $endArray; |
| 871 | + } |
| 872 | + |
| 873 | + public function dropTable( $tableName, $fName = 'DatabaseOracle::dropTable' ) { |
| 874 | + $tableName = $this->tableName($tableName); |
| 875 | + if( !$this->tableExists( $tableName ) ) { |
| 876 | + return false; |
| 877 | + } |
| 878 | + |
| 879 | + return $this->doQuery( "DROP TABLE $tableName CASCADE CONSTRAINTS PURGE" ); |
| 880 | + } |
| 881 | + |
866 | 882 | function timestamp( $ts = 0 ) { |
867 | 883 | return wfTimestamp( TS_ORACLE, $ts ); |
868 | 884 | } |
— | — | @@ -910,6 +926,7 @@ |
911 | 927 | * Query whether a given table exists (in the given schema, or the default mw one if not given) |
912 | 928 | */ |
913 | 929 | function tableExists( $table ) { |
| 930 | + $table = trim($this->tableName($table), '"'); |
914 | 931 | $SQL = "SELECT 1 FROM user_tables WHERE table_name='$table'"; |
915 | 932 | $res = $this->doQuery( $SQL ); |
916 | 933 | if ( $res ) { |
— | — | @@ -1048,7 +1065,7 @@ |
1049 | 1066 | } |
1050 | 1067 | } else { |
1051 | 1068 | foreach ( $replacements as $mwVar => $scVar ) { |
1052 | | - $cmd = str_replace( '&' . $scVar . '.', '{$' . $mwVar . '}', $cmd ); |
| 1069 | + $cmd = str_replace( '&' . $scVar . '.', '`{$' . $mwVar . '}`', $cmd ); |
1053 | 1070 | } |
1054 | 1071 | |
1055 | 1072 | $cmd = $this->replaceVars( $cmd ); |
— | — | @@ -1126,24 +1143,35 @@ |
1127 | 1144 | return "'" . $this->strencode( $s ) . "'"; |
1128 | 1145 | } |
1129 | 1146 | |
| 1147 | + public function addIdentifierQuotes( $s ) { |
| 1148 | + if ( !$this->mFlags & DBO_DDLMODE ) { |
| 1149 | + $s = '"' . str_replace( '"', '""', $s ) . '"'; |
| 1150 | + } |
| 1151 | + return $s; |
| 1152 | + } |
| 1153 | + |
1130 | 1154 | function selectRow( $table, $vars, $conds, $fname = 'DatabaseOracle::selectRow', $options = array(), $join_conds = array() ) { |
1131 | 1155 | global $wgContLang; |
1132 | 1156 | |
1133 | | - $conds2 = array(); |
1134 | | - $conds = ( $conds != null && !is_array( $conds ) ) ? array( $conds ) : $conds; |
1135 | | - foreach ( $conds as $col => $val ) { |
1136 | | - $col_info = $this->fieldInfoMulti( $table, $col ); |
1137 | | - $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; |
1138 | | - if ( $col_type == 'CLOB' ) { |
1139 | | - $conds2['TO_CHAR(' . $col . ')'] = $wgContLang->checkTitleEncoding( $val ); |
1140 | | - } elseif ( $col_type == 'VARCHAR2' && !mb_check_encoding( $val ) ) { |
1141 | | - $conds2[$col] = $wgContLang->checkTitleEncoding( $val ); |
1142 | | - } else { |
1143 | | - $conds2[$col] = $val; |
| 1157 | + if ($conds != null) { |
| 1158 | + $conds2 = array(); |
| 1159 | + $conds = ( !is_array( $conds ) ) ? array( $conds ) : $conds; |
| 1160 | + foreach ( $conds as $col => $val ) { |
| 1161 | + $col_info = $this->fieldInfoMulti( $table, $col ); |
| 1162 | + $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; |
| 1163 | + if ( $col_type == 'CLOB' ) { |
| 1164 | + $conds2['TO_CHAR(' . $col . ')'] = $wgContLang->checkTitleEncoding( $val ); |
| 1165 | + } elseif ( $col_type == 'VARCHAR2' && !mb_check_encoding( $val ) ) { |
| 1166 | + $conds2[$col] = $wgContLang->checkTitleEncoding( $val ); |
| 1167 | + } else { |
| 1168 | + $conds2[$col] = $val; |
| 1169 | + } |
1144 | 1170 | } |
| 1171 | + |
| 1172 | + return parent::selectRow( $table, $vars, $conds2, $fname, $options, $join_conds ); |
| 1173 | + } else { |
| 1174 | + return parent::selectRow( $table, $vars, $conds, $fname, $options, $join_conds ); |
1145 | 1175 | } |
1146 | | - |
1147 | | - return parent::selectRow( $table, $vars, $conds2, $fname, $options, $join_conds ); |
1148 | 1176 | } |
1149 | 1177 | |
1150 | 1178 | /** |
— | — | @@ -1192,9 +1220,9 @@ |
1193 | 1221 | public function delete( $table, $conds, $fname = 'DatabaseOracle::delete' ) { |
1194 | 1222 | global $wgContLang; |
1195 | 1223 | |
1196 | | - if ( $wgContLang != null && $conds != '*' ) { |
| 1224 | + if ( $wgContLang != null && $conds != null && $conds != '*' ) { |
1197 | 1225 | $conds2 = array(); |
1198 | | - $conds = ( $conds != null && !is_array( $conds ) ) ? array( $conds ) : $conds; |
| 1226 | + $conds = ( !is_array( $conds ) ) ? array( $conds ) : $conds; |
1199 | 1227 | foreach ( $conds as $col => $val ) { |
1200 | 1228 | $col_info = $this->fieldInfoMulti( $table, $col ); |
1201 | 1229 | $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; |
Index: branches/REL1_17/phase3/includes/db/Database.php |
— | — | @@ -540,6 +540,27 @@ |
541 | 541 | return new DatabaseMysql( $server, $user, $password, $dbName, $flags ); |
542 | 542 | } |
543 | 543 | |
| 544 | + /** |
| 545 | + * Given a DB type, construct the name of the appropriate child class of |
| 546 | + * DatabaseBase. This is designed to replace all of the manual stuff like: |
| 547 | + * $class = 'Database' . ucfirst( strtolower( $type ) ); |
| 548 | + * as well as validate against the canonical list of DB types we have |
| 549 | + * |
| 550 | + * @param $dbType String A possible DB type |
| 551 | + * @return DatabaseBase subclass or null |
| 552 | + */ |
| 553 | + public final static function classFromType( $dbType ) { |
| 554 | + $canonicalDBTypes = array( |
| 555 | + 'mysql', 'postgres', 'sqlite', 'oracle', 'mssql', 'ibm_db2' |
| 556 | + ); |
| 557 | + $dbType = strtolower( $dbType ); |
| 558 | + if( in_array( $dbType, $canonicalDBTypes ) ) { |
| 559 | + return 'Database' . ucfirst( $dbType ); |
| 560 | + } else { |
| 561 | + return null; |
| 562 | + } |
| 563 | + } |
| 564 | + |
544 | 565 | protected function installErrorHandler() { |
545 | 566 | $this->mPHPError = false; |
546 | 567 | $this->htmlErrors = ini_set( 'html_errors', '0' ); |
Property changes on: branches/REL1_17/phase3/includes/db/Database.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
547 | 568 | Merged /trunk/phase3/includes/db/Database.php:r79828,79830,79848,79853,79950-79951,79954,79989,80006-80007,80013,80016,80080,80083,80124,80128,80238 |
Index: branches/REL1_17/phase3/includes/db/LoadBalancer.php |
— | — | @@ -625,7 +625,7 @@ |
626 | 626 | } |
627 | 627 | |
628 | 628 | # Get class for this database type |
629 | | - $class = 'Database' . ucfirst( $type ); |
| 629 | + $class = DatabaseBase::classFromType( $type ); |
630 | 630 | |
631 | 631 | # Create object |
632 | 632 | wfDebug( "Connecting to $host $dbname...\n" ); |
Index: branches/REL1_17/phase3/includes/filerepo/ForeignDBRepo.php |
— | — | @@ -35,7 +35,7 @@ |
36 | 36 | |
37 | 37 | function getMasterDB() { |
38 | 38 | if ( !isset( $this->dbConn ) ) { |
39 | | - $class = 'Database' . ucfirst( $this->dbType ); |
| 39 | + $class = DatabaseBase::classFromType( $this->dbType ); |
40 | 40 | $this->dbConn = new $class( $this->dbServer, $this->dbUser, |
41 | 41 | $this->dbPassword, $this->dbName, $this->dbFlags, |
42 | 42 | $this->tablePrefix ); |
Property changes on: branches/REL1_17/phase3/includes/filerepo/ForeignDBRepo.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
43 | 43 | Merged /trunk/phase3/includes/filerepo/ForeignDBRepo.php:r79828,79830,79848,79853,79950-79951,79954,79989,80006-80007,80013,80016,80080,80083,80124,80128,80238 |
Index: branches/REL1_17/phase3/includes/installer/CoreInstaller.php |
— | — | @@ -263,7 +263,7 @@ |
264 | 264 | */ |
265 | 265 | public function setParserLanguage( $lang ) { |
266 | 266 | $this->parserOptions->setTargetLanguage( $lang ); |
267 | | - $this->parserOptions->setUserLang( $lang ); |
| 267 | + $this->parserOptions->setUserLang( $lang->getCode() ); |
268 | 268 | } |
269 | 269 | |
270 | 270 | /** |
— | — | @@ -345,45 +345,37 @@ |
346 | 346 | array( 'name' => 'sysop', 'callback' => array( $this, 'createSysop' ) ), |
347 | 347 | array( 'name' => 'mainpage', 'callback' => array( $this, 'createMainpage' ) ), |
348 | 348 | ); |
| 349 | + |
| 350 | + // Build the array of install steps starting from the core install list, |
| 351 | + // then adding any callbacks that wanted to attach after a given step |
| 352 | + foreach( $coreInstallSteps as $step ) { |
| 353 | + $this->installSteps[] = $step; |
| 354 | + if( isset( $this->extraInstallSteps[ $step['name'] ] ) ) { |
| 355 | + $this->installSteps = array_merge( |
| 356 | + $this->installSteps, |
| 357 | + $this->extraInstallSteps[ $step['name'] ] |
| 358 | + ); |
| 359 | + } |
| 360 | + } |
| 361 | + |
| 362 | + // Prepend any steps that want to be at the beginning |
| 363 | + if( isset( $this->extraInstallSteps['BEGINNING'] ) ) { |
| 364 | + $this->installSteps = array_merge( |
| 365 | + $this->extraInstallSteps['BEGINNING'], |
| 366 | + $this->installSteps |
| 367 | + ); |
| 368 | + } |
| 369 | + |
| 370 | + // Extensions should always go first, chance to tie into hooks and such |
349 | 371 | if( count( $this->getVar( '_Extensions' ) ) ) { |
350 | | - array_unshift( $coreInstallSteps, |
| 372 | + array_unshift( $this->installSteps, |
351 | 373 | array( 'name' => 'extensions', 'callback' => array( $this, 'includeExtensions' ) ) |
352 | 374 | ); |
353 | 375 | } |
354 | | - $this->installSteps = $coreInstallSteps; |
355 | | - foreach( $this->extraInstallSteps as $step ) { |
356 | | - // Put the step at the beginning |
357 | | - if( !strval( $step['position' ] ) ) { |
358 | | - array_unshift( $installSteps, $step['callback'] ); |
359 | | - continue; |
360 | | - } else { |
361 | | - // Walk the $coreInstallSteps array to see if we can modify |
362 | | - // $this->installSteps with a callback that wants to attach after |
363 | | - // a given step |
364 | | - array_walk( |
365 | | - $coreInstallSteps, |
366 | | - array( $this, 'installStepCallback' ), |
367 | | - $step |
368 | | - ); |
369 | | - } |
370 | | - } |
371 | 376 | return $this->installSteps; |
372 | 377 | } |
373 | 378 | |
374 | 379 | /** |
375 | | - * Callback for getInstallSteps() - used for finding if a given $insertableStep |
376 | | - * should be inserted after the current $coreStep in question |
377 | | - */ |
378 | | - private function installStepCallback( $coreStep, $key, $insertableStep ) { |
379 | | - if( $coreStep['name'] == $insertableStep['position'] ) { |
380 | | - $front = array_slice( $this->installSteps, 0, $key + 1 ); |
381 | | - $front[] = $insertableStep['callback']; |
382 | | - $back = array_slice( $this->installSteps, $key + 1 ); |
383 | | - $this->installSteps = array_merge( $front, $back ); |
384 | | - } |
385 | | - } |
386 | | - |
387 | | - /** |
388 | 380 | * Actually perform the installation. |
389 | 381 | * |
390 | 382 | * @param $startCB A callback array for the beginning of each step |
— | — | @@ -592,9 +584,7 @@ |
593 | 585 | * @param $callback Array A valid callback array, with name and callback given |
594 | 586 | * @param $findStep String the step to find. Omit to put the step at the beginning |
595 | 587 | */ |
596 | | - public function addInstallStep( $callback, $findStep = '' ) { |
597 | | - $this->extraInstallSteps[] = array( |
598 | | - 'position' => $findStep, 'callback' => $callback |
599 | | - ); |
| 588 | + public function addInstallStep( $callback, $findStep = 'BEGINNING' ) { |
| 589 | + $this->extraInstallSteps[$findStep][] = $callback; |
600 | 590 | } |
601 | 591 | } |
Property changes on: branches/REL1_17/phase3/includes/installer/CoreInstaller.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
602 | 592 | Merged /trunk/phase3/includes/installer/CoreInstaller.php:r79828,79830,79848,79853,79950-79951,79954,79989,80006-80007,80013,80016,80080,80083,80124,80128,80238 |
Index: branches/REL1_17/phase3/includes/installer/Installer.i18n.php |
— | — | @@ -229,6 +229,7 @@ |
230 | 230 | 'config-header-oracle' => 'Oracle settings', |
231 | 231 | 'config-invalid-db-type' => 'Invalid database type', |
232 | 232 | 'config-missing-db-name' => 'You must enter a value for "Database name"', |
| 233 | + 'config-missing-db-host' => 'You must enter a value for "Database host"', |
233 | 234 | 'config-missing-db-server-oracle' => 'You must enter a value for "Database TNS"', |
234 | 235 | 'config-invalid-db-server-oracle' => 'Invalid database TNS "$1". |
235 | 236 | Use only ASCII letters (a-z, A-Z), numbers (0-9), underscores (_) and dots (.).', |
— | — | @@ -450,7 +451,11 @@ |
451 | 452 | 'config-install-pg-schema-failed' => 'Tables creation failed. |
452 | 453 | Make sure that the user "$1" can write to the schema "$2".', |
453 | 454 | 'config-install-pg-commit' => 'Committing changes', |
| 455 | + 'config-pg-plpgsql' => 'Checking for language PL/pgSQL', |
454 | 456 | 'config-pg-no-plpgsql' => 'You need to install the language PL/pgSQL in the database $1', |
| 457 | + 'config-install-pg-ts2' => 'Checking for tsearch2', |
| 458 | + 'config-install-pg-ts2-failed' => "'''FAILED''' tsearch2 must be installed in the database $1 |
| 459 | +Please read [$2 these instructions] or ask on #postgresql on irc.freenode.net</li>\n", |
455 | 460 | 'config-install-user' => 'Creating database user', |
456 | 461 | 'config-install-user-failed' => 'Granting permission to user "$1" failed: $2', |
457 | 462 | 'config-install-tables' => 'Creating tables', |
Index: branches/REL1_17/phase3/includes/installer/DatabaseInstaller.php |
— | — | @@ -129,8 +129,8 @@ |
130 | 130 | return $status; |
131 | 131 | } |
132 | 132 | |
| 133 | + $this->db->setFlag( DBO_DDLMODE ); // For Oracle's handling of schema files |
133 | 134 | $this->db->begin( __METHOD__ ); |
134 | | - |
135 | 135 | $error = $this->db->sourceFile( $this->db->getSchema() ); |
136 | 136 | if( $error !== true ) { |
137 | 137 | $this->db->reportQueryError( $error, 0, '', __METHOD__ ); |
Property changes on: branches/REL1_17/phase3/includes/installer/DatabaseInstaller.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
138 | 138 | Merged /trunk/phase3/includes/installer/DatabaseInstaller.php:r79828,79830,79848,79853,79950-79951,79954,79989,80006-80007,80013,80016,80080,80083,80124,80128,80238 |
Index: branches/REL1_17/phase3/includes/installer/MysqlInstaller.php |
— | — | @@ -74,6 +74,9 @@ |
75 | 75 | |
76 | 76 | // Validate them. |
77 | 77 | $status = Status::newGood(); |
| 78 | + if ( !strlen( $newValues['wgDBserver'] ) ) { |
| 79 | + $status->fatal( 'config-missing-db-host' ); |
| 80 | + } |
78 | 81 | if ( !strlen( $newValues['wgDBname'] ) ) { |
79 | 82 | $status->fatal( 'config-missing-db-name' ); |
80 | 83 | } elseif ( !preg_match( '/^[a-z0-9_-]+$/i', $newValues['wgDBname'] ) ) { |
— | — | @@ -410,7 +413,7 @@ |
411 | 414 | $conn = $status->value; |
412 | 415 | $dbName = $this->getVar( 'wgDBname' ); |
413 | 416 | if( !$conn->selectDB( $dbName ) ) { |
414 | | - $conn->query( "CREATE DATABASE `$dbName`", __METHOD__ ); |
| 417 | + $conn->query( "CREATE DATABASE " . $conn->addIdentifierQuotes( $dbName ), __METHOD__ ); |
415 | 418 | $conn->selectDB( $dbName ); |
416 | 419 | } |
417 | 420 | return $status; |
Index: branches/REL1_17/phase3/includes/installer/OracleInstaller.php |
— | — | @@ -15,7 +15,7 @@ |
16 | 16 | class OracleInstaller extends DatabaseInstaller { |
17 | 17 | |
18 | 18 | protected $globalNames = array( |
19 | | - 'wgDBport', |
| 19 | + 'wgDBserver', |
20 | 20 | 'wgDBname', |
21 | 21 | 'wgDBuser', |
22 | 22 | 'wgDBpassword', |
— | — | @@ -24,9 +24,10 @@ |
25 | 25 | |
26 | 26 | protected $internalDefaults = array( |
27 | 27 | '_OracleDefTS' => 'USERS', |
28 | | - '_OracleTempTS' => 'TEMP', |
29 | | - '_OracleUseSysdba' => true |
| 28 | + '_OracleTempTS' => 'TEMP' |
30 | 29 | ); |
| 30 | + |
| 31 | + protected $useSysDBA = false; |
31 | 32 | |
32 | 33 | public $minimumVersion = '9.0.1'; // 9iR1 |
33 | 34 | |
— | — | @@ -92,6 +93,7 @@ |
93 | 94 | } |
94 | 95 | |
95 | 96 | // Try to connect |
| 97 | + $this->useSysDBA = true; |
96 | 98 | $status = $this->getConnection(); |
97 | 99 | if ( !$status->isOK() ) { |
98 | 100 | return $status; |
— | — | @@ -110,13 +112,13 @@ |
111 | 113 | public function getConnection() { |
112 | 114 | $status = Status::newGood(); |
113 | 115 | try { |
114 | | - if ( $this->getVar( '_OracleUseSysdba' ) ) { |
| 116 | + if ( $this->useSysDBA ) { |
115 | 117 | $this->db = new DatabaseOracle( |
116 | 118 | $this->getVar( 'wgDBserver' ), |
117 | 119 | $this->getVar( '_InstallUser' ), |
118 | 120 | $this->getVar( '_InstallPassword' ), |
119 | 121 | $this->getVar( 'wgDBname' ), |
120 | | - DBO_SYSDBA, |
| 122 | + DBO_SYSDBA | DBO_DDLMODE, |
121 | 123 | $this->getVar( 'wgDBprefix' ) |
122 | 124 | ); |
123 | 125 | } else { |
— | — | @@ -147,17 +149,15 @@ |
148 | 150 | public function preInstall() { |
149 | 151 | # Add our user callback to installSteps, right before the tables are created. |
150 | 152 | $callback = array( |
151 | | - array( |
152 | | - 'name' => 'user', |
153 | | - 'callback' => array( $this, 'setupUser' ), |
154 | | - ) |
| 153 | + 'name' => 'user', |
| 154 | + 'callback' => array( $this, 'setupUser' ) |
155 | 155 | ); |
156 | 156 | $this->parent->addInstallStepFollowing( "database", $callback ); |
157 | 157 | } |
158 | 158 | |
159 | 159 | |
160 | 160 | public function setupDatabase() { |
161 | | - $this->parent->setVar( '_OracleUseSysdba', false ); |
| 161 | + $this->useSysDBA = false; |
162 | 162 | $status = Status::newGood(); |
163 | 163 | return $status; |
164 | 164 | } |
— | — | @@ -168,6 +168,8 @@ |
169 | 169 | if ( !$this->getVar( '_CreateDBAccount' ) ) { |
170 | 170 | return Status::newGood(); |
171 | 171 | } |
| 172 | + |
| 173 | + $this->useSysDBA = true; |
172 | 174 | $status = $this->getConnection(); |
173 | 175 | if ( !$status->isOK() ) { |
174 | 176 | return $status; |
— | — | @@ -180,6 +182,7 @@ |
181 | 183 | */ |
182 | 184 | $GLOBALS['_OracleDefTS'] = $this->getVar( '_OracleDefTS' ); |
183 | 185 | $GLOBALS['_OracleTempTS'] = $this->getVar( '_OracleTempTS' ); |
| 186 | + $this->db->setFlag( DBO_DDLMODE ); |
184 | 187 | $error = $this->db->sourceFile( "$IP/maintenance/oracle/user.sql" ); |
185 | 188 | if ( $error !== true || !$this->db->selectDB( $this->getVar( 'wgDBuser' ) ) ) { |
186 | 189 | $status->fatal( 'config-install-user-failed', $this->getVar( 'wgDBuser' ), $error ); |
Index: branches/REL1_17/phase3/includes/installer/PostgresInstaller.php |
— | — | @@ -25,6 +25,7 @@ |
26 | 26 | ); |
27 | 27 | |
28 | 28 | var $minimumVersion = '8.1'; |
| 29 | + private $ts2MaxVersion = '8.3'; // Doing ts2 is not necessary in PG > 8.3 |
29 | 30 | |
30 | 31 | function getName() { |
31 | 32 | return 'postgres'; |
— | — | @@ -80,6 +81,12 @@ |
81 | 82 | return $status; |
82 | 83 | } |
83 | 84 | |
| 85 | +/* //Make sure install user can create |
| 86 | + $status->merge( $this->canCreateAccounts() ); |
| 87 | + if ( !$status->isOK() ) { |
| 88 | + return $status; |
| 89 | + } */ |
| 90 | + |
84 | 91 | // Check version |
85 | 92 | $version = $this->db->getServerVersion(); |
86 | 93 | if ( version_compare( $version, $this->minimumVersion ) < 0 ) { |
— | — | @@ -91,7 +98,7 @@ |
92 | 99 | return $status; |
93 | 100 | } |
94 | 101 | |
95 | | - function getConnection() { |
| 102 | + function getConnection($database = 'template1') { |
96 | 103 | $status = Status::newGood(); |
97 | 104 | |
98 | 105 | try { |
— | — | @@ -99,7 +106,7 @@ |
100 | 107 | $this->getVar( 'wgDBserver' ), |
101 | 108 | $this->getVar( '_InstallUser' ), |
102 | 109 | $this->getVar( '_InstallPassword' ), |
103 | | - $this->getVar( 'wgDBname' ) ); |
| 110 | + $database ); |
104 | 111 | $status->value = $this->db; |
105 | 112 | } catch ( DBConnectionError $e ) { |
106 | 113 | $status->fatal( 'config-connection-error', $e->getMessage() ); |
— | — | @@ -107,13 +114,101 @@ |
108 | 115 | return $status; |
109 | 116 | } |
110 | 117 | |
| 118 | + protected function canCreateAccounts() { |
| 119 | + $status = $this->getConnection(); |
| 120 | + if ( !$status->isOK() ) { |
| 121 | + return false; |
| 122 | + } |
| 123 | + $conn = $status->value; |
| 124 | + |
| 125 | + $superuser = $this->getVar( '_InstallUser' ); |
| 126 | + |
| 127 | + $rights = $conn->selectField( 'pg_catalog.pg_user', |
| 128 | + 'CASE WHEN usesuper IS TRUE THEN |
| 129 | + CASE WHEN usecreatedb IS TRUE THEN 3 ELSE 1 END |
| 130 | + ELSE CASE WHEN usecreatedb IS TRUE THEN 2 ELSE 0 END |
| 131 | + END AS rights', |
| 132 | + array( 'usename' => $superuser ), __METHOD__ |
| 133 | + ); |
| 134 | + |
| 135 | + if( !$rights ) { |
| 136 | + return false; |
| 137 | + } |
| 138 | + |
| 139 | + if( $rights != 1 && $rights != 3 ) { |
| 140 | + return false; |
| 141 | + } |
| 142 | + |
| 143 | + return true; |
| 144 | + } |
| 145 | + |
| 146 | + public function getSettingsForm() { |
| 147 | + if ( $this->canCreateAccounts() ) { |
| 148 | + $noCreateMsg = false; |
| 149 | + } else { |
| 150 | + $noCreateMsg = 'config-db-web-no-create-privs'; |
| 151 | + } |
| 152 | + $s = $this->getWebUserBox( $noCreateMsg ); |
| 153 | + |
| 154 | + return $s; |
| 155 | + } |
| 156 | + |
| 157 | + public function submitSettingsForm() { |
| 158 | + $status = $this->submitWebUserBox(); |
| 159 | + if ( !$status->isOK() ) { |
| 160 | + return $status; |
| 161 | + } |
| 162 | + |
| 163 | + // Validate the create checkbox |
| 164 | + $canCreate = $this->canCreateAccounts(); |
| 165 | + if ( !$canCreate ) { |
| 166 | + $this->setVar( '_CreateDBAccount', false ); |
| 167 | + $create = false; |
| 168 | + } else { |
| 169 | + $create = $this->getVar( '_CreateDBAccount' ); |
| 170 | + } |
| 171 | + |
| 172 | + if ( !$create ) { |
| 173 | + // Test the web account |
| 174 | + try { |
| 175 | + new DatabasePostgres( |
| 176 | + $this->getVar( 'wgDBserver' ), |
| 177 | + $this->getVar( 'wgDBuser' ), |
| 178 | + $this->getVar( 'wgDBpassword' ), |
| 179 | + false, |
| 180 | + false, |
| 181 | + 0, |
| 182 | + $this->getVar( 'wgDBprefix' ) |
| 183 | + ); |
| 184 | + } catch ( DBConnectionError $e ) { |
| 185 | + return Status::newFatal( 'config-connection-error', $e->getMessage() ); |
| 186 | + } |
| 187 | + } |
| 188 | + |
| 189 | + return Status::newGood(); |
| 190 | + } |
| 191 | + |
111 | 192 | public function preInstall() { |
112 | | - # Add our user callback to installSteps, right before the tables are created. |
113 | | - $callback = array( |
| 193 | + $commitCB = array( |
114 | 194 | 'name' => 'pg-commit', |
115 | 195 | 'callback' => array( $this, 'commitChanges' ), |
116 | 196 | ); |
117 | | - $this->parent->addInstallStepFollowing( 'interwiki', $callback ); |
| 197 | + $userCB = array( |
| 198 | + 'name' => 'user', |
| 199 | + 'callback' => array( $this, 'setupUser' ), |
| 200 | + ); |
| 201 | + $ts2CB = array( |
| 202 | + 'name' => 'pg-ts2', |
| 203 | + 'callback' => array( $this, 'setupTs2' ), |
| 204 | + ); |
| 205 | + $plpgCB = array( |
| 206 | + 'name' => 'pg-plpgsql', |
| 207 | + 'callback' => array( $this, 'setupPLpgSQL' ), |
| 208 | + ); |
| 209 | + $this->parent->addInstallStep( $commitCB, 'interwiki' ); |
| 210 | + $this->parent->addInstallStep( $userCB ); |
| 211 | + $this->parent->addInstallStep( $ts2CB, 'database' ); |
| 212 | + $this->parent->addInstallStep( $plpgCB, 'database' ); |
118 | 213 | } |
119 | 214 | |
120 | 215 | function setupDatabase() { |
— | — | @@ -123,30 +218,113 @@ |
124 | 219 | } |
125 | 220 | $conn = $status->value; |
126 | 221 | |
127 | | - // Make sure that we can write to the correct schema |
128 | | - // If not, Postgres will happily and silently go to the next search_path item |
129 | | - $schema = $this->getVar( 'wgDBmwschema' ); |
130 | | - $ctest = 'mediawiki_test_table'; |
131 | | - $safeschema = $conn->addIdentifierQuotes( $schema ); |
132 | | - if ( $conn->tableExists( $ctest, $schema ) ) { |
133 | | - $conn->query( "DROP TABLE $safeschema.$ctest" ); |
| 222 | + $dbName = $this->getVar( 'wgDBname' ); |
| 223 | + $SQL = "SELECT 1 FROM pg_catalog.pg_database WHERE datname = " . $conn->addQuotes( $dbName ); |
| 224 | + $rows = $conn->numRows( $conn->query( $SQL ) ); |
| 225 | + if( !$rows ) { |
| 226 | + $schema = $this->getVar( 'wgDBmwschema' ); |
| 227 | + $user = $this->getVar( 'wgDBuser' ); |
| 228 | + |
| 229 | + $safeschema = $conn->addIdentifierQuotes( $schema ); |
| 230 | + $safeuser = $conn->addIdentifierQuotes( $user ); |
| 231 | + |
| 232 | + $safedb = $conn->addIdentifierQuotes( $dbName ); |
| 233 | + |
| 234 | + $conn->query( "CREATE DATABASE $safedb OWNER $safeuser", __METHOD__ ); |
| 235 | + |
| 236 | + $conn = new DatabasePostgres( |
| 237 | + $this->getVar( 'wgDBserver' ), |
| 238 | + $this->getVar( 'wgDBuser' ), |
| 239 | + $this->getVar( 'wgDBpassword' ), |
| 240 | + $dbName, |
| 241 | + false, |
| 242 | + 0, |
| 243 | + $this->getVar( 'wgDBprefix' ) |
| 244 | + ); |
| 245 | + |
| 246 | + $result = $conn->schemaExists( $schema ); |
| 247 | + if( !$result ) { |
| 248 | + $result = $conn->query( "CREATE SCHEMA $safeschema AUTHORIZATION $safeuser" ); |
| 249 | + if( !$result ) { |
| 250 | + $status->fatal( 'config-install-pg-schema-failed', $user, $schema ); |
| 251 | + } |
| 252 | + } else { |
| 253 | + $safeschema2 = $conn->addQuotes( $schema ); |
| 254 | + $SQL = "SELECT 'GRANT ALL ON '||pg_catalog.quote_ident(relname)||' TO $safeuser;'\n". |
| 255 | + "FROM pg_catalog.pg_class p, pg_catalog.pg_namespace n\n" . |
| 256 | + "WHERE relnamespace = n.oid AND n.nspname = $safeschema2\n" . |
| 257 | + "AND p.relkind IN ('r','S','v')\n"; |
| 258 | + $SQL .= "UNION\n"; |
| 259 | + $SQL .= "SELECT 'GRANT ALL ON FUNCTION '||pg_catalog.quote_ident(proname)||'('||\n". |
| 260 | + "pg_catalog.oidvectortypes(p.proargtypes)||') TO $safeuser;'\n" . |
| 261 | + "FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n\n" . |
| 262 | + "WHERE p.pronamespace = n.oid AND n.nspname = $safeschema2"; |
| 263 | + $res = $conn->query( $SQL ); |
| 264 | + $conn->query( "SET search_path = $safeschema" ); |
| 265 | + } |
134 | 266 | } |
135 | | - $res = $conn->query( "CREATE TABLE $safeschema.$ctest(a int)" ); |
136 | | - if ( !$res ) { |
137 | | - $status->fatal( 'config-install-pg-schema-failed', |
138 | | - $this->getVar( 'wgDBuser'), $schema ); |
| 267 | + return $status; |
| 268 | + } |
| 269 | + |
| 270 | + /** |
| 271 | + * Ts2 isn't needed in newer versions of Postgres, so wrap it in a nice big |
| 272 | + * version check and skip it if we're new. Maybe we can bump $minimumVersion |
| 273 | + * one day and render this obsolete :) |
| 274 | + * |
| 275 | + * @return Status |
| 276 | + */ |
| 277 | + function setupTs2() { |
| 278 | + $status = $this->getConnection(); |
| 279 | + if ( !$status->isOK() ) { |
| 280 | + return $status; |
139 | 281 | } |
140 | | - $conn->query( "DROP TABLE $safeschema.$ctest" ); |
141 | 282 | |
142 | | - return $status; |
| 283 | + if( version_compare( $this->db->getServerVersion(), $this->ts2MaxVersion, '<' ) ) { |
| 284 | + if ( !$this->db->tableExists( 'pg_ts_cfg', $this->getVar( 'wgDBts2schema' ) ) ) { |
| 285 | + return Status::newFatal( |
| 286 | + 'config-install-pg-ts2-failed', |
| 287 | + $this->getVar( 'wgDBname' ), |
| 288 | + 'http://www.devx.com/opensource/Article/21674/0/page/2' |
| 289 | + ); |
| 290 | + } |
| 291 | + $safeuser = $this->db->addQuotes( $this->getVar( 'wgDBuser' ) ); |
| 292 | + foreach ( array( 'cfg', 'cfgmap', 'dict', 'parser' ) as $table ) { |
| 293 | + $sql = "GRANT SELECT ON pg_ts_$table TO $safeuser"; |
| 294 | + $this->db->query( $sql, __METHOD__ ); |
| 295 | + } |
| 296 | + } |
| 297 | + return Status::newGood(); |
143 | 298 | } |
144 | 299 | |
145 | 300 | function commitChanges() { |
146 | 301 | $this->db->query( 'COMMIT' ); |
147 | | - |
148 | 302 | return Status::newGood(); |
149 | 303 | } |
150 | 304 | |
| 305 | + function setupUser() { |
| 306 | + if ( !$this->getVar( '_CreateDBAccount' ) ) { |
| 307 | + return Status::newGood(); |
| 308 | + } |
| 309 | + |
| 310 | + $status = $this->getConnection(); |
| 311 | + if ( !$status->isOK() ) { |
| 312 | + return $status; |
| 313 | + } |
| 314 | + |
| 315 | + $db = $this->getVar( 'wgDBname' ); |
| 316 | + $this->db->selectDB( $db ); |
| 317 | + $safeuser = $this->db->addIdentifierQuotes( $this->getVar( 'wgDBuser' ) ); |
| 318 | + $safepass = $this->db->addQuotes( $this->getVar( 'wgDBpassword' ) ); |
| 319 | + $res = $this->db->query( "CREATE USER $safeuser NOCREATEDB PASSWORD $safepass", __METHOD__ ); |
| 320 | + return $status; |
| 321 | + |
| 322 | + if ( $res !== true ) { |
| 323 | + $status->fatal( 'config-install-user-failed', $this->getVar( 'wgDBuser' ) ); |
| 324 | + } |
| 325 | + |
| 326 | + return $status; |
| 327 | + } |
| 328 | + |
151 | 329 | function getLocalSettings() { |
152 | 330 | $port = $this->getVar( 'wgDBport' ); |
153 | 331 | $schema = $this->getVar( 'wgDBmwschema' ); |
— | — | @@ -167,23 +345,28 @@ |
168 | 346 | $wgDBpassword = $this->getVar( '_InstallPassword' ); |
169 | 347 | } |
170 | 348 | |
171 | | - private function setupPLpgSQL() { |
172 | | - $rows = $this->numRows( |
| 349 | + public function setupPLpgSQL() { |
| 350 | + $status = $this->getConnection(); |
| 351 | + if ( !$status->isOK() ) { |
| 352 | + return $status; |
| 353 | + } |
| 354 | + |
| 355 | + $rows = $this->db->numRows( |
173 | 356 | $this->db->query( "SELECT 1 FROM pg_catalog.pg_language WHERE lanname = 'plpgsql'" ) |
174 | 357 | ); |
175 | 358 | if ( $rows < 1 ) { |
176 | 359 | // plpgsql is not installed, but if we have a pg_pltemplate table, we should be able to create it |
177 | 360 | $SQL = "SELECT 1 FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON (n.oid = c.relnamespace) ". |
178 | 361 | "WHERE relname = 'pg_pltemplate' AND nspname='pg_catalog'"; |
179 | | - $rows = $this->numRows( $this->db->query( $SQL ) ); |
180 | | - global $wgDBname; |
| 362 | + $rows = $this->db->numRows( $this->db->query( $SQL ) ); |
| 363 | + $dbName = $this->getVar( 'wgDBname' ); |
181 | 364 | if ( $rows >= 1 ) { |
182 | 365 | $result = $this->db->query( 'CREATE LANGUAGE plpgsql' ); |
183 | 366 | if ( !$result ) { |
184 | | - return Status::newFatal( 'config-pg-no-plpgsql', $wgDBname ); |
| 367 | + return Status::newFatal( 'config-pg-no-plpgsql', $dbName ); |
185 | 368 | } |
186 | 369 | } else { |
187 | | - return Status::newFatal( 'config-pg-no-plpgsql', $wgDBname ); |
| 370 | + return Status::newFatal( 'config-pg-no-plpgsql', $dbName ); |
188 | 371 | } |
189 | 372 | } |
190 | 373 | return Status::newGood(); |
Index: branches/REL1_17/phase3/includes/installer/WebInstallerPage.php |
— | — | @@ -300,7 +300,7 @@ |
301 | 301 | } |
302 | 302 | |
303 | 303 | // Set the relevant variables from LocalSettings.php |
304 | | - $requiredVars = array( 'wgDBtype', 'wgDBuser', 'wgDBpassword' ); |
| 304 | + $requiredVars = array( 'wgDBtype' ); |
305 | 305 | $status = $this->importVariables( $requiredVars , $vars ); |
306 | 306 | $installer = $this->parent->getDBInstaller(); |
307 | 307 | $status->merge( $this->importVariables( $installer->getGlobalNames(), $vars ) ); |
— | — | @@ -384,7 +384,7 @@ |
385 | 385 | |
386 | 386 | $dbSupport = ''; |
387 | 387 | foreach( $this->parent->getDBTypes() as $type ) { |
388 | | - $db = 'Database' . ucfirst( $type ); |
| 388 | + $db = DatabaseBase::classFromType( $type ); |
389 | 389 | $dbSupport .= wfMsgNoTrans( "config-support-$type", |
390 | 390 | call_user_func( array( $db, 'getSoftwareLink' ) ) ) . "\n"; |
391 | 391 | } |
Property changes on: branches/REL1_17/phase3/includes/installer/WebInstallerPage.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
392 | 392 | Merged /trunk/phase3/includes/installer/WebInstallerPage.php:r79828,79830,79848,79853,79950-79951,79954,79989,80006-80007,80013,80016,80080,80083,80124,80128,80238 |
Index: branches/REL1_17/phase3/includes/AutoLoader.php |
— | — | @@ -393,7 +393,6 @@ |
394 | 394 | 'LoadMonitor_MySQL' => 'includes/db/LoadMonitor.php', |
395 | 395 | 'MySQLField' => 'includes/db/DatabaseMysql.php', |
396 | 396 | 'MySQLMasterPos' => 'includes/db/DatabaseMysql.php', |
397 | | - 'ORABlob' => 'includes/db/DatabaseOracle.php', |
398 | 397 | 'ORAField' => 'includes/db/DatabaseOracle.php', |
399 | 398 | 'ORAResult' => 'includes/db/DatabaseOracle.php', |
400 | 399 | 'PostgresField' => 'includes/db/DatabasePostgres.php', |
Property changes on: branches/REL1_17/phase3/includes/AutoLoader.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
401 | 400 | Merged /trunk/phase3/includes/AutoLoader.php:r79828,79830,79848,79853,79950-79951,79954,79989,80006-80007,80013,80016,80080,80083,80124,80128,80238 |
Index: branches/REL1_17/phase3/includes/extauth/MediaWiki.php |
— | — | @@ -72,7 +72,7 @@ |
73 | 73 | private function initFromCond( $cond ) { |
74 | 74 | global $wgExternalAuthConf; |
75 | 75 | |
76 | | - $class = 'Database' . $wgExternalAuthConf['DBtype']; |
| 76 | + $class = DatabaseBase::classFromType( $wgExternalAuthConf['DBtype'] ); |
77 | 77 | $this->mDb = new $class( |
78 | 78 | $wgExternalAuthConf['DBserver'], |
79 | 79 | $wgExternalAuthConf['DBuser'], |
Property changes on: branches/REL1_17/phase3/includes/extauth/MediaWiki.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
80 | 80 | Merged /trunk/phase3/includes/extauth/MediaWiki.php:r79828,79830,79848,79853,79950-79951,79954,79989,80006-80007,80013,80016,80080,80083,80124,80128,80238 |
Index: branches/REL1_17/phase3/config/index.php |
— | — | @@ -39,7 +39,7 @@ |
40 | 40 | } |
41 | 41 | $wgLang = Language::factory( $langCode ); |
42 | 42 | |
43 | | - $installer->setParserLanguage( $wgLang->getCode() ); |
| 43 | + $installer->setParserLanguage( $wgLang ); |
44 | 44 | |
45 | 45 | $wgMetaNamespace = $wgCanonicalNamespaceNames[NS_PROJECT]; |
46 | 46 | |
Property changes on: branches/REL1_17/phase3 |
___________________________________________________________________ |
Modified: svn:mergeinfo |
47 | 47 | Merged /trunk/phase3:r79828,79830,79848,79853,79950-79951,79954,79989,80006-80007,80013,80016,80080,80083,80124,80128,80238 |