r55117 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r55116‎ | r55117 | r55118 >
Date:21:29, 15 August 2009
Author:leonsp
Status:ok
Tags:
Comment:
config/index.php:
* Made installation on IBM DB2 more robust
* Replaced E_ALL with E_ALL | E_STRICT

includes/db/DatabaseIbm_db2.php
* Enabled DB2_CASE_LOWER option for all connections and statements
* Enabled DB2_DEFERRED_PREPARE_ON for all statements -- delays statement preparation until execution to reduce database load
* Enabled DB2_ROWCOUNT_PREFETCH_ON for all statements -- makes db2_num_rows() work correctly
* Cleaned up error handling
* Cleaned up method signatures
* Rewrote insertion to use prepared statements -- required for inserting more than 32k of text
* Insertion will never try to insert a NULL value into a primary key
* Now relying on implicit casting in DB2 9.7 -- no longer sniffing to see if column is integer or string before adding quotes
* Implemented actual prepared statement handling -- required for correct INSERT, UPDATE behaviour
* In install mode, the class will print additional messages to the install bullet scroll
* Added bitwise operations (BITNOT, BITAND, BITOR)

includes/specials/SpecialAncientpages.php
* Added skeleton DB2 syntax to the database-specific switch statement

maintenance/convertLinks.inc
* Made limit clause database-agnostic

maintenance/ibm_db2/README
* Contents replaced with link to http://www.mediawiki.org/wiki/Manual:IBM_DB2

maintenance/ibm_db2/tables.sql
* Revised types to better match the MySQL schema
* All tables names now the same as MySQL -- was using Postgres names before
* Added some additional indices
* Added the change_tag, tag_summary, valid_tag, user_properties, log_search, and l10n_cache tables
* Added several new columns

maintenance/storage/compressOld.inc
* Made limit clause database-agnostic
Modified paths:
  • /trunk/phase3/config/index.php (modified) (history)
  • /trunk/phase3/includes/db/DatabaseIbm_db2.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialAncientpages.php (modified) (history)
  • /trunk/phase3/maintenance/convertLinks.inc (modified) (history)
  • /trunk/phase3/maintenance/ibm_db2/README (modified) (history)
  • /trunk/phase3/maintenance/ibm_db2/tables.sql (modified) (history)
  • /trunk/phase3/maintenance/storage/compressOld.inc (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/specials/SpecialAncientpages.php
@@ -30,6 +30,10 @@
3131 case 'mysql':
3232 $epoch = 'UNIX_TIMESTAMP(rev_timestamp)';
3333 break;
 34+ case 'ibm_db2':
 35+ // TODO implement proper conversion to a Unix epoch
 36+ $epoch = 'rev_timestamp';
 37+ break;
3438 case 'oracle':
3539 $epoch = '((trunc(rev_timestamp) - to_date(\'19700101\',\'YYYYMMDD\')) * 86400)';
3640 break;
Index: trunk/phase3/includes/db/DatabaseIbm_db2.php
@@ -16,16 +16,21 @@
1717 class BlankObject {
1818 }
1919
 20+
2021 /**
2122 * This represents a column in a DB2 database
2223 * @ingroup Database
2324 */
2425 class IBM_DB2Field {
25 - private $name, $tablename, $type, $nullable, $max_length;
 26+ private $name = '';
 27+ private $tablename = '';
 28+ private $type = '';
 29+ private $nullable = false;
 30+ private $max_length = 0;
2631
2732 /**
2833 * Builder method for the class
29 - * @param Object $db Database interface
 34+ * @param DatabaseIbm_db2 $db Database interface
3035 * @param string $table table name
3136 * @param string $field column name
3237 * @return IBM_DB2Field
@@ -136,11 +141,26 @@
137142 /// Number of rows returned by last SELECT
138143 protected $mNumRows = NULL;
139144
 145+ /// Connection config options - see constructor
 146+ public $mConnOptions = array();
 147+ /// Statement config options -- see constructor
 148+ public $mStmtOptions = array();
140149
 150+
141151 const CATALOGED = "cataloged";
142152 const UNCATALOGED = "uncataloged";
143153 const USE_GLOBAL = "get from global";
144154
 155+ const NONE_OPTION = 0x00;
 156+ const CONN_OPTION = 0x01;
 157+ const STMT_OPTION = 0x02;
 158+
 159+ const REGULAR_MODE = 'regular';
 160+ const INSTALL_MODE = 'install';
 161+
 162+ // Whether this is regular operation or the initial installation
 163+ protected $mMode = self::REGULAR_MODE;
 164+
145165 /// Last sequence value used for a primary key
146166 protected $mInsertId = NULL;
147167
@@ -219,7 +239,7 @@
220240 */
221241
222242 /*
223 - * These need to be implemented TODO
 243+ * These have been implemented
224244 *
225245 * Administrative: 7 / 7
226246 * constructor [Done]
@@ -412,10 +432,43 @@
413433 $this->mSchema = $schema;
414434 }
415435
 436+ // configure the connection and statement objects
 437+ $this->setDB2Option('db2_attr_case', 'DB2_CASE_LOWER', self::CONN_OPTION | self::STMT_OPTION);
 438+ $this->setDB2Option('deferred_prepare', 'DB2_DEFERRED_PREPARE_ON', self::STMT_OPTION);
 439+ $this->setDB2Option('rowcount', 'DB2_ROWCOUNT_PREFETCH_ON', self::STMT_OPTION);
 440+
416441 $this->open( $server, $user, $password, $dbName);
417442 }
418443
419444 /**
 445+ * Enables options only if the ibm_db2 extension version supports them
 446+ * @param string $name Name of the option in the options array
 447+ * @param string $const Name of the constant holding the right option value
 448+ * @param int $type Whether this is a Connection or Statement otion
 449+ */
 450+ private function setDB2Option($name, $const, $type) {
 451+ if (defined($const)) {
 452+ if ($type & self::CONN_OPTION) $this->mConnOptions[$name] = constant($const);
 453+ if ($type & self::STMT_OPTION) $this->mStmtOptions[$name] = constant($const);
 454+ }
 455+ else {
 456+ $this->installPrint("$const is not defined. ibm_db2 version is likely too low.");
 457+ }
 458+ }
 459+
 460+ /**
 461+ * Outputs debug information in the appropriate place
 462+ * @param string $string The relevant debug message
 463+ */
 464+ private function installPrint($string) {
 465+ wfDebug("$string");
 466+ if ($this->mMode == self::INSTALL_MODE) {
 467+ print "<li>$string</li>";
 468+ flush();
 469+ }
 470+ }
 471+
 472+ /**
420473 * Opens a database connection and returns it
421474 * Closes any existing connection
422475 * @return a fresh connection
@@ -437,7 +490,7 @@
438491 // Test for IBM DB2 support, to avoid suppressed fatal error
439492 if ( !function_exists( 'db2_connect' ) ) {
440493 $error = "DB2 functions missing, have you enabled the ibm_db2 extension for PHP?\n";
441 - wfDebug($error);
 494+ $this->installPrint($error);
442495 $this->reportConnectionError($error);
443496 }
444497
@@ -461,16 +514,16 @@
462515 elseif ( $cataloged == self::UNCATALOGED ) {
463516 $this->openUncataloged($dbName, $user, $password, $server, $port);
464517 }
465 - // Don't do this
 518+ // Apply connection config
 519+ db2_set_option($this->mConn, $this->mConnOptions, 1);
466520 // Not all MediaWiki code is transactional
467 - // Rather, turn it off in the begin function and turn on after a commit
468 - // db2_autocommit($this->mConn, DB2_AUTOCOMMIT_OFF);
 521+ // Rather, turn autocommit off in the begin function and turn on after a commit
469522 db2_autocommit($this->mConn, DB2_AUTOCOMMIT_ON);
470523
471524 if ( $this->mConn == false ) {
472 - wfDebug( "DB connection error\n" );
473 - wfDebug( "Server: $server, Database: $dbName, User: $user, Password: " . substr( $password, 0, 3 ) . "...\n" );
474 - wfDebug( $this->lastError()."\n" );
 525+ $this->installPrint( "DB connection error\n" );
 526+ $this->installPrint( "Server: $server, Database: $dbName, User: $user, Password: " . substr( $password, 0, 3 ) . "...\n" );
 527+ $this->installPrint( $this->lastError()."\n" );
475528 return null;
476529 }
477530
@@ -543,20 +596,16 @@
544597 * Forces a database rollback
545598 */
546599 public function lastError() {
547 - if ($this->lastError2()) {
548 - $this->rollback();
549 - return true;
 600+ $connerr = db2_conn_errormsg();
 601+ if ($connerr) {
 602+ //$this->rollback();
 603+ return $connerr;
550604 }
551 - return false;
552 - }
553 -
554 - private function lastError2() {
555 - $connerr = db2_conn_errormsg();
556 - if ($connerr) return $connerr;
557605 $stmterr = db2_stmt_errormsg();
558 - if ($stmterr) return $stmterr;
559 - if ($this->mConn) return "No open connection.";
560 - if ($this->mOpened) return "No open connection allegedly.";
 606+ if ($stmterr) {
 607+ //$this->rollback();
 608+ return $stmterr;
 609+ }
561610
562611 return false;
563612 }
@@ -592,7 +641,7 @@
593642 // Switch into the correct namespace
594643 $this->applySchema();
595644
596 - $ret = db2_exec( $this->mConn, $sql );
 645+ $ret = db2_exec( $this->mConn, $sql, $this->mStmtOptions );
597646 if( !$ret ) {
598647 print "<br><pre>";
599648 print $sql;
@@ -714,7 +763,14 @@
715764
716765 // TODO: populate interwiki links
717766
718 - $this->commit();
 767+ if ($this->lastError()) {
 768+ print "<li>Errors encountered during table creation -- rolled back</li>\n";
 769+ print "<li>Please install again</li>\n";
 770+ $this->rollback();
 771+ }
 772+ else {
 773+ $this->commit();
 774+ }
719775 }
720776 catch (MWException $mwe)
721777 {
@@ -729,7 +785,7 @@
730786 * @return escaped string
731787 */
732788 public function addQuotes( $s ) {
733 - //wfDebug("DB2::addQuotes($s)\n");
 789+ //$this->installPrint("DB2::addQuotes($s)\n");
734790 if ( is_null( $s ) ) {
735791 return "NULL";
736792 } else if ($s instanceof Blob) {
@@ -745,38 +801,6 @@
746802 }
747803
748804 /**
749 - * Escapes strings
750 - * Only escapes numbers going into non-numeric fields
751 - * @param string s string to escape
752 - * @return escaped string
753 - */
754 - public function addQuotesSmart( $table, $field, $s ) {
755 - if ( is_null( $s ) ) {
756 - return "NULL";
757 - } else if ($s instanceof Blob) {
758 - return "'".$s->fetch($s)."'";
759 - }
760 - $s = $this->strencode($s);
761 - if ( is_numeric($s) ) {
762 - // Check with the database if the column is actually numeric
763 - // This allows for numbers in titles, etc
764 - $res = $this->doQuery("SELECT $field FROM $table FETCH FIRST 1 ROWS ONLY");
765 - $type = db2_field_type($res, strtoupper($field));
766 - if ( $this->is_numeric_type( $type ) ) {
767 - //wfDebug("DB2: Numeric value going in a numeric column: $s in $type $field in $table\n");
768 - return $s;
769 - }
770 - else {
771 - wfDebug("DB2: Numeric in non-numeric: '$s' in $type $field in $table\n");
772 - return "'$s'";
773 - }
774 - }
775 - else {
776 - return "'$s'";
777 - }
778 - }
779 -
780 - /**
781805 * Verifies that a DB2 column/field type is numeric
782806 * @return bool true if numeric
783807 * @param string $type DB2 column type
@@ -830,7 +854,7 @@
831855 /**
832856 * Start a transaction (mandatory)
833857 */
834 - public function begin() {
 858+ public function begin( $fname = 'DatabaseIbm_db2::begin' ) {
835859 // turn off auto-commit
836860 db2_autocommit($this->mConn, DB2_AUTOCOMMIT_OFF);
837861 $this->mTrxLevel = 1;
@@ -840,7 +864,7 @@
841865 * End a transaction
842866 * Must have a preceding begin()
843867 */
844 - public function commit() {
 868+ public function commit( $fname = 'DatabaseIbm_db2::commit' ) {
845869 db2_commit($this->mConn);
846870 // turn auto-commit back on
847871 db2_autocommit($this->mConn, DB2_AUTOCOMMIT_ON);
@@ -850,7 +874,7 @@
851875 /**
852876 * Cancel a transaction
853877 */
854 - public function rollback() {
 878+ public function rollback( $fname = 'DatabaseIbm_db2::rollback' ) {
855879 db2_rollback($this->mConn);
856880 // turn auto-commit back on
857881 // not sure if this is appropriate
@@ -868,7 +892,7 @@
869893 * LIST_NAMES - comma separated field names
870894 */
871895 public function makeList( $a, $mode = LIST_COMMA ) {
872 - wfDebug("DB2::makeList()\n");
 896+ $this->installPrint("DB2::makeList()\n");
873897 if ( !is_array( $a ) ) {
874898 throw new DBUnexpectedError( $this, 'Database::makeList called with incorrect parameters' );
875899 }
@@ -931,76 +955,6 @@
932956 }
933957
934958 /**
935 - * Makes an encoded list of strings from an array
936 - * Quotes numeric values being inserted into non-numeric fields
937 - * @return string
938 - * @param string $table name of the table
939 - * @param array $a list of values
940 - * @param $mode:
941 - * LIST_COMMA - comma separated, no field names
942 - * LIST_AND - ANDed WHERE clause (without the WHERE)
943 - * LIST_OR - ORed WHERE clause (without the WHERE)
944 - * LIST_SET - comma separated with field names, like a SET clause
945 - * LIST_NAMES - comma separated field names
946 - */
947 - public function makeListSmart( $table, $a, $mode = LIST_COMMA ) {
948 - if ( !is_array( $a ) ) {
949 - throw new DBUnexpectedError( $this, 'Database::makeList called with incorrect parameters' );
950 - }
951 -
952 - $first = true;
953 - $list = '';
954 - foreach ( $a as $field => $value ) {
955 - if ( !$first ) {
956 - if ( $mode == LIST_AND ) {
957 - $list .= ' AND ';
958 - } elseif($mode == LIST_OR) {
959 - $list .= ' OR ';
960 - } else {
961 - $list .= ',';
962 - }
963 - } else {
964 - $first = false;
965 - }
966 - if ( ($mode == LIST_AND || $mode == LIST_OR) && is_numeric( $field ) ) {
967 - $list .= "($value)";
968 - } elseif ( ($mode == LIST_SET) && is_numeric( $field ) ) {
969 - $list .= "$value";
970 - } elseif ( ($mode == LIST_AND || $mode == LIST_OR) && is_array($value) ) {
971 - if( count( $value ) == 0 ) {
972 - throw new MWException( __METHOD__.': empty input' );
973 - } elseif( count( $value ) == 1 ) {
974 - // Special-case single values, as IN isn't terribly efficient
975 - // Don't necessarily assume the single key is 0; we don't
976 - // enforce linear numeric ordering on other arrays here.
977 - $value = array_values( $value );
978 - $list .= $field." = ".$this->addQuotes( $value[0] );
979 - } else {
980 - $list .= $field." IN (".$this->makeList($value).") ";
981 - }
982 - } elseif( is_null($value) ) {
983 - if ( $mode == LIST_AND || $mode == LIST_OR ) {
984 - $list .= "$field IS ";
985 - } elseif ( $mode == LIST_SET ) {
986 - $list .= "$field = ";
987 - }
988 - $list .= 'NULL';
989 - } else {
990 - if ( $mode == LIST_AND || $mode == LIST_OR || $mode == LIST_SET ) {
991 - $list .= "$field = ";
992 - }
993 - if ( $mode == LIST_NAMES ) {
994 - $list .= $value;
995 - }
996 - else {
997 - $list .= $this->addQuotesSmart( $table, $field, $value );
998 - }
999 - }
1000 - }
1001 - return $list;
1002 - }
1003 -
1004 - /**
1005959 * Construct a LIMIT query with optional offset
1006960 * This is used for query pages
1007961 * $sql string SQL query we will append the limit too
@@ -1012,7 +966,7 @@
1013967 throw new DBUnexpectedError( $this, "Invalid non-numeric limit passed to limitResult()\n" );
1014968 }
1015969 if( $offset ) {
1016 - wfDebug("Offset parameter not supported in limitResult()\n");
 970+ $this->installPrint("Offset parameter not supported in limitResult()\n");
1017971 }
1018972 // TODO implement proper offset handling
1019973 // idea: get all the rows between 0 and offset, advance cursor to offset
@@ -1026,14 +980,16 @@
1027981 */
1028982 public function tableName( $name ) {
1029983 # Replace reserved words with better ones
1030 - switch( $name ) {
1031 - case 'user':
1032 - return 'mwuser';
1033 - case 'text':
1034 - return 'pagecontent';
1035 - default:
1036 - return $name;
1037 - }
 984+// switch( $name ) {
 985+// case 'user':
 986+// return 'mwuser';
 987+// case 'text':
 988+// return 'pagecontent';
 989+// default:
 990+// return $name;
 991+// }
 992+ // we want maximum compatibility with MySQL schema
 993+ return $name;
1038994 }
1039995
1040996 /**
@@ -1052,12 +1008,17 @@
10531009 * @return next value in that sequence
10541010 */
10551011 public function nextSequenceValue( $seqName ) {
 1012+ // Not using sequences in the primary schema to allow for easy third-party migration scripts
 1013+ // Emulating MySQL behaviour of using NULL to signal that sequences aren't used
 1014+ /*
10561015 $safeseq = preg_replace( "/'/", "''", $seqName );
10571016 $res = $this->query( "VALUES NEXTVAL FOR $safeseq" );
10581017 $row = $this->fetchRow( $res );
10591018 $this->mInsertId = $row[0];
10601019 $this->freeResult( $res );
10611020 return $this->mInsertId;
 1021+ */
 1022+ return NULL;
10621023 }
10631024
10641025 /**
@@ -1082,28 +1043,27 @@
10831044 * @return bool Success of insert operation. IGNORE always returns true.
10841045 */
10851046 public function insert( $table, $args, $fname = 'DatabaseIbm_db2::insert', $options = array() ) {
1086 - wfDebug("DB2::insert($table)\n");
 1047+ $this->installPrint("DB2::insert($table)\n");
10871048 if ( !count( $args ) ) {
10881049 return true;
10891050 }
1090 -
 1051+ // get database-specific table name (not used)
10911052 $table = $this->tableName( $table );
1092 -
1093 - if ( !is_array( $options ) )
1094 - $options = array( $options );
1095 -
1096 - if ( isset( $args[0] ) && is_array( $args[0] ) ) {
1097 - }
1098 - else {
 1053+ // format options as an array
 1054+ if ( !is_array( $options ) ) $options = array( $options );
 1055+ // format args as an array of arrays
 1056+ if ( !( isset( $args[0] ) && is_array( $args[0] ) ) ) {
10991057 $args = array($args);
11001058 }
 1059+ // prevent insertion of NULL into primary key columns
 1060+ $args = $this->removeNullPrimaryKeys($table, $args);
 1061+
 1062+ // get column names
11011063 $keys = array_keys( $args[0] );
 1064+ $key_count = count($keys);
11021065
11031066 // If IGNORE is set, we use savepoints to emulate mysql's behavior
11041067 $ignore = in_array( 'IGNORE', $options ) ? 'mw' : '';
1105 -
1106 - // Cache autocommit value at the start
1107 - $oldautocommit = db2_autocommit($this->mConn);
11081068
11091069 // If we are not in a transaction, we need to be for savepoint trickery
11101070 $didbegin = 0;
@@ -1119,58 +1079,50 @@
11201080 }
11211081
11221082 $sql = "INSERT INTO $table (" . implode( ',', $keys ) . ') VALUES ';
 1083+ switch($key_count) {
 1084+ //case 0 impossible
 1085+ case 1:
 1086+ $sql .= '(?)';
 1087+ break;
 1088+ default:
 1089+ $sql .= '(?' . str_repeat(',?', $key_count-1) . ')';
 1090+ }
 1091+ $stmt = $this->prepare($sql);
11231092
11241093 if ( !$ignore ) {
11251094 $first = true;
11261095 foreach ( $args as $row ) {
1127 - if ( $first ) {
1128 - $first = false;
1129 - } else {
1130 - $sql .= ',';
1131 - }
1132 - $sql .= '(' . $this->makeListSmart( $table, $row ) . ')';
 1096+ // insert each row into the database
 1097+ $this->execute($stmt, $row);
11331098 }
1134 - $res = (bool)$this->query( $sql, $fname, $ignore );
11351099 }
11361100 else {
 1101+ // we must have autocommit turned off -- transaction mode on
 1102+ $this->begin();
 1103+
11371104 $res = true;
1138 - $origsql = $sql;
11391105 foreach ( $args as $row ) {
1140 - $tempsql = $origsql;
1141 - $tempsql .= '(' . $this->makeListSmart( $table, $row ) . ')';
1142 -
11431106 if ( $ignore ) {
1144 - db2_exec($this->mConn, "SAVEPOINT $ignore");
 1107+ $overhead = "SAVEPOINT $ignore ON ROLLBACK RETAIN CURSORS";
 1108+ db2_exec($this->mConn, $overhead, $this->mStmtOptions);
11451109 }
1146 -
1147 - $tempres = (bool)$this->query( $tempsql, $fname, $ignore );
1148 -
 1110+
 1111+ $this->execute($sql, $row);
11491112 if ( $ignore ) {
1150 - $bar = db2_stmt_error();
1151 - if ($bar != false) {
1152 - db2_exec( $this->mConn, "ROLLBACK TO SAVEPOINT $ignore" );
 1113+ $bar = $this->lastError();
 1114+ if (!$bar) {
 1115+ db2_exec( $this->mConn, "ROLLBACK TO SAVEPOINT $ignore", $this->mStmtOptions );
11531116 }
11541117 else {
1155 - db2_exec( $this->mConn, "RELEASE SAVEPOINT $ignore" );
 1118+ db2_exec( $this->mConn, "RELEASE SAVEPOINT $ignore", $this->mStmtOptions );
11561119 $numrowsinserted++;
11571120 }
11581121 }
1159 -
1160 - // If any of them fail, we fail overall for this function call
1161 - // Note that this will be ignored if IGNORE is set
1162 - if (! $tempres)
1163 - $res = false;
11641122 }
11651123 }
11661124
1167 - if ($didbegin) {
1168 - $this->commit();
1169 - }
1170 - // if autocommit used to be on, it's ok to commit everything
1171 - else if ($oldautocommit)
1172 - {
1173 - $this->commit();
1174 - }
 1125+ // commit either way
 1126+ $this->commit();
11751127
11761128 if ( $ignore ) {
11771129 $olde = error_reporting( $olde );
@@ -1185,6 +1137,35 @@
11861138 }
11871139
11881140 /**
 1141+ * Given a table name and a hash of columns with values
 1142+ * Removes primary key columns from the hash where the value is NULL
 1143+ *
 1144+ * @param string $table Name of the table
 1145+ * @param array $args Array of hashes of column names with values
 1146+ * @return array Filtered array of hashes
 1147+ */
 1148+ private function removeNullPrimaryKeys($table, $args) {
 1149+ $schema = $this->mSchema;
 1150+ // find out the primary keys
 1151+ $keyres = db2_primary_keys($this->mConn, null, strtoupper($schema), strtoupper($table));
 1152+ $keys = array();
 1153+ for ($row = $this->fetchObject($keyres); $row != null; $row = $this->fetchRow($keyres)) {
 1154+ $keys[] = strtolower($row->column_name);
 1155+ }
 1156+ // remove primary keys
 1157+ foreach ($args as $ai => $row) {
 1158+ foreach ($keys as $ki => $key) {
 1159+ if ($row[$key] == NULL) {
 1160+ unset($row[$key]);
 1161+ }
 1162+ }
 1163+ $args[$ai] = $row;
 1164+ }
 1165+ // return modified hash
 1166+ return $args;
 1167+ }
 1168+
 1169+ /**
11891170 * UPDATE wrapper, takes a condition array and a SET array
11901171 *
11911172 * @param string $table The table to UPDATE
@@ -1196,12 +1177,12 @@
11971178 * more of IGNORE, LOW_PRIORITY
11981179 * @return bool
11991180 */
1200 - function update( $table, $values, $conds, $fname = 'Database::update', $options = array() ) {
 1181+ public function update( $table, $values, $conds, $fname = 'Database::update', $options = array() ) {
12011182 $table = $this->tableName( $table );
12021183 $opts = $this->makeUpdateOptions( $options );
1203 - $sql = "UPDATE $opts $table SET " . $this->makeListSmart( $table, $values, LIST_SET );
 1184+ $sql = "UPDATE $opts $table SET " . $this->makeList( $values, LIST_SET );
12041185 if ( $conds != '*' ) {
1205 - $sql .= " WHERE " . $this->makeListSmart( $table, $conds, LIST_AND );
 1186+ $sql .= " WHERE " . $this->makeList( $conds, LIST_AND );
12061187 }
12071188 return $this->query( $sql, $fname );
12081189 }
@@ -1211,14 +1192,14 @@
12121193 *
12131194 * Use $conds == "*" to delete all rows
12141195 */
1215 - function delete( $table, $conds, $fname = 'Database::delete' ) {
 1196+ public function delete( $table, $conds, $fname = 'Database::delete' ) {
12161197 if ( !$conds ) {
12171198 throw new DBUnexpectedError( $this, 'Database::delete() called with no conditions' );
12181199 }
12191200 $table = $this->tableName( $table );
12201201 $sql = "DELETE FROM $table";
12211202 if ( $conds != '*' ) {
1222 - $sql .= ' WHERE ' . $this->makeListSmart( $table, $conds, LIST_AND );
 1203+ $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
12231204 }
12241205 return $this->query( $sql, $fname );
12251206 }
@@ -1297,7 +1278,7 @@
12981279 /**
12991280 * Returns the number of rows in the result set
13001281 * Has to be called right after the corresponding select query
1301 - * @param Object $res result set
 1282+ * @param object $res result set
13021283 * @return int number of rows
13031284 */
13041285 public function numRows( $res ) {
@@ -1314,7 +1295,7 @@
13151296
13161297 /**
13171298 * Moves the row pointer of the result set
1318 - * @param Object $res result set
 1299+ * @param object $res result set
13191300 * @param int $row row number
13201301 * @return success or failure
13211302 */
@@ -1331,7 +1312,7 @@
13321313
13331314 /**
13341315 * Frees memory associated with a statement resource
1335 - * @param Object $res Statement resource to free
 1316+ * @param object $res Statement resource to free
13361317 * @return bool success or failure
13371318 */
13381319 public function freeResult( $res ) {
@@ -1345,7 +1326,7 @@
13461327
13471328 /**
13481329 * Returns the number of columns in a resource
1349 - * @param Object $res Statement resource
 1330+ * @param object $res Statement resource
13501331 * @return Number of fields/columns in resource
13511332 */
13521333 public function numFields( $res ) {
@@ -1357,7 +1338,7 @@
13581339
13591340 /**
13601341 * Returns the nth column name
1361 - * @param Object $res Statement resource
 1342+ * @param object $res Statement resource
13621343 * @param int $n Index of field or column
13631344 * @return string name of nth column
13641345 */
@@ -1410,7 +1391,7 @@
14111392 $obj = $this->fetchObject($res2);
14121393 $this->mNumRows = $obj->num_rows;
14131394
1414 - wfDebug("DatabaseIbm_db2::select: There are $this->mNumRows rows.\n");
 1395+ $this->installPrint("DatabaseIbm_db2::select: There are $this->mNumRows rows.\n");
14151396
14161397 return $res;
14171398 }
@@ -1487,7 +1468,7 @@
14881469 case '40001': // sql0911n, Deadlock or timeout, rollback
14891470 case '57011': // sql0904n, Resource unavailable, no rollback
14901471 case '57033': // sql0913n, Deadlock or timeout, no rollback
1491 - wfDebug("In a deadlock because of SQLSTATE $err");
 1472+ $this->installPrint("In a deadlock because of SQLSTATE $err");
14921473 return true;
14931474 }
14941475 return false;
@@ -1521,7 +1502,7 @@
15221503 * @return string ''
15231504 * @deprecated
15241505 */
1525 - public function getStatus( $which ) { wfDebug('Not implemented for DB2: getStatus()'); return ''; }
 1506+ public function getStatus( $which="%" ) { $this->installPrint('Not implemented for DB2: getStatus()'); return ''; }
15261507 /**
15271508 * Not implemented
15281509 * TODO
@@ -1531,19 +1512,25 @@
15321513 * Not implemented
15331514 * @deprecated
15341515 */
1535 - public function setFakeSlaveLag( $lag ) { wfDebug('Not implemented for DB2: setFakeSlaveLag()'); }
 1516+ public function setFakeSlaveLag( $lag ) { $this->installPrint('Not implemented for DB2: setFakeSlaveLag()'); }
15361517 /**
15371518 * Not implemented
15381519 * @deprecated
15391520 */
1540 - public function setFakeMaster( $enabled ) { wfDebug('Not implemented for DB2: setFakeMaster()'); }
 1521+ public function setFakeMaster( $enabled = true ) { $this->installPrint('Not implemented for DB2: setFakeMaster()'); }
15411522 /**
15421523 * Not implemented
15431524 * @return string $sql
15441525 * @deprecated
15451526 */
1546 - public function limitResultForUpdate($sql, $num) { return $sql; }
 1527+ public function limitResultForUpdate($sql, $num) { $this->installPrint('Not implemented for DB2: limitResultForUpdate()'); return $sql; }
15471528
 1529+ /**
 1530+ * Only useful with fake prepare like in base Database class
 1531+ * @return string
 1532+ */
 1533+ public function fillPreparedArg( $matches ) { $this->installPrint('Not useful for DB2: fillPreparedArg()'); return ''; }
 1534+
15481535 ######################################
15491536 # Reflection
15501537 ######################################
@@ -1608,7 +1595,7 @@
16091596
16101597 /**
16111598 * db2_field_type() wrapper
1612 - * @param Object $res Result of executed statement
 1599+ * @param object $res Result of executed statement
16131600 * @param mixed $index number or name of the column
16141601 * @return string column type
16151602 */
@@ -1750,4 +1737,127 @@
17511738 // TODO
17521739 // see SpecialAncientpages
17531740 }
 1741+
 1742+ ######################################
 1743+ # Prepared statements
 1744+ ######################################
 1745+
 1746+ /**
 1747+ * Intended to be compatible with the PEAR::DB wrapper functions.
 1748+ * http://pear.php.net/manual/en/package.database.db.intro-execute.php
 1749+ *
 1750+ * ? = scalar value, quoted as necessary
 1751+ * ! = raw SQL bit (a function for instance)
 1752+ * & = filename; reads the file and inserts as a blob
 1753+ * (we don't use this though...)
 1754+ * @param string $sql SQL statement with appropriate markers
 1755+ * @return resource a prepared DB2 SQL statement
 1756+ */
 1757+ public function prepare( $sql, $func = 'DB2::prepare' ) {
 1758+ $stmt = db2_prepare($this->mConn, $sql, $this->mStmtOptions);
 1759+ return $stmt;
 1760+ }
 1761+
 1762+ /**
 1763+ * Frees resources associated with a prepared statement
 1764+ * @return bool success or failure
 1765+ */
 1766+ public function freePrepared( $prepared ) {
 1767+ return db2_free_stmt($prepared);
 1768+ }
 1769+
 1770+ /**
 1771+ * Execute a prepared query with the various arguments
 1772+ * @param string $prepared the prepared sql
 1773+ * @param mixed $args Either an array here, or put scalars as varargs
 1774+ * @return resource Results object
 1775+ */
 1776+ public function execute( $prepared, $args = null ) {
 1777+ if( !is_array( $args ) ) {
 1778+ # Pull the var args
 1779+ $args = func_get_args();
 1780+ array_shift( $args );
 1781+ }
 1782+ $res = db2_execute($prepared, $args);
 1783+ return $res;
 1784+ }
 1785+
 1786+ /**
 1787+ * Prepare & execute an SQL statement, quoting and inserting arguments
 1788+ * in the appropriate places.
 1789+ * @param $query String
 1790+ * @param $args ...
 1791+ */
 1792+ public function safeQuery( $query, $args = null ) {
 1793+ // copied verbatim from Database.php
 1794+ $prepared = $this->prepare( $query, 'DB2::safeQuery' );
 1795+ if( !is_array( $args ) ) {
 1796+ # Pull the var args
 1797+ $args = func_get_args();
 1798+ array_shift( $args );
 1799+ }
 1800+ $retval = $this->execute( $prepared, $args );
 1801+ $this->freePrepared( $prepared );
 1802+ return $retval;
 1803+ }
 1804+
 1805+ /**
 1806+ * For faking prepared SQL statements on DBs that don't support
 1807+ * it directly.
 1808+ * @param resource $preparedQuery String: a 'preparable' SQL statement
 1809+ * @param array $args Array of arguments to fill it with
 1810+ * @return string executable statement
 1811+ */
 1812+ public function fillPrepared( $preparedQuery, $args ) {
 1813+ reset( $args );
 1814+ $this->preparedArgs =& $args;
 1815+
 1816+ foreach ($args as $i => $arg) {
 1817+ db2_bind_param($preparedQuery, $i+1, $args[$i]);
 1818+ }
 1819+
 1820+ return $preparedQuery;
 1821+ }
 1822+
 1823+ /**
 1824+ * Switches module between regular and install modes
 1825+ */
 1826+ public function setMode($mode) {
 1827+ $old = $this->mMode;
 1828+ $this->mMode = $mode;
 1829+ return $old;
 1830+ }
 1831+
 1832+ /**
 1833+ * Bitwise negation of a column or value in SQL
 1834+ * Same as (~field) in C
 1835+ * @param string $field
 1836+ * @return string
 1837+ */
 1838+ function bitNot($field) {
 1839+ //expecting bit-fields smaller than 4bytes
 1840+ return 'BITNOT('.$bitField.')';
 1841+ }
 1842+
 1843+ /**
 1844+ * Bitwise AND of two columns or values in SQL
 1845+ * Same as (fieldLeft & fieldRight) in C
 1846+ * @param string $fieldLeft
 1847+ * @param string $fieldRight
 1848+ * @return string
 1849+ */
 1850+ function bitAnd($fieldLeft, $fieldRight) {
 1851+ return 'BITAND('.$fieldLeft.', '.$fieldRight.')';
 1852+ }
 1853+
 1854+ /**
 1855+ * Bitwise OR of two columns or values in SQL
 1856+ * Same as (fieldLeft | fieldRight) in C
 1857+ * @param string $fieldLeft
 1858+ * @param string $fieldRight
 1859+ * @return string
 1860+ */
 1861+ function bitOr($fieldLeft, $fieldRight) {
 1862+ return 'BITOR('.$fieldLeft.', '.$fieldRight.')';
 1863+ }
17541864 }
Index: trunk/phase3/maintenance/storage/compressOld.inc
@@ -57,7 +57,8 @@
5858 'old_text' => $compress
5959 ), array( /* WHERE */
6060 'old_id' => $row->old_id
61 - ), $fname, 'LIMIT 1'
 61+ ), $fname,
 62+ array( 'LIMIT' => 1 )
6263 );
6364 return true;
6465 }
Index: trunk/phase3/maintenance/convertLinks.inc
@@ -45,8 +45,10 @@
4646
4747 $dbw = wfGetDB( DB_MASTER );
4848 list ($cur, $links, $links_temp, $links_backup) = $dbw->tableNamesN( 'cur', 'links', 'links_temp', 'links_backup' );
49 -
50 - $res = $dbw->query( "SELECT l_from FROM $links LIMIT 1" );
 49+
 50+ // Get database-agnostic limit clause
 51+ $sql_limit = $dbw->limitResult( "SELECT l_from FROM $links", 1 );
 52+ $res = $dbw->query( $sql_limit );
5153 if ( $dbw->fieldType( $res, 0 ) == "int" ) {
5254 wfOut( "Schema already converted\n" );
5355 return;
Index: trunk/phase3/maintenance/ibm_db2/tables.sql
@@ -5,94 +5,102 @@
66 -- not have to run it by itself unless doing a manual install.
77 -- This is the IBM DB2 version.
88 -- For information about each table, please see the notes in maintenance/tables.sql
99
1010
11 -
12 -
13 -CREATE SEQUENCE user_user_id_seq AS INTEGER START WITH 0 INCREMENT BY 1;
14 -CREATE TABLE mwuser ( -- replace reserved word 'user'
15 - user_id INTEGER NOT NULL PRIMARY KEY, -- DEFAULT nextval('user_user_id_seq'),
 11+CREATE TABLE user (
 12+ user_id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
1613 user_name VARCHAR(255) NOT NULL UNIQUE,
1714 user_real_name VARCHAR(255),
18 - user_password clob(1K),
19 - user_newpassword clob(1K),
20 - user_newpass_time TIMESTAMP,
 15+ user_password VARCHAR(1024),
 16+ user_newpassword VARCHAR(1024),
 17+ user_newpass_time TIMESTAMP(3),
2118 user_token VARCHAR(255),
2219 user_email VARCHAR(255),
2320 user_email_token VARCHAR(255),
24 - user_email_token_expires TIMESTAMP,
25 - user_email_authenticated TIMESTAMP,
26 - user_options CLOB(64K),
27 - user_touched TIMESTAMP,
28 - user_registration TIMESTAMP,
 21+ user_email_token_expires TIMESTAMP(3),
 22+ user_email_authenticated TIMESTAMP(3),
 23+ -- obsolete, replace by user_properties table
 24+ user_options CLOB(64K) INLINE LENGTH 4096,
 25+ user_touched TIMESTAMP(3),
 26+ user_registration TIMESTAMP(3),
2927 user_editcount INTEGER
3028 );
31 -CREATE INDEX user_email_token_idx ON mwuser (user_email_token);
 29+CREATE INDEX user_email_token_idx ON user (user_email_token);
 30+--leonsp:
 31+CREATE UNIQUE INDEX user_include_idx
 32+ ON user(user_id)
 33+ INCLUDE (user_name, user_real_name, user_password, user_newpassword, user_newpass_time, user_token,
 34+ user_email, user_email_token, user_email_token_expires, user_email_authenticated,
 35+ user_touched, user_registration, user_editcount);
3236
3337 -- Create a dummy user to satisfy fk contraints especially with revisions
34 -INSERT INTO mwuser
35 - VALUES (NEXTVAL FOR user_user_id_seq,'Anonymous','', NULL,NULL,CURRENT_TIMESTAMP,NULL, NULL,NULL,NULL,NULL, NULL,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,0);
 38+INSERT INTO user(
 39+user_name, user_real_name, user_password, user_newpassword, user_newpass_time,
 40+user_email, user_email_authenticated, user_options, user_token, user_registration, user_editcount)
 41+VALUES (
 42+'Anonymous','', NULL, NULL, CURRENT_TIMESTAMP,
 43+NULL, NULL, NULL, NULL, CURRENT_timestamp, 0);
3644
 45+
3746 CREATE TABLE user_groups (
38 - ug_user INTEGER REFERENCES mwuser(user_id) ON DELETE CASCADE,
 47+ ug_user INTEGER REFERENCES user(user_id) ON DELETE CASCADE,
3948 ug_group VARCHAR(255) NOT NULL
4049 );
4150 CREATE UNIQUE INDEX user_groups_unique ON user_groups (ug_user, ug_group);
 51+--leonsp:
 52+CREATE UNIQUE INDEX user_groups_include_idx
 53+ ON user_groups(ug_user)
 54+ INCLUDE (ug_group);
4255
 56+
4357 CREATE TABLE user_newtalk (
44 - user_id INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE CASCADE,
45 - user_ip VARCHAR(255),
46 - user_last_timestamp TIMESTAMP
 58+ -- registered users key
 59+ user_id INTEGER NOT NULL REFERENCES user(user_id) ON DELETE CASCADE,
 60+ -- anonymous users key
 61+ user_ip VARCHAR(40),
 62+ user_last_timestamp TIMESTAMP(3)
4763 );
4864 CREATE INDEX user_newtalk_id_idx ON user_newtalk (user_id);
4965 CREATE INDEX user_newtalk_ip_idx ON user_newtalk (user_ip);
 66+--leonsp:
 67+CREATE UNIQUE INDEX user_newtalk_include_idx
 68+ ON user_newtalk(user_id, user_ip)
 69+ INCLUDE (user_last_timestamp);
5070
5171
52 -CREATE SEQUENCE page_page_id_seq;
5372 CREATE TABLE page (
54 - page_id INTEGER NOT NULL PRIMARY KEY, -- DEFAULT NEXT VALUE FOR user_user_id_seq,
 73+ page_id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
5574 page_namespace SMALLINT NOT NULL,
5675 page_title VARCHAR(255) NOT NULL,
57 - page_restrictions clob(1K),
 76+ page_restrictions VARCHAR(1024),
5877 page_counter BIGINT NOT NULL DEFAULT 0,
5978 page_is_redirect SMALLINT NOT NULL DEFAULT 0,
6079 page_is_new SMALLINT NOT NULL DEFAULT 0,
6180 page_random NUMERIC(15,14) NOT NULL,
62 - page_touched TIMESTAMP,
 81+ page_touched TIMESTAMP(3),
6382 page_latest INTEGER NOT NULL, -- FK?
6483 page_len INTEGER NOT NULL
6584 );
6685 CREATE UNIQUE INDEX page_unique_name ON page (page_namespace, page_title);
6786 CREATE INDEX page_random_idx ON page (page_random);
6887 CREATE INDEX page_len_idx ON page (page_len);
 88+--leonsp:
 89+CREATE UNIQUE INDEX page_id_include
 90+ ON page (page_id)
 91+ INCLUDE (page_namespace, page_title, page_restrictions, page_counter, page_is_redirect, page_is_new, page_random, page_touched, page_latest, page_len);
 92+CREATE UNIQUE INDEX page_name_include
 93+ ON page (page_namespace, page_title)
 94+ INCLUDE (page_id, page_restrictions, page_counter, page_is_redirect, page_is_new, page_random, page_touched, page_latest, page_len);
6995
7096
71 -
72 -CREATE SEQUENCE rev_rev_id_val;
7397 CREATE TABLE revision (
74 - rev_id INTEGER NOT NULL UNIQUE, --DEFAULT nextval('rev_rev_id_val'),
 98+ rev_id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
7599 rev_page INTEGER REFERENCES page (page_id) ON DELETE CASCADE,
76100 rev_text_id INTEGER, -- FK
77 - rev_comment clob(1K), -- changed from VARCHAR(255)
78 - rev_user INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE RESTRICT,
 101+ rev_comment VARCHAR(1024),
 102+ rev_user INTEGER NOT NULL REFERENCES user(user_id) ON DELETE RESTRICT,
79103 rev_user_text VARCHAR(255) NOT NULL,
80 - rev_timestamp TIMESTAMP NOT NULL,
 104+ rev_timestamp TIMESTAMP(3) NOT NULL,
81105 rev_minor_edit SMALLINT NOT NULL DEFAULT 0,
82106 rev_deleted SMALLINT NOT NULL DEFAULT 0,
83107 rev_len INTEGER,
@@ -105,34 +113,40 @@
106114 CREATE INDEX rev_user_text_idx ON revision (rev_user_text);
107115
108116
109 -CREATE SEQUENCE text_old_id_val;
110 -CREATE TABLE pagecontent ( -- replaces reserved word 'text'
111 - old_id INTEGER NOT NULL,
 117+-- CREATE SEQUENCE text_old_id_val;
 118+CREATE TABLE text ( -- replaces reserved word 'text'
 119+ --old_id INTEGER NOT NULL,
 120+ old_id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
112121 --PRIMARY KEY DEFAULT nextval('text_old_id_val'),
113 - old_text CLOB(16M),
114 - old_flags clob(1K)
 122+ old_text CLOB(16M) INLINE LENGTH 4096,
 123+ old_flags VARCHAR(1024)
115124 );
116125
117 -CREATE SEQUENCE pr_id_val;
 126+--CREATE SEQUENCE pr_id_val;
118127 CREATE TABLE page_restrictions (
119 - pr_id INTEGER NOT NULL UNIQUE,
120 - --DEFAULT nextval('pr_id_val'),
 128+ --pr_id INTEGER NOT NULL UNIQUE, --DEFAULT nextval('pr_id_val'),
 129+ --pr_id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
 130+ pr_id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
121131 pr_page INTEGER NOT NULL
122132 --(used to be nullable)
123133 REFERENCES page (page_id) ON DELETE CASCADE,
124 - pr_type VARCHAR(255) NOT NULL,
125 - pr_level VARCHAR(255) NOT NULL,
 134+ pr_type VARCHAR(60) NOT NULL,
 135+ pr_level VARCHAR(60) NOT NULL,
126136 pr_cascade SMALLINT NOT NULL,
127137 pr_user INTEGER,
128 - pr_expiry TIMESTAMP,
129 - PRIMARY KEY (pr_page, pr_type)
 138+ pr_expiry TIMESTAMP(3)
 139+ --PRIMARY KEY (pr_page, pr_type)
130140 );
131141 --ALTER TABLE page_restrictions ADD CONSTRAINT page_restrictions_pk PRIMARY KEY (pr_page,pr_type);
 142+CREATE UNIQUE INDEX pr_pagetype ON page_restrictions (pr_page,pr_type);
 143+CREATE INDEX pr_typelevel ON page_restrictions (pr_type,pr_level);
 144+CREATE INDEX pr_level ON page_restrictions (pr_level);
 145+CREATE INDEX pr_cascade ON page_restrictions (pr_cascade);
132146
133147 CREATE TABLE page_props (
134148 pp_page INTEGER NOT NULL REFERENCES page (page_id) ON DELETE CASCADE,
135149 pp_propname VARCHAR(255) NOT NULL,
136 - pp_value CLOB(64K) NOT NULL,
 150+ pp_value CLOB(64K) INLINE LENGTH 4096 NOT NULL,
137151 PRIMARY KEY (pp_page,pp_propname)
138152 );
139153 --ALTER TABLE page_props ADD CONSTRAINT page_props_pk PRIMARY KEY (pp_page,pp_propname);
@@ -143,15 +157,15 @@
144158 CREATE TABLE archive (
145159 ar_namespace SMALLINT NOT NULL,
146160 ar_title VARCHAR(255) NOT NULL,
147 - ar_text CLOB(16M),
 161+ ar_text CLOB(16M) INLINE LENGTH 4096,
148162 ar_page_id INTEGER,
149163 ar_parent_id INTEGER,
150 - ar_comment clob(1K),
151 - ar_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL,
 164+ ar_comment VARCHAR(1024),
 165+ ar_user INTEGER REFERENCES user(user_id) ON DELETE SET NULL,
152166 ar_user_text VARCHAR(255) NOT NULL,
153 - ar_timestamp TIMESTAMP NOT NULL,
 167+ ar_timestamp TIMESTAMP(3) NOT NULL,
154168 ar_minor_edit SMALLINT NOT NULL DEFAULT 0,
155 - ar_flags clob(1K),
 169+ ar_flags VARCHAR(1024),
156170 ar_rev_id INTEGER,
157171 ar_text_id INTEGER,
158172 ar_deleted SMALLINT NOT NULL DEFAULT 0,
@@ -164,8 +178,10 @@
165179
166180 CREATE TABLE redirect (
167181 rd_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE,
168 - rd_namespace SMALLINT NOT NULL,
169 - rd_title VARCHAR(255) NOT NULL
 182+ rd_namespace SMALLINT NOT NULL DEFAULT 0,
 183+ rd_title VARCHAR(255) NOT NULL DEFAULT '',
 184+ rd_interwiki varchar(32),
 185+ rd_fragment VARCHAR(255)
170186 );
171187 CREATE INDEX redirect_ns_title ON redirect (rd_namespace,rd_title,rd_from);
172188
@@ -183,18 +199,20 @@
184200 tl_title VARCHAR(255) NOT NULL
185201 );
186202 CREATE UNIQUE INDEX templatelinks_unique ON templatelinks (tl_namespace,tl_title,tl_from);
 203+CREATE UNIQUE INDEX tl_from_idx ON templatelinks (tl_from,tl_namespace,tl_title);
187204
188205 CREATE TABLE imagelinks (
189206 il_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE,
190207 il_to VARCHAR(255) NOT NULL
191208 );
192 -CREATE UNIQUE INDEX il_from ON imagelinks (il_to,il_from);
 209+CREATE UNIQUE INDEX il_from_idx ON imagelinks (il_to,il_from);
 210+CREATE UNIQUE INDEX il_to_idx ON imagelinks (il_from,il_to);
193211
194212 CREATE TABLE categorylinks (
195213 cl_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE,
196214 cl_to VARCHAR(255) NOT NULL,
197 - cl_sortkey VARCHAR(255),
198 - cl_timestamp TIMESTAMP NOT NULL
 215+ cl_sortkey VARCHAR(70),
 216+ cl_timestamp TIMESTAMP(3) NOT NULL
199217 );
200218 CREATE UNIQUE INDEX cl_from ON categorylinks (cl_from, cl_to);
201219 CREATE INDEX cl_sortkey ON categorylinks (cl_to, cl_sortkey, cl_from);
@@ -203,15 +221,35 @@
204222
205223 CREATE TABLE externallinks (
206224 el_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE,
207 - el_to VARCHAR(255) NOT NULL,
208 - el_index VARCHAR(255) NOT NULL
 225+ el_to VARCHAR(1024) NOT NULL,
 226+ el_index VARCHAR(1024) NOT NULL
209227 );
210228 CREATE INDEX externallinks_from_to ON externallinks (el_from,el_to);
211229 CREATE INDEX externallinks_index ON externallinks (el_index);
212230
 231+
 232+--
 233+-- Track external user accounts, if ExternalAuth is used
 234+--
 235+CREATE TABLE external_user (
 236+ -- Foreign key to user_id
 237+ eu_wiki_id INTEGER NOT NULL PRIMARY KEY,
 238+
 239+ -- Some opaque identifier provided by the external database
 240+ eu_external_id VARCHAR(255) NOT NULL
 241+);
 242+CREATE UNIQUE INDEX eu_external_id_idx
 243+ ON external_user (eu_external_id)
 244+ INCLUDE (eu_wiki_id);
 245+CREATE UNIQUE INDEX eu_wiki_id_idx
 246+ ON external_user (eu_wiki_id)
 247+ INCLUDE (eu_external_id);
 248+
 249+
 250+
213251 CREATE TABLE langlinks (
214252 ll_from INTEGER NOT NULL REFERENCES page (page_id) ON DELETE CASCADE,
215 - ll_lang VARCHAR(255),
 253+ ll_lang VARCHAR(20),
216254 ll_title VARCHAR(255)
217255 );
218256 CREATE UNIQUE INDEX langlinks_unique ON langlinks (ll_from,ll_lang);
@@ -233,23 +271,22 @@
234272 hc_id BIGINT NOT NULL
235273 );
236274
237 -CREATE SEQUENCE ipblocks_ipb_id_val;
238275 CREATE TABLE ipblocks (
239276 ipb_id INTEGER NOT NULL PRIMARY KEY,
240277 --DEFAULT nextval('ipblocks_ipb_id_val'),
241 - ipb_address VARCHAR(255),
242 - ipb_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL,
243 - ipb_by INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE CASCADE,
 278+ ipb_address VARCHAR(1024),
 279+ ipb_user INTEGER REFERENCES user(user_id) ON DELETE SET NULL,
 280+ ipb_by INTEGER NOT NULL REFERENCES user(user_id) ON DELETE CASCADE,
244281 ipb_by_text VARCHAR(255) NOT NULL DEFAULT '',
245 - ipb_reason VARCHAR(255) NOT NULL,
246 - ipb_timestamp TIMESTAMP NOT NULL,
 282+ ipb_reason VARCHAR(1024) NOT NULL,
 283+ ipb_timestamp TIMESTAMP(3) NOT NULL,
247284 ipb_auto SMALLINT NOT NULL DEFAULT 0,
248285 ipb_anon_only SMALLINT NOT NULL DEFAULT 0,
249286 ipb_create_account SMALLINT NOT NULL DEFAULT 1,
250287 ipb_enable_autoblock SMALLINT NOT NULL DEFAULT 1,
251 - ipb_expiry TIMESTAMP NOT NULL,
252 - ipb_range_start VARCHAR(255),
253 - ipb_range_end VARCHAR(255),
 288+ ipb_expiry TIMESTAMP(3) NOT NULL,
 289+ ipb_range_start VARCHAR(1024),
 290+ ipb_range_end VARCHAR(1024),
254291 ipb_deleted SMALLINT NOT NULL DEFAULT 0,
255292 ipb_block_email SMALLINT NOT NULL DEFAULT 0
256293
@@ -265,15 +302,15 @@
266303 img_size INTEGER NOT NULL,
267304 img_width INTEGER NOT NULL,
268305 img_height INTEGER NOT NULL,
269 - img_metadata CLOB(16M) NOT NULL DEFAULT '',
 306+ img_metadata CLOB(16M) INLINE LENGTH 4096 NOT NULL DEFAULT '',
270307 img_bits SMALLINT,
271308 img_media_type VARCHAR(255),
272309 img_major_mime VARCHAR(255) DEFAULT 'unknown',
273 - img_minor_mime VARCHAR(255) DEFAULT 'unknown',
274 - img_description clob(1K) NOT NULL DEFAULT '',
275 - img_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL,
 310+ img_minor_mime VARCHAR(32) DEFAULT 'unknown',
 311+ img_description VARCHAR(1024) NOT NULL DEFAULT '',
 312+ img_user INTEGER REFERENCES user(user_id) ON DELETE SET NULL,
276313 img_user_text VARCHAR(255) NOT NULL DEFAULT '',
277 - img_timestamp TIMESTAMP,
 314+ img_timestamp TIMESTAMP(3),
278315 img_sha1 VARCHAR(255) NOT NULL DEFAULT ''
279316 );
280317 CREATE INDEX img_size_idx ON image (img_size);
@@ -287,11 +324,11 @@
288325 oi_width INTEGER NOT NULL,
289326 oi_height INTEGER NOT NULL,
290327 oi_bits SMALLINT NOT NULL,
291 - oi_description clob(1K),
292 - oi_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL,
 328+ oi_description VARCHAR(1024),
 329+ oi_user INTEGER REFERENCES user(user_id) ON DELETE SET NULL,
293330 oi_user_text VARCHAR(255) NOT NULL,
294 - oi_timestamp TIMESTAMP NOT NULL,
295 - oi_metadata CLOB(16M) NOT NULL DEFAULT '',
 331+ oi_timestamp TIMESTAMP(3) NOT NULL,
 332+ oi_metadata CLOB(16M) INLINE LENGTH 4096 NOT NULL DEFAULT '',
296333 oi_media_type VARCHAR(255) ,
297334 oi_major_mime VARCHAR(255) NOT NULL DEFAULT 'unknown',
298335 oi_minor_mime VARCHAR(255) NOT NULL DEFAULT 'unknown',
@@ -312,22 +349,22 @@
313350 fa_name VARCHAR(255) NOT NULL,
314351 fa_archive_name VARCHAR(255),
315352 fa_storage_group VARCHAR(255),
316 - fa_storage_key VARCHAR(255),
317 - fa_deleted_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL,
318 - fa_deleted_timestamp TIMESTAMP NOT NULL,
 353+ fa_storage_key VARCHAR(32),
 354+ fa_deleted_user INTEGER REFERENCES user(user_id) ON DELETE SET NULL,
 355+ fa_deleted_timestamp TIMESTAMP(3) NOT NULL,
319356 fa_deleted_reason VARCHAR(255),
320357 fa_size INTEGER NOT NULL,
321358 fa_width INTEGER NOT NULL,
322359 fa_height INTEGER NOT NULL,
323 - fa_metadata CLOB(16M) NOT NULL DEFAULT '',
 360+ fa_metadata CLOB(16M) INLINE LENGTH 4096 NOT NULL DEFAULT '',
324361 fa_bits SMALLINT,
325362 fa_media_type VARCHAR(255),
326363 fa_major_mime VARCHAR(255) DEFAULT 'unknown',
327364 fa_minor_mime VARCHAR(255) DEFAULT 'unknown',
328 - fa_description clob(1K) NOT NULL,
329 - fa_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL,
 365+ fa_description VARCHAR(1024) NOT NULL,
 366+ fa_user INTEGER REFERENCES user(user_id) ON DELETE SET NULL,
330367 fa_user_text VARCHAR(255) NOT NULL,
331 - fa_timestamp TIMESTAMP,
 368+ fa_timestamp TIMESTAMP(3),
332369 fa_deleted SMALLINT NOT NULL DEFAULT 0
333370 );
334371 CREATE INDEX fa_name_time ON filearchive (fa_name, fa_timestamp);
@@ -339,9 +376,9 @@
340377 CREATE TABLE recentchanges (
341378 rc_id INTEGER NOT NULL PRIMARY KEY,
342379 --PRIMARY KEY DEFAULT nextval('rc_rc_id_seq'),
343 - rc_timestamp TIMESTAMP NOT NULL,
344 - rc_cur_time TIMESTAMP NOT NULL,
345 - rc_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL,
 380+ rc_timestamp TIMESTAMP(3) NOT NULL,
 381+ rc_cur_time TIMESTAMP(3) NOT NULL,
 382+ rc_user INTEGER REFERENCES user(user_id) ON DELETE SET NULL,
346383 rc_user_text VARCHAR(255) NOT NULL,
347384 rc_namespace SMALLINT NOT NULL,
348385 rc_title VARCHAR(255) NOT NULL,
@@ -356,14 +393,15 @@
357394 rc_moved_to_ns SMALLINT,
358395 rc_moved_to_title VARCHAR(255),
359396 rc_patrolled SMALLINT NOT NULL DEFAULT 0,
360 - rc_ip VARCHAR(255), -- was CIDR type
 397+ rc_ip VARCHAR(40), -- was CIDR type
361398 rc_old_len INTEGER,
362399 rc_new_len INTEGER,
363400 rc_deleted SMALLINT NOT NULL DEFAULT 0,
364401 rc_logid INTEGER NOT NULL DEFAULT 0,
365402 rc_log_type VARCHAR(255),
366403 rc_log_action VARCHAR(255),
367 - rc_params CLOB(64K)
 404+ rc_params CLOB(64K) INLINE LENGTH 4096
 405+
368406 );
369407 CREATE INDEX rc_timestamp ON recentchanges (rc_timestamp);
370408 CREATE INDEX rc_namespace_title ON recentchanges (rc_namespace, rc_title);
@@ -374,26 +412,26 @@
375413
376414
377415 CREATE TABLE watchlist (
378 - wl_user INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE CASCADE,
 416+ wl_user INTEGER NOT NULL REFERENCES user(user_id) ON DELETE CASCADE,
379417 wl_namespace SMALLINT NOT NULL DEFAULT 0,
380418 wl_title VARCHAR(255) NOT NULL,
381 - wl_notificationtimestamp TIMESTAMP
 419+ wl_notificationtimestamp TIMESTAMP(3)
382420 );
383421 CREATE UNIQUE INDEX wl_user_namespace_title ON watchlist (wl_namespace, wl_title, wl_user);
384422
385423
386424 CREATE TABLE math (
387 - math_inputhash VARGRAPHIC(255) NOT NULL UNIQUE,
388 - math_outputhash VARGRAPHIC(255) NOT NULL,
 425+ math_inputhash VARCHAR(16) FOR BIT DATA NOT NULL UNIQUE,
 426+ math_outputhash VARCHAR(16) FOR BIT DATA NOT NULL,
389427 math_html_conservativeness SMALLINT NOT NULL,
390 - math_html VARCHAR(255),
391 - math_mathml VARCHAR(255)
 428+ math_html CLOB(64K) INLINE LENGTH 4096,
 429+ math_mathml CLOB(64K) INLINE LENGTH 4096
392430 );
393431
394432
395433 CREATE TABLE interwiki (
396 - iw_prefix VARCHAR(255) NOT NULL UNIQUE,
397 - iw_url CLOB(64K) NOT NULL,
 434+ iw_prefix VARCHAR(32) NOT NULL UNIQUE,
 435+ iw_url CLOB(64K) INLINE LENGTH 4096 NOT NULL,
398436 iw_local SMALLINT NOT NULL,
399437 iw_trans SMALLINT NOT NULL DEFAULT 0
400438 );
@@ -411,7 +449,7 @@
412450
413451 CREATE TABLE querycache_info (
414452 qci_type VARCHAR(255) UNIQUE NOT NULL,
415 - qci_timestamp TIMESTAMP
 453+ qci_timestamp TIMESTAMP(3)
416454 );
417455
418456
@@ -429,8 +467,8 @@
430468
431469 CREATE TABLE objectcache (
432470 keyname VARCHAR(255) NOT NULL UNIQUE, -- was nullable
433 - value CLOB(16M) NOT NULL DEFAULT '',
434 - exptime TIMESTAMP NOT NULL
 471+ value CLOB(16M) INLINE LENGTH 4096 NOT NULL DEFAULT '',
 472+ exptime TIMESTAMP(3) NOT NULL
435473 );
436474 CREATE INDEX objectcacache_exptime ON objectcache (exptime);
437475
@@ -439,35 +477,41 @@
440478 CREATE TABLE transcache (
441479 tc_url VARCHAR(255) NOT NULL UNIQUE,
442480 tc_contents VARCHAR(255) NOT NULL,
443 - tc_time TIMESTAMP NOT NULL
 481+ tc_time TIMESTAMP(3) NOT NULL
444482 );
445483
446484 CREATE SEQUENCE log_log_id_seq;
447485 CREATE TABLE logging (
448 - log_id INTEGER NOT NULL PRIMARY KEY,
 486+ log_id INTEGER NOT NULL PRIMARY KEY,
449487 --PRIMARY KEY DEFAULT nextval('log_log_id_seq'),
450 - log_type VARCHAR(255) NOT NULL,
451 - log_action VARCHAR(255) NOT NULL,
452 - log_timestamp TIMESTAMP NOT NULL,
453 - log_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL,
454 - log_namespace SMALLINT NOT NULL,
455 - log_title VARCHAR(255) NOT NULL,
456 - log_comment VARCHAR(255),
457 - log_params CLOB(64K),
458 - log_deleted SMALLINT NOT NULL DEFAULT 0
 488+ log_type VARCHAR(32) NOT NULL,
 489+ log_action VARCHAR(32) NOT NULL,
 490+ log_timestamp TIMESTAMP(3) NOT NULL,
 491+ log_user INTEGER REFERENCES user(user_id) ON DELETE SET NULL,
 492+ -- Name of the user who performed this action
 493+ log_user_text VARCHAR(255) NOT NULL default '',
 494+ log_namespace SMALLINT NOT NULL,
 495+ log_title VARCHAR(255) NOT NULL,
 496+ log_page INTEGER,
 497+ log_comment VARCHAR(255),
 498+ log_params CLOB(64K) INLINE LENGTH 4096,
 499+ log_deleted SMALLINT NOT NULL DEFAULT 0
459500 );
460501 CREATE INDEX logging_type_name ON logging (log_type, log_timestamp);
461502 CREATE INDEX logging_user_time ON logging (log_timestamp, log_user);
462503 CREATE INDEX logging_page_time ON logging (log_namespace, log_title, log_timestamp);
 504+CREATE INDEX log_user_type_time ON logging (log_user, log_type, log_timestamp);
 505+CREATE INDEX log_page_id_time ON logging (log_page,log_timestamp);
463506
 507+
464508 CREATE SEQUENCE trackbacks_tb_id_seq;
465509 CREATE TABLE trackbacks (
466510 tb_id INTEGER NOT NULL PRIMARY KEY,
467511 --PRIMARY KEY DEFAULT nextval('trackbacks_tb_id_seq'),
468512 tb_page INTEGER REFERENCES page(page_id) ON DELETE CASCADE,
469513 tb_title VARCHAR(255) NOT NULL,
470 - tb_url CLOB(64K) NOT NULL,
471 - tb_ex VARCHAR(255),
 514+ tb_url CLOB(64K) INLINE LENGTH 4096 NOT NULL,
 515+ tb_ex CLOB(64K) INLINE LENGTH 4096,
472516 tb_name VARCHAR(255)
473517 );
474518 CREATE INDEX trackback_page ON trackbacks (tb_page);
@@ -480,7 +524,7 @@
481525 job_cmd VARCHAR(255) NOT NULL,
482526 job_namespace SMALLINT NOT NULL,
483527 job_title VARCHAR(255) NOT NULL,
484 - job_params CLOB(64K) NOT NULL
 528+ job_params CLOB(64K) INLINE LENGTH 4096 NOT NULL
485529 );
486530 CREATE INDEX job_cmd_namespace_title ON job (job_cmd, job_namespace, job_title);
487531
@@ -504,7 +548,7 @@
505549 -- FOR EACH ROW EXECUTE PROCEDURE ts2_page_title();
506550
507551
 552+--ALTER TABLE text ADD textvector tsvector;
508553 --CREATE FUNCTION ts2_page_text() RETURNS TRIGGER LANGUAGE plpgsql AS
509554 --$mw$
510555 --BEGIN
@@ -517,14 +561,14 @@
518562 --END;
519563 --$mw$;
520564
 565+--CREATE TRIGGER ts2_page_text BEFORE INSERT OR UPDATE ON text
521566 -- FOR EACH ROW EXECUTE PROCEDURE ts2_page_text();
522567
523568 -- These are added by the setup script due to version compatibility issues
524569 -- If using 8.1, we switch from "gin" to "gist"
525570
526571 --CREATE INDEX ts2_page_title ON page USING gin(titlevector);
 572+--CREATE INDEX ts2_page_text ON text USING gin(textvector);
527573
528574 --TODO
529575 --CREATE FUNCTION add_interwiki (TEXT,INT,SMALLINT) RETURNS INT LANGUAGE SQL AS
@@ -554,11 +598,11 @@
555599 CREATE TABLE protected_titles (
556600 pt_namespace SMALLINT NOT NULL,
557601 pt_title VARCHAR(255) NOT NULL,
558 - pt_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL,
559 - pt_reason clob(1K),
560 - pt_timestamp TIMESTAMP NOT NULL,
561 - pt_expiry TIMESTAMP ,
562 - pt_create_perm VARCHAR(255) NOT NULL DEFAULT ''
 602+ pt_user INTEGER REFERENCES user(user_id) ON DELETE SET NULL,
 603+ pt_reason VARCHAR(1024),
 604+ pt_timestamp TIMESTAMP(3) NOT NULL,
 605+ pt_expiry TIMESTAMP(3) ,
 606+ pt_create_perm VARCHAR(60) NOT NULL DEFAULT ''
563607 );
564608 CREATE UNIQUE INDEX protected_titles_unique ON protected_titles(pt_namespace, pt_title);
565609
@@ -568,7 +612,7 @@
569613 ul_key VARCHAR(255) NOT NULL PRIMARY KEY
570614 );
571615
572 -CREATE SEQUENCE category_id_seq;
 616+--CREATE SEQUENCE category_id_seq;
573617 CREATE TABLE category (
574618 cat_id INTEGER NOT NULL PRIMARY KEY,
575619 --PRIMARY KEY DEFAULT nextval('category_id_seq'),
@@ -581,24 +625,101 @@
582626 CREATE UNIQUE INDEX category_title ON category(cat_title);
583627 CREATE INDEX category_pages ON category(cat_pages);
584628
 629+-- added for 1.15
 630+
 631+-- A table to track tags for revisions, logs and recent changes.
 632+CREATE TABLE change_tag (
 633+ ct_rc_id INTEGER,
 634+ ct_log_id INTEGER,
 635+ ct_rev_id INTEGER,
 636+ ct_tag varchar(255) NOT NULL,
 637+ ct_params CLOB(64K) INLINE LENGTH 4096
 638+);
 639+CREATE UNIQUE INDEX change_tag_rc_tag ON change_tag (ct_rc_id,ct_tag);
 640+CREATE UNIQUE INDEX change_tag_log_tag ON change_tag (ct_log_id,ct_tag);
 641+CREATE UNIQUE INDEX change_tag_rev_tag ON change_tag (ct_rev_id,ct_tag);
 642+-- Covering index, so we can pull all the info only out of the index.
 643+CREATE INDEX change_tag_tag_id ON change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id);
 644+
 645+
 646+-- Rollup table to pull a LIST of tags simply
 647+CREATE TABLE tag_summary (
 648+ ts_rc_id INTEGER,
 649+ ts_log_id INTEGER,
 650+ ts_rev_id INTEGER,
 651+ ts_tags CLOB(64K) INLINE LENGTH 4096 NOT NULL
 652+);
 653+CREATE UNIQUE INDEX tag_summary_rc_id ON tag_summary (ts_rc_id);
 654+CREATE UNIQUE INDEX tag_summary_log_id ON tag_summary (ts_log_id);
 655+CREATE UNIQUE INDEX tag_summary_rev_id ON tag_summary (ts_rev_id);
 656+
 657+
 658+CREATE TABLE valid_tag (
 659+ vt_tag varchar(255) NOT NULL PRIMARY KEY
 660+);
 661+
 662+--
 663+-- User preferences and perhaps other fun stuff. :)
 664+-- Replaces the old user.user_options blob, with a couple nice properties:
 665+--
 666+-- 1) We only store non-default settings, so changes to the defaults
 667+-- are now reflected for everybody, not just new accounts.
 668+-- 2) We can more easily do bulk lookups, statistics, or modifications of
 669+-- saved options since it's a sane table structure.
 670+--
 671+CREATE TABLE user_properties (
 672+ -- Foreign key to user.user_id
 673+ up_user INTEGER NOT NULL,
 674+
 675+ -- Name of the option being saved. This is indexed for bulk lookup.
 676+ up_property VARCHAR(32) FOR BIT DATA NOT NULL,
 677+
 678+ -- Property value as a string.
 679+ up_value CLOB(64K) INLINE LENGTH 4096
 680+);
 681+CREATE UNIQUE INDEX user_properties_user_property ON user_properties (up_user,up_property);
 682+CREATE INDEX user_properties_property ON user_properties (up_property);
 683+
 684+CREATE TABLE log_search (
 685+ -- The type of ID (rev ID, log ID, rev TIMESTAMP(3), username)
 686+ ls_field VARCHAR(32) FOR BIT DATA NOT NULL,
 687+ -- The value of the ID
 688+ ls_value varchar(255) NOT NULL,
 689+ -- Key to log_id
 690+ ls_log_id INTEGER NOT NULL default 0
 691+);
 692+CREATE UNIQUE INDEX ls_field_val ON log_search (ls_field,ls_value,ls_log_id);
 693+CREATE INDEX ls_log_id ON log_search (ls_log_id);
 694+
585695 CREATE TABLE mediawiki_version (
586 - type VARCHAR(255) NOT NULL,
587 - mw_version VARCHAR(255) NOT NULL,
588 - notes VARCHAR(255) ,
 696+ type VARCHAR(1024) NOT NULL,
 697+ mw_version VARCHAR(1024) NOT NULL,
 698+ notes VARCHAR(1024) ,
589699
590 - pg_version VARCHAR(255) ,
591 - pg_dbname VARCHAR(255) ,
592 - pg_user VARCHAR(255) ,
593 - pg_port VARCHAR(255) ,
594 - mw_schema VARCHAR(255) ,
595 - ts2_schema VARCHAR(255) ,
596 - ctype VARCHAR(255) ,
 700+ pg_version VARCHAR(1024) ,
 701+ pg_dbname VARCHAR(1024) ,
 702+ pg_user VARCHAR(1024) ,
 703+ pg_port VARCHAR(1024) ,
 704+ mw_schema VARCHAR(1024) ,
 705+ ts2_schema VARCHAR(1024) ,
 706+ ctype VARCHAR(1024) ,
597707
598 - sql_version VARCHAR(255) ,
599 - sql_date VARCHAR(255) ,
600 - cdate TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP
 708+ sql_version VARCHAR(1024) ,
 709+ sql_date VARCHAR(1024) ,
 710+ cdate TIMESTAMP(3) NOT NULL DEFAULT CURRENT TIMESTAMP
601711 );
602712
603713 INSERT INTO mediawiki_version (type,mw_version,sql_version,sql_date)
604714 VALUES ('Creation','??','$LastChangedRevision: 34049 $','$LastChangedDate: 2008-04-30 10:20:36 -0400 (Wed, 30 Apr 2008) $');
605715
 716+-- Table for storing localisation data
 717+CREATE TABLE l10n_cache (
 718+ -- Language code
 719+ lc_lang VARCHAR(32) NOT NULL,
 720+ -- Cache key
 721+ lc_key VARCHAR(255) NOT NULL,
 722+ -- Value
 723+ lc_value CLOB(16M) INLINE LENGTH 4096 NOT NULL
 724+);
 725+CREATE INDEX lc_lang_key ON l10n_cache (lc_lang, lc_key);
 726+
Index: trunk/phase3/maintenance/ibm_db2/README
@@ -1,41 +1,3 @@
2 -== Syntax differences between other databases and IBM DB2 ==
3 -{| border cellspacing=0 cellpadding=4
4 -!MySQL!!IBM DB2
5 -|-
6 -
7 -|SELECT 1 FROM $table LIMIT 1
8 -|SELECT COUNT(*) FROM SYSIBM.SYSTABLES ST
9 -WHERE ST.NAME = '$table' AND ST.CREATOR = '$schema'
10 -|-
11 -|MySQL code tries to read one row and interprets lack of error as proof of existence.
12 -|DB2 code counts the number of TABLES of that name in the database. There ought to be 1 for it to exist.
13 -|-
14 -|BEGIN
15 -|(implicit)
16 -|-
17 -|TEXT
18 -|VARCHAR(255) or CLOB
19 -|-
20 -|TIMESTAMPTZ
21 -|TIMESTAMP
22 -|-
23 -|BYTEA
24 -|VARGRAPHIC(255)
25 -|-
26 -|DEFAULT nextval('some_kind_of_sequence'),
27 -|GENERATED ALWAYS AS IDENTITY (START WITH 0, INCREMENT BY 1),
28 -|-
29 -|CIDR
30 -|VARCHAR(255)
31 -|-
32 -|LIMIT 10
33 -|FETCH FIRST 10 ROWS ONLY
34 -|-
35 -|ROLLBACK TO
36 -|ROLLBACK TO SAVEPOINT
37 -|-
38 -|RELEASE
39 -|RELEASE SAVEPOINT
40 -|}
412 == See also ==
 3+*[http://www.mediawiki.org/wiki/Manual:IBM_DB2 Installation instructions]
424 *[http://ca.php.net/manual/en/function.db2-connect.php PHP Manual for DB2 functions]
\ No newline at end of file
Index: trunk/phase3/config/index.php
@@ -19,7 +19,7 @@
2020 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2121 # http://www.gnu.org/copyleft/gpl.html
2222
23 -error_reporting( E_ALL );
 23+error_reporting( E_ALL | E_STRICT );
2424 header( "Content-type: text/html; charset=utf-8" );
2525 @ini_set( "display_errors", true );
2626
@@ -328,7 +328,7 @@
329329 $ourdb[$db]['havedriver'] = 1;
330330 }
331331 }
332 -error_reporting( E_ALL );
 332+error_reporting( E_ALL | E_STRICT );
333333
334334 if (!$phpdatabases) {
335335 print "Could not find a suitable database driver!<ul>";
@@ -686,7 +686,7 @@
687687 $errs["DBprefix_ora"] = "Invalid table prefix";
688688 }
689689
690 -error_reporting( E_ALL );
 690+error_reporting( E_ALL | E_STRICT );
691691
692692 /**
693693 * Initialise $wgLang and $wgContLang to something so we can
@@ -848,7 +848,7 @@
849849 chdir( "config" );
850850
851851 $wgTitle = Title::newFromText( "Installation script" );
852 - error_reporting( E_ALL );
 852+ error_reporting( E_ALL | E_STRICT );
853853 print "<li>Loading class: " . htmlspecialchars( $dbclass ) . "</li>\n";
854854 if ( $conf->DBtype != 'sqlite' ) {
855855 $dbc = new $dbclass;
@@ -930,6 +930,10 @@
931931 echo( "<li>Attempting to connect to database \"" . htmlspecialchars( $wgDBname ) .
932932 "\" as \"" . htmlspecialchars( $db_user ) . "\"..." );
933933 $wgDatabase = $dbc->newFromParams($wgDBserver, $db_user, $db_pass, $wgDBname, 1);
 934+ // enable extra debug messages
 935+ $dbc->setMode(DatabaseIbm_db2::INSTALL_MODE);
 936+ $wgDatabase->setMode(DatabaseIbm_db2::INSTALL_MODE);
 937+
934938 if (!$wgDatabase->isOpen()) {
935939 print " error: " . htmlspecialchars( $wgDatabase->lastError() ) . "</li>\n";
936940 } else {
@@ -1017,7 +1021,7 @@
10181022 $myver = $wgDatabase->getServerVersion();
10191023 }
10201024 } else { # not mysql
1021 - error_reporting( E_ALL );
 1025+ error_reporting( E_ALL | E_STRICT );
10221026 $wgSuperUser = '';
10231027 ## Possible connect as a superuser
10241028 // Changed !mysql to postgres check since it seems to only apply to postgres
@@ -1182,6 +1186,7 @@
11831187 chdir( "config" );
11841188 print "</pre>\n";
11851189 print "<ul><li>Finished update checks.</li>\n";
 1190+ // if tables don't yet exist
11861191 } else {
11871192 # Determine available storage engines if possible
11881193 if ( $conf->DBtype == 'mysql' && version_compare( $myver, "4.1.2", "ge" ) ) {
@@ -1216,6 +1221,20 @@
12171222 }
12181223
12191224 print " done.</li>\n";
 1225+
 1226+
 1227+ if ($conf->DBtype == 'ibm_db2') {
 1228+ // Now that table creation is done, make sure everything is committed
 1229+ // Do this before doing inserts through API
 1230+ if ($wgDatabase->lastError()) {
 1231+ print "<li>Errors encountered during table creation -- rolled back</li>\n";
 1232+ $wgDatabase->rollback();
 1233+ }
 1234+ else {
 1235+ print "<li>MediaWiki tables successfully created</li>\n";
 1236+ $wgDatabase->commit();
 1237+ }
 1238+ }
12201239
12211240 print "<li>Initializing statistics...</li>\n";
12221241 $wgDatabase->insert( 'site_stats',
@@ -1279,8 +1298,6 @@
12801299 $revid = $revision->insertOn( $wgDatabase );
12811300 $article->updateRevisionOn( $wgDatabase, $revision );
12821301 }
1283 - // Now that all database work is done, make sure everything is committed
1284 - $wgDatabase->commit();
12851302
12861303 /* Write out the config file now that all is well */
12871304 print "<li style=\"list-style: none\">\n";

Status & tagging log