* $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
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.
* 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 ===
* …
* 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;
*/
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
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
* @phan-return array{tables:string[],fields:string[],joins:array}
*/
public function getJoin( $key ) {
+ self::checkDeprecation( $key );
+
if ( !isset( $this->joinCache[$key] ) ) {
$tables = [];
$fields = [];
* @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" );
}
* 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] ) ) {
* 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 = [];
*/
$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.
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.
return [
'ActorMigration' => function ( MediaWikiServices $services ) : ActorMigration {
- return new ActorMigration(
- $services->getMainConfig()->get( 'ActorTableSchemaMigrationStage' )
- );
+ return new ActorMigration( SCHEMA_COMPAT_NEW );
},
'BadFileLookup' => function ( MediaWikiServices $services ) : BadFileLookup {
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();
$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();
* @return void
*/
protected function run( ApiPageSet $resultPageSet = null ) {
- global $wgActorTableSchemaMigrationStage;
-
$db = $this->getDB();
$params = $this->extractRequestParams( false );
$services = MediaWikiServices::getInstance();
$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';
}
public function execute() {
- global $wgActorTableSchemaMigrationStage;
-
$params = $this->extractRequestParams();
$activeUserDays = $this->getConfig()->get( 'ActiveUserDays' );
] ] );
// 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 ),
}
public function execute() {
- global $wgActorTableSchemaMigrationStage;
-
$db = $this->getDB();
$params = $this->extractRequestParams();
$this->requireMaxOneParameter( $params, 'group', 'excludegroup', 'rights', 'excluderights' );
$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'] );
}
protected function run( ApiPageSet $resultPageSet = null ) {
- global $wgActorTableSchemaMigrationStage;
-
$params = $this->extractRequestParams( false );
$revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
$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';
$fld_patrolled = false, $fld_tags = false, $fld_size = false, $fld_sizediff = false;
public function execute() {
- global $wgActorTableSchemaMigrationStage;
-
// Parse some parameters
$this->params = $this->extractRequestParams();
// 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'] );
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;
$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 {
$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();
* @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'] );
* @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;
}
use ActorMigration;
use AutoCommitUpdate;
-use BadMethodCallException;
use CommentStore;
use DeferredUpdates;
use Hooks;
}
}
- /**
- * 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.
* @param string $caller The calling method
*/
public function doQuery( array $userIds, $options = [], $caller = '' ) {
- global $wgActorTableSchemaMigrationStage;
-
$usersToCheck = [];
$usersToQuery = [];
// 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 ) !== '' ) {
$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;
}
}
}
}
- /**
- * 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.
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.
}
}
- /**
- * 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.
$oldver, $comment, $pageText, $props = false, $timestamp = false, $user = null, $tags = [],
$createNullRevision = true, $revert = false
) {
- global $wgActorTableSchemaMigrationStage;
-
if ( is_null( $user ) ) {
global $wgUser;
$user = $wgUser;
'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
}
protected function doDBInserts() {
- global $wgActorTableSchemaMigrationStage;
-
$now = time();
$dbw = $this->file->repo->getMasterDB();
'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 = [];
$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 );
}
}
}
- /**
- * 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.
* @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" .
}
}
}
+
+ /**
+ * 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 );
+ }
}
[ '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' ],
[ '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' ],
[ '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' ],
[ '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' ],
// 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' ],
// 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' ],
[ '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' ],
[ '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' ],
];
}
[ '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' ],
[ '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 ''" ],
[ '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)' ],
[ '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)' ],
[ '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 ],
[ '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' ],
[ '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' ],
];
}
// 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' ],
// 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' ],
// 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' ],
[ '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' ],
];
}
* @throws MWException
*/
public function insert( IDatabase $dbw = null ) {
- global $wgActorTableSchemaMigrationStage;
-
$dbw = $dbw ?: wfGetDB( DB_MASTER );
if ( $this->timestamp === null ) {
$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 ) {
*/
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();
$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 ) {
* @since 1.23 Added 'perItemStatus' param
*/
public function setVisibility( array $params ) {
- global $wgActorTableSchemaMigrationStage;
-
$status = Status::newGood();
$bitPars = $params['value'];
$missing = array_flip( $this->ids );
$this->clearFileOps();
$idsForLog = [];
- $authorIds = $authorIPs = $authorActors = [];
+ $authorActors = [];
if ( $perItemStatus ) {
$status->itemStatuses = [];
$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.
// 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,
[
* 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
$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'],
* @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
}
$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__
);
$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__
);
$dbw->update(
'recentchanges',
[ self::buildSetBitDeletedField( 'rc_deleted', $op, $delUser, $dbw ) ],
- [ 'rc_user_text' => $name ],
+ [ 'rc_actor' => $actorId ],
__METHOD__
);
$dbw->update(
'oldimage',
[ self::buildSetBitDeletedField( 'oi_deleted', $op, $delUser, $dbw ) ],
- [ 'oi_user_text' => $name ],
+ [ 'oi_actor' => $actorId ],
__METHOD__
);
$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',
}
public function execute( $par ) {
- global $wgActorTableSchemaMigrationStage;
-
$this->setHeaders();
$this->outputHeader();
$out = $this->getOutput();
$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
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',
'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' ),
}
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'
]
];
* 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.
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 ) {
$this->loadFromId( $flags );
break;
case 'actor':
+ case 'name':
// Make sure this thread sees its own changes
$lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
if ( $lb->hasOrMadeRecentMasterChanges() ) {
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':
* @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';
* @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.
$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';
* 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;
* 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' );
}
$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 !== '' ) {
* @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;
}
* @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' );
}
$dbw = wfGetDB( DB_MASTER );
$dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) use ( $newTouched ) {
- global $wgActorTableSchemaMigrationStage;
-
$dbw->update( 'user',
[ /* SET */
'user_name' => $this->mName,
);
}
- 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;
* @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();
}
/**
* - 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',
'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;
}
--- /dev/null
+--
+-- 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;
}
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 );
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;
);
wfWaitForSlaves();
- $dbw = $this->getDB( DB_MASTER );
$actorIdSubquery = $this->makeActorIdSubquery( $dbw, $userField, $nameField );
$next = '1=1';
$countUpdated = 0;
* @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
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';
);
wfWaitForSlaves();
- $dbw = $this->getDB( DB_MASTER );
$actorIdSubquery = $this->makeActorIdSubquery( $dbw, $userField, $nameField );
$next = [];
$countUpdated = 0;
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,
);
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);
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,
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 ''
);
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,
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 ''
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,
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);
* @license GPL-2.0-or-later
*/
-use Wikimedia\Rdbms\IDatabase;
-
require_once __DIR__ . '/Maintenance.php';
/**
* @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__ );
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" );
}
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
*
}
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
$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 {
$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__ );
--- /dev/null
+--
+-- 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;
--- /dev/null
+--
+-- 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;
--- /dev/null
+--
+-- 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;
--- /dev/null
+--
+-- 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;
--- /dev/null
+--
+-- 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;
--- /dev/null
+--
+-- 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;
--- /dev/null
+--
+-- 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;
-- 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,
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
-- 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,
-- 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 '',
) /*$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);
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,
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
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
-- 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));
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,
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)
-- 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.
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
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).
-- 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)
* @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',
'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' );
}
<?php
use MediaWiki\User\UserIdentity;
-use MediaWiki\MediaWikiServices;
+use Wikimedia\ScopedCallback;
use Wikimedia\TestingAccessWrapper;
/**
*/
class ActorMigrationTest extends MediaWikiLangTestCase {
+ protected $resetActorMigration = null;
+ protected static $amId = 0;
+
protected $tablesUsed = [
- 'revision',
- 'revision_actor_temp',
- 'ipblocks',
- 'recentchanges',
'actor',
];
+ protected function setUp() {
+ parent::setUp();
+
+ $w = TestingAccessWrapper::newFromClass( ActorMigration::class );
+ $data = [
+ 'tempTables' => $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
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' ],
],
],
],
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' => [],
],
],
* @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',
];
$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 );
"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 ) {
}
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 ],
];
}
* @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() );
}
/**
*/
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 ) );
}
* @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, [] );
}
* @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 );
];
}
+ 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()
+ );
+ }
+ }
+
}
--- /dev/null
+-- 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
+);
];
}
- 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",
];
}
yield 'MCR, comment, actor' => [
[
'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
],
[
'tables' => [
'wgContentHandlerUseDB' => true,
'wgMultiContentRevisionSchemaMigrationStage'
=> SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
],
[
'tables' => [
'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' ],
],
]
];
[
'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' ],
],
]
];
[
'wgContentHandlerUseDB' => true,
'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
],
[ 'page', 'user' ],
[
],
'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' ],
],
]
];
'wgContentHandlerUseDB' => true,
'wgMultiContentRevisionSchemaMigrationStage'
=> SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
],
[ 'page', 'user' ],
[
$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' => [
'wgContentHandlerUseDB' => true,
'wgMultiContentRevisionSchemaMigrationStage'
=> SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
],
[ 'page', 'user' ],
[
$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' => [
'wgContentHandlerUseDB' => true,
'wgMultiContentRevisionSchemaMigrationStage'
=> SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
],
[],
[
'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' ],
],
]
];
'wgContentHandlerUseDB' => true,
'wgMultiContentRevisionSchemaMigrationStage'
=> SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
],
[ 'page', 'user' ],
[
'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,
],
[],
[
'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' ],
],
]
];
[
'wgContentHandlerUseDB' => true,
'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
],
[ 'page', 'user' ],
[
'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' ],
],
]
];
[
'wgContentHandlerUseDB' => false,
'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
],
[],
[
'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' ],
],
],
];
[
'wgContentHandlerUseDB' => false,
'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
],
[ 'page' ],
[
'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' => [
'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' ],
],
],
];
[
'wgContentHandlerUseDB' => false,
'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
],
[ 'user' ],
[
'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' ],
],
],
];
[
'wgContentHandlerUseDB' => false,
'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
],
[ 'text' ],
[
'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' => [
'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' ],
],
],
];
[
'wgContentHandlerUseDB' => false,
'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
],
[ 'text', 'page', 'user' ],
[
'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' => [
'user' => [
'LEFT JOIN',
[
- 'rev_user != 0',
- 'user_id = rev_user',
+ 'actor_rev_user.actor_user != 0',
+ 'user_id = actor_rev_user.actor_user',
],
],
'text' => [
'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' ],
],
],
];
];
}
- 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
$this->setMwGlobals( [
'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
] );
}
* @covers \MediaWiki\Revision\RevisionStore::getKnownCurrentRevision
*/
public function testGetKnownCurrentRevision_userNameChange() {
- global $wgActorTableSchemaMigrationStage;
-
$cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
$this->setService( 'MainWANObjectCache', $cache );
$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() );
* @covers \MediaWiki\Revision\RevisionStore::newRevisionFromRow
*/
public function testNewRevisionFromRow_userNameChange() {
- global $wgActorTableSchemaMigrationStage;
-
$page = $this->getTestPage();
$text = __METHOD__;
/** @var Revision $rev */
$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
$this->setMwGlobals( [
'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
] );
if ( !$this->testPage ) {
* @covers Revision::loadFromTitle
*/
public function testLoadFromTitle() {
- $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
$title = $this->getMockTitle();
$conditions = [
*/
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 ),
/**
* @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'] ) );
}
$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',
$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 ],
- ];
- }
-
}
* @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() )
}
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',
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,
'log_comment_text' => 'test!',
'log_comment_data' => null,
],
- [ 'type' => 'foobarize', 'comment' => 'test!' ],
- SCHEMA_COMPAT_NEW,
+ [ 'type' => 'foobarize', 'comment' => 'test!' ]
],
];
}
$this->tablesUsed += $this->getMcrTablesToReset();
$this->setMwGlobals( [
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
] );
}
public function testRcHidemyselfFilter() {
- $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
-
$user = $this->getTestUser()->getUser();
$user->getActorId( wfGetDB( DB_MASTER ) );
$this->assertConditions(
);
}
- 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(
);
}
- 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
}
public function testFilterUserExpLevelAllExperienceLevels() {
- $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
-
$this->assertConditions(
[
# expected
);
}
- 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 );
-
$this->assertConditions(
[
# expected
);
}
- 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 );
-
$this->assertConditions(
[
# expected
);
}
- 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 );
-
$this->assertConditions(
[
# expected
);
}
- 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 );
-
$conds = $this->buildQuery( [ 'userExpLevel' => 'unregistered;experienced' ] );
$this->assertRegExp(
);
}
- 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( [
$this->setMwGlobals( [
'wgGroupPermissions' => [],
'wgRevokePermissions' => [],
- 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
] );
$this->setUpPermissionGlobals();
'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
*/
$logs[] = [
'log_type' => 'patrol',
'log_action' => 'patrol',
- 'log_user' => 7251,
+ 'log_actor' => 7251,
'log_params' => '',
'log_timestamp' => $dbw->timestamp( '20041223210426' ),
'log_namespace' => NS_MAIN,
$logs[] = [
'log_type' => 'patrol',
'log_action' => 'autopatrol',
- 'log_user' => 7252,
+ 'log_actor' => 7252,
'log_params' => '',
'log_timestamp' => $dbw->timestamp( '20051223210426' ),
'log_namespace' => NS_MAIN,
$logs[] = [
'log_type' => 'block',
'log_action' => 'block',
- 'log_user' => 7253,
+ 'log_actor' => 7253,
'log_params' => '',
'log_timestamp' => $dbw->timestamp( '20061223210426' ),
'log_namespace' => NS_MAIN,
$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,
$logs[] = [
'log_type' => 'patrol',
'log_action' => 'autopatrol',
- 'log_user' => 7254,
+ 'log_actor' => 7254,
'log_params' => '',
'log_timestamp' => $dbw->timestamp( '20071223210426' ),
'log_namespace' => NS_MAIN,
$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,
$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,
$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,
$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,
(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',
],
];
$remainingLogs = wfGetDB( DB_REPLICA )->select(
[ 'logging' ],
- [ 'log_type', 'log_action', 'log_user' ],
+ [ 'log_type', 'log_action', 'log_actor' ],
[],
__METHOD__,
[ 'ORDER BY' => 'log_id' ]
$remainingLogs = wfGetDB( DB_REPLICA )->select(
[ 'logging' ],
- [ 'log_type', 'log_action', 'log_user' ],
+ [ 'log_type', 'log_action', 'log_actor' ],
[],
__METHOD__,
[ 'ORDER BY' => 'log_id' ]
$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(