From e478c230f6d3f1b7638d4443682eff0df7650def Mon Sep 17 00:00:00 2001 From: Erik Bernhardson Date: Mon, 23 Sep 2013 15:38:01 -0700 Subject: [PATCH] Add new recentchanges field rc_source to replace rc_type The existing field to differentiate between kinds of recentchanges rows is the rc_type field. We want to allow extensions to insert their own custom data into recentchanges, but we have learned via the NS_* series of constants that requiring extensions to "register" a specific number is very error prone. The solution, which this commit implements the first phase of, is to utilize a new 16 byte string field rc_source. Within that field change types will be prefixed strings such as 'mw.edit' and 'mw.new'. This commit adds the new field and begins populating it with data. At some point in the future the rc_type field will be dropped. While WMF wiki's will simply wait out the 30 day recentchanges history, other wiki's have the option of letting update.php populate rc_source, or manually applying the db change and utilizing the PopulateRecentChangeSource maintenance script. Change-Id: Iaddd6c446373a68d31586ed54346db7d04e13b2c --- RELEASE-NOTES-1.22 | 9 ++ includes/RecentChange.php | 14 +++ includes/installer/MysqlUpdater.php | 1 + includes/installer/PostgresUpdater.php | 3 + includes/installer/SqliteUpdater.php | 3 + maintenance/archives/patch-rc_source.sql | 16 +++ maintenance/populateRecentChangesSource.php | 105 ++++++++++++++++++++ maintenance/postgres/tables.sql | 1 + maintenance/rebuildrecentchanges.php | 1 + maintenance/tables.sql | 4 + 10 files changed, 157 insertions(+) create mode 100644 maintenance/archives/patch-rc_source.sql create mode 100644 maintenance/populateRecentChangesSource.php diff --git a/RELEASE-NOTES-1.22 b/RELEASE-NOTES-1.22 index 3112e2681d..dadedd2d93 100644 --- a/RELEASE-NOTES-1.22 +++ b/RELEASE-NOTES-1.22 @@ -366,6 +366,15 @@ changes to languages because of Bugzilla reports. * (bug 46751) Made Buryat (Russia) (буряад) (bxr) fallback to Russian. === Other changes in 1.22 === +* The rc_type field in the recentchanges table has been superseded by a new + rc_source field. The rc_source field is a string representation of the + change type where rc_type was a numeric constant. This field is not yet + queried but will be in a future point release of 1.22. +** Utilize update.php to create and populate this new field. On larger wiki's + which do not wish to update recentchanges table in one large update please + review the sql and comments in maintenance/archives/patch-rc_source.sql. +** The rc_type field of recentchanges will be deprecated in a future point + release. * BREAKING CHANGE: Implementation of MediaWiki's JS and JSON value encoding has changed: ** MediaWiki no longer supports PHP installations in which the native JSON diff --git a/includes/RecentChange.php b/includes/RecentChange.php index 980bd0a041..282890f726 100644 --- a/includes/RecentChange.php +++ b/includes/RecentChange.php @@ -30,6 +30,7 @@ * rc_namespace namespace # * rc_title non-prefixed db key * rc_type is new entry, used to determine whether updating is necessary + * rc_source string representation of change source * rc_minor is minor * rc_cur_id page_id of associated page entry * rc_user user id who made the entry @@ -64,6 +65,14 @@ * @todo document functions and variables */ class RecentChange { + + // Constants for the rc_source field. Extensions may also have + // their own source constants. + const SRC_EDIT = 'mw.edit'; + const SRC_NEW = 'mw.new'; + const SRC_LOG = 'mw.log'; + const SRC_EXTERNAL = 'mw.external'; // obsolete + var $mAttribs = array(), $mExtra = array(); /** @@ -159,6 +168,7 @@ class RecentChange { 'rc_this_oldid', 'rc_last_oldid', 'rc_type', + 'rc_source', 'rc_patrolled', 'rc_ip', 'rc_old_len', @@ -489,6 +499,7 @@ class RecentChange { 'rc_namespace' => $title->getNamespace(), 'rc_title' => $title->getDBkey(), 'rc_type' => RC_EDIT, + 'rc_source' => self::SRC_EDIT, 'rc_minor' => $minor ? 1 : 0, 'rc_cur_id' => $title->getArticleID(), 'rc_user' => $user->getId(), @@ -548,6 +559,7 @@ class RecentChange { 'rc_namespace' => $title->getNamespace(), 'rc_title' => $title->getDBkey(), 'rc_type' => RC_NEW, + 'rc_source' => self::SRC_NEW, 'rc_minor' => $minor ? 1 : 0, 'rc_cur_id' => $title->getArticleID(), 'rc_user' => $user->getId(), @@ -657,6 +669,7 @@ class RecentChange { 'rc_namespace' => $target->getNamespace(), 'rc_title' => $target->getDBkey(), 'rc_type' => RC_LOG, + 'rc_source' => self::SRC_LOG, 'rc_minor' => 0, 'rc_cur_id' => $target->getArticleID(), 'rc_user' => $user->getId(), @@ -716,6 +729,7 @@ class RecentChange { 'rc_comment' => $row->rev_comment, 'rc_minor' => $row->rev_minor_edit ? 1 : 0, 'rc_type' => $row->page_is_new ? RC_NEW : RC_EDIT, + 'rc_source' => $row->page_is_new ? self::SRC_NEW : self::SRC_EDIT, 'rc_cur_id' => $row->page_id, 'rc_this_oldid' => $row->rev_id, 'rc_last_oldid' => isset( $row->rc_last_oldid ) ? $row->rc_last_oldid : 0, diff --git a/includes/installer/MysqlUpdater.php b/includes/installer/MysqlUpdater.php index 02faf7c4bb..9220005c0b 100644 --- a/includes/installer/MysqlUpdater.php +++ b/includes/installer/MysqlUpdater.php @@ -231,6 +231,7 @@ class MysqlUpdater extends DatabaseUpdater { // 1.22 array( 'doIwlinksIndexNonUnique' ), array( 'addIndex', 'iwlinks', 'iwl_prefix_from_title', 'patch-iwlinks-from-title-index.sql' ), + array( 'addField', 'recentchanges', 'rc_source', 'patch-rc_source.sql' ), ); } diff --git a/includes/installer/PostgresUpdater.php b/includes/installer/PostgresUpdater.php index 58a54c4219..5868aa8f86 100644 --- a/includes/installer/PostgresUpdater.php +++ b/includes/installer/PostgresUpdater.php @@ -353,6 +353,9 @@ class PostgresUpdater extends DatabaseUpdater { array( 'addInterwikiType' ), # end array( 'tsearchFixes' ), + + // 1.22 + array( 'addPgField', 'recentchanges', 'rc_source', "TEXT NOT NULL DEFAULT ''" ), ); } diff --git a/includes/installer/SqliteUpdater.php b/includes/installer/SqliteUpdater.php index 28d8d66b1b..17c4f5455b 100644 --- a/includes/installer/SqliteUpdater.php +++ b/includes/installer/SqliteUpdater.php @@ -109,6 +109,9 @@ class SqliteUpdater extends DatabaseUpdater { array( 'addIndex', 'page_props', 'pp_propname_page', 'patch-page_props-propname-page-index.sql' ), array( 'addIndex', 'image', 'img_media_mime', 'patch-img_media_mime-index.sql' ), array( 'addIndex', 'iwlinks', 'iwl_prefix_from_title', 'patch-iwlinks-from-title-index.sql' ), + + // 1.22 + array( 'addField', 'recentchanges', 'rc_source', 'patch-rc_source.sql' ), ); } diff --git a/maintenance/archives/patch-rc_source.sql b/maintenance/archives/patch-rc_source.sql new file mode 100644 index 0000000000..7dedd7451b --- /dev/null +++ b/maintenance/archives/patch-rc_source.sql @@ -0,0 +1,16 @@ +-- first step of migrating recentchanges rc_type to rc_source +ALTER TABLE /*$wgDBprefix*/recentchanges + ADD rc_source varbinary(16) NOT NULL default ''; + +-- Populate rc_source field with the data from rc_type +-- Large wiki's might prefer the PopulateRecentChangeSource maintenance +-- script to batch updates into groups rather than all at once. +UPDATE /*$wgDBprefix*/recentchanges + SET rc_source = CASE + WHEN rc_type = 0 THEN 'mw.edit' + WHEN rc_type = 1 THEN 'mw.new' + WHEN rc_type = 3 THEN 'mw.log' + WHEN rc_type = 5 THEN 'mw.external' + ELSE '' + END +WHERE rc_source = ''; diff --git a/maintenance/populateRecentChangesSource.php b/maintenance/populateRecentChangesSource.php new file mode 100644 index 0000000000..0e8e501252 --- /dev/null +++ b/maintenance/populateRecentChangesSource.php @@ -0,0 +1,105 @@ +mDescription = "Populates rc_source field of the recentchanges table with the data in rc_type."; + $this->setBatchSize( 100 ); + } + + protected function doDBUpdates() { + $dbw = $this->getDB( DB_MASTER ); + if ( !$dbw->fieldExists( 'recentchanges', 'rc_source' ) ) { + $this->error( 'rc_source field in recentchanges table does not exist.' ); + } + + $start = $dbw->selectField( 'recentchanges', 'MIN(rc_id)', false, __METHOD__ ); + if ( !$start ) { + $this->output( "Nothing to do.\n" ); + return true; + } + $end = $dbw->selectField( 'recentchanges', 'MAX(rc_id)', false, __METHOD__ ); + $end += $this->mBatchSize - 1; + $blockStart = $start; + $blockEnd = $start + $this->mBatchSize - 1; + + $updatedValues = $this->buildUpdateCondition( $dbw ); + + while ( $blockEnd <= $end ) { + $cond = "rc_id BETWEEN $blockStart AND $blockEnd"; + + $dbw->update( + 'recentchanges', + array( $updatedValues ), + array( + "rc_source = ''", + "rc_id BETWEEN $blockStart AND $blockEnd" + ), + __METHOD__ + ); + + $this->output( "." ); + wfWaitForSlaves(); + + $blockStart += $this->mBatchSize; + $blockEnd += $this->mBatchSize; + } + + $this->output( "\nDone.\n" ); + } + + protected function getUpdateKey() { + return __CLASS__; + } + + protected function buildUpdateCondition( DatabaseBase $dbw ) { + $rcNew = $dbw->addQuotes( RC_NEW ); + $rcSrcNew = $dbw->addQuotes( RecentChange::SRC_NEW ); + $rcEdit = $dbw->addQuotes( RC_EDIT ); + $rcSrcEdit = $dbw->addQuotes( RecentChange::SRC_EDIT ); + $rcLog = $dbw->addQuotes( RC_LOG ); + $rcSrcLog = $dbw->addQuotes( RecentChange::SRC_LOG ); + $rcExternal = $dbw->addQuotes( RC_EXTERNAL ); + $rcSrcExternal = $dbw->addQuotes( RecentChange::SRC_EXTERNAL ); + + return "rc_source = CASE + WHEN rc_type = $rcNew THEN $rcSrcNew + WHEN rc_type = $rcEdit THEN $rcSrcEdit + WHEN rc_type = $rcLog THEN $rcSrcLog + WHEN rc_type = $rcExternal THEN $rcSrcExternal + ELSE '' + END"; + } +} + +$maintClass = "PopulateRecentChangesSource"; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/postgres/tables.sql b/maintenance/postgres/tables.sql index 4d44705c76..5322254b98 100644 --- a/maintenance/postgres/tables.sql +++ b/maintenance/postgres/tables.sql @@ -405,6 +405,7 @@ CREATE TABLE recentchanges ( rc_this_oldid INTEGER NOT NULL, rc_last_oldid INTEGER NOT NULL, rc_type SMALLINT NOT NULL DEFAULT 0, + rc_source TEXT NOT NULL, rc_patrolled SMALLINT NOT NULL DEFAULT 0, rc_ip CIDR, rc_old_len INTEGER, diff --git a/maintenance/rebuildrecentchanges.php b/maintenance/rebuildrecentchanges.php index 18348258b0..315176c12c 100644 --- a/maintenance/rebuildrecentchanges.php +++ b/maintenance/rebuildrecentchanges.php @@ -83,6 +83,7 @@ class RebuildRecentchanges extends Maintenance { 'rc_this_oldid' => 'rev_id', 'rc_last_oldid' => 0, // is this ok? 'rc_type' => $dbw->conditional( 'page_is_new != 0', RC_NEW, RC_EDIT ), + 'rc_source' => $dbw->conditional( 'page_is_new != 0', $dbw->addQuotes( RecentChange::SRC_NEW ), $dbw->addQuotes( RecentChange::SRC_EDIT ) ), 'rc_deleted' => 'rev_deleted' ), array( 'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ), diff --git a/maintenance/tables.sql b/maintenance/tables.sql index df1bc06f84..b3150914a3 100644 --- a/maintenance/tables.sql +++ b/maintenance/tables.sql @@ -1058,6 +1058,10 @@ CREATE TABLE /*_*/recentchanges ( -- The type of change entry (RC_EDIT,RC_NEW,RC_LOG,RC_EXTERNAL) rc_type tinyint unsigned NOT NULL default 0, + -- The source of the change entry (replaces rc_type) + -- default of '' is temporary, needed for initial migration + rc_source varchar(16) binary not null default '', + -- If the Recent Changes Patrol option is enabled, -- users may mark edits as having been reviewed to -- remove a warning flag on the RC list. -- 2.20.1