From: jenkins-bot Date: Mon, 9 Sep 2019 17:56:26 +0000 (+0000) Subject: Merge "Follow-up 8697ba8: No need for two dependencies on the same module" X-Git-Tag: 1.34.0-rc.0~312 X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=commitdiff_plain;h=b02658c48097517aaedcf9c50266d78eee92a8a0;hp=955490fe45542562c1e3448ab6859e9e3dbdfce1 Merge "Follow-up 8697ba8: No need for two dependencies on the same module" --- diff --git a/RELEASE-NOTES-1.34 b/RELEASE-NOTES-1.34 index f77354a6a3..9ac26e8389 100644 --- a/RELEASE-NOTES-1.34 +++ b/RELEASE-NOTES-1.34 @@ -91,6 +91,8 @@ $wgPasswordPolicy['policies']['default']['PasswordNotInLargeBlacklist'] = false; * $wgDBOracleDRCP - If you must use persistent connections, set DBO_PERSISTENT in the 'flags' field for servers in $wgDBServers (or $wgLBFactoryConf). * $wgMemCachedDebug - Set the cache "debug" field in $wgObjectCaches instead. +* $wgActorTableSchemaMigrationStage has been removed. Extension code for + MediaWiki 1.31+ finding it unset should treat it as being SCHEMA_COMPAT_NEW. === New user-facing features in 1.34 === * Special:Mute has been added as a quick way for users to block unwanted emails @@ -375,7 +377,19 @@ because of Phabricator reports. should only be used to unblock a blocked user. * Parameters for index.php from PATH_INFO, such as the title, are no longer written to $_GET. -* … +* The selectFields() methods on classes LocalFile, ArchivedFile, OldLocalFile, + DatabaseBlock, and RecentChange, deprecated in 1.31, have been removed. Use + the corresponding getQueryInfo() methods instead. +* The following methods on Revision, deprecated since 1.31, have been removed. + Use RevisionStore::getQueryInfo() or RevisionStore::getArchiveQueryInfo() + instead. + * Revision::userJoinCond() + * Revision::pageJoinCond() + * Revision::selectFields() + * Revision::selectArchiveFields() + * Revision::selectTextFields() + * Revision::selectPageFields() + * Revision::selectUserFields() === Deprecations in 1.34 === * The MWNamespace class is deprecated. Use NamespaceInfo. @@ -499,6 +513,10 @@ because of Phabricator reports. * Specifying a SpecialPage object for the list of special pages (either through the SpecialPage_initList hook or by adding to $wgSpecialPages) is now deprecated. +* Use of ActorMigration with 'ar_user', 'img_user', 'oi_user', 'fa_user', + 'rc_user', 'log_user', and 'ipb_by' is deprecated. Queries should be adjusted + to use the corresponding actor fields directly. Note that use with + 'rev_user' is *not* deprecated at this time. === Other changes in 1.34 === * … diff --git a/includes/ActorMigration.php b/includes/ActorMigration.php index 5dde8a04d4..c79074df75 100644 --- a/includes/ActorMigration.php +++ b/includes/ActorMigration.php @@ -28,15 +28,18 @@ use Wikimedia\Rdbms\IDatabase; * This class handles the logic for the actor table migration. * * This is not intended to be a long-term part of MediaWiki; it will be - * deprecated and removed along with $wgActorTableSchemaMigrationStage. + * deprecated and removed once actor migration is complete. * * @since 1.31 + * @since 1.34 Use with 'ar_user', 'img_user', 'oi_user', 'fa_user', + * 'rc_user', 'log_user', and 'ipb_by' is deprecated. Callers should + * reference the corresponding actor fields directly. */ class ActorMigration { /** * Constant for extensions to feature-test whether $wgActorTableSchemaMigrationStage - * expects MIGRATION_* or SCHEMA_COMPAT_* + * (in MW <1.34) expects MIGRATION_* or SCHEMA_COMPAT_* */ const MIGRATION_STAGE_SCHEMA_COMPAT = 1; @@ -68,6 +71,28 @@ class ActorMigration { */ private static $formerTempTables = []; + /** + * Define fields that are deprecated for use with this class. + * @var (string|null)[] Keys are '$key', value is null for soft deprecation + * or a string naming the deprecated version for hard deprecation. + */ + private static $deprecated = [ + 'ar_user' => null, // 1.34 + 'img_user' => null, // 1.34 + 'oi_user' => null, // 1.34 + 'fa_user' => null, // 1.34 + 'rc_user' => null, // 1.34 + 'log_user' => null, // 1.34 + 'ipb_by' => null, // 1.34 + ]; + + /** + * Define fields that are removed for use with this class. + * @var string[] Keys are '$key', value is the MediaWiki version in which + * use was removed. + */ + private static $removed = []; + /** * Define fields that use non-standard mapping * @var array Keys are the user id column name, values are arrays with two @@ -112,6 +137,21 @@ class ActorMigration { return MediaWikiServices::getInstance()->getActorMigration(); } + /** + * Issue deprecation warning/error as appropriate. + * @param string $key + */ + private static function checkDeprecation( $key ) { + if ( isset( self::$removed[$key] ) ) { + throw new InvalidArgumentException( + "Use of " . static::class . " for '$key' was removed in MediaWiki " . self::$removed[$key] + ); + } + if ( !empty( self::$deprecated[$key] ) ) { + wfDeprecated( static::class . " for '$key'", self::$deprecated[$key], false, 3 ); + } + } + /** * Return an SQL condition to test if a user field is anonymous * @param string $field Field name or SQL fragment @@ -152,6 +192,8 @@ class ActorMigration { * @phan-return array{tables:string[],fields:string[],joins:array} */ public function getJoin( $key ) { + self::checkDeprecation( $key ); + if ( !isset( $this->joinCache[$key] ) ) { $tables = []; $fields = []; @@ -203,6 +245,8 @@ class ActorMigration { * @return array to merge into `$values` to `IDatabase->update()` or `$a` to `IDatabase->insert()` */ public function getInsertValues( IDatabase $dbw, $key, UserIdentity $user ) { + self::checkDeprecation( $key ); + if ( isset( self::$tempTables[$key] ) ) { throw new InvalidArgumentException( "Must use getInsertValuesWithTempTable() for $key" ); } @@ -236,6 +280,8 @@ class ActorMigration { * and extra fields needed for the temp table. */ public function getInsertValuesWithTempTable( IDatabase $dbw, $key, UserIdentity $user ) { + self::checkDeprecation( $key ); + if ( isset( self::$formerTempTables[$key] ) ) { wfDeprecated( __METHOD__ . " for $key", self::$formerTempTables[$key] ); } elseif ( !isset( self::$tempTables[$key] ) ) { @@ -319,6 +365,8 @@ class ActorMigration { * All tables and joins are aliased, so `+` is safe to use. */ public function getWhere( IDatabase $db, $key, $users, $useId = true ) { + self::checkDeprecation( $key ); + $tables = []; $conds = []; $joins = []; diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 00708f459c..f6ac3422de 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -8979,24 +8979,6 @@ $wgMultiContentRevisionSchemaMigrationStage = SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_ */ $wgXmlDumpSchemaVersion = XML_DUMP_SCHEMA_VERSION_10; -/** - * Actor table schema migration stage. - * - * Use the SCHEMA_COMPAT_XXX flags. Supported values: - * - SCHEMA_COMPAT_OLD - * - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD - * - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW - * - SCHEMA_COMPAT_NEW - * - * Note that reading the old and new schema at the same time is not supported - * in 1.32, but was (with significant query performance issues) in 1.31. - * - * @since 1.31 - * @since 1.32 changed allowed flags - * @var int An appropriate combination of SCHEMA_COMPAT_XXX flags. - */ -$wgActorTableSchemaMigrationStage = SCHEMA_COMPAT_NEW; - /** * Flag to enable Partial Blocks. This allows an admin to prevent a user from editing specific pages * or namespaces. diff --git a/includes/Revision.php b/includes/Revision.php index c6e727e69b..292d6ba574 100644 --- a/includes/Revision.php +++ b/includes/Revision.php @@ -298,203 +298,6 @@ class Revision implements IDBAccessObject { return $rec ? new Revision( $rec ) : null; } - /** - * Return the value of a select() JOIN conds array for the user table. - * This will get user table rows for logged-in users. - * @since 1.19 - * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'user' ] ) instead. - * @return array - */ - public static function userJoinCond() { - global $wgActorTableSchemaMigrationStage; - - wfDeprecated( __METHOD__, '1.31' ); - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - // If code is using this instead of self::getQueryInfo(), there's - // no way the join it's trying to do can work once the old fields - // aren't being used anymore. - throw new BadMethodCallException( - 'Cannot use ' . __METHOD__ - . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW' - ); - } - - return [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ]; - } - - /** - * Return the value of a select() page conds array for the page table. - * This will assure that the revision(s) are not orphaned from live pages. - * @since 1.19 - * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'page' ] ) instead. - * @return array - */ - public static function pageJoinCond() { - wfDeprecated( __METHOD__, '1.31' ); - return [ 'JOIN', [ 'page_id = rev_page' ] ]; - } - - /** - * Return the list of revision fields that should be selected to create - * a new revision. - * @deprecated since 1.31, use RevisionStore::getQueryInfo() instead. - * @return array - */ - public static function selectFields() { - global $wgContentHandlerUseDB, $wgActorTableSchemaMigrationStage; - global $wgMultiContentRevisionSchemaMigrationStage; - - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - // If code is using this instead of self::getQueryInfo(), there's a - // decent chance it's going to try to directly access - // $row->rev_user or $row->rev_user_text and we can't give it - // useful values here once those aren't being used anymore. - throw new BadMethodCallException( - 'Cannot use ' . __METHOD__ - . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW' - ); - } - - if ( !( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) ) { - // If code is using this instead of self::getQueryInfo(), there's a - // decent chance it's going to try to directly access - // $row->rev_text_id or $row->rev_content_model and we can't give it - // useful values here once those aren't being written anymore, - // and may not exist at all. - throw new BadMethodCallException( - 'Cannot use ' . __METHOD__ . ' when $wgMultiContentRevisionSchemaMigrationStage ' - . 'does not have SCHEMA_COMPAT_WRITE_OLD set.' - ); - } - - wfDeprecated( __METHOD__, '1.31' ); - - $fields = [ - 'rev_id', - 'rev_page', - 'rev_text_id', - 'rev_timestamp', - 'rev_user_text', - 'rev_user', - 'rev_actor' => 'NULL', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - ]; - - $fields += CommentStore::getStore()->getFields( 'rev_comment' ); - - if ( $wgContentHandlerUseDB ) { - $fields[] = 'rev_content_format'; - $fields[] = 'rev_content_model'; - } - - return $fields; - } - - /** - * Return the list of revision fields that should be selected to create - * a new revision from an archive row. - * @deprecated since 1.31, use RevisionStore::getArchiveQueryInfo() instead. - * @return array - */ - public static function selectArchiveFields() { - global $wgContentHandlerUseDB, $wgActorTableSchemaMigrationStage; - global $wgMultiContentRevisionSchemaMigrationStage; - - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - // If code is using this instead of self::getQueryInfo(), there's a - // decent chance it's going to try to directly access - // $row->ar_user or $row->ar_user_text and we can't give it - // useful values here once those aren't being used anymore. - throw new BadMethodCallException( - 'Cannot use ' . __METHOD__ - . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW' - ); - } - - if ( !( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) ) { - // If code is using this instead of self::getQueryInfo(), there's a - // decent chance it's going to try to directly access - // $row->ar_text_id or $row->ar_content_model and we can't give it - // useful values here once those aren't being written anymore, - // and may not exist at all. - throw new BadMethodCallException( - 'Cannot use ' . __METHOD__ . ' when $wgMultiContentRevisionSchemaMigrationStage ' - . 'does not have SCHEMA_COMPAT_WRITE_OLD set.' - ); - } - - wfDeprecated( __METHOD__, '1.31' ); - - $fields = [ - 'ar_id', - 'ar_page_id', - 'ar_rev_id', - 'ar_text_id', - 'ar_timestamp', - 'ar_user_text', - 'ar_user', - 'ar_actor' => 'NULL', - 'ar_minor_edit', - 'ar_deleted', - 'ar_len', - 'ar_parent_id', - 'ar_sha1', - ]; - - $fields += CommentStore::getStore()->getFields( 'ar_comment' ); - - if ( $wgContentHandlerUseDB ) { - $fields[] = 'ar_content_format'; - $fields[] = 'ar_content_model'; - } - return $fields; - } - - /** - * Return the list of text fields that should be selected to read the - * revision text - * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'text' ] ) instead. - * @return array - */ - public static function selectTextFields() { - wfDeprecated( __METHOD__, '1.31' ); - return [ - 'old_text', - 'old_flags' - ]; - } - - /** - * Return the list of page fields that should be selected from page table - * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'page' ] ) instead. - * @return array - */ - public static function selectPageFields() { - wfDeprecated( __METHOD__, '1.31' ); - return [ - 'page_namespace', - 'page_title', - 'page_id', - 'page_latest', - 'page_is_redirect', - 'page_len', - ]; - } - - /** - * Return the list of user fields that should be selected from user table - * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'user' ] ) instead. - * @return array - */ - public static function selectUserFields() { - wfDeprecated( __METHOD__, '1.31' ); - return [ 'user_name' ]; - } - /** * Return the tables, fields, and join conditions to be selected to create * a new revision object. diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index f42ef31f05..0b0aaf54c8 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -77,9 +77,7 @@ use Wikimedia\ObjectFactory; return [ 'ActorMigration' => function ( MediaWikiServices $services ) : ActorMigration { - return new ActorMigration( - $services->getMainConfig()->get( 'ActorTableSchemaMigrationStage' ) - ); + return new ActorMigration( SCHEMA_COMPAT_NEW ); }, 'BadFileLookup' => function ( MediaWikiServices $services ) : BadFileLookup { diff --git a/includes/actions/InfoAction.php b/includes/actions/InfoAction.php index 7bcfc8821d..207721e583 100644 --- a/includes/actions/InfoAction.php +++ b/includes/actions/InfoAction.php @@ -743,8 +743,6 @@ class InfoAction extends FormlessAction { self::getCacheKey( $cache, $page->getTitle(), $page->getLatest() ), WANObjectCache::TTL_WEEK, function ( $oldValue, &$ttl, &$setOpts ) use ( $page, $config, $fname, $services ) { - global $wgActorTableSchemaMigrationStage; - $title = $page->getTitle(); $id = $title->getArticleID(); @@ -752,19 +750,11 @@ class InfoAction extends FormlessAction { $dbrWatchlist = wfGetDB( DB_REPLICA, 'watchlist' ); $setOpts += Database::getCacheSetOptions( $dbr, $dbrWatchlist ); - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - $tables = [ 'revision_actor_temp' ]; - $field = 'revactor_actor'; - $pageField = 'revactor_page'; - $tsField = 'revactor_timestamp'; - $joins = []; - } else { - $tables = [ 'revision' ]; - $field = 'rev_user_text'; - $pageField = 'rev_page'; - $tsField = 'rev_timestamp'; - $joins = []; - } + $tables = [ 'revision_actor_temp' ]; + $field = 'revactor_actor'; + $pageField = 'revactor_page'; + $tsField = 'revactor_timestamp'; + $joins = []; $watchedItemStore = $services->getWatchedItemStore(); diff --git a/includes/api/ApiQueryAllRevisions.php b/includes/api/ApiQueryAllRevisions.php index 3751102494..3d4c49bb0f 100644 --- a/includes/api/ApiQueryAllRevisions.php +++ b/includes/api/ApiQueryAllRevisions.php @@ -40,8 +40,6 @@ class ApiQueryAllRevisions extends ApiQueryRevisionsBase { * @return void */ protected function run( ApiPageSet $resultPageSet = null ) { - global $wgActorTableSchemaMigrationStage; - $db = $this->getDB(); $params = $this->extractRequestParams( false ); $services = MediaWikiServices::getInstance(); @@ -54,9 +52,7 @@ class ApiQueryAllRevisions extends ApiQueryRevisionsBase { $tsField = 'rev_timestamp'; $idField = 'rev_id'; $pageField = 'rev_page'; - if ( $params['user'] !== null && - ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) - ) { + if ( $params['user'] !== null ) { // The query is probably best done using the actor_timestamp index on // revision_actor_temp. Use the denormalized fields from that table. $tsField = 'revactor_timestamp'; diff --git a/includes/api/ApiQueryAllUsers.php b/includes/api/ApiQueryAllUsers.php index e0513e22d6..a7d4fb90a0 100644 --- a/includes/api/ApiQueryAllUsers.php +++ b/includes/api/ApiQueryAllUsers.php @@ -41,8 +41,6 @@ class ApiQueryAllUsers extends ApiQueryBase { } public function execute() { - global $wgActorTableSchemaMigrationStage; - $params = $this->extractRequestParams(); $activeUserDays = $this->getConfig()->get( 'ActiveUserDays' ); @@ -181,22 +179,17 @@ class ApiQueryAllUsers extends ApiQueryBase { ] ] ); // Actually count the actions using a subquery (T66505 and T66507) - $tables = [ 'recentchanges' ]; - $joins = []; - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_OLD ) { - $userCond = 'rc_user_text = user_name'; - } else { - $tables[] = 'actor'; - $joins['actor'] = [ 'JOIN', 'rc_actor = actor_id' ]; - $userCond = 'actor_user = user_id'; - } + $tables = [ 'recentchanges', 'actor' ]; + $joins = [ + 'actor' => [ 'JOIN', 'rc_actor = actor_id' ], + ]; $timestamp = $db->timestamp( wfTimestamp( TS_UNIX ) - $activeUserSeconds ); $this->addFields( [ 'recentactions' => '(' . $db->selectSQLText( $tables, 'COUNT(*)', [ - $userCond, + 'actor_user = user_id', 'rc_type != ' . $db->addQuotes( RC_EXTERNAL ), // no wikidata 'rc_log_type IS NULL OR rc_log_type != ' . $db->addQuotes( 'newusers' ), 'rc_timestamp >= ' . $db->addQuotes( $timestamp ), diff --git a/includes/api/ApiQueryContributors.php b/includes/api/ApiQueryContributors.php index a1945c4a81..f2e306fe83 100644 --- a/includes/api/ApiQueryContributors.php +++ b/includes/api/ApiQueryContributors.php @@ -46,8 +46,6 @@ class ApiQueryContributors extends ApiQueryBase { } public function execute() { - global $wgActorTableSchemaMigrationStage; - $db = $this->getDB(); $params = $this->extractRequestParams(); $this->requireMaxOneParameter( $params, 'group', 'excludegroup', 'rights', 'excluderights' ); @@ -80,14 +78,10 @@ class ApiQueryContributors extends ApiQueryBase { $result = $this->getResult(); $revQuery = MediaWikiServices::getInstance()->getRevisionStore()->getQueryInfo(); - // For SCHEMA_COMPAT_READ_NEW, target indexes on the - // revision_actor_temp table, otherwise on the revision table. - $pageField = ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) - ? 'revactor_page' : 'rev_page'; - $idField = ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) - ? 'revactor_actor' : $revQuery['fields']['rev_user']; - $countField = ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) - ? 'revactor_actor' : $revQuery['fields']['rev_user_text']; + // Target indexes on the revision_actor_temp table. + $pageField = 'revactor_page'; + $idField = 'revactor_actor'; + $countField = 'revactor_actor'; // First, count anons $this->addTables( $revQuery['tables'] ); diff --git a/includes/api/ApiQueryRevisions.php b/includes/api/ApiQueryRevisions.php index d616ad4f9a..5b2b1b72b9 100644 --- a/includes/api/ApiQueryRevisions.php +++ b/includes/api/ApiQueryRevisions.php @@ -85,8 +85,6 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase { } protected function run( ApiPageSet $resultPageSet = null ) { - global $wgActorTableSchemaMigrationStage; - $params = $this->extractRequestParams( false ); $revisionStore = MediaWikiServices::getInstance()->getRevisionStore(); @@ -137,9 +135,7 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase { $idField = 'rev_id'; $tsField = 'rev_timestamp'; $pageField = 'rev_page'; - if ( $params['user'] !== null && - ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) - ) { + if ( $params['user'] !== null ) { // We're going to want to use the page_actor_timestamp index (on revision_actor_temp) // so use that table's denormalized fields. $idField = 'revactor_rev'; diff --git a/includes/api/ApiQueryUserContribs.php b/includes/api/ApiQueryUserContribs.php index 919c7631b3..189f9572ee 100644 --- a/includes/api/ApiQueryUserContribs.php +++ b/includes/api/ApiQueryUserContribs.php @@ -42,8 +42,6 @@ class ApiQueryUserContribs extends ApiQueryBase { $fld_patrolled = false, $fld_tags = false, $fld_size = false, $fld_sizediff = false; public function execute() { - global $wgActorTableSchemaMigrationStage; - // Parse some parameters $this->params = $this->extractRequestParams(); @@ -82,8 +80,6 @@ class ApiQueryUserContribs extends ApiQueryBase { // a wiki with users "Test00000001" to "Test99999999"), use a // generator with batched lookup and continuation. $userIter = call_user_func( function () use ( $dbSecondary, $sort, $op, $fname ) { - global $wgActorTableSchemaMigrationStage; - $fromName = false; if ( !is_null( $this->params['continue'] ) ) { $continue = explode( '|', $this->params['continue'] ); @@ -97,26 +93,13 @@ class ApiQueryUserContribs extends ApiQueryBase { do { $from = $fromName ? "$op= " . $dbSecondary->addQuotes( $fromName ) : false; - - // For the new schema, pull from the actor table. For the - // old, pull from rev_user. - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - $res = $dbSecondary->select( - 'actor', - [ 'actor_id', 'user_id' => 'COALESCE(actor_user,0)', 'user_name' => 'actor_name' ], - array_merge( [ "actor_name$like" ], $from ? [ "actor_name $from" ] : [] ), - $fname, - [ 'ORDER BY' => [ "user_name $sort" ], 'LIMIT' => $limit ] - ); - } else { - $res = $dbSecondary->select( - 'revision', - [ 'actor_id' => 'NULL', 'user_id' => 'rev_user', 'user_name' => 'rev_user_text' ], - array_merge( [ "rev_user_text$like" ], $from ? [ "rev_user_text $from" ] : [] ), - $fname, - [ 'DISTINCT', 'ORDER BY' => [ "rev_user_text $sort" ], 'LIMIT' => $limit ] - ); - } + $res = $dbSecondary->select( + 'actor', + [ 'actor_id', 'user_id' => 'COALESCE(actor_user,0)', 'user_name' => 'actor_name' ], + array_merge( [ "actor_name$like" ], $from ? [ "actor_name $from" ] : [] ), + $fname, + [ 'ORDER BY' => [ "user_name $sort" ], 'LIMIT' => $limit ] + ); $count = 0; $fromName = false; @@ -159,25 +142,13 @@ class ApiQueryUserContribs extends ApiQueryBase { $from = "$op= $fromId"; } - // For the new schema, just select from the actor table. For the - // old, select from user. - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - $res = $dbSecondary->select( - 'actor', - [ 'actor_id', 'user_id' => 'actor_user', 'user_name' => 'actor_name' ], - array_merge( [ 'actor_user' => $ids ], $from ? [ "actor_id $from" ] : [] ), - __METHOD__, - [ 'ORDER BY' => "user_id $sort" ] - ); - } else { - $res = $dbSecondary->select( - 'user', - [ 'actor_id' => 'NULL', 'user_id' => 'user_id', 'user_name' => 'user_name' ], - array_merge( [ 'user_id' => $ids ], $from ? [ "user_id $from" ] : [] ), - __METHOD__, - [ 'ORDER BY' => "user_id $sort" ] - ); - } + $res = $dbSecondary->select( + 'actor', + [ 'actor_id', 'user_id' => 'actor_user', 'user_name' => 'actor_name' ], + array_merge( [ 'actor_user' => $ids ], $from ? [ "actor_id $from" ] : [] ), + __METHOD__, + [ 'ORDER BY' => "user_id $sort" ] + ); $userIter = UserArray::newFromResult( $res ); $batchSize = count( $ids ); } else { @@ -222,57 +193,22 @@ class ApiQueryUserContribs extends ApiQueryBase { $from = "$op= " . $dbSecondary->addQuotes( $fromName ); } - // For the new schema, just select from the actor table. For the - // old, select from user then merge in any unknown users (IPs and imports). - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - $res = $dbSecondary->select( - 'actor', - [ 'actor_id', 'user_id' => 'actor_user', 'user_name' => 'actor_name' ], - array_merge( [ 'actor_name' => array_keys( $names ) ], $from ? [ "actor_id $from" ] : [] ), - __METHOD__, - [ 'ORDER BY' => "actor_name $sort" ] - ); - $userIter = UserArray::newFromResult( $res ); - } else { - $res = $dbSecondary->select( - 'user', - [ 'actor_id' => 'NULL', 'user_id', 'user_name' ], - array_merge( [ 'user_name' => array_keys( $names ) ], $from ? [ "user_name $from" ] : [] ), - __METHOD__ - ); - foreach ( $res as $row ) { - $names[$row->user_name] = $row; - } - if ( $this->params['dir'] == 'newer' ) { - ksort( $names, SORT_STRING ); - } else { - krsort( $names, SORT_STRING ); - } - $neg = $op === '>' ? -1 : 1; - $userIter = call_user_func( function () use ( $names, $fromName, $neg ) { - foreach ( $names as $name => $row ) { - if ( $fromName === false || $neg * strcmp( $name, $fromName ) <= 0 ) { - $user = $row ? User::newFromRow( $row ) : User::newFromName( $name, false ); - yield $user; - } - } - } ); - } + $res = $dbSecondary->select( + 'actor', + [ 'actor_id', 'user_id' => 'actor_user', 'user_name' => 'actor_name' ], + array_merge( [ 'actor_name' => array_keys( $names ) ], $from ? [ "actor_id $from" ] : [] ), + __METHOD__, + [ 'ORDER BY' => "actor_name $sort" ] + ); + $userIter = UserArray::newFromResult( $res ); $batchSize = count( $names ); } - // With the new schema, the DB query will order by actor so update $this->orderBy to match. - if ( $batchSize > 1 && ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) ) { + // The DB query will order by actor so update $this->orderBy to match. + if ( $batchSize > 1 ) { $this->orderBy = 'actor'; } - // Use the 'contributions' replica, but only if we're querying by user ID (T216656). - if ( $this->orderBy === 'id' && - !( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) - ) { - $this->selectNamedDB( 'contributions', DB_REPLICA, 'contributions' ); - } - $count = 0; $limit = $this->params['limit']; $userIter->rewind(); @@ -325,47 +261,33 @@ class ApiQueryUserContribs extends ApiQueryBase { * @param int $limit */ private function prepareQuery( array $users, $limit ) { - global $wgActorTableSchemaMigrationStage; - $this->resetQueryParams(); $db = $this->getDB(); $revQuery = MediaWikiServices::getInstance()->getRevisionStore()->getQueryInfo( [ 'page' ] ); - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - $revWhere = ActorMigration::newMigration()->getWhere( $db, 'rev_user', $users ); - $orderUserField = 'rev_actor'; - $userField = $this->orderBy === 'actor' ? 'revactor_actor' : 'actor_name'; - $tsField = 'revactor_timestamp'; - $idField = 'revactor_rev'; - - // T221511: MySQL/MariaDB (10.1.37) can sometimes irrationally decide that querying `actor` - // before `revision_actor_temp` and filesorting is somehow better than querying $limit+1 rows - // from `revision_actor_temp`. Tell it not to reorder the query (and also reorder it ourselves - // because as generated by RevisionStore it'll have `revision` first rather than - // `revision_actor_temp`). But not when uctag is used, as it seems as likely to be harmed as - // helped in that case, and not when there's only one User because in that case it fetches - // the one `actor` row as a constant and doesn't filesort. - if ( count( $users ) > 1 && !isset( $this->params['tag'] ) ) { - $revQuery['joins']['revision'] = $revQuery['joins']['temp_rev_user']; - unset( $revQuery['joins']['temp_rev_user'] ); - $this->addOption( 'STRAIGHT_JOIN' ); - // It isn't actually necesssary to reorder $revQuery['tables'] as Database does the right thing - // when join conditions are given for all joins, but Gergő is wary of relying on that so pull - // `revision_actor_temp` to the start. - $revQuery['tables'] = - [ 'temp_rev_user' => $revQuery['tables']['temp_rev_user'] ] + $revQuery['tables']; - } - } else { - // If we're dealing with user names (rather than IDs) in read-old mode, - // pass false for ActorMigration::getWhere()'s $useId parameter so - // $revWhere['conds'] isn't an OR. - $revWhere = ActorMigration::newMigration() - ->getWhere( $db, 'rev_user', $users, $this->orderBy === 'id' ); - $orderUserField = $this->orderBy === 'id' ? 'rev_user' : 'rev_user_text'; - $userField = $revQuery['fields'][$orderUserField]; - $tsField = 'rev_timestamp'; - $idField = 'rev_id'; + $revWhere = ActorMigration::newMigration()->getWhere( $db, 'rev_user', $users ); + $orderUserField = 'rev_actor'; + $userField = $this->orderBy === 'actor' ? 'revactor_actor' : 'actor_name'; + $tsField = 'revactor_timestamp'; + $idField = 'revactor_rev'; + + // T221511: MySQL/MariaDB (10.1.37) can sometimes irrationally decide that querying `actor` + // before `revision_actor_temp` and filesorting is somehow better than querying $limit+1 rows + // from `revision_actor_temp`. Tell it not to reorder the query (and also reorder it ourselves + // because as generated by RevisionStore it'll have `revision` first rather than + // `revision_actor_temp`). But not when uctag is used, as it seems as likely to be harmed as + // helped in that case, and not when there's only one User because in that case it fetches + // the one `actor` row as a constant and doesn't filesort. + if ( count( $users ) > 1 && !isset( $this->params['tag'] ) ) { + $revQuery['joins']['revision'] = $revQuery['joins']['temp_rev_user']; + unset( $revQuery['joins']['temp_rev_user'] ); + $this->addOption( 'STRAIGHT_JOIN' ); + // It isn't actually necesssary to reorder $revQuery['tables'] as Database does the right thing + // when join conditions are given for all joins, but Gergő is wary of relying on that so pull + // `revision_actor_temp` to the start. + $revQuery['tables'] = + [ 'temp_rev_user' => $revQuery['tables']['temp_rev_user'] ] + $revQuery['tables']; } $this->addTables( $revQuery['tables'] ); diff --git a/includes/api/ApiQueryUserInfo.php b/includes/api/ApiQueryUserInfo.php index 12d7435453..28dea3b9e4 100644 --- a/includes/api/ApiQueryUserInfo.php +++ b/includes/api/ApiQueryUserInfo.php @@ -303,32 +303,17 @@ class ApiQueryUserInfo extends ApiQueryBase { * @return string|null ISO 8601 timestamp of current user's last contribution or null if none */ protected function getLatestContributionTime() { - global $wgActorTableSchemaMigrationStage; - $user = $this->getUser(); $dbr = $this->getDB(); - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - if ( $user->getActorId() === null ) { - return null; - } - $res = $dbr->selectField( 'revision_actor_temp', - 'MAX(revactor_timestamp)', - [ 'revactor_actor' => $user->getActorId() ], - __METHOD__ - ); - } else { - if ( $user->isLoggedIn() ) { - $conds = [ 'rev_user' => $user->getId() ]; - } else { - $conds = [ 'rev_user_text' => $user->getName() ]; - } - $res = $dbr->selectField( 'revision', - 'MAX(rev_timestamp)', - $conds, - __METHOD__ - ); + if ( $user->getActorId() === null ) { + return null; } + $res = $dbr->selectField( 'revision_actor_temp', + 'MAX(revactor_timestamp)', + [ 'revactor_actor' => $user->getActorId() ], + __METHOD__ + ); return $res ? wfTimestamp( TS_ISO_8601, $res ) : null; } diff --git a/includes/block/DatabaseBlock.php b/includes/block/DatabaseBlock.php index 6007abdf41..b1a8e215b8 100644 --- a/includes/block/DatabaseBlock.php +++ b/includes/block/DatabaseBlock.php @@ -24,7 +24,6 @@ namespace MediaWiki\Block; use ActorMigration; use AutoCommitUpdate; -use BadMethodCallException; use CommentStore; use DeferredUpdates; use Hooks; @@ -161,47 +160,6 @@ class DatabaseBlock extends AbstractBlock { } } - /** - * Return the list of ipblocks fields that should be selected to create - * a new block. - * @deprecated since 1.31, use self::getQueryInfo() instead. - * @return array - */ - public static function selectFields() { - global $wgActorTableSchemaMigrationStage; - - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - // If code is using this instead of self::getQueryInfo(), there's a - // decent chance it's going to try to directly access - // $row->ipb_by or $row->ipb_by_text and we can't give it - // useful values here once those aren't being used anymore. - throw new BadMethodCallException( - 'Cannot use ' . __METHOD__ - . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW' - ); - } - - wfDeprecated( __METHOD__, '1.31' ); - return [ - 'ipb_id', - 'ipb_address', - 'ipb_by', - 'ipb_by_text', - 'ipb_by_actor' => 'NULL', - 'ipb_timestamp', - 'ipb_auto', - 'ipb_anon_only', - 'ipb_create_account', - 'ipb_enable_autoblock', - 'ipb_expiry', - 'ipb_deleted', - 'ipb_block_email', - 'ipb_allow_usertalk', - 'ipb_parent_block_id', - 'ipb_sitewide', - ] + CommentStore::getStore()->getFields( 'ipb_reason' ); - } - /** * Return the tables, fields, and join conditions to be selected to create * a new block object. diff --git a/includes/cache/UserCache.php b/includes/cache/UserCache.php index 8f816d9013..bc0bbfa1ce 100644 --- a/includes/cache/UserCache.php +++ b/includes/cache/UserCache.php @@ -78,8 +78,6 @@ class UserCache { * @param string $caller The calling method */ public function doQuery( array $userIds, $options = [], $caller = '' ) { - global $wgActorTableSchemaMigrationStage; - $usersToCheck = []; $usersToQuery = []; @@ -100,21 +98,12 @@ class UserCache { // Lookup basic info for users not yet loaded... if ( count( $usersToQuery ) ) { $dbr = wfGetDB( DB_REPLICA ); - $tables = [ 'user' ]; + $tables = [ 'user', 'actor' ]; $conds = [ 'user_id' => $usersToQuery ]; - $fields = [ 'user_name', 'user_real_name', 'user_registration', 'user_id' ]; - $joinConds = []; - - // Technically we shouldn't allow this without SCHEMA_COMPAT_READ_NEW, - // but it does little harm and might be needed for write callers loading a User. - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_NEW ) { - $tables[] = 'actor'; - $fields[] = 'actor_id'; - $joinConds['actor'] = [ - ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) ? 'JOIN' : 'LEFT JOIN', - [ 'actor_user = user_id' ] - ]; - } + $fields = [ 'user_name', 'user_real_name', 'user_registration', 'user_id', 'actor_id' ]; + $joinConds = [ + 'actor' => [ 'JOIN', 'actor_user = user_id' ], + ]; $comment = __METHOD__; if ( strval( $caller ) !== '' ) { @@ -127,9 +116,7 @@ class UserCache { $this->cache[$userId]['name'] = $row->user_name; $this->cache[$userId]['real_name'] = $row->user_real_name; $this->cache[$userId]['registration'] = $row->user_registration; - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_NEW ) { - $this->cache[$userId]['actor'] = $row->actor_id; - } + $this->cache[$userId]['actor'] = $row->actor_id; $usersToCheck[$userId] = $row->user_name; } } diff --git a/includes/changes/RecentChange.php b/includes/changes/RecentChange.php index 1d590d9c36..e18482505c 100644 --- a/includes/changes/RecentChange.php +++ b/includes/changes/RecentChange.php @@ -221,55 +221,6 @@ class RecentChange implements Taggable { } } - /** - * Return the list of recentchanges fields that should be selected to create - * a new recentchanges object. - * @deprecated since 1.31, use self::getQueryInfo() instead. - * @return array - */ - public static function selectFields() { - global $wgActorTableSchemaMigrationStage; - - wfDeprecated( __METHOD__, '1.31' ); - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - // If code is using this instead of self::getQueryInfo(), there's a - // decent chance it's going to try to directly access - // $row->rc_user or $row->rc_user_text and we can't give it - // useful values here once those aren't being used anymore. - throw new BadMethodCallException( - 'Cannot use ' . __METHOD__ - . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW' - ); - } - - return [ - 'rc_id', - 'rc_timestamp', - 'rc_user', - 'rc_user_text', - 'rc_actor' => 'NULL', - 'rc_namespace', - 'rc_title', - 'rc_minor', - 'rc_bot', - 'rc_new', - 'rc_cur_id', - 'rc_this_oldid', - 'rc_last_oldid', - 'rc_type', - 'rc_source', - 'rc_patrolled', - 'rc_ip', - 'rc_old_len', - 'rc_new_len', - 'rc_deleted', - 'rc_logid', - 'rc_log_type', - 'rc_log_action', - 'rc_params', - ] + CommentStore::getStore()->getFields( 'rc_comment' ); - } - /** * Return the tables, fields, and join conditions to be selected to create * a new recentchanges object. diff --git a/includes/filerepo/file/ArchivedFile.php b/includes/filerepo/file/ArchivedFile.php index 6a3e819a33..17fa146440 100644 --- a/includes/filerepo/file/ArchivedFile.php +++ b/includes/filerepo/file/ArchivedFile.php @@ -213,50 +213,6 @@ class ArchivedFile { return $file; } - /** - * Fields in the filearchive table - * @deprecated since 1.31, use self::getQueryInfo() instead. - * @return string[] - */ - static function selectFields() { - global $wgActorTableSchemaMigrationStage; - - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - // If code is using this instead of self::getQueryInfo(), there's a - // decent chance it's going to try to directly access - // $row->fa_user or $row->fa_user_text and we can't give it - // useful values here once those aren't being used anymore. - throw new BadMethodCallException( - 'Cannot use ' . __METHOD__ - . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW' - ); - } - - wfDeprecated( __METHOD__, '1.31' ); - return [ - 'fa_id', - 'fa_name', - 'fa_archive_name', - 'fa_storage_key', - 'fa_storage_group', - 'fa_size', - 'fa_bits', - 'fa_width', - 'fa_height', - 'fa_metadata', - 'fa_media_type', - 'fa_major_mime', - 'fa_minor_mime', - 'fa_user', - 'fa_user_text', - 'fa_actor' => 'NULL', - 'fa_timestamp', - 'fa_deleted', - 'fa_deleted_timestamp', /* Used by LocalFileRestoreBatch */ - 'fa_sha1', - ] + MediaWikiServices::getInstance()->getCommentStore()->getFields( 'fa_description' ); - } - /** * Return the tables, fields, and join conditions to be selected to create * a new archivedfile object. diff --git a/includes/filerepo/file/LocalFile.php b/includes/filerepo/file/LocalFile.php index 3090632448..ceb8dda9c7 100644 --- a/includes/filerepo/file/LocalFile.php +++ b/includes/filerepo/file/LocalFile.php @@ -202,44 +202,6 @@ class LocalFile extends File { } } - /** - * Fields in the image table - * @deprecated since 1.31, use self::getQueryInfo() instead. - * @return string[] - */ - static function selectFields() { - global $wgActorTableSchemaMigrationStage; - - wfDeprecated( __METHOD__, '1.31' ); - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - // If code is using this instead of self::getQueryInfo(), there's a - // decent chance it's going to try to directly access - // $row->img_user or $row->img_user_text and we can't give it - // useful values here once those aren't being used anymore. - throw new BadMethodCallException( - 'Cannot use ' . __METHOD__ - . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW' - ); - } - - return [ - 'img_name', - 'img_size', - 'img_width', - 'img_height', - 'img_metadata', - 'img_bits', - 'img_media_type', - 'img_major_mime', - 'img_minor_mime', - 'img_user', - 'img_user_text', - 'img_actor' => 'NULL', - 'img_timestamp', - 'img_sha1', - ] + MediaWikiServices::getInstance()->getCommentStore()->getFields( 'img_description' ); - } - /** * Return the tables, fields, and join conditions to be selected to create * a new localfile object. @@ -1449,8 +1411,6 @@ class LocalFile extends File { $oldver, $comment, $pageText, $props = false, $timestamp = false, $user = null, $tags = [], $createNullRevision = true, $revert = false ) { - global $wgActorTableSchemaMigrationStage; - if ( is_null( $user ) ) { global $wgUser; $user = $wgUser; @@ -1553,40 +1513,10 @@ class LocalFile extends File { 'oi_major_mime' => 'img_major_mime', 'oi_minor_mime' => 'img_minor_mime', 'oi_sha1' => 'img_sha1', + 'oi_actor' => 'img_actor', ]; $joins = []; - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) { - $fields['oi_user'] = 'img_user'; - $fields['oi_user_text'] = 'img_user_text'; - } - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $fields['oi_actor'] = 'img_actor'; - } - - if ( - ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_BOTH ) === SCHEMA_COMPAT_WRITE_BOTH - ) { - // Upgrade any rows that are still old-style. Otherwise an upgrade - // might be missed if a deletion happens while the migration script - // is running. - $res = $dbw->select( - [ 'image' ], - [ 'img_name', 'img_user', 'img_user_text' ], - [ 'img_name' => $this->getName(), 'img_actor' => 0 ], - __METHOD__ - ); - foreach ( $res as $row ) { - $actorId = User::newFromAnyId( $row->img_user, $row->img_user_text, null )->getActorId( $dbw ); - $dbw->update( - 'image', - [ 'img_actor' => $actorId ], - [ 'img_name' => $row->img_name, 'img_actor' => 0 ], - __METHOD__ - ); - } - } - # (T36993) Note: $oldver can be empty here, if the previous # version of the file was broken. Allow registration of the new # version to continue anyway, because that's better than having diff --git a/includes/filerepo/file/LocalFileDeleteBatch.php b/includes/filerepo/file/LocalFileDeleteBatch.php index 61faa09535..85988f6141 100644 --- a/includes/filerepo/file/LocalFileDeleteBatch.php +++ b/includes/filerepo/file/LocalFileDeleteBatch.php @@ -178,8 +178,6 @@ class LocalFileDeleteBatch { } protected function doDBInserts() { - global $wgActorTableSchemaMigrationStage; - $now = time(); $dbw = $this->file->repo->getMasterDB(); @@ -225,7 +223,8 @@ class LocalFileDeleteBatch { 'fa_minor_mime' => 'img_minor_mime', 'fa_description_id' => 'img_description_id', 'fa_timestamp' => 'img_timestamp', - 'fa_sha1' => 'img_sha1' + 'fa_sha1' => 'img_sha1', + 'fa_actor' => 'img_actor', ]; $joins = []; @@ -234,37 +233,6 @@ class LocalFileDeleteBatch { $commentStore->insert( $dbw, 'fa_deleted_reason', $this->reason ) ); - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) { - $fields['fa_user'] = 'img_user'; - $fields['fa_user_text'] = 'img_user_text'; - } - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $fields['fa_actor'] = 'img_actor'; - } - - if ( - ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_BOTH ) === SCHEMA_COMPAT_WRITE_BOTH - ) { - // Upgrade any rows that are still old-style. Otherwise an upgrade - // might be missed if a deletion happens while the migration script - // is running. - $res = $dbw->select( - [ 'image' ], - [ 'img_name', 'img_user', 'img_user_text' ], - [ 'img_name' => $this->file->getName(), 'img_actor' => 0 ], - __METHOD__ - ); - foreach ( $res as $row ) { - $actorId = User::newFromAnyId( $row->img_user, $row->img_user_text, null )->getActorId( $dbw ); - $dbw->update( - 'image', - [ 'img_actor' => $actorId ], - [ 'img_name' => $row->img_name, 'img_actor' => 0 ], - __METHOD__ - ); - } - } - $dbw->insertSelect( 'filearchive', $tables, $fields, [ 'img_name' => $this->file->getName() ], __METHOD__, [], [], $joins ); } diff --git a/includes/filerepo/file/OldLocalFile.php b/includes/filerepo/file/OldLocalFile.php index 584e001211..f5b7d4384c 100644 --- a/includes/filerepo/file/OldLocalFile.php +++ b/includes/filerepo/file/OldLocalFile.php @@ -106,46 +106,6 @@ class OldLocalFile extends LocalFile { } } - /** - * Fields in the oldimage table - * @deprecated since 1.31, use self::getQueryInfo() instead. - * @return string[] - */ - static function selectFields() { - global $wgActorTableSchemaMigrationStage; - - wfDeprecated( __METHOD__, '1.31' ); - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - // If code is using this instead of self::getQueryInfo(), there's a - // decent chance it's going to try to directly access - // $row->oi_user or $row->oi_user_text and we can't give it - // useful values here once those aren't being used anymore. - throw new BadMethodCallException( - 'Cannot use ' . __METHOD__ - . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW' - ); - } - - return [ - 'oi_name', - 'oi_archive_name', - 'oi_size', - 'oi_width', - 'oi_height', - 'oi_metadata', - 'oi_bits', - 'oi_media_type', - 'oi_major_mime', - 'oi_minor_mime', - 'oi_user', - 'oi_user_text', - 'oi_actor' => 'NULL', - 'oi_timestamp', - 'oi_deleted', - 'oi_sha1', - ] + MediaWikiServices::getInstance()->getCommentStore()->getFields( 'oi_description' ); - } - /** * Return the tables, fields, and join conditions to be selected to create * a new oldlocalfile object. diff --git a/includes/installer/DatabaseUpdater.php b/includes/installer/DatabaseUpdater.php index e1df8444d9..3412aef2ef 100644 --- a/includes/installer/DatabaseUpdater.php +++ b/includes/installer/DatabaseUpdater.php @@ -1308,10 +1308,7 @@ abstract class DatabaseUpdater { * @since 1.31 */ protected function migrateActors() { - global $wgActorTableSchemaMigrationStage; - if ( ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) && - !$this->updateRowExists( 'MigrateActors' ) - ) { + if ( !$this->updateRowExists( 'MigrateActors' ) ) { $this->output( "Migrating actors to the 'actor' table, printing progress markers. For large\n" . "databases, you may want to hit Ctrl-C and do this manually with\n" . @@ -1401,4 +1398,43 @@ abstract class DatabaseUpdater { } } } + + /** + * Only run a function if the `actor` table does not exist + * + * The transition to the actor table is dropping several indexes (and a few + * fields) that old upgrades want to add. This function is used to prevent + * those from running to re-add things when the `actor` table exists, while + * still allowing them to run if this really is an upgrade from an old MW + * version. + * + * @since 1.34 + * @param string|array|static $func Normally this is the string naming the method on $this to + * call. It may also be an array callable. If passed $this, it's assumed to be a call from + * runUpdates() with $passSelf = true: $params[0] is assumed to be the real $func and $this + * is prepended to the rest of $params. + * @param mixed ...$params Parameters for `$func` + * @return mixed Whatever $func returns, or null when skipped. + */ + protected function ifNoActorTable( $func, ...$params ) { + if ( $this->tableExists( 'actor' ) ) { + return null; + } + + // Handle $passSelf from runUpdates(). + $passSelf = false; + if ( $func === $this ) { + $passSelf = true; + $func = array_shift( $params ); + } + + if ( !is_array( $func ) && method_exists( $this, $func ) ) { + $func = [ $this, $func ]; + } elseif ( $passSelf ) { + array_unshift( $params, $this ); + } + + // @phan-suppress-next-line PhanUndeclaredInvokeInCallable Phan is confused + return $func( ...$params ); + } } diff --git a/includes/installer/MysqlUpdater.php b/includes/installer/MysqlUpdater.php index 0d516b48fe..64c017bbd9 100644 --- a/includes/installer/MysqlUpdater.php +++ b/includes/installer/MysqlUpdater.php @@ -101,8 +101,10 @@ class MysqlUpdater extends DatabaseUpdater { [ 'addTable', 'querycache_info', 'patch-querycacheinfo.sql' ], [ 'addTable', 'filearchive', 'patch-filearchive.sql' ], [ 'addField', 'ipblocks', 'ipb_anon_only', 'patch-ipb_anon_only.sql' ], - [ 'addIndex', 'recentchanges', 'rc_ns_usertext', 'patch-recentchanges-utindex.sql' ], - [ 'addIndex', 'recentchanges', 'rc_user_text', 'patch-rc_user_text-index.sql' ], + [ 'ifNoActorTable', 'addIndex', 'recentchanges', 'rc_ns_usertext', + 'patch-recentchanges-utindex.sql' ], + [ 'ifNoActorTable', 'addIndex', 'recentchanges', 'rc_user_text', + 'patch-rc_user_text-index.sql' ], // 1.9 [ 'addField', 'user', 'user_newpass_time', 'patch-user_newpass_time.sql' ], @@ -130,9 +132,12 @@ class MysqlUpdater extends DatabaseUpdater { [ 'addField', 'ipblocks', 'ipb_block_email', 'patch-ipb_emailban.sql' ], [ 'doCategorylinksIndicesUpdate' ], [ 'addField', 'oldimage', 'oi_metadata', 'patch-oi_metadata.sql' ], - [ 'addIndex', 'archive', 'usertext_timestamp', 'patch-archive-user-index.sql' ], - [ 'addIndex', 'image', 'img_usertext_timestamp', 'patch-image-user-index.sql' ], - [ 'addIndex', 'oldimage', 'oi_usertext_timestamp', 'patch-oldimage-user-index.sql' ], + [ 'ifNoActorTable', 'addIndex', 'archive', 'usertext_timestamp', + 'patch-archive-user-index.sql' ], + [ 'ifNoActorTable', 'addIndex', 'image', 'img_usertext_timestamp', + 'patch-image-user-index.sql' ], + [ 'ifNoActorTable', 'addIndex', 'oldimage', 'oi_usertext_timestamp', + 'patch-oldimage-user-index.sql' ], [ 'addField', 'archive', 'ar_page_id', 'patch-archive-page_id.sql' ], [ 'addField', 'image', 'img_sha1', 'patch-img_sha1.sql' ], @@ -140,7 +145,7 @@ class MysqlUpdater extends DatabaseUpdater { [ 'addTable', 'protected_titles', 'patch-protected_titles.sql' ], // 1.13 - [ 'addField', 'ipblocks', 'ipb_by_text', 'patch-ipb_by_text.sql' ], + [ 'ifNoActorTable', 'addField', 'ipblocks', 'ipb_by_text', 'patch-ipb_by_text.sql' ], [ 'addTable', 'page_props', 'patch-page_props.sql' ], [ 'addTable', 'updatelog', 'patch-updatelog.sql' ], [ 'addTable', 'category', 'patch-category.sql' ], @@ -150,7 +155,7 @@ class MysqlUpdater extends DatabaseUpdater { [ 'doPopulateParentId' ], [ 'checkBin', 'protected_titles', 'pt_title', 'patch-pt_title-encoding.sql', ], [ 'doMaybeProfilingMemoryUpdate' ], - [ 'doFilearchiveIndicesUpdate' ], + [ 'ifNoActorTable', 'doFilearchiveIndicesUpdate' ], // 1.14 [ 'addField', 'site_stats', 'ss_active_users', 'patch-ss_active_users.sql' ], @@ -163,9 +168,9 @@ class MysqlUpdater extends DatabaseUpdater { // 1.16 [ 'addTable', 'user_properties', 'patch-user_properties.sql' ], [ 'addTable', 'log_search', 'patch-log_search.sql' ], - [ 'addField', 'logging', 'log_user_text', 'patch-log_user_text.sql' ], + [ 'ifNoActorTable', 'addField', 'logging', 'log_user_text', 'patch-log_user_text.sql' ], # listed separately from the previous update because 1.16 was released without this update - [ 'doLogUsertextPopulation' ], + [ 'ifNoActorTable', 'doLogUsertextPopulation' ], [ 'doLogSearchPopulation' ], [ 'addTable', 'l10n_cache', 'patch-l10n_cache.sql' ], [ 'dropIndex', 'change_tag', 'ct_rc_id', 'patch-change_tag-indexes.sql' ], @@ -240,9 +245,10 @@ class MysqlUpdater extends DatabaseUpdater { // 1.23 [ 'addField', 'recentchanges', 'rc_source', 'patch-rc_source.sql' ], - [ 'addIndex', 'logging', 'log_user_text_type_time', + [ 'ifNoActorTable', 'addIndex', 'logging', 'log_user_text_type_time', 'patch-logging_user_text_type_time_index.sql' ], - [ 'addIndex', 'logging', 'log_user_text_time', 'patch-logging_user_text_time_index.sql' ], + [ 'ifNoActorTable', 'addIndex', 'logging', 'log_user_text_time', + 'patch-logging_user_text_time_index.sql' ], [ 'addField', 'page', 'page_links_updated', 'patch-page_links_updated.sql' ], [ 'addField', 'user', 'user_password_expires', 'patch-user_password_expire.sql' ], @@ -288,13 +294,14 @@ class MysqlUpdater extends DatabaseUpdater { [ 'doNonUniquePlTlIl' ], [ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ], [ 'modifyField', 'recentchanges', 'rc_ip', 'patch-rc_ip_modify.sql' ], - [ 'addIndex', 'archive', 'usertext_timestamp', 'patch-rename-ar_usertext_timestamp.sql' ], + [ 'ifNoActorTable', 'addIndex', 'archive', 'usertext_timestamp', + 'patch-rename-ar_usertext_timestamp.sql' ], // 1.29 [ 'addField', 'externallinks', 'el_index_60', 'patch-externallinks-el_index_60.sql' ], [ 'dropIndex', 'user_groups', 'ug_user_group', 'patch-user_groups-primary-key.sql' ], [ 'addField', 'user_groups', 'ug_expiry', 'patch-user_groups-ug_expiry.sql' ], - [ 'addIndex', 'image', 'img_user_timestamp', 'patch-image-user-index-2.sql' ], + [ 'ifNoActorTable', 'addIndex', 'image', 'img_user_timestamp', 'patch-image-user-index-2.sql' ], // 1.30 [ 'modifyField', 'image', 'img_media_type', 'patch-add-3d.sql' ], @@ -377,6 +384,9 @@ class MysqlUpdater extends DatabaseUpdater { [ 'dropTable', 'tag_summary' ], [ 'dropField', 'protected_titles', 'pt_reason', 'patch-drop-comment-fields.sql' ], [ 'modifyTable', 'job', 'patch-job-params-mediumblob.sql' ], + + // 1.34 + [ 'dropField', 'logging', 'log_user', 'patch-drop-user-fields.sql' ], ]; } diff --git a/includes/installer/PostgresUpdater.php b/includes/installer/PostgresUpdater.php index 31827a1ab7..b2c7d66ae7 100644 --- a/includes/installer/PostgresUpdater.php +++ b/includes/installer/PostgresUpdater.php @@ -110,7 +110,7 @@ class PostgresUpdater extends DatabaseUpdater { [ 'addPgField', 'image', 'img_sha1', "TEXT NOT NULL DEFAULT ''" ], [ 'addPgField', 'ipblocks', 'ipb_allow_usertalk', 'SMALLINT NOT NULL DEFAULT 0' ], [ 'addPgField', 'ipblocks', 'ipb_anon_only', 'SMALLINT NOT NULL DEFAULT 0' ], - [ 'addPgField', 'ipblocks', 'ipb_by_text', "TEXT NOT NULL DEFAULT ''" ], + [ 'ifNoActorTable', 'addPgField', 'ipblocks', 'ipb_by_text', "TEXT NOT NULL DEFAULT ''" ], [ 'addPgField', 'ipblocks', 'ipb_block_email', 'SMALLINT NOT NULL DEFAULT 0' ], [ 'addPgField', 'ipblocks', 'ipb_create_account', 'SMALLINT NOT NULL DEFAULT 1' ], [ 'addPgField', 'ipblocks', 'ipb_deleted', 'SMALLINT NOT NULL DEFAULT 0' ], @@ -152,7 +152,7 @@ class PostgresUpdater extends DatabaseUpdater { [ 'addPgField', 'revision', 'rev_content_format', 'TEXT' ], [ 'addPgField', 'site_stats', 'ss_active_users', "INTEGER DEFAULT '-1'" ], [ 'addPgField', 'user_newtalk', 'user_last_timestamp', 'TIMESTAMPTZ' ], - [ 'addPgField', 'logging', 'log_user_text', "TEXT NOT NULL DEFAULT ''" ], + [ 'ifNoActorTable', 'addPgField', 'logging', 'log_user_text', "TEXT NOT NULL DEFAULT ''" ], [ 'addPgField', 'logging', 'log_page', 'INTEGER' ], [ 'addPgField', 'interwiki', 'iw_api', "TEXT NOT NULL DEFAULT ''" ], [ 'addPgField', 'interwiki', 'iw_wikiid', "TEXT NOT NULL DEFAULT ''" ], @@ -240,7 +240,7 @@ class PostgresUpdater extends DatabaseUpdater { [ 'checkOiDeleted' ], # New indexes - [ 'addPgIndex', 'archive', 'archive_user_text', '(ar_user_text)' ], + [ 'ifNoActorTable', 'addPgIndex', 'archive', 'archive_user_text', '(ar_user_text)' ], [ 'addPgIndex', 'image', 'img_sha1', '(img_sha1)' ], [ 'addPgIndex', 'ipblocks', 'ipb_parent_block_id', '(ipb_parent_block_id)' ], [ 'addPgIndex', 'oldimage', 'oi_sha1', '(oi_sha1)' ], @@ -253,7 +253,7 @@ class PostgresUpdater extends DatabaseUpdater { [ 'addPgIndex', 'watchlist', 'wl_user', '(wl_user)' ], [ 'addPgIndex', 'watchlist', 'wl_user_notificationtimestamp', '(wl_user, wl_notificationtimestamp)' ], - [ 'addPgIndex', 'logging', 'logging_user_type_time', + [ 'ifNoActorTable', 'addPgIndex', 'logging', 'logging_user_type_time', '(log_user, log_type, log_timestamp)' ], [ 'addPgIndex', 'logging', 'logging_page_id_time', '(log_page,log_timestamp)' ], [ 'addPgIndex', 'iwlinks', 'iwl_prefix_from_title', '(iwl_prefix, iwl_from, iwl_title)' ], @@ -263,9 +263,10 @@ class PostgresUpdater extends DatabaseUpdater { [ 'addPgIndex', 'job', 'job_cmd_token', '(job_cmd, job_token, job_random)' ], [ 'addPgIndex', 'job', 'job_cmd_token_id', '(job_cmd, job_token, job_id)' ], [ 'addPgIndex', 'filearchive', 'fa_sha1', '(fa_sha1)' ], - [ 'addPgIndex', 'logging', 'logging_user_text_type_time', + [ 'ifNoActorTable', 'addPgIndex', 'logging', 'logging_user_text_type_time', '(log_user_text, log_type, log_timestamp)' ], - [ 'addPgIndex', 'logging', 'logging_user_text_time', '(log_user_text, log_timestamp)' ], + [ 'ifNoActorTable', 'addPgIndex', 'logging', 'logging_user_text_time', + '(log_user_text, log_timestamp)' ], [ 'checkIndex', 'pagelink_unique', [ [ 'pl_from', 'int4_ops', 'btree', 0 ], @@ -363,30 +364,36 @@ class PostgresUpdater extends DatabaseUpdater { [ 'checkIwlPrefix' ], # All FK columns should be deferred - [ 'changeFkeyDeferrable', 'archive', 'ar_user', 'mwuser(user_id) ON DELETE SET NULL' ], + [ 'ifNoActorTable', 'changeFkeyDeferrable', 'archive', 'ar_user', + 'mwuser(user_id) ON DELETE SET NULL' ], [ 'changeFkeyDeferrable', 'categorylinks', 'cl_from', 'page(page_id) ON DELETE CASCADE' ], [ 'changeFkeyDeferrable', 'externallinks', 'el_from', 'page(page_id) ON DELETE CASCADE' ], [ 'changeFkeyDeferrable', 'filearchive', 'fa_deleted_user', 'mwuser(user_id) ON DELETE SET NULL' ], - [ 'changeFkeyDeferrable', 'filearchive', 'fa_user', 'mwuser(user_id) ON DELETE SET NULL' ], - [ 'changeFkeyDeferrable', 'image', 'img_user', 'mwuser(user_id) ON DELETE SET NULL' ], + [ 'ifNoActorTable', 'changeFkeyDeferrable', 'filearchive', 'fa_user', + 'mwuser(user_id) ON DELETE SET NULL' ], + [ 'ifNoActorTable', 'changeFkeyDeferrable', 'image', 'img_user', + 'mwuser(user_id) ON DELETE SET NULL' ], [ 'changeFkeyDeferrable', 'imagelinks', 'il_from', 'page(page_id) ON DELETE CASCADE' ], - [ 'changeFkeyDeferrable', 'ipblocks', 'ipb_by', 'mwuser(user_id) ON DELETE CASCADE' ], + [ 'ifNoActorTable', 'changeFkeyDeferrable', 'ipblocks', 'ipb_by', + 'mwuser(user_id) ON DELETE CASCADE' ], [ 'changeFkeyDeferrable', 'ipblocks', 'ipb_user', 'mwuser(user_id) ON DELETE SET NULL' ], [ 'changeFkeyDeferrable', 'ipblocks', 'ipb_parent_block_id', 'ipblocks(ipb_id) ON DELETE SET NULL' ], [ 'changeFkeyDeferrable', 'langlinks', 'll_from', 'page(page_id) ON DELETE CASCADE' ], - [ 'changeFkeyDeferrable', 'logging', 'log_user', 'mwuser(user_id) ON DELETE SET NULL' ], + [ 'ifNoActorTable', 'changeFkeyDeferrable', 'logging', 'log_user', + 'mwuser(user_id) ON DELETE SET NULL' ], [ 'changeFkeyDeferrable', 'oldimage', 'oi_name', 'image(img_name) ON DELETE CASCADE ON UPDATE CASCADE' ], - [ 'changeFkeyDeferrable', 'oldimage', 'oi_user', 'mwuser(user_id) ON DELETE SET NULL' ], + [ 'ifNoActorTable', 'changeFkeyDeferrable', 'oldimage', 'oi_user', + 'mwuser(user_id) ON DELETE SET NULL' ], [ 'changeFkeyDeferrable', 'pagelinks', 'pl_from', 'page(page_id) ON DELETE CASCADE' ], [ 'changeFkeyDeferrable', 'page_props', 'pp_page', 'page (page_id) ON DELETE CASCADE' ], [ 'changeFkeyDeferrable', 'page_restrictions', 'pr_page', 'page(page_id) ON DELETE CASCADE' ], [ 'changeFkeyDeferrable', 'protected_titles', 'pt_user', 'mwuser(user_id) ON DELETE SET NULL' ], - [ 'changeFkeyDeferrable', 'recentchanges', 'rc_user', + [ 'ifNoActorTable', 'changeFkeyDeferrable', 'recentchanges', 'rc_user', 'mwuser(user_id) ON DELETE SET NULL' ], [ 'changeFkeyDeferrable', 'redirect', 'rd_from', 'page(page_id) ON DELETE CASCADE' ], [ 'changeFkeyDeferrable', 'revision', 'rev_page', 'page (page_id) ON DELETE CASCADE' ], @@ -618,6 +625,34 @@ class PostgresUpdater extends DatabaseUpdater { [ 'dropDefault', 'logging', 'log_comment_id' ], [ 'dropPgField', 'protected_titles', 'pt_reason' ], [ 'dropDefault', 'protected_titles', 'pt_reason_id' ], + + // 1.34 + [ 'dropPgIndex', 'archive', 'archive_user_text' ], + [ 'dropPgField', 'archive', 'ar_user' ], + [ 'dropPgField', 'archive', 'ar_user_text' ], + [ 'dropDefault', 'archive', 'ar_actor' ], + [ 'dropPgField', 'ipblocks', 'ipb_by' ], + [ 'dropPgField', 'ipblocks', 'ipb_by_text' ], + [ 'dropDefault', 'ipblocks', 'ipb_by_actor' ], + [ 'dropPgField', 'image', 'img_user' ], + [ 'dropPgField', 'image', 'img_user_text' ], + [ 'dropDefault', 'image', 'img_actor' ], + [ 'dropPgField', 'oldimage', 'oi_user' ], + [ 'dropPgField', 'oldimage', 'oi_user_text' ], + [ 'dropDefault', 'oldimage', 'oi_actor' ], + [ 'dropPgField', 'filearchive', 'fa_user' ], + [ 'dropPgField', 'filearchive', 'fa_user_text' ], + [ 'dropDefault', 'filearchive', 'fa_actor' ], + [ 'dropPgField', 'recentchanges', 'rc_user' ], + [ 'dropPgField', 'recentchanges', 'rc_user_text' ], + [ 'dropDefault', 'recentchanges', 'rc_actor' ], + [ 'dropPgIndex', 'logging', 'logging_user_time' ], + [ 'dropPgIndex', 'logging', 'logging_user_type_time' ], + [ 'dropPgIndex', 'logging', 'logging_user_text_type_time' ], + [ 'dropPgIndex', 'logging', 'logging_user_text_time' ], + [ 'dropPgField', 'logging', 'log_user' ], + [ 'dropPgField', 'logging', 'log_user_text' ], + [ 'dropDefault', 'logging', 'log_actor' ], ]; } diff --git a/includes/installer/SqliteUpdater.php b/includes/installer/SqliteUpdater.php index 17ced507a2..7c3878ce44 100644 --- a/includes/installer/SqliteUpdater.php +++ b/includes/installer/SqliteUpdater.php @@ -47,9 +47,9 @@ class SqliteUpdater extends DatabaseUpdater { // 1.16 [ 'addTable', 'user_properties', 'patch-user_properties.sql' ], [ 'addTable', 'log_search', 'patch-log_search.sql' ], - [ 'addField', 'logging', 'log_user_text', 'patch-log_user_text.sql' ], + [ 'ifNoActorTable', 'addField', 'logging', 'log_user_text', 'patch-log_user_text.sql' ], # listed separately from the previous update because 1.16 was released without this update - [ 'doLogUsertextPopulation' ], + [ 'ifNoActorTable', 'doLogUsertextPopulation' ], [ 'doLogSearchPopulation' ], [ 'addTable', 'l10n_cache', 'patch-l10n_cache.sql' ], [ 'dropIndex', 'change_tag', 'ct_rc_id', 'patch-change_tag-indexes.sql' ], @@ -119,9 +119,10 @@ class SqliteUpdater extends DatabaseUpdater { // 1.23 [ 'addField', 'recentchanges', 'rc_source', 'patch-rc_source.sql' ], - [ 'addIndex', 'logging', 'log_user_text_type_time', + [ 'ifNoActorTable', 'addIndex', 'logging', 'log_user_text_type_time', 'patch-logging_user_text_type_time_index.sql' ], - [ 'addIndex', 'logging', 'log_user_text_time', 'patch-logging_user_text_time_index.sql' ], + [ 'ifNoActorTable', 'addIndex', 'logging', 'log_user_text_time', + 'patch-logging_user_text_time_index.sql' ], [ 'addField', 'page', 'page_links_updated', 'patch-page_links_updated.sql' ], [ 'addField', 'user', 'user_password_expires', 'patch-user_password_expire.sql' ], @@ -159,7 +160,7 @@ class SqliteUpdater extends DatabaseUpdater { // 1.29 [ 'addField', 'externallinks', 'el_index_60', 'patch-externallinks-el_index_60.sql' ], [ 'addField', 'user_groups', 'ug_expiry', 'patch-user_groups-ug_expiry.sql' ], - [ 'addIndex', 'image', 'img_user_timestamp', 'patch-image-user-index-2.sql' ], + [ 'ifNoActorTable', 'addIndex', 'image', 'img_user_timestamp', 'patch-image-user-index-2.sql' ], // 1.30 [ 'modifyField', 'image', 'img_media_type', 'patch-add-3d.sql' ], @@ -249,6 +250,15 @@ class SqliteUpdater extends DatabaseUpdater { [ 'dropField', 'recentchanges', 'rc_comment', 'patch-recentchanges-drop-rc_comment.sql' ], [ 'dropField', 'logging', 'log_comment', 'patch-logging-drop-log_comment.sql' ], [ 'dropField', 'protected_titles', 'pt_reason', 'patch-protected_titles-drop-pt_reason.sql' ], + + // 1.34 + [ 'dropField', 'archive', 'ar_user', 'patch-archive-drop-ar_user.sql' ], + [ 'dropField', 'ipblocks', 'ipb_by', 'patch-ipblocks-drop-ipb_by.sql' ], + [ 'dropField', 'image', 'img_user', 'patch-image-drop-img_user.sql' ], + [ 'dropField', 'oldimage', 'oi_user', 'patch-oldimage-drop-oi_user.sql' ], + [ 'dropField', 'filearchive', 'fa_user', 'patch-filearchive-drop-fa_user.sql' ], + [ 'dropField', 'recentchanges', 'rc_user', 'patch-recentchanges-drop-rc_user.sql' ], + [ 'dropField', 'logging', 'log_user', 'patch-logging-drop-log_user.sql' ], ]; } diff --git a/includes/logging/ManualLogEntry.php b/includes/logging/ManualLogEntry.php index 5326705ff1..523a2f8ea1 100644 --- a/includes/logging/ManualLogEntry.php +++ b/includes/logging/ManualLogEntry.php @@ -253,8 +253,6 @@ class ManualLogEntry extends LogEntryBase implements Taggable { * @throws MWException */ public function insert( IDatabase $dbw = null ) { - global $wgActorTableSchemaMigrationStage; - $dbw = $dbw ?: wfGetDB( DB_MASTER ); if ( $this->timestamp === null ) { @@ -267,31 +265,6 @@ class ManualLogEntry extends LogEntryBase implements Taggable { $params = $this->getParameters(); $relations = $this->relations; - // Ensure actor relations are set - if ( ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) && - empty( $relations['target_author_actor'] ) - ) { - $actorIds = []; - if ( !empty( $relations['target_author_id'] ) ) { - foreach ( $relations['target_author_id'] as $id ) { - $actorIds[] = User::newFromId( $id )->getActorId( $dbw ); - } - } - if ( !empty( $relations['target_author_ip'] ) ) { - foreach ( $relations['target_author_ip'] as $ip ) { - $actorIds[] = User::newFromName( $ip, false )->getActorId( $dbw ); - } - } - if ( $actorIds ) { - $relations['target_author_actor'] = $actorIds; - $params['authorActors'] = $actorIds; - } - } - if ( !( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) ) { - unset( $relations['target_author_id'], $relations['target_author_ip'] ); - unset( $params['authorIds'], $params['authorIPs'] ); - } - // Additional fields for which there's no space in the database table schema $revId = $this->getAssociatedRevId(); if ( $revId ) { diff --git a/includes/page/WikiPage.php b/includes/page/WikiPage.php index fea1bf64ef..c167f3a4cf 100644 --- a/includes/page/WikiPage.php +++ b/includes/page/WikiPage.php @@ -2841,7 +2841,7 @@ class WikiPage implements Page, IDBAccessObject { */ protected function archiveRevisions( $dbw, $id, $suppress ) { global $wgContentHandlerUseDB, $wgMultiContentRevisionSchemaMigrationStage, - $wgActorTableSchemaMigrationStage, $wgDeleteRevisionsBatchSize; + $wgDeleteRevisionsBatchSize; // Given the lock above, we can be confident in the title and page ID values $namespace = $this->getTitle()->getNamespace(); @@ -2968,9 +2968,7 @@ class WikiPage implements Page, IDBAccessObject { $dbw->delete( 'revision', [ 'rev_id' => $revids ], __METHOD__ ); $dbw->delete( 'revision_comment_temp', [ 'revcomment_rev' => $revids ], __METHOD__ ); - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $dbw->delete( 'revision_actor_temp', [ 'revactor_rev' => $revids ], __METHOD__ ); - } + $dbw->delete( 'revision_actor_temp', [ 'revactor_rev' => $revids ], __METHOD__ ); // Also delete records from ip_changes as applicable. if ( count( $ipRevIds ) > 0 ) { diff --git a/includes/revisiondelete/RevDelList.php b/includes/revisiondelete/RevDelList.php index 74dd7bc58e..f4ea54f0a1 100644 --- a/includes/revisiondelete/RevDelList.php +++ b/includes/revisiondelete/RevDelList.php @@ -113,8 +113,6 @@ abstract class RevDelList extends RevisionListBase { * @since 1.23 Added 'perItemStatus' param */ public function setVisibility( array $params ) { - global $wgActorTableSchemaMigrationStage; - $status = Status::newGood(); $bitPars = $params['value']; @@ -143,7 +141,7 @@ abstract class RevDelList extends RevisionListBase { $missing = array_flip( $this->ids ); $this->clearFileOps(); $idsForLog = []; - $authorIds = $authorIPs = $authorActors = []; + $authorActors = []; if ( $perItemStatus ) { $status->itemStatuses = []; @@ -225,29 +223,7 @@ abstract class RevDelList extends RevisionListBase { $virtualOldBits |= $removedBits; $status->successCount++; - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) { - if ( $item->getAuthorId() > 0 ) { - $authorIds[] = $item->getAuthorId(); - } elseif ( IP::isIPAddress( $item->getAuthorName() ) ) { - $authorIPs[] = $item->getAuthorName(); - } - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $actorId = $item->getAuthorActor(); - // During migration, the actor field might be empty. If so, populate - // it here. - if ( !$actorId ) { - if ( $item->getAuthorId() > 0 ) { - $user = User::newFromId( $item->getAuthorId() ); - } else { - $user = User::newFromName( $item->getAuthorName(), false ); - } - $actorId = $user->getActorId( $dbw ); - } - $authorActors[] = $actorId; - } - } elseif ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $authorActors[] = $item->getAuthorActor(); - } + $authorActors[] = $item->getAuthorActor(); // Save the old and new bits in $visibilityChangeMap for // later use. @@ -291,13 +267,7 @@ abstract class RevDelList extends RevisionListBase { // Log it $authorFields = []; - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) { - $authorFields['authorIds'] = $authorIds; - $authorFields['authorIPs'] = $authorIPs; - } - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $authorFields['authorActors'] = $authorActors; - } + $authorFields['authorActors'] = $authorActors; $this->updateLog( $logType, [ @@ -363,8 +333,6 @@ abstract class RevDelList extends RevisionListBase { * title: The target title * ids: The ID list * comment: The log comment - * authorIds: The array of the user IDs of the offenders - * authorIPs: The array of the IP/anon user offenders * authorActors: The array of the actor IDs of the offenders * tags: The array of change tags to apply to the log entry * @throws MWException @@ -387,12 +355,6 @@ abstract class RevDelList extends RevisionListBase { $relations = [ $field => $params['ids'], ]; - if ( isset( $params['authorIds'] ) ) { - $relations += [ - 'target_author_id' => $params['authorIds'], - 'target_author_ip' => $params['authorIPs'], - ]; - } if ( isset( $params['authorActors'] ) ) { $relations += [ 'target_author_actor' => $params['authorActors'], diff --git a/includes/revisiondelete/RevisionDeleteUser.php b/includes/revisiondelete/RevisionDeleteUser.php index 5644b95814..9a9ab196b5 100644 --- a/includes/revisiondelete/RevisionDeleteUser.php +++ b/includes/revisiondelete/RevisionDeleteUser.php @@ -44,8 +44,6 @@ class RevisionDeleteUser { * @return bool True on success, false on failure (e.g. invalid user ID) */ private static function setUsernameBitfields( $name, $userId, $op, IDatabase $dbw = null ) { - global $wgActorTableSchemaMigrationStage; - if ( !$userId || ( $op !== '|' && $op !== '&' ) ) { return false; // sanity check } @@ -69,19 +67,26 @@ class RevisionDeleteUser { $userTitle = Title::makeTitleSafe( NS_USER, $name ); $userDbKey = $userTitle->getDBkey(); - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) { + $actorId = $dbw->selectField( 'actor', 'actor_id', [ 'actor_name' => $name ], __METHOD__ ); + if ( $actorId ) { # Hide name from live edits - $dbw->update( - 'revision', - [ self::buildSetBitDeletedField( 'rev_deleted', $op, $delUser, $dbw ) ], - [ 'rev_user' => $userId ], - __METHOD__ ); + $ids = $dbw->selectFieldValues( + 'revision_actor_temp', 'revactor_rev', [ 'revactor_actor' => $actorId ], __METHOD__ + ); + if ( $ids ) { + $dbw->update( + 'revision', + [ self::buildSetBitDeletedField( 'rev_deleted', $op, $delUser, $dbw ) ], + [ 'rev_id' => $ids ], + __METHOD__ + ); + } # Hide name from deleted edits $dbw->update( 'archive', [ self::buildSetBitDeletedField( 'ar_deleted', $op, $delUser, $dbw ) ], - [ 'ar_user_text' => $name ], + [ 'ar_actor' => $actorId ], __METHOD__ ); @@ -89,7 +94,7 @@ class RevisionDeleteUser { $dbw->update( 'logging', [ self::buildSetBitDeletedField( 'log_deleted', $op, $delUser, $dbw ) ], - [ 'log_user' => $userId, 'log_type != ' . $dbw->addQuotes( 'suppress' ) ], + [ 'log_actor' => $actorId, 'log_type != ' . $dbw->addQuotes( 'suppress' ) ], __METHOD__ ); @@ -97,7 +102,7 @@ class RevisionDeleteUser { $dbw->update( 'recentchanges', [ self::buildSetBitDeletedField( 'rc_deleted', $op, $delUser, $dbw ) ], - [ 'rc_user_text' => $name ], + [ 'rc_actor' => $actorId ], __METHOD__ ); @@ -105,7 +110,7 @@ class RevisionDeleteUser { $dbw->update( 'oldimage', [ self::buildSetBitDeletedField( 'oi_deleted', $op, $delUser, $dbw ) ], - [ 'oi_user_text' => $name ], + [ 'oi_actor' => $actorId ], __METHOD__ ); @@ -113,69 +118,11 @@ class RevisionDeleteUser { $dbw->update( 'filearchive', [ self::buildSetBitDeletedField( 'fa_deleted', $op, $delUser, $dbw ) ], - [ 'fa_user_text' => $name ], + [ 'fa_actor' => $actorId ], __METHOD__ ); } - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $actorId = $dbw->selectField( 'actor', 'actor_id', [ 'actor_name' => $name ], __METHOD__ ); - if ( $actorId ) { - # Hide name from live edits - $ids = $dbw->selectFieldValues( - 'revision_actor_temp', 'revactor_rev', [ 'revactor_actor' => $actorId ], __METHOD__ - ); - if ( $ids ) { - $dbw->update( - 'revision', - [ self::buildSetBitDeletedField( 'rev_deleted', $op, $delUser, $dbw ) ], - [ 'rev_id' => $ids ], - __METHOD__ - ); - } - - # Hide name from deleted edits - $dbw->update( - 'archive', - [ self::buildSetBitDeletedField( 'ar_deleted', $op, $delUser, $dbw ) ], - [ 'ar_actor' => $actorId ], - __METHOD__ - ); - - # Hide name from logs - $dbw->update( - 'logging', - [ self::buildSetBitDeletedField( 'log_deleted', $op, $delUser, $dbw ) ], - [ 'log_actor' => $actorId, 'log_type != ' . $dbw->addQuotes( 'suppress' ) ], - __METHOD__ - ); - - # Hide name from RC - $dbw->update( - 'recentchanges', - [ self::buildSetBitDeletedField( 'rc_deleted', $op, $delUser, $dbw ) ], - [ 'rc_actor' => $actorId ], - __METHOD__ - ); - - # Hide name from live images - $dbw->update( - 'oldimage', - [ self::buildSetBitDeletedField( 'oi_deleted', $op, $delUser, $dbw ) ], - [ 'oi_actor' => $actorId ], - __METHOD__ - ); - - # Hide name from deleted images - $dbw->update( - 'filearchive', - [ self::buildSetBitDeletedField( 'fa_deleted', $op, $delUser, $dbw ) ], - [ 'fa_actor' => $actorId ], - __METHOD__ - ); - } - } - # Hide log entries pointing to the user page $dbw->update( 'logging', diff --git a/includes/specials/SpecialLog.php b/includes/specials/SpecialLog.php index c6927c1717..ac8baa12c1 100644 --- a/includes/specials/SpecialLog.php +++ b/includes/specials/SpecialLog.php @@ -35,8 +35,6 @@ class SpecialLog extends SpecialPage { } public function execute( $par ) { - global $wgActorTableSchemaMigrationStage; - $this->setHeaders(); $this->outputHeader(); $out = $this->getOutput(); @@ -107,13 +105,7 @@ class SpecialLog extends SpecialPage { $offenderName = $opts->getValue( 'offender' ); $offender = empty( $offenderName ) ? null : User::newFromName( $offenderName, false ); if ( $offender ) { - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - $qc = [ 'ls_field' => 'target_author_actor', 'ls_value' => $offender->getActorId() ]; - } elseif ( $offender->getId() > 0 ) { - $qc = [ 'ls_field' => 'target_author_id', 'ls_value' => $offender->getId() ]; - } else { - $qc = [ 'ls_field' => 'target_author_ip', 'ls_value' => $offender->getName() ]; - } + $qc = [ 'ls_field' => 'target_author_actor', 'ls_value' => $offender->getActorId() ]; } } else { // Allow extensions to add relations to their search types diff --git a/includes/specials/pagers/ActiveUsersPager.php b/includes/specials/pagers/ActiveUsersPager.php index 7703e206fa..0f5355d383 100644 --- a/includes/specials/pagers/ActiveUsersPager.php +++ b/includes/specials/pagers/ActiveUsersPager.php @@ -79,19 +79,16 @@ class ActiveUsersPager extends UsersPager { function getQueryInfo( $data = null ) { $dbr = $this->getDatabase(); - $useActor = (bool)( - $this->getConfig()->get( 'ActorTableSchemaMigrationStage' ) & SCHEMA_COMPAT_READ_NEW - ); - $activeUserSeconds = $this->getConfig()->get( 'ActiveUserDays' ) * 86400; $timestamp = $dbr->timestamp( wfTimestamp( TS_UNIX ) - $activeUserSeconds ); $fname = __METHOD__ . ' (' . $this->getSqlComment() . ')'; // Inner subselect to pull the active users out of querycachetwo - $tables = [ 'querycachetwo', 'user' ]; - $fields = [ 'qcc_title', 'user_id' ]; + $tables = [ 'querycachetwo', 'user', 'actor' ]; + $fields = [ 'qcc_title', 'user_id', 'actor_id' ]; $jconds = [ 'user' => [ 'JOIN', 'user_name = qcc_title' ], + 'actor' => [ 'JOIN', 'actor_user = user_id' ], ]; $conds = [ 'qcc_type' => 'activeusers', @@ -126,20 +123,12 @@ class ActiveUsersPager extends UsersPager { 'ipblocks', '1', [ 'ipb_user=user_id', 'ipb_deleted' => 1 ] ) . ')'; } - if ( $useActor ) { - $tables[] = 'actor'; - $jconds['actor'] = [ - 'JOIN', - 'actor_user = user_id', - ]; - $fields[] = 'actor_id'; - } $subquery = $dbr->buildSelectSubquery( $tables, $fields, $conds, $fname, $options, $jconds ); // Outer query to select the recent edit counts for the selected active users $tables = [ 'qcc_users' => $subquery, 'recentchanges' ]; $jconds = [ 'recentchanges' => [ 'LEFT JOIN', [ - $useActor ? 'rc_actor = actor_id' : 'rc_user_text = qcc_title', + 'rc_actor = actor_id', 'rc_type != ' . $dbr->addQuotes( RC_EXTERNAL ), // Don't count wikidata. 'rc_type != ' . $dbr->addQuotes( RC_CATEGORIZE ), // Don't count categorization changes. 'rc_log_type IS NULL OR rc_log_type != ' . $dbr->addQuotes( 'newusers' ), diff --git a/includes/specials/pagers/NewFilesPager.php b/includes/specials/pagers/NewFilesPager.php index f1b0b9ad32..be4a1bdf1e 100644 --- a/includes/specials/pagers/NewFilesPager.php +++ b/includes/specials/pagers/NewFilesPager.php @@ -97,27 +97,17 @@ class NewFilesPager extends RangeChronologicalPager { } if ( $opts->getValue( 'hidepatrolled' ) ) { - global $wgActorTableSchemaMigrationStage; - $tables[] = 'recentchanges'; $conds['rc_type'] = RC_LOG; $conds['rc_log_type'] = 'upload'; $conds['rc_patrolled'] = RecentChange::PRC_UNPATROLLED; $conds['rc_namespace'] = NS_FILE; - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) { - $jcond = 'rc_actor = ' . $imgQuery['fields']['img_actor']; - } else { - $rcQuery = ActorMigration::newMigration()->getJoin( 'rc_user' ); - $tables += $rcQuery['tables']; - $jconds += $rcQuery['joins']; - $jcond = $rcQuery['fields']['rc_user'] . ' = ' . $imgQuery['fields']['img_user']; - } $jconds['recentchanges'] = [ 'JOIN', [ 'rc_title = img_name', - $jcond, + 'rc_actor = ' . $imgQuery['fields']['img_actor'], 'rc_timestamp = img_timestamp' ] ]; diff --git a/includes/user/User.php b/includes/user/User.php index 706887962c..666f2b6979 100644 --- a/includes/user/User.php +++ b/includes/user/User.php @@ -64,7 +64,7 @@ class User implements IDBAccessObject, UserIdentity { * Version number to tag cached versions of serialized User objects. Should be increased when * {@link $mCacheVars} or one of it's members changes. */ - const VERSION = 13; + const VERSION = 14; /** * Exclude user options that are set to their default value. @@ -327,22 +327,6 @@ class User implements IDBAccessObject, UserIdentity { case 'defaults': $this->loadDefaults(); break; - case 'name': - // Make sure this thread sees its own changes - $lb = MediaWikiServices::getInstance()->getDBLoadBalancer(); - if ( $lb->hasOrMadeRecentMasterChanges() ) { - $flags |= self::READ_LATEST; - $this->queryFlagsUsed = $flags; - } - - $this->mId = self::idFromName( $this->mName, $flags ); - if ( !$this->mId ) { - // Nonexistent user placeholder object - $this->loadDefaults( $this->mName ); - } else { - $this->loadFromId( $flags ); - } - break; case 'id': // Make sure this thread sees its own changes, if the ID isn't 0 if ( $this->mId != 0 ) { @@ -356,6 +340,7 @@ class User implements IDBAccessObject, UserIdentity { $this->loadFromId( $flags ); break; case 'actor': + case 'name': // Make sure this thread sees its own changes $lb = MediaWikiServices::getInstance()->getDBLoadBalancer(); if ( $lb->hasOrMadeRecentMasterChanges() ) { @@ -366,20 +351,20 @@ class User implements IDBAccessObject, UserIdentity { list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $flags ); $row = wfGetDB( $index )->selectRow( 'actor', - [ 'actor_user', 'actor_name' ], - [ 'actor_id' => $this->mActorId ], + [ 'actor_id', 'actor_user', 'actor_name' ], + $this->mFrom === 'name' ? [ 'actor_name' => $this->mName ] : [ 'actor_id' => $this->mActorId ], __METHOD__, $options ); if ( !$row ) { // Ugh. - $this->loadDefaults(); + $this->loadDefaults( $this->mFrom === 'name' ? $this->mName : false ); } elseif ( $row->actor_user ) { $this->mId = $row->actor_user; $this->loadFromId( $flags ); } else { - $this->loadDefaults( $row->actor_name ); + $this->loadDefaults( $row->actor_name, $row->actor_id ); } break; case 'session': @@ -567,17 +552,6 @@ class User implements IDBAccessObject, UserIdentity { * @return User The corresponding User object */ public static function newFromActorId( $id ) { - global $wgActorTableSchemaMigrationStage; - - // Technically we shouldn't allow this without SCHEMA_COMPAT_READ_NEW, - // but it does little harm and might be needed for write callers loading a User. - if ( !( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_NEW ) ) { - throw new BadMethodCallException( - 'Cannot use ' . __METHOD__ - . ' when $wgActorTableSchemaMigrationStage lacks SCHEMA_COMPAT_NEW' - ); - } - $u = new User; $u->mActorId = $id; $u->mFrom = 'actor'; @@ -620,8 +594,6 @@ class User implements IDBAccessObject, UserIdentity { * @return User */ public static function newFromAnyId( $userId, $userName, $actorId, $dbDomain = false ) { - global $wgActorTableSchemaMigrationStage; - // Stop-gap solution for the problem described in T222212. // Force the User ID and Actor ID to zero for users loaded from the database // of another wiki, to prevent subtle data corruption and confusing failure modes. @@ -633,9 +605,7 @@ class User implements IDBAccessObject, UserIdentity { $user = new User; $user->mFrom = 'defaults'; - // Technically we shouldn't allow this without SCHEMA_COMPAT_READ_NEW, - // but it does little harm and might be needed for write callers loading a User. - if ( ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_NEW ) && $actorId !== null ) { + if ( $actorId !== null ) { $user->mActorId = (int)$actorId; if ( $user->mActorId !== 0 ) { $user->mFrom = 'actor'; @@ -1220,11 +1190,12 @@ class User implements IDBAccessObject, UserIdentity { * the constructor does that instead. * * @param string|bool $name + * @param int|null $actorId */ - public function loadDefaults( $name = false ) { + public function loadDefaults( $name = false, $actorId = null ) { $this->mId = 0; $this->mName = $name; - $this->mActorId = null; + $this->mActorId = $actorId; $this->mRealName = ''; $this->mEmail = ''; $this->mOptionOverrides = null; @@ -1375,8 +1346,6 @@ class User implements IDBAccessObject, UserIdentity { * user_properties Array with properties out of the user_properties table */ protected function loadFromRow( $row, $data = null ) { - global $wgActorTableSchemaMigrationStage; - if ( !is_object( $row ) ) { throw new InvalidArgumentException( '$row must be an object' ); } @@ -1385,18 +1354,14 @@ class User implements IDBAccessObject, UserIdentity { $this->mGroupMemberships = null; // deferred - // Technically we shouldn't allow this without SCHEMA_COMPAT_READ_NEW, - // but it does little harm and might be needed for write callers loading a User. - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_NEW ) { - if ( isset( $row->actor_id ) ) { - $this->mActorId = (int)$row->actor_id; - if ( $this->mActorId !== 0 ) { - $this->mFrom = 'actor'; - } - $this->setItemLoaded( 'actor' ); - } else { - $all = false; + if ( isset( $row->actor_id ) ) { + $this->mActorId = (int)$row->actor_id; + if ( $this->mActorId !== 0 ) { + $this->mFrom = 'actor'; } + $this->setItemLoaded( 'actor' ); + } else { + $all = false; } if ( isset( $row->user_name ) && $row->user_name !== '' ) { @@ -2214,7 +2179,9 @@ class User implements IDBAccessObject, UserIdentity { * @return int The user's ID; 0 if the user is anonymous or nonexistent */ public function getId() { - if ( $this->mId === null && $this->mName !== null && self::isIP( $this->mName ) ) { + if ( $this->mId === null && $this->mName !== null && + ( self::isIP( $this->mName ) || ExternalUserNames::isExternal( $this->mName ) ) + ) { // Special case, we know the user is anonymous return 0; } @@ -2280,62 +2247,43 @@ class User implements IDBAccessObject, UserIdentity { * @return int The actor's ID, or 0 if no actor ID exists and $dbw was null */ public function getActorId( IDatabase $dbw = null ) { - global $wgActorTableSchemaMigrationStage; - - // Technically we should always return 0 without SCHEMA_COMPAT_READ_NEW, - // but it does little harm and might be needed for write callers loading a User. - if ( !( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) ) { - return 0; - } - if ( !$this->isItemLoaded( 'actor' ) ) { $this->load(); } - // Currently $this->mActorId might be null if $this was loaded from a - // cache entry that was written when $wgActorTableSchemaMigrationStage - // was SCHEMA_COMPAT_OLD. Once that is no longer a possibility (i.e. when - // User::VERSION is incremented after $wgActorTableSchemaMigrationStage - // has been removed), that condition may be removed. - if ( $this->mActorId === null || !$this->mActorId && $dbw ) { + if ( !$this->mActorId && $dbw ) { $q = [ 'actor_user' => $this->getId() ?: null, 'actor_name' => (string)$this->getName(), ]; - if ( $dbw ) { - if ( $q['actor_user'] === null && self::isUsableName( $q['actor_name'] ) ) { + if ( $q['actor_user'] === null && self::isUsableName( $q['actor_name'] ) ) { + throw new CannotCreateActorException( + 'Cannot create an actor for a usable name that is not an existing user' + ); + } + if ( $q['actor_name'] === '' ) { + throw new CannotCreateActorException( 'Cannot create an actor for a user with no name' ); + } + $dbw->insert( 'actor', $q, __METHOD__, [ 'IGNORE' ] ); + if ( $dbw->affectedRows() ) { + $this->mActorId = (int)$dbw->insertId(); + } else { + // Outdated cache? + // Use LOCK IN SHARE MODE to bypass any MySQL REPEATABLE-READ snapshot. + $this->mActorId = (int)$dbw->selectField( + 'actor', + 'actor_id', + $q, + __METHOD__, + [ 'LOCK IN SHARE MODE' ] + ); + if ( !$this->mActorId ) { throw new CannotCreateActorException( - 'Cannot create an actor for a usable name that is not an existing user' - ); - } - if ( $q['actor_name'] === '' ) { - throw new CannotCreateActorException( 'Cannot create an actor for a user with no name' ); - } - $dbw->insert( 'actor', $q, __METHOD__, [ 'IGNORE' ] ); - if ( $dbw->affectedRows() ) { - $this->mActorId = (int)$dbw->insertId(); - } else { - // Outdated cache? - // Use LOCK IN SHARE MODE to bypass any MySQL REPEATABLE-READ snapshot. - $this->mActorId = (int)$dbw->selectField( - 'actor', - 'actor_id', - $q, - __METHOD__, - [ 'LOCK IN SHARE MODE' ] + "Cannot create actor ID for user_id={$this->getId()} user_name={$this->getName()}" ); - if ( !$this->mActorId ) { - throw new CannotCreateActorException( - "Cannot create actor ID for user_id={$this->getId()} user_name={$this->getName()}" - ); - } } - $this->invalidateCache(); - } else { - list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $this->queryFlagsUsed ); - $db = wfGetDB( $index ); - $this->mActorId = (int)$db->selectField( 'actor', 'actor_id', $q, __METHOD__, $options ); } + $this->invalidateCache(); $this->setItemLoaded( 'actor' ); } @@ -3979,8 +3927,6 @@ class User implements IDBAccessObject, UserIdentity { $dbw = wfGetDB( DB_MASTER ); $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) use ( $newTouched ) { - global $wgActorTableSchemaMigrationStage; - $dbw->update( 'user', [ /* SET */ 'user_name' => $this->mName, @@ -4010,14 +3956,12 @@ class User implements IDBAccessObject, UserIdentity { ); } - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $dbw->update( - 'actor', - [ 'actor_name' => $this->mName ], - [ 'actor_user' => $this->mId ], - $fname - ); - } + $dbw->update( + 'actor', + [ 'actor_name' => $this->mName ], + [ 'actor_user' => $this->mId ], + $fname + ); } ); $this->mTouched = $newTouched; @@ -4216,16 +4160,12 @@ class User implements IDBAccessObject, UserIdentity { * @param IDatabase $dbw Writable database handle */ private function updateActorId( IDatabase $dbw ) { - global $wgActorTableSchemaMigrationStage; - - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $dbw->insert( - 'actor', - [ 'actor_user' => $this->mId, 'actor_name' => $this->mName ], - __METHOD__ - ); - $this->mActorId = (int)$dbw->insertId(); - } + $dbw->insert( + 'actor', + [ 'actor_user' => $this->mId, 'actor_name' => $this->mName ], + __METHOD__ + ); + $this->mActorId = (int)$dbw->insertId(); } /** @@ -5296,10 +5236,8 @@ class User implements IDBAccessObject, UserIdentity { * - joins: (array) to include in the `$join_conds` to `IDatabase->select()` */ public static function getQueryInfo() { - global $wgActorTableSchemaMigrationStage; - $ret = [ - 'tables' => [ 'user' ], + 'tables' => [ 'user', 'user_actor' => 'actor' ], 'fields' => [ 'user_id', 'user_name', @@ -5312,21 +5250,13 @@ class User implements IDBAccessObject, UserIdentity { 'user_email_token_expires', 'user_registration', 'user_editcount', + 'user_actor.actor_id', + ], + 'joins' => [ + 'user_actor' => [ 'JOIN', 'user_actor.actor_user = user_id' ], ], - 'joins' => [], ]; - // Technically we shouldn't allow this without SCHEMA_COMPAT_READ_NEW, - // but it does little harm and might be needed for write callers loading a User. - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_NEW ) { - $ret['tables']['user_actor'] = 'actor'; - $ret['fields'][] = 'user_actor.actor_id'; - $ret['joins']['user_actor'] = [ - ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) ? 'JOIN' : 'LEFT JOIN', - [ 'user_actor.actor_user = user_id' ] - ]; - } - return $ret; } diff --git a/maintenance/Maintenance.php b/maintenance/Maintenance.php index 68329aa5a6..f89fa6281a 100644 --- a/maintenance/Maintenance.php +++ b/maintenance/Maintenance.php @@ -20,7 +20,7 @@ * @defgroup Maintenance Maintenance */ -define( MW_ENTRY_POINT, 'cli' ); +define( 'MW_ENTRY_POINT', 'cli' ); // Bail on old versions of PHP, or if composer has not been run yet to install // dependencies. diff --git a/maintenance/archives/patch-drop-user-fields.sql b/maintenance/archives/patch-drop-user-fields.sql new file mode 100644 index 0000000000..7faa593733 --- /dev/null +++ b/maintenance/archives/patch-drop-user-fields.sql @@ -0,0 +1,50 @@ +-- +-- patch-drop-user-fields.sql +-- +-- T188327. Drop old xx_user and xx_user_text fields, and defaults from xx_actor fields. + +ALTER TABLE /*_*/archive + DROP INDEX /*i*/ar_usertext_timestamp, + DROP COLUMN ar_user, + DROP COLUMN ar_user_text, + ALTER COLUMN ar_actor DROP DEFAULT; + +ALTER TABLE /*_*/ipblocks + DROP COLUMN ipb_by, + DROP COLUMN ipb_by_text, + ALTER COLUMN ipb_by_actor DROP DEFAULT; + +ALTER TABLE /*_*/image + DROP INDEX /*i*/img_user_timestamp, + DROP INDEX /*i*/img_usertext_timestamp, + DROP COLUMN img_user, + DROP COLUMN img_user_text, + ALTER COLUMN img_actor DROP DEFAULT; + +ALTER TABLE /*_*/oldimage + DROP INDEX /*i*/oi_usertext_timestamp, + DROP COLUMN oi_user, + DROP COLUMN oi_user_text, + ALTER COLUMN oi_actor DROP DEFAULT; + +ALTER TABLE /*_*/filearchive + DROP INDEX /*i*/fa_user_timestamp, + DROP COLUMN fa_user, + DROP COLUMN fa_user_text, + ALTER COLUMN fa_actor DROP DEFAULT; + +ALTER TABLE /*_*/recentchanges + DROP INDEX /*i*/rc_ns_usertext, + DROP INDEX /*i*/rc_user_text, + DROP COLUMN rc_user, + DROP COLUMN rc_user_text, + ALTER COLUMN rc_actor DROP DEFAULT; + +ALTER TABLE /*_*/logging + DROP INDEX /*i*/user_time, + DROP INDEX /*i*/log_user_type_time, + DROP INDEX /*i*/log_user_text_type_time, + DROP INDEX /*i*/log_user_text_time, + DROP COLUMN log_user, + DROP COLUMN log_user_text, + ALTER COLUMN log_actor DROP DEFAULT; diff --git a/maintenance/getReplicaServer.php b/maintenance/getReplicaServer.php index d861348dbd..7e9104ccea 100644 --- a/maintenance/getReplicaServer.php +++ b/maintenance/getReplicaServer.php @@ -38,9 +38,7 @@ class GetReplicaServer extends Maintenance { } public function execute() { - if ( $this->getConfig()->get( 'AllDBsAreLocalhost' ) ) { - $host = 'localhost'; - } elseif ( $this->hasOption( 'group' ) ) { + if ( $this->hasOption( 'group' ) ) { $db = $this->getDB( DB_REPLICA, $this->getOption( 'group' ) ); $host = $db->getServer(); } else { diff --git a/maintenance/includes/MigrateActors.php b/maintenance/includes/MigrateActors.php index 1b35a20217..48dcf8dabd 100644 --- a/maintenance/includes/MigrateActors.php +++ b/maintenance/includes/MigrateActors.php @@ -51,15 +51,6 @@ class MigrateActors extends LoggedUpdateMaintenance { } protected function doDBUpdates() { - $actorTableSchemaMigrationStage = $this->getConfig()->get( 'ActorTableSchemaMigrationStage' ); - - if ( !( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) ) { - $this->output( - "...cannot update while \$wgActorTableSchemaMigrationStage lacks SCHEMA_COMPAT_WRITE_NEW\n" - ); - return false; - } - $tables = $this->getOption( 'tables' ); if ( $tables !== null ) { $this->tables = explode( ',', $tables ); @@ -265,6 +256,12 @@ class MigrateActors extends LoggedUpdateMaintenance { return 0; } + $dbw = $this->getDB( DB_MASTER ); + if ( !$dbw->fieldExists( $table, $userField, __METHOD__ ) ) { + $this->output( "No need to migrate $table.$userField, field does not exist\n" ); + return 0; + } + $complainedAboutUsers = []; $primaryKey = (array)$primaryKey; @@ -274,7 +271,6 @@ class MigrateActors extends LoggedUpdateMaintenance { ); wfWaitForSlaves(); - $dbw = $this->getDB( DB_MASTER ); $actorIdSubquery = $this->makeActorIdSubquery( $dbw, $userField, $nameField ); $next = '1=1'; $countUpdated = 0; @@ -357,6 +353,7 @@ class MigrateActors extends LoggedUpdateMaintenance { * @param string $nameField User name field name * @param string $newPrimaryKey Primary key of the new table. * @param string $actorField Actor field name + * @return int Number of errors */ protected function migrateToTemp( $table, $primaryKey, $extra, $userField, $nameField, $newPrimaryKey, $actorField @@ -366,6 +363,12 @@ class MigrateActors extends LoggedUpdateMaintenance { return 0; } + $dbw = $this->getDB( DB_MASTER ); + if ( !$dbw->fieldExists( $table, $userField, __METHOD__ ) ) { + $this->output( "No need to migrate $table.$userField, field does not exist\n" ); + return 0; + } + $complainedAboutUsers = []; $newTable = $table . '_actor_temp'; @@ -374,7 +377,6 @@ class MigrateActors extends LoggedUpdateMaintenance { ); wfWaitForSlaves(); - $dbw = $this->getDB( DB_MASTER ); $actorIdSubquery = $this->makeActorIdSubquery( $dbw, $userField, $nameField ); $next = []; $countUpdated = 0; diff --git a/maintenance/postgres/tables.sql b/maintenance/postgres/tables.sql index 87fb3967a1..20096a209e 100644 --- a/maintenance/postgres/tables.sql +++ b/maintenance/postgres/tables.sql @@ -244,9 +244,7 @@ CREATE TABLE archive ( ar_parent_id INTEGER NULL, ar_sha1 TEXT NOT NULL DEFAULT '', ar_comment_id INTEGER NOT NULL, - ar_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED, - ar_user_text TEXT NOT NULL DEFAULT '', - ar_actor INTEGER NOT NULL DEFAULT 0, + ar_actor INTEGER NOT NULL, ar_timestamp TIMESTAMPTZ NOT NULL, ar_minor_edit SMALLINT NOT NULL DEFAULT 0, ar_rev_id INTEGER NOT NULL, @@ -258,7 +256,6 @@ CREATE TABLE archive ( ); ALTER SEQUENCE archive_ar_id_seq OWNED BY archive.ar_id; CREATE INDEX archive_name_title_timestamp ON archive (ar_namespace,ar_title,ar_timestamp); -CREATE INDEX archive_user_text ON archive (ar_user_text); CREATE INDEX archive_actor ON archive (ar_actor); CREATE UNIQUE INDEX ar_revid_uniq ON archive (ar_rev_id); @@ -404,9 +401,7 @@ CREATE TABLE ipblocks ( ipb_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('ipblocks_ipb_id_seq'), ipb_address TEXT NULL, ipb_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED, - ipb_by INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, - ipb_by_text TEXT NOT NULL DEFAULT '', - ipb_by_actor INTEGER NOT NULL DEFAULT 0, + ipb_by_actor INTEGER NOT NULL, ipb_reason_id INTEGER NOT NULL, ipb_timestamp TIMESTAMPTZ NOT NULL, ipb_auto SMALLINT NOT NULL DEFAULT 0, @@ -448,9 +443,7 @@ CREATE TABLE image ( img_major_mime TEXT DEFAULT 'unknown', img_minor_mime TEXT DEFAULT 'unknown', img_description_id INTEGER NOT NULL, - img_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED, - img_user_text TEXT NOT NULL DEFAULT '', - img_actor INTEGER NOT NULL DEFAULT 0, + img_actor INTEGER NOT NULL, img_timestamp TIMESTAMPTZ, img_sha1 TEXT NOT NULL DEFAULT '' ); @@ -466,9 +459,7 @@ CREATE TABLE oldimage ( oi_height INTEGER NOT NULL, oi_bits SMALLINT NULL, oi_description_id INTEGER NOT NULL, - oi_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED, - oi_user_text TEXT NOT NULL DEFAULT '', - oi_actor INTEGER NOT NULL DEFAULT 0, + oi_actor INTEGER NOT NULL, oi_timestamp TIMESTAMPTZ NULL, oi_metadata BYTEA NOT NULL DEFAULT '', oi_media_type TEXT NULL, @@ -502,9 +493,7 @@ CREATE TABLE filearchive ( fa_major_mime TEXT DEFAULT 'unknown', fa_minor_mime TEXT DEFAULT 'unknown', fa_description_id INTEGER NOT NULL, - fa_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED, - fa_user_text TEXT NOT NULL DEFAULT '', - fa_actor INTEGER NOT NULL DEFAULT 0, + fa_actor INTEGER NOT NULL, fa_timestamp TIMESTAMPTZ, fa_deleted SMALLINT NOT NULL DEFAULT 0, fa_sha1 TEXT NOT NULL DEFAULT '' @@ -548,9 +537,7 @@ CREATE SEQUENCE recentchanges_rc_id_seq; CREATE TABLE recentchanges ( rc_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('recentchanges_rc_id_seq'), rc_timestamp TIMESTAMPTZ NOT NULL, - rc_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED, - rc_user_text TEXT NOT NULL DEFAULT '', - rc_actor INTEGER NOT NULL DEFAULT 0, + rc_actor INTEGER NOT NULL, rc_namespace SMALLINT NOT NULL, rc_title TEXT NOT NULL, rc_comment_id INTEGER NOT NULL, @@ -646,27 +633,21 @@ CREATE TABLE logging ( log_type TEXT NOT NULL, log_action TEXT NOT NULL, log_timestamp TIMESTAMPTZ NOT NULL, - log_user INTEGER NOT NULL DEFAULT 0 REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED, - log_actor INTEGER NOT NULL DEFAULT 0, + log_actor INTEGER NOT NULL, log_namespace SMALLINT NOT NULL, log_title TEXT NOT NULL, log_comment_id INTEGER NOT NULL, log_params TEXT, log_deleted SMALLINT NOT NULL DEFAULT 0, - log_user_text TEXT NOT NULL DEFAULT '', log_page INTEGER ); ALTER SEQUENCE logging_log_id_seq OWNED BY logging.log_id; CREATE INDEX logging_type_name ON logging (log_type, log_timestamp); -CREATE INDEX logging_user_time ON logging (log_timestamp, log_user); CREATE INDEX logging_actor_time_backwards ON logging (log_timestamp, log_actor); CREATE INDEX logging_page_time ON logging (log_namespace, log_title, log_timestamp); CREATE INDEX logging_times ON logging (log_timestamp); -CREATE INDEX logging_user_type_time ON logging (log_user, log_type, log_timestamp); CREATE INDEX logging_actor_type_time ON logging (log_actor, log_type, log_timestamp); CREATE INDEX logging_page_id_time ON logging (log_page, log_timestamp); -CREATE INDEX logging_user_text_type_time ON logging (log_user_text, log_type, log_timestamp); -CREATE INDEX logging_user_text_time ON logging (log_user_text, log_timestamp); CREATE INDEX logging_actor_time ON logging (log_actor, log_timestamp); CREATE INDEX logging_type_action ON logging (log_type, log_action, log_timestamp); diff --git a/maintenance/reassignEdits.php b/maintenance/reassignEdits.php index 54f1862e10..f3b856cbcf 100644 --- a/maintenance/reassignEdits.php +++ b/maintenance/reassignEdits.php @@ -23,8 +23,6 @@ * @license GPL-2.0-or-later */ -use Wikimedia\Rdbms\IDatabase; - require_once __DIR__ . '/Maintenance.php'; /** @@ -76,8 +74,6 @@ class ReassignEdits extends Maintenance { * @return int Number of entries changed, or that would be changed */ private function doReassignEdits( &$from, &$to, $rc = false, $report = false ) { - $actorTableSchemaMigrationStage = $this->getConfig()->get( 'ActorTableSchemaMigrationStage' ); - $dbw = $this->getDB( DB_MASTER ); $this->beginTransaction( $dbw, __METHOD__ ); @@ -136,36 +132,22 @@ class ReassignEdits extends Maintenance { if ( $total ) { # Reassign edits $this->output( "\nReassigning current edits..." ); - if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) { - $dbw->update( - 'revision', - [ - 'rev_user' => $to->getId(), - 'rev_user_text' => $to->getName(), - ], - $from->isLoggedIn() - ? [ 'rev_user' => $from->getId() ] : [ 'rev_user_text' => $from->getName() ], - __METHOD__ - ); - } - if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $dbw->update( - 'revision_actor_temp', - [ 'revactor_actor' => $to->getActorId( $dbw ) ], - [ 'revactor_actor' => $from->getActorId() ], - __METHOD__ - ); - } + $dbw->update( + 'revision_actor_temp', + [ 'revactor_actor' => $to->getActorId( $dbw ) ], + [ 'revactor_actor' => $from->getActorId() ], + __METHOD__ + ); $this->output( "done.\nReassigning deleted edits..." ); $dbw->update( 'archive', - $this->userSpecification( $dbw, $to, 'ar_user', 'ar_user_text', 'ar_actor' ), + [ 'ar_actor' => $to->getActorId( $dbw ) ], [ $arQueryInfo['conds'] ], __METHOD__ ); $this->output( "done.\n" ); # Update recent changes if required if ( $rc ) { $this->output( "Updating recent changes..." ); $dbw->update( 'recentchanges', - $this->userSpecification( $dbw, $to, 'rc_user', 'rc_user_text', 'rc_actor' ), + [ 'rc_actor' => $to->getActorId( $dbw ) ], [ $rcQueryInfo['conds'] ], __METHOD__ ); $this->output( "done.\n" ); } @@ -177,33 +159,6 @@ class ReassignEdits extends Maintenance { return (int)$total; } - /** - * Return user specifications for an UPDATE - * i.e. user => id, user_text => text - * - * @param IDatabase $dbw Database handle - * @param User $user User for the spec - * @param string $idfield Field name containing the identifier - * @param string $utfield Field name containing the user text - * @param string $acfield Field name containing the actor ID - * @return array - */ - private function userSpecification( IDatabase $dbw, &$user, $idfield, $utfield, $acfield ) { - $actorTableSchemaMigrationStage = $this->getConfig()->get( 'ActorTableSchemaMigrationStage' ); - - $ret = []; - if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) { - $ret += [ - $idfield => $user->getId(), - $utfield => $user->getName(), - ]; - } - if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $ret += [ $acfield => $user->getActorId( $dbw ) ]; - } - return $ret; - } - /** * Initialise the user object * diff --git a/maintenance/removeUnusedAccounts.php b/maintenance/removeUnusedAccounts.php index 16a7346a6a..ca90468c18 100644 --- a/maintenance/removeUnusedAccounts.php +++ b/maintenance/removeUnusedAccounts.php @@ -39,8 +39,6 @@ class RemoveUnusedAccounts extends Maintenance { } public function execute() { - $actorTableSchemaMigrationStage = $this->getConfig()->get( 'ActorTableSchemaMigrationStage' ); - $this->output( "Remove unused accounts\n\n" ); # Do an initial scan for inactive accounts and report the result @@ -48,18 +46,14 @@ class RemoveUnusedAccounts extends Maintenance { $delUser = []; $delActor = []; $dbr = $this->getDB( DB_REPLICA ); - if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $res = $dbr->select( - [ 'user', 'actor' ], - [ 'user_id', 'user_name', 'user_touched', 'actor_id' ], - '', - __METHOD__, - [], - [ 'actor' => [ 'LEFT JOIN', 'user_id = actor_user' ] ] - ); - } else { - $res = $dbr->select( 'user', [ 'user_id', 'user_name', 'user_touched' ], '', __METHOD__ ); - } + $res = $dbr->select( + [ 'user', 'actor' ], + [ 'user_id', 'user_name', 'user_touched', 'actor_id' ], + '', + __METHOD__, + [], + [ 'actor' => [ 'LEFT JOIN', 'user_id = actor_user' ] ] + ); if ( $this->hasOption( 'ignore-groups' ) ) { $excludedGroups = explode( ',', $this->getOption( 'ignore-groups' ) ); } else { @@ -94,30 +88,22 @@ class RemoveUnusedAccounts extends Maintenance { $this->output( "\nDeleting unused accounts..." ); $dbw = $this->getDB( DB_MASTER ); $dbw->delete( 'user', [ 'user_id' => $delUser ], __METHOD__ ); - if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - # Keep actor rows referenced from ipblocks - $keep = $dbw->selectFieldValues( - 'ipblocks', 'ipb_by_actor', [ 'ipb_by_actor' => $delActor ], __METHOD__ - ); - $del = array_diff( $delActor, $keep ); - if ( $del ) { - $dbw->delete( 'actor', [ 'actor_id' => $del ], __METHOD__ ); - } - if ( $keep ) { - $dbw->update( 'actor', [ 'actor_user' => 0 ], [ 'actor_id' => $keep ], __METHOD__ ); - } + # Keep actor rows referenced from ipblocks + $keep = $dbw->selectFieldValues( + 'ipblocks', 'ipb_by_actor', [ 'ipb_by_actor' => $delActor ], __METHOD__ + ); + $del = array_diff( $delActor, $keep ); + if ( $del ) { + $dbw->delete( 'actor', [ 'actor_id' => $del ], __METHOD__ ); + } + if ( $keep ) { + $dbw->update( 'actor', [ 'actor_user' => 0 ], [ 'actor_id' => $keep ], __METHOD__ ); } $dbw->delete( 'user_groups', [ 'ug_user' => $delUser ], __METHOD__ ); $dbw->delete( 'user_former_groups', [ 'ufg_user' => $delUser ], __METHOD__ ); $dbw->delete( 'user_properties', [ 'up_user' => $delUser ], __METHOD__ ); - if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $dbw->delete( 'logging', [ 'log_actor' => $delActor ], __METHOD__ ); - $dbw->delete( 'recentchanges', [ 'rc_actor' => $delActor ], __METHOD__ ); - } - if ( $actorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) { - $dbw->delete( 'logging', [ 'log_user' => $delUser ], __METHOD__ ); - $dbw->delete( 'recentchanges', [ 'rc_user' => $delUser ], __METHOD__ ); - } + $dbw->delete( 'logging', [ 'log_actor' => $delActor ], __METHOD__ ); + $dbw->delete( 'recentchanges', [ 'rc_actor' => $delActor ], __METHOD__ ); $this->output( "done.\n" ); # Update the site_stats.ss_users field $users = $dbw->selectField( 'user', 'COUNT(*)', [], __METHOD__ ); diff --git a/maintenance/sqlite/archives/patch-archive-drop-ar_user.sql b/maintenance/sqlite/archives/patch-archive-drop-ar_user.sql new file mode 100644 index 0000000000..ceb7d7dd0d --- /dev/null +++ b/maintenance/sqlite/archives/patch-archive-drop-ar_user.sql @@ -0,0 +1,44 @@ +-- +-- patch-archive-drop-ar_user.sql +-- +-- T188327. Drop old xx_user and xx_user_text fields, and defaults from xx_actor fields. + +BEGIN; + +DROP TABLE IF EXISTS /*_*/archive_tmp; +CREATE TABLE /*_*/archive_tmp ( + ar_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, + ar_namespace int NOT NULL default 0, + ar_title varchar(255) binary NOT NULL default '', + ar_comment_id bigint unsigned NOT NULL, + ar_actor bigint unsigned NOT NULL, + ar_timestamp binary(14) NOT NULL default '', + ar_minor_edit tinyint NOT NULL default 0, + ar_rev_id int unsigned NOT NULL, + ar_text_id int unsigned NOT NULL DEFAULT 0, + ar_deleted tinyint unsigned NOT NULL default 0, + ar_len int unsigned, + ar_page_id int unsigned, + ar_parent_id int unsigned default NULL, + ar_sha1 varbinary(32) NOT NULL default '', + ar_content_model varbinary(32) DEFAULT NULL, + ar_content_format varbinary(64) DEFAULT NULL +) /*$wgDBTableOptions*/; + +INSERT OR IGNORE INTO /*_*/archive_tmp ( + ar_id, ar_namespace, ar_title, ar_comment_id, ar_actor, + ar_timestamp, ar_minor_edit, ar_rev_id, ar_text_id, ar_deleted, + ar_len, ar_page_id, ar_parent_id, ar_sha1, ar_content_model, ar_content_format + ) SELECT + ar_id, ar_namespace, ar_title, ar_comment_id, ar_actor, + ar_timestamp, ar_minor_edit, ar_rev_id, ar_text_id, ar_deleted, + ar_len, ar_page_id, ar_parent_id, ar_sha1, ar_content_model, ar_content_format + FROM /*_*/archive; + +DROP TABLE /*_*/archive; +ALTER TABLE /*_*/archive_tmp RENAME TO /*_*/archive; +CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp); +CREATE INDEX /*i*/ar_actor_timestamp ON /*_*/archive (ar_actor,ar_timestamp); +CREATE UNIQUE INDEX /*i*/ar_revid_uniq ON /*_*/archive (ar_rev_id); + +COMMIT; diff --git a/maintenance/sqlite/archives/patch-filearchive-drop-fa_user.sql b/maintenance/sqlite/archives/patch-filearchive-drop-fa_user.sql new file mode 100644 index 0000000000..0a20a56805 --- /dev/null +++ b/maintenance/sqlite/archives/patch-filearchive-drop-fa_user.sql @@ -0,0 +1,55 @@ +-- +-- patch-filearchive-drop-fa_user.sql +-- +-- T188327. Drop old xx_user and xx_user_text fields, and defaults from xx_actor fields. + +BEGIN; + +DROP TABLE IF EXISTS /*_*/filearchive_tmp; +CREATE TABLE /*_*/filearchive_tmp ( + fa_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, + fa_name varchar(255) binary NOT NULL default '', + fa_archive_name varchar(255) binary default '', + fa_storage_group varbinary(16), + fa_storage_key varbinary(64) default '', + fa_deleted_user int, + fa_deleted_timestamp binary(14) default '', + fa_deleted_reason_id bigint unsigned NOT NULL, + fa_size int unsigned default 0, + fa_width int default 0, + fa_height int default 0, + fa_metadata mediumblob, + fa_bits int default 0, + fa_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE", "3D") default NULL, + fa_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart", "chemical") default "unknown", + fa_minor_mime varbinary(100) default "unknown", + fa_description_id bigint unsigned NOT NULL, + fa_actor bigint unsigned NOT NULL DEFAULT 0, + fa_timestamp binary(14) default '', + fa_deleted tinyint unsigned NOT NULL default 0, + fa_sha1 varbinary(32) NOT NULL default '' +) /*$wgDBTableOptions*/; + +INSERT OR IGNORE INTO /*_*/filearchive_tmp ( + fa_id, fa_name, fa_archive_name, fa_storage_group, fa_storage_key, + fa_deleted_user, fa_deleted_timestamp, fa_deleted_reason_id, + fa_size, fa_width, fa_height, fa_metadata, fa_bits, + fa_media_type, fa_major_mime, fa_minor_mime, fa_description_id, + fa_actor, fa_timestamp, fa_deleted, fa_sha1 + ) SELECT + fa_id, fa_name, fa_archive_name, fa_storage_group, fa_storage_key, + fa_deleted_user, fa_deleted_timestamp, fa_deleted_reason_id, + fa_size, fa_width, fa_height, fa_metadata, fa_bits, + fa_media_type, fa_major_mime, fa_minor_mime, fa_description_id, + fa_actor, fa_timestamp, fa_deleted, fa_sha1 + FROM /*_*/filearchive; + +DROP TABLE /*_*/filearchive; +ALTER TABLE /*_*/filearchive_tmp RENAME TO /*_*/filearchive; +CREATE INDEX /*i*/fa_name ON /*_*/filearchive (fa_name, fa_timestamp); +CREATE INDEX /*i*/fa_storage_group ON /*_*/filearchive (fa_storage_group, fa_storage_key); +CREATE INDEX /*i*/fa_deleted_timestamp ON /*_*/filearchive (fa_deleted_timestamp); +CREATE INDEX /*i*/fa_actor_timestamp ON /*_*/filearchive (fa_actor,fa_timestamp); +CREATE INDEX /*i*/fa_sha1 ON /*_*/filearchive (fa_sha1(10)); + +COMMIT; diff --git a/maintenance/sqlite/archives/patch-image-drop-img_user.sql b/maintenance/sqlite/archives/patch-image-drop-img_user.sql new file mode 100644 index 0000000000..d93e12240d --- /dev/null +++ b/maintenance/sqlite/archives/patch-image-drop-img_user.sql @@ -0,0 +1,43 @@ +-- +-- patch-image-drop-img_description.sql +-- +-- T188327. Drop old xx_user and xx_user_text fields, and defaults from xx_actor fields. + +BEGIN; + +DROP TABLE IF EXISTS /*_*/image_tmp; +CREATE TABLE /*_*/image_tmp ( + img_name varchar(255) binary NOT NULL default '' PRIMARY KEY, + img_size int unsigned NOT NULL default 0, + img_width int NOT NULL default 0, + img_height int NOT NULL default 0, + img_metadata mediumblob NOT NULL, + img_bits int NOT NULL default 0, + img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE", "3D") default NULL, + img_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart", "chemical") NOT NULL default "unknown", + img_minor_mime varbinary(100) NOT NULL default "unknown", + img_description_id bigint unsigned NOT NULL, + img_actor bigint unsigned NOT NULL, + img_timestamp varbinary(14) NOT NULL default '', + img_sha1 varbinary(32) NOT NULL default '' +) /*$wgDBTableOptions*/; + +INSERT OR IGNORE INTO /*_*/image_tmp ( + img_name, img_size, img_width, img_height, img_metadata, img_bits, + img_media_type, img_major_mime, img_minor_mime, img_description_id, + img_actor, img_timestamp, img_sha1 + ) SELECT + img_name, img_size, img_width, img_height, img_metadata, img_bits, + img_media_type, img_major_mime, img_minor_mime, img_description_id, + img_actor, img_timestamp, img_sha1 + FROM /*_*/image; + +DROP TABLE /*_*/image; +ALTER TABLE /*_*/image_tmp RENAME TO /*_*/image; +CREATE INDEX /*i*/img_actor_timestamp ON /*_*/image (img_actor,img_timestamp); +CREATE INDEX /*i*/img_size ON /*_*/image (img_size); +CREATE INDEX /*i*/img_timestamp ON /*_*/image (img_timestamp); +CREATE INDEX /*i*/img_sha1 ON /*_*/image (img_sha1(10)); +CREATE INDEX /*i*/img_media_mime ON /*_*/image (img_media_type,img_major_mime,img_minor_mime); + +COMMIT; diff --git a/maintenance/sqlite/archives/patch-ipblocks-drop-ipb_by.sql b/maintenance/sqlite/archives/patch-ipblocks-drop-ipb_by.sql new file mode 100644 index 0000000000..2de5e098c2 --- /dev/null +++ b/maintenance/sqlite/archives/patch-ipblocks-drop-ipb_by.sql @@ -0,0 +1,51 @@ +-- +-- patch-ipblocks-drop-ipb_by.sql +-- +-- T188327. Drop old xx_user and xx_user_text fields, and defaults from xx_actor fields. + +BEGIN; + +DROP TABLE IF EXISTS ipblocks_tmp; +CREATE TABLE /*_*/ipblocks_tmp ( + ipb_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, + ipb_address tinyblob NOT NULL, + ipb_user int unsigned NOT NULL default 0, + ipb_by_actor bigint unsigned NOT NULL, + ipb_reason_id bigint unsigned NOT NULL, + ipb_timestamp binary(14) NOT NULL default '', + ipb_auto bool NOT NULL default 0, + ipb_anon_only bool NOT NULL default 0, + ipb_create_account bool NOT NULL default 1, + ipb_enable_autoblock bool NOT NULL default '1', + ipb_expiry varbinary(14) NOT NULL default '', + ipb_range_start tinyblob NOT NULL, + ipb_range_end tinyblob NOT NULL, + ipb_deleted bool NOT NULL default 0, + ipb_block_email bool NOT NULL default 0, + ipb_allow_usertalk bool NOT NULL default 0, + ipb_parent_block_id int default NULL, + ipb_sitewide bool NOT NULL default 1 +) /*$wgDBTableOptions*/; + +INSERT OR IGNORE INTO /*_*/ipblocks_tmp ( + ipb_id, ipb_address, ipb_user, ipb_by_actor, ipb_reason_id, + ipb_timestamp, ipb_auto, ipb_anon_only, ipb_create_account, + ipb_enable_autoblock, ipb_expiry, ipb_range_start, ipb_range_end, + ipb_deleted, ipb_block_email, ipb_allow_usertalk, ipb_parent_block_id, ipb_sitewide + ) SELECT + ipb_id, ipb_address, ipb_user, ipb_by_actor, ipb_reason_id, + ipb_timestamp, ipb_auto, ipb_anon_only, ipb_create_account, + ipb_enable_autoblock, ipb_expiry, ipb_range_start, ipb_range_end, + ipb_deleted, ipb_block_email, ipb_allow_usertalk, ipb_parent_block_id, ipb_sitewide + FROM /*_*/ipblocks; + +DROP TABLE /*_*/ipblocks; +ALTER TABLE /*_*/ipblocks_tmp RENAME TO /*_*/ipblocks; +CREATE UNIQUE INDEX /*i*/ipb_address ON /*_*/ipblocks (ipb_address(255), ipb_user, ipb_auto, ipb_anon_only); +CREATE INDEX /*i*/ipb_user ON /*_*/ipblocks (ipb_user); +CREATE INDEX /*i*/ipb_range ON /*_*/ipblocks (ipb_range_start(8), ipb_range_end(8)); +CREATE INDEX /*i*/ipb_timestamp ON /*_*/ipblocks (ipb_timestamp); +CREATE INDEX /*i*/ipb_expiry ON /*_*/ipblocks (ipb_expiry); +CREATE INDEX /*i*/ipb_parent_block_id ON /*_*/ipblocks (ipb_parent_block_id); + +COMMIT; diff --git a/maintenance/sqlite/archives/patch-logging-drop-log_user.sql b/maintenance/sqlite/archives/patch-logging-drop-log_user.sql new file mode 100644 index 0000000000..0f5871aee9 --- /dev/null +++ b/maintenance/sqlite/archives/patch-logging-drop-log_user.sql @@ -0,0 +1,41 @@ +-- +-- patch-logging-drop-log_user.sql +-- +-- T188327. Drop old xx_user and xx_user_text fields, and defaults from xx_actor fields. + +BEGIN; + +DROP TABLE IF EXISTS /*_*/logging_tmp; +CREATE TABLE /*_*/logging_tmp ( + log_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, + log_type varbinary(32) NOT NULL default '', + log_action varbinary(32) NOT NULL default '', + log_timestamp binary(14) NOT NULL default '19700101000000', + log_actor bigint unsigned NOT NULL DEFAULT 0, + log_namespace int NOT NULL default 0, + log_title varchar(255) binary NOT NULL default '', + log_page int unsigned NULL, + log_comment_id bigint unsigned NOT NULL, + log_params blob NOT NULL, + log_deleted tinyint unsigned NOT NULL default 0 +) /*$wgDBTableOptions*/; + +INSERT OR IGNORE INTO /*_*/logging_tmp ( + log_id, log_type, log_action, log_timestamp, log_actor, + log_namespace, log_title, log_page, log_comment_id, log_params, log_deleted + ) SELECT + log_id, log_type, log_action, log_timestamp, log_actor, + log_namespace, log_title, log_page, log_comment_id, log_params, log_deleted + FROM /*_*/logging; + +DROP TABLE /*_*/logging; +ALTER TABLE /*_*/logging_tmp RENAME TO /*_*/logging; +CREATE INDEX /*i*/type_time ON /*_*/logging (log_type, log_timestamp); +CREATE INDEX /*i*/actor_time ON /*_*/logging (log_actor, log_timestamp); +CREATE INDEX /*i*/page_time ON /*_*/logging (log_namespace, log_title, log_timestamp); +CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp); +CREATE INDEX /*i*/log_actor_type_time ON /*_*/logging (log_actor, log_type, log_timestamp); +CREATE INDEX /*i*/log_page_id_time ON /*_*/logging (log_page,log_timestamp); +CREATE INDEX /*i*/log_type_action ON /*_*/logging (log_type, log_action, log_timestamp); + +COMMIT; diff --git a/maintenance/sqlite/archives/patch-oldimage-drop-oi_user.sql b/maintenance/sqlite/archives/patch-oldimage-drop-oi_user.sql new file mode 100644 index 0000000000..87352382fd --- /dev/null +++ b/maintenance/sqlite/archives/patch-oldimage-drop-oi_user.sql @@ -0,0 +1,44 @@ +-- +-- patch-oldimage-drop-oi_user.sql +-- +-- T188327. Drop old xx_user and xx_user_text fields, and defaults from xx_actor fields. + +BEGIN; + +DROP TABLE IF EXISTS /*_*/oldimage_tmp; +CREATE TABLE /*_*/oldimage_tmp ( + oi_name varchar(255) binary NOT NULL default '', + oi_archive_name varchar(255) binary NOT NULL default '', + oi_size int unsigned NOT NULL default 0, + oi_width int NOT NULL default 0, + oi_height int NOT NULL default 0, + oi_bits int NOT NULL default 0, + oi_description_id bigint unsigned NOT NULL, + oi_actor bigint unsigned NOT NULL, + oi_timestamp binary(14) NOT NULL default '', + oi_metadata mediumblob NOT NULL, + oi_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE", "3D") default NULL, + oi_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart", "chemical") NOT NULL default "unknown", + oi_minor_mime varbinary(100) NOT NULL default "unknown", + oi_deleted tinyint unsigned NOT NULL default 0, + oi_sha1 varbinary(32) NOT NULL default '' +) /*$wgDBTableOptions*/; + +INSERT OR IGNORE INTO /*_*/oldimage_tmp ( + oi_name, oi_archive_name, oi_size, oi_width, oi_height, oi_bits, + oi_description_id, oi_actor, oi_timestamp, oi_metadata, + oi_media_type, oi_major_mime, oi_minor_mime, oi_deleted, oi_sha1 + ) SELECT + oi_name, oi_archive_name, oi_size, oi_width, oi_height, oi_bits, + oi_description_id, oi_actor, oi_timestamp, oi_metadata, + oi_media_type, oi_major_mime, oi_minor_mime, oi_deleted, oi_sha1 + FROM /*_*/oldimage; + +DROP TABLE /*_*/oldimage; +ALTER TABLE /*_*/oldimage_tmp RENAME TO /*_*/oldimage; +CREATE INDEX /*i*/oi_actor_timestamp ON /*_*/oldimage (oi_actor,oi_timestamp); +CREATE INDEX /*i*/oi_name_timestamp ON /*_*/oldimage (oi_name,oi_timestamp); +CREATE INDEX /*i*/oi_name_archive_name ON /*_*/oldimage (oi_name,oi_archive_name(14)); +CREATE INDEX /*i*/oi_sha1 ON /*_*/oldimage (oi_sha1(10)); + +COMMIT; diff --git a/maintenance/sqlite/archives/patch-recentchanges-drop-rc_user.sql b/maintenance/sqlite/archives/patch-recentchanges-drop-rc_user.sql new file mode 100644 index 0000000000..ba1f434a51 --- /dev/null +++ b/maintenance/sqlite/archives/patch-recentchanges-drop-rc_user.sql @@ -0,0 +1,59 @@ +-- +-- patch-recentchanges-drop-rc_user.sql +-- +-- T188327. Drop old xx_user and xx_user_text fields, and defaults from xx_actor fields. + +BEGIN; + +DROP TABLE IF EXISTS /*_*/recentchanges_tmp; +CREATE TABLE /*_*/recentchanges_tmp ( + rc_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, + rc_timestamp varbinary(14) NOT NULL default '', + rc_actor bigint unsigned NOT NULL DEFAULT 0, + rc_namespace int NOT NULL default 0, + rc_title varchar(255) binary NOT NULL default '', + rc_comment_id bigint unsigned NOT NULL, + rc_minor tinyint unsigned NOT NULL default 0, + rc_bot tinyint unsigned NOT NULL default 0, + rc_new tinyint unsigned NOT NULL default 0, + rc_cur_id int unsigned NOT NULL default 0, + rc_this_oldid int unsigned NOT NULL default 0, + rc_last_oldid int unsigned NOT NULL default 0, + rc_type tinyint unsigned NOT NULL default 0, + rc_source varchar(16) binary not null default '', + rc_patrolled tinyint unsigned NOT NULL default 0, + rc_ip varbinary(40) NOT NULL default '', + rc_old_len int, + rc_new_len int, + rc_deleted tinyint unsigned NOT NULL default 0, + rc_logid int unsigned NOT NULL default 0, + rc_log_type varbinary(255) NULL default NULL, + rc_log_action varbinary(255) NULL default NULL, + rc_params blob NULL +) /*$wgDBTableOptions*/; + +INSERT OR IGNORE INTO /*_*/recentchanges_tmp ( + rc_id, rc_timestamp, rc_actor, rc_namespace, rc_title, + rc_comment_id, rc_minor, rc_bot, rc_new, rc_cur_id, rc_this_oldid, rc_last_oldid, + rc_type, rc_source, rc_patrolled, rc_ip, rc_old_len, rc_new_len, rc_deleted, + rc_logid, rc_log_type, rc_log_action, rc_params + ) SELECT + rc_id, rc_timestamp, rc_actor, rc_namespace, rc_title, + rc_comment_id, rc_minor, rc_bot, rc_new, rc_cur_id, rc_this_oldid, rc_last_oldid, + rc_type, rc_source, rc_patrolled, rc_ip, rc_old_len, rc_new_len, rc_deleted, + rc_logid, rc_log_type, rc_log_action, rc_params + FROM /*_*/recentchanges; + +DROP TABLE /*_*/recentchanges; +ALTER TABLE /*_*/recentchanges_tmp RENAME TO /*_*/recentchanges; +CREATE INDEX /*i*/rc_timestamp ON /*_*/recentchanges (rc_timestamp); +CREATE INDEX /*i*/rc_namespace_title_timestamp ON /*_*/recentchanges (rc_namespace, rc_title, rc_timestamp); +CREATE INDEX /*i*/rc_cur_id ON /*_*/recentchanges (rc_cur_id); +CREATE INDEX /*i*/new_name_timestamp ON /*_*/recentchanges (rc_new,rc_namespace,rc_timestamp); +CREATE INDEX /*i*/rc_ip ON /*_*/recentchanges (rc_ip); +CREATE INDEX /*i*/rc_ns_actor ON /*_*/recentchanges (rc_namespace, rc_actor); +CREATE INDEX /*i*/rc_actor ON /*_*/recentchanges (rc_actor, rc_timestamp); +CREATE INDEX /*i*/rc_name_type_patrolled_timestamp ON /*_*/recentchanges (rc_namespace, rc_type, rc_patrolled, rc_timestamp); +CREATE INDEX /*i*/rc_this_oldid ON /*_*/recentchanges (rc_this_oldid); + +COMMIT; diff --git a/maintenance/tables.sql b/maintenance/tables.sql index df15abff3a..55c67754d5 100644 --- a/maintenance/tables.sql +++ b/maintenance/tables.sql @@ -594,9 +594,7 @@ CREATE TABLE /*_*/archive ( -- Basic revision stuff... ar_comment_id bigint unsigned NOT NULL, - ar_user int unsigned NOT NULL default 0, -- Deprecated in favor of ar_actor - ar_user_text varchar(255) binary NOT NULL DEFAULT '', -- Deprecated in favor of ar_actor - ar_actor bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that ar_user/ar_user_text should be used) + ar_actor bigint unsigned NOT NULL, ar_timestamp binary(14) NOT NULL default '', ar_minor_edit tinyint NOT NULL default 0, @@ -661,7 +659,6 @@ CREATE TABLE /*_*/archive ( CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp); -- Index for Special:DeletedContributions -CREATE INDEX /*i*/ar_usertext_timestamp ON /*_*/archive (ar_user_text,ar_timestamp); CREATE INDEX /*i*/ar_actor_timestamp ON /*_*/archive (ar_actor,ar_timestamp); -- Index for linking archive rows with tables that normally link with revision @@ -1034,14 +1031,8 @@ CREATE TABLE /*_*/ipblocks ( -- Blocked user ID or 0 for IP blocks. ipb_user int unsigned NOT NULL default 0, - -- User ID who made the block. - ipb_by int unsigned NOT NULL default 0, -- Deprecated in favor of ipb_by_actor - - -- User name of blocker - ipb_by_text varchar(255) binary NOT NULL default '', -- Deprecated in favor of ipb_by_actor - -- Actor who made the block. - ipb_by_actor bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that ipb_by/ipb_by_text should be used) + ipb_by_actor bigint unsigned NOT NULL, -- Key to comment_id. Text comment made by blocker. ipb_reason_id bigint unsigned NOT NULL, @@ -1177,14 +1168,8 @@ CREATE TABLE /*_*/image ( -- This is displayed in image upload history and logs. img_description_id bigint unsigned NOT NULL, - -- user_id and user_name of uploader. - -- Deprecated in favor of img_actor. - img_user int unsigned NOT NULL default 0, - img_user_text varchar(255) binary NOT NULL DEFAULT '', - -- actor_id of the uploader. - -- ("DEFAULT 0" is temporary, signaling that img_user/img_user_text should be used) - img_actor bigint unsigned NOT NULL DEFAULT 0, + img_actor bigint unsigned NOT NULL, -- Time of the upload. img_timestamp varbinary(14) NOT NULL default '', @@ -1194,8 +1179,6 @@ CREATE TABLE /*_*/image ( ) /*$wgDBTableOptions*/; -- Used by Special:Newimages and ApiQueryAllImages -CREATE INDEX /*i*/img_user_timestamp ON /*_*/image (img_user,img_timestamp); -CREATE INDEX /*i*/img_usertext_timestamp ON /*_*/image (img_user_text,img_timestamp); CREATE INDEX /*i*/img_actor_timestamp ON /*_*/image (img_actor,img_timestamp); -- Used by Special:ListFiles for sort-by-size CREATE INDEX /*i*/img_size ON /*_*/image (img_size); @@ -1226,9 +1209,7 @@ CREATE TABLE /*_*/oldimage ( oi_height int NOT NULL default 0, oi_bits int NOT NULL default 0, oi_description_id bigint unsigned NOT NULL, - oi_user int unsigned NOT NULL default 0, -- Deprecated in favor of oi_actor - oi_user_text varchar(255) binary NOT NULL DEFAULT '', -- Deprecated in favor of oi_actor - oi_actor bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that oi_user/oi_user_text should be used) + oi_actor bigint unsigned NOT NULL, oi_timestamp binary(14) NOT NULL default '', oi_metadata mediumblob NOT NULL, @@ -1239,7 +1220,6 @@ CREATE TABLE /*_*/oldimage ( oi_sha1 varbinary(32) NOT NULL default '' ) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/oi_usertext_timestamp ON /*_*/oldimage (oi_user_text,oi_timestamp); CREATE INDEX /*i*/oi_actor_timestamp ON /*_*/oldimage (oi_actor,oi_timestamp); CREATE INDEX /*i*/oi_name_timestamp ON /*_*/oldimage (oi_name,oi_timestamp); -- oi_archive_name truncated to 14 to avoid key length overflow @@ -1287,9 +1267,7 @@ CREATE TABLE /*_*/filearchive ( fa_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart", "chemical") default "unknown", fa_minor_mime varbinary(100) default "unknown", fa_description_id bigint unsigned NOT NULL, - fa_user int unsigned default 0, -- Deprecated in favor of fa_actor - fa_user_text varchar(255) binary DEFAULT '', -- Deprecated in favor of fa_actor - fa_actor bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that fa_user/fa_user_text should be used) + fa_actor bigint unsigned NOT NULL, fa_timestamp binary(14) default '', -- Visibility of deleted revisions, bitfield @@ -1306,7 +1284,6 @@ CREATE INDEX /*i*/fa_storage_group ON /*_*/filearchive (fa_storage_group, fa_sto -- sort by deletion time CREATE INDEX /*i*/fa_deleted_timestamp ON /*_*/filearchive (fa_deleted_timestamp); -- sort by uploader -CREATE INDEX /*i*/fa_user_timestamp ON /*_*/filearchive (fa_user_text,fa_timestamp); CREATE INDEX /*i*/fa_actor_timestamp ON /*_*/filearchive (fa_actor,fa_timestamp); -- find file by sha1, 10 bytes will be enough for hashes to be indexed CREATE INDEX /*i*/fa_sha1 ON /*_*/filearchive (fa_sha1(10)); @@ -1378,9 +1355,7 @@ CREATE TABLE /*_*/recentchanges ( rc_timestamp varbinary(14) NOT NULL default '', -- As in revision - rc_user int unsigned NOT NULL default 0, -- Deprecated in favor of rc_actor - rc_user_text varchar(255) binary NOT NULL DEFAULT '', -- Deprecated in favor of rc_actor - rc_actor bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that rc_user/rc_user_text should be used) + rc_actor bigint unsigned NOT NULL, -- When pages are renamed, their RC entries do _not_ change. rc_namespace int NOT NULL default 0, @@ -1461,11 +1436,9 @@ CREATE INDEX /*i*/new_name_timestamp ON /*_*/recentchanges (rc_new,rc_namespace, CREATE INDEX /*i*/rc_ip ON /*_*/recentchanges (rc_ip); -- Probably intended for Special:NewPages namespace filter -CREATE INDEX /*i*/rc_ns_usertext ON /*_*/recentchanges (rc_namespace, rc_user_text); CREATE INDEX /*i*/rc_ns_actor ON /*_*/recentchanges (rc_namespace, rc_actor); -- SiteStats active user count, Special:ActiveUsers, Special:NewPages user filter -CREATE INDEX /*i*/rc_user_text ON /*_*/recentchanges (rc_user_text, rc_timestamp); CREATE INDEX /*i*/rc_actor ON /*_*/recentchanges (rc_actor, rc_timestamp); -- ApiQueryRecentChanges (T140108) @@ -1595,14 +1568,8 @@ CREATE TABLE /*_*/logging ( -- Timestamp. Duh. log_timestamp binary(14) NOT NULL default '19700101000000', - -- The user who performed this action; key to user_id - log_user int unsigned NOT NULL default 0, -- Deprecated in favor of log_actor - - -- Name of the user who performed this action - log_user_text varchar(255) binary NOT NULL default '', -- Deprecated in favor of log_actor - -- The actor who performed this action - log_actor bigint unsigned NOT NULL DEFAULT 0, -- ("DEFAULT 0" is temporary, signaling that log_user/log_user_text should be used) + log_actor bigint unsigned NOT NULL, -- Key to the page affected. Where a user is the target, -- this will point to the user page. @@ -1625,7 +1592,6 @@ CREATE TABLE /*_*/logging ( CREATE INDEX /*i*/type_time ON /*_*/logging (log_type, log_timestamp); -- Special:Log performer filter -CREATE INDEX /*i*/user_time ON /*_*/logging (log_user, log_timestamp); CREATE INDEX /*i*/actor_time ON /*_*/logging (log_actor, log_timestamp); -- Special:Log title filter, log extract @@ -1635,7 +1601,6 @@ CREATE INDEX /*i*/page_time ON /*_*/logging (log_namespace, log_title, log_times CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp); -- Special:Log filter by performer and type -CREATE INDEX /*i*/log_user_type_time ON /*_*/logging (log_user, log_type, log_timestamp); CREATE INDEX /*i*/log_actor_type_time ON /*_*/logging (log_actor, log_type, log_timestamp); -- Apparently just used for a few maintenance pages (findMissingFiles.php, Flow). @@ -1645,12 +1610,6 @@ CREATE INDEX /*i*/log_page_id_time ON /*_*/logging (log_page,log_timestamp); -- Special:Log action filter CREATE INDEX /*i*/log_type_action ON /*_*/logging (log_type, log_action, log_timestamp); --- Special:Log filter by type and anonymous performer -CREATE INDEX /*i*/log_user_text_type_time ON /*_*/logging (log_user_text, log_type, log_timestamp); - --- Special:Log filter by anonymous performer -CREATE INDEX /*i*/log_user_text_time ON /*_*/logging (log_user_text, log_timestamp); - CREATE TABLE /*_*/log_search ( -- The type of ID (rev ID, log ID, rev timestamp, username) diff --git a/resources/src/mediawiki.Title/Title.js b/resources/src/mediawiki.Title/Title.js index 3084e12fb1..3f39fd16e6 100644 --- a/resources/src/mediawiki.Title/Title.js +++ b/resources/src/mediawiki.Title/Title.js @@ -137,11 +137,11 @@ var '[^' + mw.config.get( 'wgLegalTitleChars' ) + ']' + // URL percent encoding sequences interfere with the ability // to round-trip titles -- you can't link to them consistently. - '|%[0-9A-Fa-f]{2}' + + '|%[\\dA-Fa-f]{2}' + // XML/HTML character references produce similar issues. - '|&[A-Za-z0-9\u0080-\uFFFF]+;' + - '|&#[0-9]+;' + - '|&#x[0-9A-Fa-f]+;' + '|&[\\dA-Za-z\u0080-\uFFFF]+;' + + '|&#\\d+;' + + '|&#x[\\dA-Fa-f]+;' ), // From MediaWikiTitleCodec::splitTitleString() in PHP @@ -149,7 +149,7 @@ var rWhitespace = /[ _\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+/g, // From MediaWikiTitleCodec::splitTitleString() in PHP - rUnicodeBidi = /[\u200E\u200F\u202A-\u202E]/g, + rUnicodeBidi = /[\u200E\u200F\u202A-\u202E]+/g, /** * Slightly modified from Flinfo. Credit goes to Lupo and Flominator. @@ -173,13 +173,13 @@ var }, // URL encoding (possibly) { - pattern: /%([0-9A-Fa-f]{2})/g, + pattern: /%([\dA-Fa-f]{2})/g, replace: '% $1', generalRule: true }, // HTML-character-entities { - pattern: /&(([A-Za-z0-9\x80-\xff]+|#[0-9]+|#x[0-9A-Fa-f]+);)/g, + pattern: /&(([\dA-Za-z\x80-\xff]+|#\d+|#x[\dA-Fa-f]+);)/g, replace: '& $1', generalRule: true }, @@ -228,7 +228,7 @@ var * @return {Object|boolean} */ parse = function ( title, defaultNamespace ) { - var namespace, m, id, i, fragment, ext; + var namespace, m, id, i, fragment; namespace = defaultNamespace === undefined ? NS_MAIN : defaultNamespace; @@ -294,7 +294,7 @@ var } // Reject illegal characters - if ( title.match( rInvalid ) ) { + if ( rInvalid.test( title ) ) { return false; } @@ -336,21 +336,9 @@ var return false; } - // For backwards-compatibility with old mw.Title, we separate the extension from the - // rest of the title. - i = title.lastIndexOf( '.' ); - if ( i === -1 || title.length <= i + 1 ) { - // Extensions are the non-empty segment after the last dot - ext = null; - } else { - ext = title.slice( i + 1 ); - title = title.slice( 0, i ); - } - return { namespace: namespace, title: title, - ext: ext, fragment: fragment }; }, @@ -438,7 +426,6 @@ function Title( title, namespace ) { this.namespace = parsed.namespace; this.title = parsed.title; - this.ext = parsed.ext; this.fragment = parsed.fragment; } @@ -465,7 +452,6 @@ Title.newFromText = function ( title, namespace ) { t = Object.create( Title.prototype ); t.namespace = parsed.namespace; t.title = parsed.title; - t.ext = parsed.ext; t.fragment = parsed.fragment; return t; @@ -600,7 +586,6 @@ Title.newFromUserInput = function ( title, defaultNamespaceOrOptions, options ) * @return {mw.Title|null} A valid Title object or null if the title is invalid */ Title.newFromFileName = function ( uncleanName ) { - return Title.newFromUserInput( 'File:' + uncleanName, { forUploading: true } ); @@ -622,10 +607,10 @@ Title.newFromImg = function ( img ) { thumbPhpRegex = /thumb\.php/, regexes = [ // Thumbnails - /\/[a-f0-9]\/[a-f0-9]{2}\/([^\s/]+)\/[^\s/]+-[^\s/]*$/, + /\/[\da-f]\/[\da-f]{2}\/([^\s/]+)\/[^\s/]+-[^\s/]*$/, // Full size images - /\/[a-f0-9]\/[a-f0-9]{2}\/([^\s/]+)$/, + /\/[\da-f]\/[\da-f]{2}\/([^\s/]+)$/, // Thumbnails in non-hashed upload directories /\/([^\s/]+)\/[^\s/]+-(?:\1|thumbnail)[^\s/]*$/, @@ -638,9 +623,7 @@ Title.newFromImg = function ( img ) { src = img.jquery ? img[ 0 ].src : img.src; - matches = src.match( thumbPhpRegex ); - - if ( matches ) { + if ( thumbPhpRegex.test( src ) ) { return mw.Title.newFromText( 'File:' + mw.util.getParamValue( 'f', src ) ); } @@ -759,16 +742,16 @@ Title.exist = { Title.normalizeExtension = function ( extension ) { var lower = extension.toLowerCase(), - squish = { + normalizations = { htm: 'html', jpeg: 'jpg', mpeg: 'mpg', tiff: 'tif', ogv: 'ogg' }; - if ( Object.prototype.hasOwnProperty.call( squish, lower ) ) { - return squish[ lower ]; - } else if ( /^[0-9a-z]+$/.test( lower ) ) { + if ( Object.hasOwnProperty.call( normalizations, lower ) ) { + return normalizations[ lower ]; + } else if ( /^[\da-z]+$/.test( lower ) ) { return lower; } else { return ''; @@ -824,13 +807,11 @@ Title.prototype = { * @return {string} */ getName: function () { - if ( - mw.config.get( 'wgCaseSensitiveNamespaces' ).indexOf( this.namespace ) !== -1 || - !this.title.length - ) { - return this.title; + var ext = this.getExtension(); + if ( ext === null ) { + return this.getMain(); } - return mw.Title.phpCharToUpper( this.title[ 0 ] ) + this.title.slice( 1 ); + return this.getMain().slice( 0, -ext.length - 1 ); }, /** @@ -852,7 +833,11 @@ Title.prototype = { * @return {string|null} Name extension or null if there is none */ getExtension: function () { - return this.ext; + var lastDot = this.title.lastIndexOf( '.' ); + if ( lastDot === -1 ) { + return null; + } + return this.title.slice( lastDot + 1 ) || null; }, /** @@ -863,7 +848,8 @@ Title.prototype = { * @return {string} */ getDotExtension: function () { - return this.ext === null ? '' : '.' + this.ext; + var ext = this.getExtension(); + return ext === null ? '' : '.' + ext; }, /** @@ -874,7 +860,13 @@ Title.prototype = { * @return {string} */ getMain: function () { - return this.getName() + this.getDotExtension(); + if ( + mw.config.get( 'wgCaseSensitiveNamespaces' ).indexOf( this.namespace ) !== -1 || + !this.title.length + ) { + return this.title; + } + return mw.Title.phpCharToUpper( this.title[ 0 ] ) + this.title.slice( 1 ); }, /** diff --git a/tests/parser/ParserTestRunner.php b/tests/parser/ParserTestRunner.php index c8b8ef92a1..91c3d40de9 100644 --- a/tests/parser/ParserTestRunner.php +++ b/tests/parser/ParserTestRunner.php @@ -1246,8 +1246,6 @@ class ParserTestRunner { * @return array */ private function listTables() { - global $wgActorTableSchemaMigrationStage; - $tables = [ 'user', 'user_properties', 'user_former_groups', 'page', 'page_restrictions', 'protected_titles', 'revision', 'ip_changes', 'text', 'pagelinks', 'imagelinks', 'categorylinks', 'templatelinks', 'externallinks', 'langlinks', 'iwlinks', @@ -1256,15 +1254,9 @@ class ParserTestRunner { 'querycache', 'objectcache', 'job', 'l10n_cache', 'redirect', 'querycachetwo', 'archive', 'user_groups', 'page_props', 'category', 'slots', 'content', 'slot_roles', 'content_models', - 'comment', 'revision_comment_temp', + 'comment', 'revision_comment_temp', 'actor', 'revision_actor_temp', ]; - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - // The new tables for actors are in use - $tables[] = 'actor'; - $tables[] = 'revision_actor_temp'; - } - if ( in_array( $this->db->getType(), [ 'mysql', 'sqlite' ] ) ) { array_push( $tables, 'searchindex' ); } diff --git a/tests/phpunit/includes/ActorMigrationTest.php b/tests/phpunit/includes/ActorMigrationTest.php index 46c0c42a48..a82b697225 100644 --- a/tests/phpunit/includes/ActorMigrationTest.php +++ b/tests/phpunit/includes/ActorMigrationTest.php @@ -1,7 +1,7 @@ $w->tempTables, + 'formerTempTables' => $w->formerTempTables, + 'deprecated' => $w->deprecated, + 'removed' => $w->removed, + 'specialFields' => $w->specialFields, + ]; + $this->resetActorMigration = new ScopedCallback( function ( $w, $data ) { + foreach ( $data as $k => $v ) { + $w->$k = $v; + } + }, [ $w, $data ] ); + + $w->tempTables = [ + 'am2_user' => [ + 'table' => 'actormigration2_temp', + 'pk' => 'am2t_id', + 'field' => 'am2t_actor', + 'joinPK' => 'am2_id', + 'extra' => [], + ] + ]; + $w->specialFields = [ + 'am3_xxx' => [ 'am3_xxx_text', 'am3_xxx_actor' ], + ]; + } + + protected function tearDown() { + parent::tearDown(); + ScopedCallback::consume( $this->resetActorMigration ); + } + + protected function getSchemaOverrides( IMaintainableDatabase $db ) { + return [ + 'scripts' => [ + __DIR__ . '/ActorMigrationTest.sql', + ], + 'drop' => [], + 'create' => [ 'actormigration1', 'actormigration2', 'actormigration2_temp', 'actormigration3' ], + 'alter' => [], + ]; + } + /** * @dataProvider provideConstructor * @param int $stage @@ -80,156 +126,156 @@ class ActorMigrationTest extends MediaWikiLangTestCase { public static function provideGetJoin() { return [ 'Simple table, old' => [ - SCHEMA_COMPAT_OLD, 'rc_user', [ + SCHEMA_COMPAT_OLD, 'am1_user', [ 'tables' => [], 'fields' => [ - 'rc_user' => 'rc_user', - 'rc_user_text' => 'rc_user_text', - 'rc_actor' => 'NULL', + 'am1_user' => 'am1_user', + 'am1_user_text' => 'am1_user_text', + 'am1_actor' => 'NULL', ], 'joins' => [], ], ], 'Simple table, read-old' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rc_user', [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'am1_user', [ 'tables' => [], 'fields' => [ - 'rc_user' => 'rc_user', - 'rc_user_text' => 'rc_user_text', - 'rc_actor' => 'NULL', + 'am1_user' => 'am1_user', + 'am1_user_text' => 'am1_user_text', + 'am1_actor' => 'NULL', ], 'joins' => [], ], ], 'Simple table, read-new' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rc_user', [ - 'tables' => [ 'actor_rc_user' => 'actor' ], + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'am1_user', [ + 'tables' => [ 'actor_am1_user' => 'actor' ], 'fields' => [ - 'rc_user' => 'actor_rc_user.actor_user', - 'rc_user_text' => 'actor_rc_user.actor_name', - 'rc_actor' => 'rc_actor', + 'am1_user' => 'actor_am1_user.actor_user', + 'am1_user_text' => 'actor_am1_user.actor_name', + 'am1_actor' => 'am1_actor', ], 'joins' => [ - 'actor_rc_user' => [ 'JOIN', 'actor_rc_user.actor_id = rc_actor' ], + 'actor_am1_user' => [ 'JOIN', 'actor_am1_user.actor_id = am1_actor' ], ], ], ], 'Simple table, new' => [ - SCHEMA_COMPAT_NEW, 'rc_user', [ - 'tables' => [ 'actor_rc_user' => 'actor' ], + SCHEMA_COMPAT_NEW, 'am1_user', [ + 'tables' => [ 'actor_am1_user' => 'actor' ], 'fields' => [ - 'rc_user' => 'actor_rc_user.actor_user', - 'rc_user_text' => 'actor_rc_user.actor_name', - 'rc_actor' => 'rc_actor', + 'am1_user' => 'actor_am1_user.actor_user', + 'am1_user_text' => 'actor_am1_user.actor_name', + 'am1_actor' => 'am1_actor', ], 'joins' => [ - 'actor_rc_user' => [ 'JOIN', 'actor_rc_user.actor_id = rc_actor' ], + 'actor_am1_user' => [ 'JOIN', 'actor_am1_user.actor_id = am1_actor' ], ], ], ], - 'ipblocks, old' => [ - SCHEMA_COMPAT_OLD, 'ipb_by', [ + 'Special name, old' => [ + SCHEMA_COMPAT_OLD, 'am3_xxx', [ 'tables' => [], 'fields' => [ - 'ipb_by' => 'ipb_by', - 'ipb_by_text' => 'ipb_by_text', - 'ipb_by_actor' => 'NULL', + 'am3_xxx' => 'am3_xxx', + 'am3_xxx_text' => 'am3_xxx_text', + 'am3_xxx_actor' => 'NULL', ], 'joins' => [], ], ], - 'ipblocks, read-old' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'ipb_by', [ + 'Special name, read-old' => [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'am3_xxx', [ 'tables' => [], 'fields' => [ - 'ipb_by' => 'ipb_by', - 'ipb_by_text' => 'ipb_by_text', - 'ipb_by_actor' => 'NULL', + 'am3_xxx' => 'am3_xxx', + 'am3_xxx_text' => 'am3_xxx_text', + 'am3_xxx_actor' => 'NULL', ], 'joins' => [], ], ], - 'ipblocks, read-new' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'ipb_by', [ - 'tables' => [ 'actor_ipb_by' => 'actor' ], + 'Special name, read-new' => [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'am3_xxx', [ + 'tables' => [ 'actor_am3_xxx' => 'actor' ], 'fields' => [ - 'ipb_by' => 'actor_ipb_by.actor_user', - 'ipb_by_text' => 'actor_ipb_by.actor_name', - 'ipb_by_actor' => 'ipb_by_actor', + 'am3_xxx' => 'actor_am3_xxx.actor_user', + 'am3_xxx_text' => 'actor_am3_xxx.actor_name', + 'am3_xxx_actor' => 'am3_xxx_actor', ], 'joins' => [ - 'actor_ipb_by' => [ 'JOIN', 'actor_ipb_by.actor_id = ipb_by_actor' ], + 'actor_am3_xxx' => [ 'JOIN', 'actor_am3_xxx.actor_id = am3_xxx_actor' ], ], ], ], - 'ipblocks, new' => [ - SCHEMA_COMPAT_NEW, 'ipb_by', [ - 'tables' => [ 'actor_ipb_by' => 'actor' ], + 'Special name, new' => [ + SCHEMA_COMPAT_NEW, 'am3_xxx', [ + 'tables' => [ 'actor_am3_xxx' => 'actor' ], 'fields' => [ - 'ipb_by' => 'actor_ipb_by.actor_user', - 'ipb_by_text' => 'actor_ipb_by.actor_name', - 'ipb_by_actor' => 'ipb_by_actor', + 'am3_xxx' => 'actor_am3_xxx.actor_user', + 'am3_xxx_text' => 'actor_am3_xxx.actor_name', + 'am3_xxx_actor' => 'am3_xxx_actor', ], 'joins' => [ - 'actor_ipb_by' => [ 'JOIN', 'actor_ipb_by.actor_id = ipb_by_actor' ], + 'actor_am3_xxx' => [ 'JOIN', 'actor_am3_xxx.actor_id = am3_xxx_actor' ], ], ], ], - 'Revision, old' => [ - SCHEMA_COMPAT_OLD, 'rev_user', [ + 'Temp table, old' => [ + SCHEMA_COMPAT_OLD, 'am2_user', [ 'tables' => [], 'fields' => [ - 'rev_user' => 'rev_user', - 'rev_user_text' => 'rev_user_text', - 'rev_actor' => 'NULL', + 'am2_user' => 'am2_user', + 'am2_user_text' => 'am2_user_text', + 'am2_actor' => 'NULL', ], 'joins' => [], ], ], - 'Revision, read-old' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rev_user', [ + 'Temp table, read-old' => [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'am2_user', [ 'tables' => [], 'fields' => [ - 'rev_user' => 'rev_user', - 'rev_user_text' => 'rev_user_text', - 'rev_actor' => 'NULL', + 'am2_user' => 'am2_user', + 'am2_user_text' => 'am2_user_text', + 'am2_actor' => 'NULL', ], 'joins' => [], ], ], - 'Revision, read-new' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rev_user', [ + 'Temp table, read-new' => [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'am2_user', [ 'tables' => [ - 'temp_rev_user' => 'revision_actor_temp', - 'actor_rev_user' => 'actor', + 'temp_am2_user' => 'actormigration2_temp', + 'actor_am2_user' => 'actor', ], 'fields' => [ - 'rev_user' => 'actor_rev_user.actor_user', - 'rev_user_text' => 'actor_rev_user.actor_name', - 'rev_actor' => 'temp_rev_user.revactor_actor', + 'am2_user' => 'actor_am2_user.actor_user', + 'am2_user_text' => 'actor_am2_user.actor_name', + 'am2_actor' => 'temp_am2_user.am2t_actor', ], 'joins' => [ - 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], - 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], + 'temp_am2_user' => [ 'JOIN', 'temp_am2_user.am2t_id = am2_id' ], + 'actor_am2_user' => [ 'JOIN', 'actor_am2_user.actor_id = temp_am2_user.am2t_actor' ], ], ], ], - 'Revision, new' => [ - SCHEMA_COMPAT_NEW, 'rev_user', [ + 'Temp table, new' => [ + SCHEMA_COMPAT_NEW, 'am2_user', [ 'tables' => [ - 'temp_rev_user' => 'revision_actor_temp', - 'actor_rev_user' => 'actor', + 'temp_am2_user' => 'actormigration2_temp', + 'actor_am2_user' => 'actor', ], 'fields' => [ - 'rev_user' => 'actor_rev_user.actor_user', - 'rev_user_text' => 'actor_rev_user.actor_name', - 'rev_actor' => 'temp_rev_user.revactor_actor', + 'am2_user' => 'actor_am2_user.actor_user', + 'am2_user_text' => 'actor_am2_user.actor_name', + 'am2_actor' => 'temp_am2_user.am2t_actor', ], 'joins' => [ - 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], - 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], + 'temp_am2_user' => [ 'JOIN', 'temp_am2_user.am2t_id = am2_id' ], + 'actor_am2_user' => [ 'JOIN', 'actor_am2_user.actor_id = temp_am2_user.am2t_actor' ], ], ], ], @@ -276,164 +322,164 @@ class ActorMigrationTest extends MediaWikiLangTestCase { return [ 'Simple table, old' => [ - SCHEMA_COMPAT_OLD, 'rc_user', $genericUser, true, [ + SCHEMA_COMPAT_OLD, 'am1_user', $genericUser, true, [ 'tables' => [], - 'orconds' => [ 'userid' => "rc_user = '1'" ], + 'orconds' => [ 'userid' => "am1_user = '1'" ], 'joins' => [], ], ], 'Simple table, read-old' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rc_user', $genericUser, true, [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'am1_user', $genericUser, true, [ 'tables' => [], - 'orconds' => [ 'userid' => "rc_user = '1'" ], + 'orconds' => [ 'userid' => "am1_user = '1'" ], 'joins' => [], ], ], 'Simple table, read-new' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rc_user', $genericUser, true, [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'am1_user', $genericUser, true, [ 'tables' => [], - 'orconds' => [ 'actor' => "rc_actor = '11'" ], + 'orconds' => [ 'actor' => "am1_actor = '11'" ], 'joins' => [], ], ], 'Simple table, new' => [ - SCHEMA_COMPAT_NEW, 'rc_user', $genericUser, true, [ + SCHEMA_COMPAT_NEW, 'am1_user', $genericUser, true, [ 'tables' => [], - 'orconds' => [ 'actor' => "rc_actor = '11'" ], + 'orconds' => [ 'actor' => "am1_actor = '11'" ], 'joins' => [], ], ], - 'ipblocks, old' => [ - SCHEMA_COMPAT_OLD, 'ipb_by', $genericUser, true, [ + 'Special name, old' => [ + SCHEMA_COMPAT_OLD, 'am3_xxx', $genericUser, true, [ 'tables' => [], - 'orconds' => [ 'userid' => "ipb_by = '1'" ], + 'orconds' => [ 'userid' => "am3_xxx = '1'" ], 'joins' => [], ], ], - 'ipblocks, read-old' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'ipb_by', $genericUser, true, [ + 'Special name, read-old' => [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'am3_xxx', $genericUser, true, [ 'tables' => [], - 'orconds' => [ 'userid' => "ipb_by = '1'" ], + 'orconds' => [ 'userid' => "am3_xxx = '1'" ], 'joins' => [], ], ], - 'ipblocks, read-new' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'ipb_by', $genericUser, true, [ + 'Special name, read-new' => [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'am3_xxx', $genericUser, true, [ 'tables' => [], - 'orconds' => [ 'actor' => "ipb_by_actor = '11'" ], + 'orconds' => [ 'actor' => "am3_xxx_actor = '11'" ], 'joins' => [], ], ], - 'ipblocks, new' => [ - SCHEMA_COMPAT_NEW, 'ipb_by', $genericUser, true, [ + 'Special name, new' => [ + SCHEMA_COMPAT_NEW, 'am3_xxx', $genericUser, true, [ 'tables' => [], - 'orconds' => [ 'actor' => "ipb_by_actor = '11'" ], + 'orconds' => [ 'actor' => "am3_xxx_actor = '11'" ], 'joins' => [], ], ], - 'Revision, old' => [ - SCHEMA_COMPAT_OLD, 'rev_user', $genericUser, true, [ + 'Temp table, old' => [ + SCHEMA_COMPAT_OLD, 'am2_user', $genericUser, true, [ 'tables' => [], - 'orconds' => [ 'userid' => "rev_user = '1'" ], + 'orconds' => [ 'userid' => "am2_user = '1'" ], 'joins' => [], ], ], - 'Revision, read-old' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rev_user', $genericUser, true, [ + 'Temp table, read-old' => [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'am2_user', $genericUser, true, [ 'tables' => [], - 'orconds' => [ 'userid' => "rev_user = '1'" ], + 'orconds' => [ 'userid' => "am2_user = '1'" ], 'joins' => [], ], ], - 'Revision, read-new' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rev_user', $genericUser, true, [ + 'Temp table, read-new' => [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'am2_user', $genericUser, true, [ 'tables' => [ - 'temp_rev_user' => 'revision_actor_temp', + 'temp_am2_user' => 'actormigration2_temp', ], - 'orconds' => [ 'actor' => "temp_rev_user.revactor_actor = '11'" ], + 'orconds' => [ 'actor' => "temp_am2_user.am2t_actor = '11'" ], 'joins' => [ - 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'temp_am2_user' => [ 'JOIN', 'temp_am2_user.am2t_id = am2_id' ], ], ], ], - 'Revision, new' => [ - SCHEMA_COMPAT_NEW, 'rev_user', $genericUser, true, [ + 'Temp table, new' => [ + SCHEMA_COMPAT_NEW, 'am2_user', $genericUser, true, [ 'tables' => [ - 'temp_rev_user' => 'revision_actor_temp', + 'temp_am2_user' => 'actormigration2_temp', ], - 'orconds' => [ 'actor' => "temp_rev_user.revactor_actor = '11'" ], + 'orconds' => [ 'actor' => "temp_am2_user.am2t_actor = '11'" ], 'joins' => [ - 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'temp_am2_user' => [ 'JOIN', 'temp_am2_user.am2t_id = am2_id' ], ], ], ], 'Multiple users, old' => [ - SCHEMA_COMPAT_OLD, 'rc_user', $complicatedUsers, true, [ + SCHEMA_COMPAT_OLD, 'am1_user', $complicatedUsers, true, [ 'tables' => [], 'orconds' => [ - 'userid' => "rc_user IN ('1','2','3') ", - 'username' => "rc_user_text IN ('192.168.12.34','192.168.12.35') " + 'userid' => "am1_user IN ('1','2','3') ", + 'username' => "am1_user_text IN ('192.168.12.34','192.168.12.35') " ], 'joins' => [], ], ], 'Multiple users, read-old' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rc_user', $complicatedUsers, true, [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'am1_user', $complicatedUsers, true, [ 'tables' => [], 'orconds' => [ - 'userid' => "rc_user IN ('1','2','3') ", - 'username' => "rc_user_text IN ('192.168.12.34','192.168.12.35') " + 'userid' => "am1_user IN ('1','2','3') ", + 'username' => "am1_user_text IN ('192.168.12.34','192.168.12.35') " ], 'joins' => [], ], ], 'Multiple users, read-new' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rc_user', $complicatedUsers, true, [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'am1_user', $complicatedUsers, true, [ 'tables' => [], - 'orconds' => [ 'actor' => "rc_actor IN ('11','12','34') " ], + 'orconds' => [ 'actor' => "am1_actor IN ('11','12','34') " ], 'joins' => [], ], ], 'Multiple users, new' => [ - SCHEMA_COMPAT_NEW, 'rc_user', $complicatedUsers, true, [ + SCHEMA_COMPAT_NEW, 'am1_user', $complicatedUsers, true, [ 'tables' => [], - 'orconds' => [ 'actor' => "rc_actor IN ('11','12','34') " ], + 'orconds' => [ 'actor' => "am1_actor IN ('11','12','34') " ], 'joins' => [], ], ], 'Multiple users, no use ID, old' => [ - SCHEMA_COMPAT_OLD, 'rc_user', $complicatedUsers, false, [ + SCHEMA_COMPAT_OLD, 'am1_user', $complicatedUsers, false, [ 'tables' => [], 'orconds' => [ - 'username' => "rc_user_text IN ('User1','User2','User3','192.168.12.34','192.168.12.35') " + 'username' => "am1_user_text IN ('User1','User2','User3','192.168.12.34','192.168.12.35') " ], 'joins' => [], ], ], 'Multiple users, read-old' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rc_user', $complicatedUsers, false, [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'am1_user', $complicatedUsers, false, [ 'tables' => [], 'orconds' => [ - 'username' => "rc_user_text IN ('User1','User2','User3','192.168.12.34','192.168.12.35') " + 'username' => "am1_user_text IN ('User1','User2','User3','192.168.12.34','192.168.12.35') " ], 'joins' => [], ], ], 'Multiple users, read-new' => [ - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rc_user', $complicatedUsers, false, [ + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'am1_user', $complicatedUsers, false, [ 'tables' => [], - 'orconds' => [ 'actor' => "rc_actor IN ('11','12','34') " ], + 'orconds' => [ 'actor' => "am1_actor IN ('11','12','34') " ], 'joins' => [], ], ], 'Multiple users, new' => [ - SCHEMA_COMPAT_NEW, 'rc_user', $complicatedUsers, false, [ + SCHEMA_COMPAT_NEW, 'am1_user', $complicatedUsers, false, [ 'tables' => [], - 'orconds' => [ 'actor' => "rc_actor IN ('11','12','34') " ], + 'orconds' => [ 'actor' => "am1_actor IN ('11','12','34') " ], 'joins' => [], ], ], @@ -445,23 +491,14 @@ class ActorMigrationTest extends MediaWikiLangTestCase { * @param string $table * @param string $key * @param string $pk - * @param array $extraFields + * @param bool $usesTemp */ - public function testInsertRoundTrip( $table, $key, $pk, $extraFields ) { + public function testInsertRoundTrip( $table, $key, $pk, $usesTemp ) { $u = $this->getTestUser()->getUser(); $user = $this->getMock( UserIdentity::class ); $user->method( 'getId' )->willReturn( $u->getId() ); $user->method( 'getName' )->willReturn( $u->getName() ); - if ( $u->getActorId( $this->db ) ) { - $user->method( 'getActorId' )->willReturn( $u->getActorId() ); - } else { - $this->db->insert( - 'actor', - [ 'actor_user' => $u->getId(), 'actor_name' => $u->getName() ], - __METHOD__ - ); - $user->method( 'getActorId' )->willReturn( $this->db->insertId() ); - } + $user->method( 'getActorId' )->willReturn( $u->getActorId( $this->db ) ); $stageNames = [ SCHEMA_COMPAT_OLD => 'old', @@ -494,15 +531,10 @@ class ActorMigrationTest extends MediaWikiLangTestCase { ]; $nameKey = $key . '_text'; - $actorKey = $key === 'ipb_by' ? 'ipb_by_actor' : substr( $key, 0, -5 ) . '_actor'; + $actorKey = ( $key === 'am3_xxx' ? $key : substr( $key, 0, -5 ) ) . '_actor'; foreach ( $stages as $writeStage => $possibleReadStages ) { - if ( $key === 'ipb_by' ) { - $extraFields['ipb_address'] = __CLASS__ . "#{$stageNames[$writeStage]}"; - } - $w = new ActorMigration( $writeStage ); - $usesTemp = $key === 'rev_user'; if ( $usesTemp ) { list( $fields, $callback ) = $w->getInsertValuesWithTempTable( $this->db, $key, $user ); @@ -527,10 +559,10 @@ class ActorMigrationTest extends MediaWikiLangTestCase { "new field, stage={$stageNames[$writeStage]}" ); } - $this->db->insert( $table, $extraFields + $fields, __METHOD__ ); - $id = $this->db->insertId(); + $id = ++self::$amId; + $this->db->insert( $table, [ $pk => $id ] + $fields, __METHOD__ ); if ( $usesTemp ) { - $callback( $id, $extraFields ); + $callback( $id, [] ); } foreach ( $possibleReadStages as $readStage ) { @@ -560,33 +592,10 @@ class ActorMigrationTest extends MediaWikiLangTestCase { } public static function provideInsertRoundTrip() { - $db = wfGetDB( DB_REPLICA ); // for timestamps - - $comment = MediaWikiServices::getInstance()->getCommentStore() - ->createComment( wfGetDB( DB_MASTER ), '' ); - return [ - 'recentchanges' => [ 'recentchanges', 'rc_user', 'rc_id', [ - 'rc_timestamp' => $db->timestamp(), - 'rc_namespace' => 0, - 'rc_title' => 'Test', - 'rc_this_oldid' => 42, - 'rc_last_oldid' => 41, - 'rc_source' => 'test', - 'rc_comment_id' => $comment->id, - ] ], - 'ipblocks' => [ 'ipblocks', 'ipb_by', 'ipb_id', [ - 'ipb_range_start' => '', - 'ipb_range_end' => '', - 'ipb_timestamp' => $db->timestamp(), - 'ipb_expiry' => $db->getInfinity(), - 'ipb_reason_id' => $comment->id, - ] ], - 'revision' => [ 'revision', 'rev_user', 'rev_id', [ - 'rev_page' => 42, - 'rev_len' => 0, - 'rev_timestamp' => $db->timestamp(), - ] ], + 'normal' => [ 'actormigration1', 'am1_user', 'am1_id', false ], + 'temp table' => [ 'actormigration2', 'am2_user', 'am2_id', true ], + 'special name' => [ 'actormigration3', 'am3_xxx', 'am3_id', false ], ]; } @@ -603,22 +612,22 @@ class ActorMigrationTest extends MediaWikiLangTestCase { * @dataProvider provideStages * @param int $stage * @expectedException InvalidArgumentException - * @expectedExceptionMessage Must use getInsertValuesWithTempTable() for rev_user + * @expectedExceptionMessage Must use getInsertValuesWithTempTable() for am2_user */ public function testInsertWrong( $stage ) { $m = new ActorMigration( $stage ); - $m->getInsertValues( $this->db, 'rev_user', $this->getTestUser()->getUser() ); + $m->getInsertValues( $this->db, 'am2_user', $this->getTestUser()->getUser() ); } /** * @dataProvider provideStages * @param int $stage * @expectedException InvalidArgumentException - * @expectedExceptionMessage Must use getInsertValues() for rc_user + * @expectedExceptionMessage Must use getInsertValues() for am1_user */ public function testInsertWithTempTableWrong( $stage ) { $m = new ActorMigration( $stage ); - $m->getInsertValuesWithTempTable( $this->db, 'rc_user', $this->getTestUser()->getUser() ); + $m->getInsertValuesWithTempTable( $this->db, 'am1_user', $this->getTestUser()->getUser() ); } /** @@ -627,12 +636,12 @@ class ActorMigrationTest extends MediaWikiLangTestCase { */ public function testInsertWithTempTableDeprecated( $stage ) { $wrap = TestingAccessWrapper::newFromClass( ActorMigration::class ); - $wrap->formerTempTables += [ 'rc_user' => '1.30' ]; + $wrap->formerTempTables += [ 'am1_user' => '1.30' ]; - $this->hideDeprecated( 'ActorMigration::getInsertValuesWithTempTable for rc_user' ); + $this->hideDeprecated( 'ActorMigration::getInsertValuesWithTempTable for am1_user' ); $m = new ActorMigration( $stage ); list( $fields, $callback ) - = $m->getInsertValuesWithTempTable( $this->db, 'rc_user', $this->getTestUser()->getUser() ); + = $m->getInsertValuesWithTempTable( $this->db, 'am1_user', $this->getTestUser()->getUser() ); $this->assertTrue( is_callable( $callback ) ); } @@ -640,12 +649,23 @@ class ActorMigrationTest extends MediaWikiLangTestCase { * @dataProvider provideStages * @param int $stage * @expectedException InvalidArgumentException - * @expectedExceptionMessage $extra[rev_timestamp] is not provided + * @expectedExceptionMessage $extra[foo_timestamp] is not provided */ public function testInsertWithTempTableCallbackMissingFields( $stage ) { + $w = TestingAccessWrapper::newFromClass( ActorMigration::class ); + $w->tempTables = [ + 'foo_user' => [ + 'table' => 'foo_temp', + 'pk' => 'footmp_id', + 'field' => 'footmp_actor', + 'joinPK' => 'foo_id', + 'extra' => [ 'footmp_timestamp' => 'foo_timestamp' ], + ], + ]; + $m = new ActorMigration( $stage ); list( $fields, $callback ) - = $m->getInsertValuesWithTempTable( $this->db, 'rev_user', $this->getTestUser()->getUser() ); + = $m->getInsertValuesWithTempTable( $this->db, 'foo_user', $this->getTestUser()->getUser() ); $callback( 1, [] ); } @@ -654,41 +674,33 @@ class ActorMigrationTest extends MediaWikiLangTestCase { * @param int $stage */ public function testInsertUserIdentity( $stage ) { - $this->setMwGlobals( [ - // for User::getActorId() - 'wgActorTableSchemaMigrationStage' => $stage - ] ); - $user = $this->getMutableTestUser()->getUser(); $userIdentity = $this->getMock( UserIdentity::class ); $userIdentity->method( 'getId' )->willReturn( $user->getId() ); $userIdentity->method( 'getName' )->willReturn( $user->getName() ); $userIdentity->method( 'getActorId' )->willReturn( 0 ); - list( $cFields, $cCallback ) = MediaWikiServices::getInstance()->getCommentStore() - ->insertWithTempTable( $this->db, 'rev_comment', '' ); $m = new ActorMigration( $stage ); list( $fields, $callback ) = - $m->getInsertValuesWithTempTable( $this->db, 'rev_user', $userIdentity ); - $extraFields = [ - 'rev_page' => 42, - 'rev_len' => 0, - 'rev_timestamp' => $this->db->timestamp(), - ] + $cFields; - $this->db->insert( 'revision', $extraFields + $fields, __METHOD__ ); - $id = $this->db->insertId(); - $callback( $id, $extraFields ); - $cCallback( $id ); - - $qi = $m->getJoin( 'rev_user' ); + $m->getInsertValuesWithTempTable( $this->db, 'am2_user', $userIdentity ); + $id = ++self::$amId; + $this->db->insert( 'actormigration2', [ 'am2_id' => $id ] + $fields, __METHOD__ ); + $callback( $id, [] ); + + $qi = $m->getJoin( 'am2_user' ); $row = $this->db->selectRow( - [ 'revision' ] + $qi['tables'], $qi['fields'], [ 'rev_id' => $id ], __METHOD__, [], $qi['joins'] + [ 'actormigration2' ] + $qi['tables'], + $qi['fields'], + [ 'am2_id' => $id ], + __METHOD__, + [], + $qi['joins'] ); - $this->assertSame( $user->getId(), (int)$row->rev_user ); - $this->assertSame( $user->getName(), $row->rev_user_text ); + $this->assertSame( $user->getId(), (int)$row->am2_user ); + $this->assertSame( $user->getName(), $row->am2_user_text ); $this->assertSame( ( $stage & SCHEMA_COMPAT_READ_NEW ) ? $user->getActorId() : 0, - (int)$row->rev_actor + (int)$row->am2_actor ); $m = new ActorMigration( $stage ); @@ -736,4 +748,24 @@ class ActorMigrationTest extends MediaWikiLangTestCase { ]; } + public function testCheckDeprecation() { + $wrap = TestingAccessWrapper::newFromClass( ActorMigration::class ); + $wrap->deprecated += [ 'soft' => null, 'hard' => '1.34' ]; + $wrap->removed += [ 'gone' => '1.34' ]; + + $this->hideDeprecated( 'ActorMigration for \'hard\'' ); + + $wrap->checkDeprecation( 'valid' ); + $wrap->checkDeprecation( 'soft' ); + $wrap->checkDeprecation( 'hard' ); + try { + $wrap->checkDeprecation( 'gone' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Use of ActorMigration for \'gone\' was removed in MediaWiki 1.34', + $ex->getMessage() + ); + } + } + } diff --git a/tests/phpunit/includes/ActorMigrationTest.sql b/tests/phpunit/includes/ActorMigrationTest.sql new file mode 100644 index 0000000000..f387dac069 --- /dev/null +++ b/tests/phpunit/includes/ActorMigrationTest.sql @@ -0,0 +1,26 @@ +-- These are carefully crafted to work in all five supported databases + +CREATE TABLE /*_*/actormigration1 ( + am1_id integer not null, + am1_user integer, + am1_user_text varchar(200), + am1_actor integer +); + +CREATE TABLE /*_*/actormigration2 ( + am2_id integer not null, + am2_user integer, + am2_user_text varchar(200) +); + +CREATE TABLE /*_*/actormigration2_temp ( + am2t_id integer not null, + am2t_actor integer +); + +CREATE TABLE /*_*/actormigration3 ( + am3_id integer not null, + am3_xxx integer, + am3_xxx_text varchar(200), + am3_xxx_actor integer +); diff --git a/tests/phpunit/includes/Revision/RevisionQueryInfoTest.php b/tests/phpunit/includes/Revision/RevisionQueryInfoTest.php index 5cc3646ca8..949b664e29 100644 --- a/tests/phpunit/includes/Revision/RevisionQueryInfoTest.php +++ b/tests/phpunit/includes/Revision/RevisionQueryInfoTest.php @@ -61,32 +61,11 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { ]; } - protected function getOldActorQueryFields( $prefix ) { - return [ - "{$prefix}_user" => "{$prefix}_user", - "{$prefix}_user_text" => "{$prefix}_user_text", - "{$prefix}_actor" => 'NULL', - ]; - } - protected function getNewActorQueryFields( $prefix, $tmp = false ) { return [ "{$prefix}_user" => "actor_{$prefix}_user.actor_user", "{$prefix}_user_text" => "actor_{$prefix}_user.actor_name", - "{$prefix}_actor" => $tmp ?: "{$prefix}_actor", - ]; - } - - protected function getNewActorJoins( $prefix ) { - return [ - "temp_{$prefix}_user" => [ - "JOIN", - "temp_{$prefix}_user.revactor_{$prefix} = {$prefix}_id", - ], - "actor_{$prefix}_user" => [ - "JOIN", - "actor_{$prefix}_user.actor_id = temp_{$prefix}_user.revactor_actor", - ], + "{$prefix}_actor" => $tmp ? "temp_{$prefix}_user.{$prefix}actor_actor" : "{$prefix}_actor", ]; } @@ -125,7 +104,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { yield 'MCR, comment, actor' => [ [ 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_NEW, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW, ], [ 'tables' => [ @@ -150,7 +128,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'wgContentHandlerUseDB' => true, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW, ], [ 'tables' => [ @@ -175,22 +152,23 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'wgContentHandlerUseDB' => true, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, ], [ 'tables' => [ 'archive', + 'actor_ar_user' => 'actor', 'comment_ar_comment' => 'comment', ], 'fields' => array_merge( $this->getArchiveQueryFields( true ), $this->getContentHandlerQueryFields( 'ar' ), - $this->getOldActorQueryFields( 'ar' ), + $this->getNewActorQueryFields( 'ar' ), $this->getNewCommentQueryFields( 'ar' ) ), 'joins' => [ 'comment_ar_comment' => [ 'JOIN', 'comment_ar_comment.comment_id = ar_comment_id' ], + 'actor_ar_user' => [ 'JOIN', 'actor_ar_user.actor_id = ar_actor' ], ], ] ]; @@ -198,21 +176,22 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { [ 'wgContentHandlerUseDB' => false, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD, ], [ 'tables' => [ 'archive', + 'actor_ar_user' => 'actor', 'comment_ar_comment' => 'comment', ], 'fields' => array_merge( $this->getArchiveQueryFields( true ), - $this->getOldActorQueryFields( 'ar' ), + $this->getNewActorQueryFields( 'ar' ), $this->getNewCommentQueryFields( 'ar' ) ), 'joins' => [ 'comment_ar_comment' => [ 'JOIN', 'comment_ar_comment.comment_id = ar_comment_id' ], + 'actor_ar_user' => [ 'JOIN', 'actor_ar_user.actor_id = ar_actor' ], ], ] ]; @@ -224,7 +203,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { [ 'wgContentHandlerUseDB' => true, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_NEW, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW, ], [ 'page', 'user' ], [ @@ -260,6 +238,8 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { ], 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], ], ] ]; @@ -268,7 +248,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'wgContentHandlerUseDB' => true, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, ], [ 'page', 'user' ], [ @@ -288,22 +267,21 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { $this->getNewActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ), $this->getNewCommentQueryFields( 'rev' ) ), - 'joins' => array_merge( - [ - 'page' => [ 'JOIN', [ 'page_id = rev_page' ] ], - 'user' => [ - 'LEFT JOIN', - [ - 'actor_rev_user.actor_user != 0', - 'user_id = actor_rev_user.actor_user', - ] - ], - 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], - 'comment_rev_comment' - => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'joins' => [ + 'page' => [ 'JOIN', [ 'page_id = rev_page' ] ], + 'user' => [ + 'LEFT JOIN', + [ + 'actor_rev_user.actor_user != 0', + 'user_id = actor_rev_user.actor_user', + ] ], - $this->getNewActorJoins( 'rev' ) - ), + 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], + 'comment_rev_comment' + => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], + ], ] ]; yield 'MCR read-new' => [ @@ -311,7 +289,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'wgContentHandlerUseDB' => true, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, ], [ 'page', 'user' ], [ @@ -331,22 +308,21 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { $this->getNewActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ), $this->getNewCommentQueryFields( 'rev' ) ), - 'joins' => array_merge( - [ - 'page' => [ 'JOIN', [ 'page_id = rev_page' ] ], - 'user' => [ - 'LEFT JOIN', - [ - 'actor_rev_user.actor_user != 0', - 'user_id = actor_rev_user.actor_user' - ] - ], - 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], - 'comment_rev_comment' - => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'joins' => [ + 'page' => [ 'JOIN', [ 'page_id = rev_page' ] ], + 'user' => [ + 'LEFT JOIN', + [ + 'actor_rev_user.actor_user != 0', + 'user_id = actor_rev_user.actor_user' + ] ], - $this->getNewActorJoins( 'rev' ) - ), + 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], + 'comment_rev_comment' + => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], + ], ] ]; yield 'MCR write-both/read-old' => [ @@ -354,7 +330,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'wgContentHandlerUseDB' => true, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, ], [], [ @@ -362,17 +337,21 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'revision', 'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment', + 'temp_rev_user' => 'revision_actor_temp', + 'actor_rev_user' => 'actor', ], 'fields' => array_merge( $this->getRevisionQueryFields( true ), $this->getContentHandlerQueryFields( 'rev' ), - $this->getOldActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ), + $this->getNewActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ), $this->getNewCommentQueryFields( 'rev' ) ), 'joins' => [ 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], 'comment_rev_comment' => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], ], ] ]; @@ -381,7 +360,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'wgContentHandlerUseDB' => true, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, ], [ 'page', 'user' ], [ @@ -391,37 +369,38 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'user', 'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment', + 'temp_rev_user' => 'revision_actor_temp', + 'actor_rev_user' => 'actor', ], 'fields' => array_merge( $this->getRevisionQueryFields( true ), $this->getContentHandlerQueryFields( 'rev' ), $this->getUserQueryFields(), $this->getPageQueryFields(), - $this->getOldActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ), + $this->getNewActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ), $this->getNewCommentQueryFields( 'rev' ) ), - 'joins' => array_merge( - [ - 'page' => [ 'JOIN', [ 'page_id = rev_page' ] ], - 'user' => [ - 'LEFT JOIN', - [ - 'rev_user != 0', - 'user_id = rev_user' - ] - ], - 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], - 'comment_rev_comment' - => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], - ] - ), + 'joins' => [ + 'page' => [ 'JOIN', [ 'page_id = rev_page' ] ], + 'user' => [ + 'LEFT JOIN', + [ + 'actor_rev_user.actor_user != 0', + 'user_id = actor_rev_user.actor_user', + ] + ], + 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], + 'comment_rev_comment' + => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], + ], ] ]; yield 'pre-MCR' => [ [ 'wgContentHandlerUseDB' => true, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD, ], [], [ @@ -429,17 +408,21 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'revision', 'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment', + 'temp_rev_user' => 'revision_actor_temp', + 'actor_rev_user' => 'actor', ], 'fields' => array_merge( $this->getRevisionQueryFields( true ), $this->getContentHandlerQueryFields( 'rev' ), - $this->getOldActorQueryFields( 'rev' ), + $this->getNewActorQueryFields( 'rev', true ), $this->getNewCommentQueryFields( 'rev' ) ), 'joins' => [ 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], 'comment_rev_comment' => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], ], ] ]; @@ -447,7 +430,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { [ 'wgContentHandlerUseDB' => true, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD, ], [ 'page', 'user' ], [ @@ -455,21 +437,28 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'revision', 'page', 'user', 'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment', + 'temp_rev_user' => 'revision_actor_temp', + 'actor_rev_user' => 'actor', ], 'fields' => array_merge( $this->getRevisionQueryFields( true ), $this->getContentHandlerQueryFields( 'rev' ), $this->getPageQueryFields(), $this->getUserQueryFields(), - $this->getOldActorQueryFields( 'rev' ), + $this->getNewActorQueryFields( 'rev', true ), $this->getNewCommentQueryFields( 'rev' ) ), 'joins' => [ 'page' => [ 'JOIN', [ 'page_id = rev_page' ] ], - 'user' => [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ], + 'user' => [ 'LEFT JOIN', [ + 'actor_rev_user.actor_user != 0', + 'user_id = actor_rev_user.actor_user', + ] ], 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], 'comment_rev_comment' => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], ], ] ]; @@ -477,7 +466,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { [ 'wgContentHandlerUseDB' => false, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD, ], [], [ @@ -485,16 +473,20 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'revision', 'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment', + 'temp_rev_user' => 'revision_actor_temp', + 'actor_rev_user' => 'actor', ], 'fields' => array_merge( $this->getRevisionQueryFields( true ), - $this->getOldActorQueryFields( 'rev' ), + $this->getNewActorQueryFields( 'rev', true ), $this->getNewCommentQueryFields( 'rev' ) ), 'joins' => [ 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], 'comment_rev_comment' => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], ], ], ]; @@ -502,7 +494,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { [ 'wgContentHandlerUseDB' => false, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD, ], [ 'page' ], [ @@ -510,11 +501,13 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'revision', 'page', 'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment', + 'temp_rev_user' => 'revision_actor_temp', + 'actor_rev_user' => 'actor', ], 'fields' => array_merge( $this->getRevisionQueryFields( true ), $this->getPageQueryFields(), - $this->getOldActorQueryFields( 'rev' ), + $this->getNewActorQueryFields( 'rev', true ), $this->getNewCommentQueryFields( 'rev' ) ), 'joins' => [ @@ -522,6 +515,8 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], 'comment_rev_comment' => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], ], ], ]; @@ -529,7 +524,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { [ 'wgContentHandlerUseDB' => false, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD, ], [ 'user' ], [ @@ -537,18 +531,25 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'revision', 'user', 'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment', + 'temp_rev_user' => 'revision_actor_temp', + 'actor_rev_user' => 'actor', ], 'fields' => array_merge( $this->getRevisionQueryFields( true ), $this->getUserQueryFields(), - $this->getOldActorQueryFields( 'rev' ), + $this->getNewActorQueryFields( 'rev', true ), $this->getNewCommentQueryFields( 'rev' ) ), 'joins' => [ - 'user' => [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ], + 'user' => [ 'LEFT JOIN', [ + 'actor_rev_user.actor_user != 0', + 'user_id = actor_rev_user.actor_user', + ] ], 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], 'comment_rev_comment' => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], ], ], ]; @@ -556,7 +557,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { [ 'wgContentHandlerUseDB' => false, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD, ], [ 'text' ], [ @@ -564,11 +564,13 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'revision', 'text', 'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment', + 'temp_rev_user' => 'revision_actor_temp', + 'actor_rev_user' => 'actor', ], 'fields' => array_merge( $this->getRevisionQueryFields( true ), $this->getTextQueryFields(), - $this->getOldActorQueryFields( 'rev' ), + $this->getNewActorQueryFields( 'rev', true ), $this->getNewCommentQueryFields( 'rev' ) ), 'joins' => [ @@ -576,6 +578,8 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], 'comment_rev_comment' => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], ], ], ]; @@ -583,7 +587,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { [ 'wgContentHandlerUseDB' => false, 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD, ], [ 'text', 'page', 'user' ], [ @@ -591,13 +594,15 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'revision', 'page', 'user', 'text', 'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment', + 'temp_rev_user' => 'revision_actor_temp', + 'actor_rev_user' => 'actor', ], 'fields' => array_merge( $this->getRevisionQueryFields( true ), $this->getPageQueryFields(), $this->getUserQueryFields(), $this->getTextQueryFields(), - $this->getOldActorQueryFields( 'rev' ), + $this->getNewActorQueryFields( 'rev', true ), $this->getNewCommentQueryFields( 'rev' ) ), 'joins' => [ @@ -608,8 +613,8 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'user' => [ 'LEFT JOIN', [ - 'rev_user != 0', - 'user_id = rev_user', + 'actor_rev_user.actor_user != 0', + 'user_id = actor_rev_user.actor_user', ], ], 'text' => [ @@ -619,6 +624,8 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], 'comment_rev_comment' => [ 'JOIN', 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ], ], ], ]; @@ -848,190 +855,6 @@ class RevisionQueryInfoTest extends MediaWikiTestCase { ]; } - public function provideSelectFields() { - yield 'with model, comment, and actor' => [ - [ - 'wgContentHandlerUseDB' => true, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, - ], - 'fields' => array_merge( - [ - 'rev_id', - 'rev_page', - 'rev_text_id', - 'rev_timestamp', - 'rev_user_text', - 'rev_user', - 'rev_actor' => 'NULL', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - ], - $this->getContentHandlerQueryFields( 'rev' ), - [ - 'rev_comment_pk' => 'rev_id', - ] - ), - ]; - yield 'no mode, no comment, no actor' => [ - [ - 'wgContentHandlerUseDB' => false, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD, - ], - 'fields' => array_merge( - [ - 'rev_id', - 'rev_page', - 'rev_text_id', - 'rev_timestamp', - 'rev_user_text', - 'rev_user', - 'rev_actor' => 'NULL', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - 'rev_comment_pk' => 'rev_id', - ] - ), - ]; - } - - public function provideSelectArchiveFields() { - yield 'with model, comment, and actor' => [ - [ - 'wgContentHandlerUseDB' => true, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, - ], - 'fields' => array_merge( - [ - 'ar_id', - 'ar_page_id', - 'ar_rev_id', - 'ar_text_id', - 'ar_timestamp', - 'ar_user_text', - 'ar_user', - 'ar_actor' => 'NULL', - 'ar_minor_edit', - 'ar_deleted', - 'ar_len', - 'ar_parent_id', - 'ar_sha1', - ], - $this->getContentHandlerQueryFields( 'ar' ), - [ - 'ar_comment_id' => 'ar_comment_id', - ] - ), - ]; - yield 'no mode, no comment, no actor' => [ - [ - 'wgContentHandlerUseDB' => false, - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD, - ], - 'fields' => array_merge( - [ - 'ar_id', - 'ar_page_id', - 'ar_rev_id', - 'ar_text_id', - 'ar_timestamp', - 'ar_user_text', - 'ar_user', - 'ar_actor' => 'NULL', - 'ar_minor_edit', - 'ar_deleted', - 'ar_len', - 'ar_parent_id', - 'ar_sha1', - 'ar_comment_id' => 'ar_comment_id', - ] - ), - ]; - } - - /** - * @dataProvider provideSelectFields - * @covers Revision::selectFields - */ - public function testRevisionSelectFields( $migrationStageSettings, $expected ) { - $this->setMwGlobals( $migrationStageSettings ); - - $this->hideDeprecated( 'Revision::selectFields' ); - $this->assertArrayEqualsIgnoringIntKeyOrder( $expected, Revision::selectFields() ); - } - - /** - * @dataProvider provideSelectArchiveFields - * @covers Revision::selectArchiveFields - */ - public function testRevisionSelectArchiveFields( $migrationStageSettings, $expected ) { - $this->setMwGlobals( $migrationStageSettings ); - - $this->hideDeprecated( 'Revision::selectArchiveFields' ); - $this->assertArrayEqualsIgnoringIntKeyOrder( $expected, Revision::selectArchiveFields() ); - } - - /** - * @covers Revision::userJoinCond - */ - public function testRevisionUserJoinCond() { - $this->hideDeprecated( 'Revision::userJoinCond' ); - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_OLD ); - $this->assertEquals( - [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ], - Revision::userJoinCond() - ); - } - - /** - * @covers Revision::pageJoinCond - */ - public function testRevisionPageJoinCond() { - $this->hideDeprecated( 'Revision::pageJoinCond' ); - $this->assertEquals( - [ 'JOIN', [ 'page_id = rev_page' ] ], - Revision::pageJoinCond() - ); - } - - /** - * @covers Revision::selectTextFields - */ - public function testRevisionSelectTextFields() { - $this->hideDeprecated( 'Revision::selectTextFields' ); - $this->assertEquals( - $this->getTextQueryFields(), - Revision::selectTextFields() - ); - } - - /** - * @covers Revision::selectPageFields - */ - public function testRevisionSelectPageFields() { - $this->hideDeprecated( 'Revision::selectPageFields' ); - $this->assertEquals( - $this->getPageQueryFields(), - Revision::selectPageFields() - ); - } - - /** - * @covers Revision::selectUserFields - */ - public function testRevisionSelectUserFields() { - $this->hideDeprecated( 'Revision::selectUserFields' ); - $this->assertEquals( - $this->getUserQueryFields(), - Revision::selectUserFields() - ); - } - /** * @covers Revision::getArchiveQueryInfo * @dataProvider provideArchiveQueryInfo diff --git a/tests/phpunit/includes/Revision/RevisionStoreDbTestBase.php b/tests/phpunit/includes/Revision/RevisionStoreDbTestBase.php index b0b9ddf313..76190e0a9b 100644 --- a/tests/phpunit/includes/Revision/RevisionStoreDbTestBase.php +++ b/tests/phpunit/includes/Revision/RevisionStoreDbTestBase.php @@ -81,7 +81,6 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { $this->setMwGlobals( [ 'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(), 'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(), - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW, ] ); } @@ -1791,8 +1790,6 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { * @covers \MediaWiki\Revision\RevisionStore::getKnownCurrentRevision */ public function testGetKnownCurrentRevision_userNameChange() { - global $wgActorTableSchemaMigrationStage; - $cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] ); $this->setService( 'MainWANObjectCache', $cache ); @@ -1811,11 +1808,9 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { $this->db->update( 'user', [ 'user_name' => $newUserName ], [ 'user_id' => $rev->getUser()->getId() ] ); - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $this->db->update( 'actor', - [ 'actor_name' => $newUserName ], - [ 'actor_user' => $rev->getUser()->getId() ] ); - } + $this->db->update( 'actor', + [ 'actor_name' => $newUserName ], + [ 'actor_user' => $rev->getUser()->getId() ] ); // Reload the revision and regrab the user name. $revAfter = $store->getKnownCurrentRevision( $page->getTitle(), $rev->getId() ); @@ -1864,8 +1859,6 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { * @covers \MediaWiki\Revision\RevisionStore::newRevisionFromRow */ public function testNewRevisionFromRow_userNameChange() { - global $wgActorTableSchemaMigrationStage; - $page = $this->getTestPage(); $text = __METHOD__; /** @var Revision $rev */ @@ -1895,11 +1888,9 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { $this->db->update( 'user', [ 'user_name' => $newUserName ], [ 'user_id' => $record->getUser()->getId() ] ); - if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { - $this->db->update( 'actor', - [ 'actor_name' => $newUserName ], - [ 'actor_user' => $record->getUser()->getId() ] ); - } + $this->db->update( 'actor', + [ 'actor_name' => $newUserName ], + [ 'actor_user' => $record->getUser()->getId() ] ); // Reload the record, passing $fromCache as true to force fresh info from the db, // and regrab the user name diff --git a/tests/phpunit/includes/RevisionDbTestBase.php b/tests/phpunit/includes/RevisionDbTestBase.php index 7b334ee409..d41c88f5a0 100644 --- a/tests/phpunit/includes/RevisionDbTestBase.php +++ b/tests/phpunit/includes/RevisionDbTestBase.php @@ -92,7 +92,6 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase { $this->setMwGlobals( [ 'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(), 'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(), - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW, ] ); if ( !$this->testPage ) { diff --git a/tests/phpunit/includes/RevisionTest.php b/tests/phpunit/includes/RevisionTest.php index 865bd31bb1..ed4a27f42a 100644 --- a/tests/phpunit/includes/RevisionTest.php +++ b/tests/phpunit/includes/RevisionTest.php @@ -601,7 +601,6 @@ class RevisionTest extends MediaWikiTestCase { * @covers Revision::loadFromTitle */ public function testLoadFromTitle() { - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW ); $title = $this->getMockTitle(); $conditions = [ diff --git a/tests/phpunit/includes/api/query/ApiQueryUserContribsTest.php b/tests/phpunit/includes/api/query/ApiQueryUserContribsTest.php index 301ed100b5..df643d2b13 100644 --- a/tests/phpunit/includes/api/query/ApiQueryUserContribsTest.php +++ b/tests/phpunit/includes/api/query/ApiQueryUserContribsTest.php @@ -8,15 +8,6 @@ */ class ApiQueryUserContribsTest extends ApiTestCase { public function addDBDataOnce() { - global $wgActorTableSchemaMigrationStage; - - $reset = new \Wikimedia\ScopedCallback( function ( $v ) { - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', $v ); - }, [ $wgActorTableSchemaMigrationStage ] ); - // Needs to WRITE_BOTH so READ_OLD tests below work. READ mode here doesn't really matter. - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', - SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW ); - $users = [ User::newFromName( '192.168.2.2', false ), User::newFromName( '192.168.2.1', false ), @@ -43,17 +34,14 @@ class ApiQueryUserContribsTest extends ApiTestCase { /** * @dataProvider provideSorting - * @param int $stage SCHEMA_COMPAT contants for $wgActorTableSchemaMigrationStage * @param array $params Extra parameters for the query * @param bool $reverse Reverse order? * @param int $revs Number of revisions to expect */ - public function testSorting( $stage, $params, $reverse, $revs ) { + public function testSorting( $params, $reverse, $revs ) { // FIXME: fails under sqlite $this->markTestSkippedIfDbType( 'sqlite' ); - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', $stage ); - if ( isset( $params['ucuserids'] ) ) { $params['ucuserids'] = implode( '|', array_map( 'User::idFromName', $params['ucuserids'] ) ); } @@ -116,38 +104,23 @@ class ApiQueryUserContribsTest extends ApiTestCase { $users2 = [ __CLASS__ . ' A', __CLASS__ . ' B', __CLASS__ . ' D' ]; $ips = [ '192.168.2.1', '192.168.2.2', '192.168.2.3', '192.168.2.4' ]; - foreach ( - [ - 'old' => SCHEMA_COMPAT_OLD, - 'read old' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, - 'read new' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, - 'new' => SCHEMA_COMPAT_NEW, - ] as $stageName => $stage - ) { - foreach ( [ false, true ] as $reverse ) { - $name = $stageName . ( $reverse ? ', reverse' : '' ); - yield "Named users, $name" => [ $stage, [ 'ucuser' => $users ], $reverse, 9 ]; - yield "Named users including a no-edit user, $name" => [ - $stage, [ 'ucuser' => $users2 ], $reverse, 6 - ]; - yield "IP users, $name" => [ $stage, [ 'ucuser' => $ips ], $reverse, 9 ]; - yield "All users, $name" => [ - $stage, [ 'ucuser' => array_merge( $users, $ips ) ], $reverse, 18 - ]; - yield "User IDs, $name" => [ $stage, [ 'ucuserids' => $users ], $reverse, 9 ]; - yield "Users by prefix, $name" => [ $stage, [ 'ucuserprefix' => __CLASS__ ], $reverse, 9 ]; - yield "IPs by prefix, $name" => [ $stage, [ 'ucuserprefix' => '192.168.2.' ], $reverse, 9 ]; - } + foreach ( [ false, true ] as $reverse ) { + $name = ( $reverse ? ', reverse' : '' ); + yield "Named users, $name" => [ [ 'ucuser' => $users ], $reverse, 9 ]; + yield "Named users including a no-edit user, $name" => [ + [ 'ucuser' => $users2 ], $reverse, 6 + ]; + yield "IP users, $name" => [ [ 'ucuser' => $ips ], $reverse, 9 ]; + yield "All users, $name" => [ + [ 'ucuser' => array_merge( $users, $ips ) ], $reverse, 18 + ]; + yield "User IDs, $name" => [ [ 'ucuserids' => $users ], $reverse, 9 ]; + yield "Users by prefix, $name" => [ [ 'ucuserprefix' => __CLASS__ ], $reverse, 9 ]; + yield "IPs by prefix, $name" => [ [ 'ucuserprefix' => '192.168.2.' ], $reverse, 9 ]; } } - /** - * @dataProvider provideInterwikiUser - * @param int $stage SCHEMA_COMPAT constants for $wgActorTableSchemaMigrationStage - */ - public function testInterwikiUser( $stage ) { - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', $stage ); - + public function testInterwikiUser() { $params = [ 'action' => 'query', 'list' => 'usercontribs', @@ -174,13 +147,4 @@ class ApiQueryUserContribsTest extends ApiTestCase { $this->assertSame( $sorted, $ids, "IDs are sorted" ); } - public static function provideInterwikiUser() { - return [ - 'old' => [ SCHEMA_COMPAT_OLD ], - 'read old' => [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD ], - 'read new' => [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW ], - 'new' => [ SCHEMA_COMPAT_NEW ], - ]; - } - } diff --git a/tests/phpunit/includes/logging/DatabaseLogEntryTest.php b/tests/phpunit/includes/logging/DatabaseLogEntryTest.php index b183cde1d2..a7040e0255 100644 --- a/tests/phpunit/includes/logging/DatabaseLogEntryTest.php +++ b/tests/phpunit/includes/logging/DatabaseLogEntryTest.php @@ -29,18 +29,12 @@ class DatabaseLogEntryTest extends MediaWikiTestCase { * @param array $selectFields * @param string[]|null $row * @param string[]|null $expectedFields - * @param int $actorMigration */ public function testNewFromId( $id, array $selectFields, array $row = null, - array $expectedFields = null, - $actorMigration + array $expectedFields = null ) { - $this->setMwGlobals( [ - 'wgActorTableSchemaMigrationStage' => $actorMigration, - ] ); - $row = $row ? (object)$row : null; $db = $this->getMock( IDatabase::class ); $db->expects( self::once() ) @@ -67,36 +61,6 @@ class DatabaseLogEntryTest extends MediaWikiTestCase { } public function provideNewFromId() { - $oldTables = [ - 'tables' => [ - 'logging', 'user', - 'comment_log_comment' => 'comment', - ], - 'fields' => [ - 'log_id', - 'log_type', - 'log_action', - 'log_timestamp', - 'log_namespace', - 'log_title', - 'log_params', - 'log_deleted', - 'user_id', - 'user_name', - 'user_editcount', - 'log_comment_text' => 'comment_log_comment.comment_text', - 'log_comment_data' => 'comment_log_comment.comment_data', - 'log_comment_cid' => 'comment_log_comment.comment_id', - 'log_user' => 'log_user', - 'log_user_text' => 'log_user_text', - 'log_actor' => 'NULL', - ], - 'options' => [], - 'join_conds' => [ - 'user' => [ 'LEFT JOIN', 'user_id=log_user' ], - 'comment_log_comment' => [ 'JOIN', 'comment_log_comment.comment_id = log_comment_id' ], - ], - ]; $newTables = [ 'tables' => [ 'logging', @@ -133,22 +97,20 @@ class DatabaseLogEntryTest extends MediaWikiTestCase { return [ [ 0, - $oldTables + [ 'conds' => [ 'log_id' => 0 ] ], - null, + $newTables + [ 'conds' => [ 'log_id' => 0 ] ], null, - SCHEMA_COMPAT_OLD, + null ], [ 123, - $oldTables + [ 'conds' => [ 'log_id' => 123 ] ], + $newTables + [ 'conds' => [ 'log_id' => 123 ] ], [ 'log_id' => 123, 'log_type' => 'foobarize', 'log_comment_text' => 'test!', 'log_comment_data' => null, ], - [ 'type' => 'foobarize', 'comment' => 'test!' ], - SCHEMA_COMPAT_OLD, + [ 'type' => 'foobarize', 'comment' => 'test!' ] ], [ 567, @@ -159,8 +121,7 @@ class DatabaseLogEntryTest extends MediaWikiTestCase { 'log_comment_text' => 'test!', 'log_comment_data' => null, ], - [ 'type' => 'foobarize', 'comment' => 'test!' ], - SCHEMA_COMPAT_NEW, + [ 'type' => 'foobarize', 'comment' => 'test!' ] ], ]; } diff --git a/tests/phpunit/includes/page/PageArchiveTestBase.php b/tests/phpunit/includes/page/PageArchiveTestBase.php index bcbc1eda19..90b118c40e 100644 --- a/tests/phpunit/includes/page/PageArchiveTestBase.php +++ b/tests/phpunit/includes/page/PageArchiveTestBase.php @@ -84,7 +84,6 @@ abstract class PageArchiveTestBase extends MediaWikiTestCase { $this->tablesUsed += $this->getMcrTablesToReset(); $this->setMwGlobals( [ - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW, 'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(), 'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(), ] ); diff --git a/tests/phpunit/includes/specialpage/ChangesListSpecialPageTest.php b/tests/phpunit/includes/specialpage/ChangesListSpecialPageTest.php index 68433c61ed..ff3e714dca 100644 --- a/tests/phpunit/includes/specialpage/ChangesListSpecialPageTest.php +++ b/tests/phpunit/includes/specialpage/ChangesListSpecialPageTest.php @@ -224,8 +224,6 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase } public function testRcHidemyselfFilter() { - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW ); - $user = $this->getTestUser()->getUser(); $user->getActorId( wfGetDB( DB_MASTER ) ); $this->assertConditions( @@ -253,41 +251,7 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase ); } - public function testRcHidemyselfFilter_old() { - $this->setMwGlobals( - 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD - ); - - $user = $this->getTestUser()->getUser(); - $user->getActorId( wfGetDB( DB_MASTER ) ); - $this->assertConditions( - [ # expected - "NOT((rc_user = '{$user->getId()}'))", - ], - [ - 'hidemyself' => 1, - ], - "rc conditions: hidemyself=1 (logged in)", - $user - ); - - $user = User::newFromName( '10.11.12.13', false ); - $id = $user->getActorId( wfGetDB( DB_MASTER ) ); - $this->assertConditions( - [ # expected - "NOT((rc_user_text = '10.11.12.13'))", - ], - [ - 'hidemyself' => 1, - ], - "rc conditions: hidemyself=1 (anon)", - $user - ); - } - public function testRcHidebyothersFilter() { - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW ); - $user = $this->getTestUser()->getUser(); $user->getActorId( wfGetDB( DB_MASTER ) ); $this->assertConditions( @@ -315,38 +279,6 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase ); } - public function testRcHidebyothersFilter_old() { - $this->setMwGlobals( - 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD - ); - - $user = $this->getTestUser()->getUser(); - $user->getActorId( wfGetDB( DB_MASTER ) ); - $this->assertConditions( - [ # expected - "(rc_user_text = '{$user->getName()}')", - ], - [ - 'hidebyothers' => 1, - ], - "rc conditions: hidebyothers=1 (logged in)", - $user - ); - - $user = User::newFromName( '10.11.12.13', false ); - $id = $user->getActorId( wfGetDB( DB_MASTER ) ); - $this->assertConditions( - [ # expected - "(rc_user_text = '10.11.12.13')", - ], - [ - 'hidebyothers' => 1, - ], - "rc conditions: hidebyothers=1 (anon)", - $user - ); - } - public function testRcHidepageedits() { $this->assertConditions( [ # expected @@ -550,8 +482,6 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase } public function testFilterUserExpLevelAllExperienceLevels() { - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW ); - $this->assertConditions( [ # expected @@ -564,26 +494,7 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase ); } - public function testFilterUserExpLevelAllExperienceLevels_old() { - $this->setMwGlobals( - 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD - ); - - $this->assertConditions( - [ - # expected - 'rc_user != 0', - ], - [ - 'userExpLevel' => 'newcomer;learner;experienced', - ], - "rc conditions: userExpLevel=newcomer;learner;experienced" - ); - } - - public function testFilterUserExpLevelRegistrered() { - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW ); - + public function testFilterUserExpLevelRegistered() { $this->assertConditions( [ # expected @@ -596,26 +507,7 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase ); } - public function testFilterUserExpLevelRegistrered_old() { - $this->setMwGlobals( - 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD - ); - - $this->assertConditions( - [ - # expected - 'rc_user != 0', - ], - [ - 'userExpLevel' => 'registered', - ], - "rc conditions: userExpLevel=registered" - ); - } - - public function testFilterUserExpLevelUnregistrered() { - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW ); - + public function testFilterUserExpLevelUnregistered() { $this->assertConditions( [ # expected @@ -628,26 +520,7 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase ); } - public function testFilterUserExpLevelUnregistrered_old() { - $this->setMwGlobals( - 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD - ); - - $this->assertConditions( - [ - # expected - 'rc_user = 0', - ], - [ - 'userExpLevel' => 'unregistered', - ], - "rc conditions: userExpLevel=unregistered" - ); - } - - public function testFilterUserExpLevelRegistreredOrLearner() { - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW ); - + public function testFilterUserExpLevelRegisteredOrLearner() { $this->assertConditions( [ # expected @@ -660,26 +533,7 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase ); } - public function testFilterUserExpLevelRegistreredOrLearner_old() { - $this->setMwGlobals( - 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD - ); - - $this->assertConditions( - [ - # expected - 'rc_user != 0', - ], - [ - 'userExpLevel' => 'registered;learner', - ], - "rc conditions: userExpLevel=registered;learner" - ); - } - - public function testFilterUserExpLevelUnregistreredOrExperienced() { - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW ); - + public function testFilterUserExpLevelUnregisteredOrExperienced() { $conds = $this->buildQuery( [ 'userExpLevel' => 'unregistered;experienced' ] ); $this->assertRegExp( @@ -690,21 +544,6 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase ); } - public function testFilterUserExpLevelUnregistreredOrExperienced_old() { - $this->setMwGlobals( - 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD - ); - - $conds = $this->buildQuery( [ 'userExpLevel' => 'unregistered;experienced' ] ); - - $this->assertRegExp( - '/\(rc_user = 0\) OR ' - . '\(\(user_editcount >= 500\) AND \(user_registration <= \'[^\']+\'\)\)/', - reset( $conds ), - "rc conditions: userExpLevel=unregistered;experienced" - ); - } - public function testFilterUserExpLevel() { $now = time(); $this->setMwGlobals( [ diff --git a/tests/phpunit/includes/user/UserTest.php b/tests/phpunit/includes/user/UserTest.php index 2d87c78cdc..3005ae9b2e 100644 --- a/tests/phpunit/includes/user/UserTest.php +++ b/tests/phpunit/includes/user/UserTest.php @@ -31,7 +31,6 @@ class UserTest extends MediaWikiTestCase { $this->setMwGlobals( [ 'wgGroupPermissions' => [], 'wgRevokePermissions' => [], - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW, ] ); $this->setUpPermissionGlobals(); @@ -1075,83 +1074,6 @@ class UserTest extends MediaWikiTestCase { 'User::newFromActorId works for an anonymous user' ); } - /** - * Actor tests with SCHEMA_COMPAT_READ_OLD - * - * The only thing different from testActorId() is the behavior if the actor - * row doesn't exist in the DB, since with SCHEMA_COMPAT_READ_NEW that - * situation can't happen. But we copy all the other tests too just for good measure. - * - * @covers User::newFromActorId - */ - public function testActorId_old() { - $this->setMwGlobals( [ - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, - ] ); - - $domain = MediaWikiServices::getInstance()->getDBLoadBalancer()->getLocalDomainID(); - $this->hideDeprecated( 'User::selectFields' ); - - // Newly-created user has an actor ID - $user = User::createNew( 'UserTestActorIdOld1' ); - $id = $user->getId(); - $this->assertTrue( $user->getActorId() > 0, 'User::createNew sets an actor ID' ); - - $user = User::newFromName( 'UserTestActorIdOld2' ); - $user->addToDatabase(); - $this->assertTrue( $user->getActorId() > 0, 'User::addToDatabase sets an actor ID' ); - - $user = User::newFromName( 'UserTestActorIdOld1' ); - $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be retrieved for user loaded by name' ); - - $user = User::newFromId( $id ); - $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be retrieved for user loaded by ID' ); - - $user2 = User::newFromActorId( $user->getActorId() ); - $this->assertEquals( $user->getId(), $user2->getId(), - 'User::newFromActorId works for an existing user' ); - - $row = $this->db->selectRow( 'user', User::selectFields(), [ 'user_id' => $id ], __METHOD__ ); - $user = User::newFromRow( $row ); - $this->assertTrue( $user->getActorId() > 0, - 'Actor ID can be retrieved for user loaded with User::selectFields()' ); - - $this->db->delete( 'actor', [ 'actor_user' => $id ], __METHOD__ ); - User::purge( $domain, $id ); - // Because WANObjectCache->delete() stupidly doesn't delete from the process cache. - - MediaWikiServices::getInstance()->getMainWANObjectCache()->clearProcessCache(); - - $user = User::newFromId( $id ); - $this->assertFalse( $user->getActorId() > 0, 'No Actor ID by default if none in database' ); - $this->assertTrue( $user->getActorId( $this->db ) > 0, 'Actor ID can be created if none in db' ); - - $user->setName( 'UserTestActorIdOld4-renamed' ); - $user->saveSettings(); - $this->assertEquals( - $user->getName(), - $this->db->selectField( - 'actor', 'actor_name', [ 'actor_id' => $user->getActorId() ], __METHOD__ - ), - 'User::saveSettings updates actor table for name change' - ); - - // For sanity - $ip = '192.168.12.34'; - $this->db->delete( 'actor', [ 'actor_name' => $ip ], __METHOD__ ); - - $user = User::newFromName( $ip, false ); - $this->assertFalse( $user->getActorId() > 0, 'Anonymous user has no actor ID by default' ); - $this->assertTrue( $user->getActorId( $this->db ) > 0, - 'Actor ID can be created for an anonymous user' ); - - $user = User::newFromName( $ip, false ); - $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be loaded for an anonymous user' ); - $user2 = User::newFromActorId( $user->getActorId() ); - $this->assertEquals( $user->getName(), $user2->getName(), - 'User::newFromActorId works for an anonymous user' ); - } - /** * @covers User::newFromAnyId */ diff --git a/tests/phpunit/maintenance/deleteAutoPatrolLogsTest.php b/tests/phpunit/maintenance/deleteAutoPatrolLogsTest.php index b8d13838e9..cd0d7a5205 100644 --- a/tests/phpunit/maintenance/deleteAutoPatrolLogsTest.php +++ b/tests/phpunit/maintenance/deleteAutoPatrolLogsTest.php @@ -37,7 +37,7 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { $logs[] = [ 'log_type' => 'patrol', 'log_action' => 'patrol', - 'log_user' => 7251, + 'log_actor' => 7251, 'log_params' => '', 'log_timestamp' => $dbw->timestamp( '20041223210426' ), 'log_namespace' => NS_MAIN, @@ -49,7 +49,7 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { $logs[] = [ 'log_type' => 'patrol', 'log_action' => 'autopatrol', - 'log_user' => 7252, + 'log_actor' => 7252, 'log_params' => '', 'log_timestamp' => $dbw->timestamp( '20051223210426' ), 'log_namespace' => NS_MAIN, @@ -61,7 +61,7 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { $logs[] = [ 'log_type' => 'block', 'log_action' => 'block', - 'log_user' => 7253, + 'log_actor' => 7253, 'log_params' => '', 'log_timestamp' => $dbw->timestamp( '20061223210426' ), 'log_namespace' => NS_MAIN, @@ -73,7 +73,7 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { $logs[] = [ 'log_type' => 'patrol', 'log_action' => 'patrol', - 'log_user' => 7253, + 'log_actor' => 7253, 'log_params' => 'nanana', 'log_timestamp' => $dbw->timestamp( '20061223210426' ), 'log_namespace' => NS_MAIN, @@ -85,7 +85,7 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { $logs[] = [ 'log_type' => 'patrol', 'log_action' => 'autopatrol', - 'log_user' => 7254, + 'log_actor' => 7254, 'log_params' => '', 'log_timestamp' => $dbw->timestamp( '20071223210426' ), 'log_namespace' => NS_MAIN, @@ -97,7 +97,7 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { $logs[] = [ 'log_type' => 'patrol', 'log_action' => 'patrol', - 'log_user' => 7255, + 'log_actor' => 7255, 'log_params' => serialize( [ '6::auto' => true ] ), 'log_timestamp' => $dbw->timestamp( '20081223210426' ), 'log_namespace' => NS_MAIN, @@ -109,7 +109,7 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { $logs[] = [ 'log_type' => 'patrol', 'log_action' => 'patrol', - 'log_user' => 7256, + 'log_actor' => 7256, 'log_params' => serialize( [ '6::auto' => false ] ), 'log_timestamp' => $dbw->timestamp( '20091223210426' ), 'log_namespace' => NS_MAIN, @@ -121,7 +121,7 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { $logs[] = [ 'log_type' => 'patrol', 'log_action' => 'patrol', - 'log_user' => 7257, + 'log_actor' => 7257, 'log_params' => "9227851\n0\n1", 'log_timestamp' => $dbw->timestamp( '20081223210426' ), 'log_namespace' => NS_MAIN, @@ -133,7 +133,7 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { $logs[] = [ 'log_type' => 'patrol', 'log_action' => 'patrol', - 'log_user' => 7258, + 'log_actor' => 7258, 'log_params' => "9227851\n0\n0", 'log_timestamp' => $dbw->timestamp( '20091223210426' ), 'log_namespace' => NS_MAIN, @@ -149,47 +149,47 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { (object)[ 'log_type' => 'patrol', 'log_action' => 'patrol', - 'log_user' => '7251', + 'log_actor' => '7251', ], (object)[ 'log_type' => 'patrol', 'log_action' => 'autopatrol', - 'log_user' => '7252', + 'log_actor' => '7252', ], (object)[ 'log_type' => 'block', 'log_action' => 'block', - 'log_user' => '7253', + 'log_actor' => '7253', ], (object)[ 'log_type' => 'patrol', 'log_action' => 'patrol', - 'log_user' => '7253', + 'log_actor' => '7253', ], (object)[ 'log_type' => 'patrol', 'log_action' => 'autopatrol', - 'log_user' => '7254', + 'log_actor' => '7254', ], (object)[ 'log_type' => 'patrol', 'log_action' => 'patrol', - 'log_user' => '7255', + 'log_actor' => '7255', ], (object)[ 'log_type' => 'patrol', 'log_action' => 'patrol', - 'log_user' => '7256', + 'log_actor' => '7256', ], (object)[ 'log_type' => 'patrol', 'log_action' => 'patrol', - 'log_user' => '7257', + 'log_actor' => '7257', ], (object)[ 'log_type' => 'patrol', 'log_action' => 'patrol', - 'log_user' => '7258', + 'log_actor' => '7258', ], ]; @@ -266,7 +266,7 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { $remainingLogs = wfGetDB( DB_REPLICA )->select( [ 'logging' ], - [ 'log_type', 'log_action', 'log_user' ], + [ 'log_type', 'log_action', 'log_actor' ], [], __METHOD__, [ 'ORDER BY' => 'log_id' ] @@ -288,7 +288,7 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { $remainingLogs = wfGetDB( DB_REPLICA )->select( [ 'logging' ], - [ 'log_type', 'log_action', 'log_user' ], + [ 'log_type', 'log_action', 'log_actor' ], [], __METHOD__, [ 'ORDER BY' => 'log_id' ] @@ -297,12 +297,12 @@ class DeleteAutoPatrolLogsTest extends MaintenanceBaseTestCase { $deleted = [ 'log_type' => 'patrol', 'log_action' => 'autopatrol', - 'log_user' => '7254', + 'log_actor' => '7254', ]; $notDeleted = [ 'log_type' => 'patrol', 'log_action' => 'autopatrol', - 'log_user' => '7252', + 'log_actor' => '7252', ]; $remainingLogs = array_map(