X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FActorMigration.php;h=0c33eb9bfcfbfb0e82999f52330416c3fc2f58a4;hb=f2b01310d90060ba2ccba3e6d36b67e942bff978;hp=161c7a923b47c04e80aac5fcf97c1924bdf44e50;hpb=a2c8c2969420a0f150c03f76e3a0bf9028fcda43;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/ActorMigration.php b/includes/ActorMigration.php index 161c7a923b..0c33eb9bfc 100644 --- a/includes/ActorMigration.php +++ b/includes/ActorMigration.php @@ -34,6 +34,12 @@ use Wikimedia\Rdbms\IDatabase; */ class ActorMigration { + /** + * Constant for extensions to feature-test whether $wgActorTableSchemaMigrationStage + * expects MIGRATION_* or SCHEMA_COMPAT_* + */ + const MIGRATION_STAGE_SCHEMA_COMPAT = 1; + /** * Define fields that use temporary tables for transitional purposes * @var array Keys are '$key', values are arrays with four fields: @@ -74,11 +80,27 @@ class ActorMigration { /** @var array|null Cache for `self::getJoin()` */ private $joinCache = null; - /** @var int One of the MIGRATION_* constants */ + /** @var int Combination of SCHEMA_COMPAT_* constants */ private $stage; /** @private */ public function __construct( $stage ) { + if ( ( $stage & SCHEMA_COMPAT_WRITE_BOTH ) === 0 ) { + throw new InvalidArgumentException( '$stage must include a write mode' ); + } + if ( ( $stage & SCHEMA_COMPAT_READ_BOTH ) === 0 ) { + throw new InvalidArgumentException( '$stage must include a read mode' ); + } + if ( ( $stage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_BOTH ) { + throw new InvalidArgumentException( 'Cannot read both schemas' ); + } + if ( ( $stage & SCHEMA_COMPAT_READ_OLD ) && !( $stage & SCHEMA_COMPAT_WRITE_OLD ) ) { + throw new InvalidArgumentException( 'Cannot read the old schema without also writing it' ); + } + if ( ( $stage & SCHEMA_COMPAT_READ_NEW ) && !( $stage & SCHEMA_COMPAT_WRITE_NEW ) ) { + throw new InvalidArgumentException( 'Cannot read the new schema without also writing it' ); + } + $this->stage = $stage; } @@ -96,7 +118,7 @@ class ActorMigration { * @return string */ public function isAnon( $field ) { - return $this->stage === MIGRATION_NEW ? "$field IS NULL" : "$field = 0"; + return ( $this->stage & SCHEMA_COMPAT_READ_NEW ) ? "$field IS NULL" : "$field = 0"; } /** @@ -105,7 +127,7 @@ class ActorMigration { * @return string */ public function isNotAnon( $field ) { - return $this->stage === MIGRATION_NEW ? "$field IS NOT NULL" : "$field != 0"; + return ( $this->stage & SCHEMA_COMPAT_READ_NEW ) ? "$field IS NOT NULL" : "$field != 0"; } /** @@ -140,18 +162,16 @@ class ActorMigration { list( $text, $actor ) = self::getFieldNames( $key ); - if ( $this->stage === MIGRATION_OLD ) { + if ( $this->stage & SCHEMA_COMPAT_READ_OLD ) { $fields[$key] = $key; $fields[$text] = $text; $fields[$actor] = 'NULL'; } else { - $join = $this->stage === MIGRATION_NEW ? 'JOIN' : 'LEFT JOIN'; - if ( isset( self::$tempTables[$key] ) ) { $t = self::$tempTables[$key]; $alias = "temp_$key"; $tables[$alias] = $t['table']; - $joins[$alias] = [ $join, "{$alias}.{$t['pk']} = {$t['joinPK']}" ]; + $joins[$alias] = [ 'JOIN', "{$alias}.{$t['pk']} = {$t['joinPK']}" ]; $joinField = "{$alias}.{$t['field']}"; } else { $joinField = $actor; @@ -159,15 +179,10 @@ class ActorMigration { $alias = "actor_$key"; $tables[$alias] = 'actor'; - $joins[$alias] = [ $join, "{$alias}.actor_id = {$joinField}" ]; + $joins[$alias] = [ 'JOIN', "{$alias}.actor_id = {$joinField}" ]; - if ( $this->stage === MIGRATION_NEW ) { - $fields[$key] = "{$alias}.actor_user"; - $fields[$text] = "{$alias}.actor_name"; - } else { - $fields[$key] = "COALESCE( {$alias}.actor_user, $key )"; - $fields[$text] = "COALESCE( {$alias}.actor_name, $text )"; - } + $fields[$key] = "{$alias}.actor_user"; + $fields[$text] = "{$alias}.actor_name"; $fields[$actor] = $joinField; } @@ -197,11 +212,11 @@ class ActorMigration { list( $text, $actor ) = self::getFieldNames( $key ); $ret = []; - if ( $this->stage <= MIGRATION_WRITE_BOTH ) { + if ( $this->stage & SCHEMA_COMPAT_WRITE_OLD ) { $ret[$key] = $user->getId(); $ret[$text] = $user->getName(); } - if ( $this->stage >= MIGRATION_WRITE_BOTH ) { + if ( $this->stage & SCHEMA_COMPAT_WRITE_NEW ) { // We need to be able to assign an actor ID if none exists if ( !$user instanceof User && !$user->getActorId() ) { $user = User::newFromAnyId( $user->getId(), $user->getName(), null ); @@ -220,7 +235,7 @@ class ActorMigration { * @param UserIdentity $user User to set in the update * @return array with two values: * - array to merge into `$values` to `IDatabase->update()` or `$a` to `IDatabase->insert()` - * - callback to call with the the primary key for the main table insert + * - callback to call with the primary key for the main table insert * and extra fields needed for the temp table. */ public function getInsertValuesWithTempTable( IDatabase $dbw, $key, UserIdentity $user ) { @@ -233,11 +248,11 @@ class ActorMigration { list( $text, $actor ) = self::getFieldNames( $key ); $ret = []; $callback = null; - if ( $this->stage <= MIGRATION_WRITE_BOTH ) { + if ( $this->stage & SCHEMA_COMPAT_WRITE_OLD ) { $ret[$key] = $user->getId(); $ret[$text] = $user->getName(); } - if ( $this->stage >= MIGRATION_WRITE_BOTH ) { + if ( $this->stage & SCHEMA_COMPAT_WRITE_NEW ) { // We need to be able to assign an actor ID if none exists if ( !$user instanceof User && !$user->getActorId() ) { $user = User::newFromAnyId( $user->getId(), $user->getName(), null ); @@ -301,6 +316,8 @@ class ActorMigration { * - orconds: (array[]) array of alternatives in case a union of multiple * queries would be more efficient than a query with OR. May have keys * 'actor', 'userid', 'username'. + * Since 1.32, this is guaranteed to contain just one alternative if + * $users contains a single user. * - joins: (array) to include in the `$join_conds` to `IDatabase->select()` * All tables and joins are aliased, so `+` is safe to use. */ @@ -332,44 +349,26 @@ class ActorMigration { list( $text, $actor ) = self::getFieldNames( $key ); // Combine data into conditions to be ORed together - $actorNotEmpty = []; - if ( $this->stage === MIGRATION_OLD ) { - $actors = []; - $actorEmpty = []; - } elseif ( isset( self::$tempTables[$key] ) ) { - $t = self::$tempTables[$key]; - $alias = "temp_$key"; - $tables[$alias] = $t['table']; - $joins[$alias] = [ - $this->stage === MIGRATION_NEW ? 'JOIN' : 'LEFT JOIN', - "{$alias}.{$t['pk']} = {$t['joinPK']}" - ]; - $joinField = "{$alias}.{$t['field']}"; - $actorEmpty = [ $joinField => null ]; - if ( $this->stage !== MIGRATION_NEW ) { - // Otherwise the resulting test can evaluate to NULL, and - // NOT(NULL) is NULL rather than true. - $actorNotEmpty = [ "$joinField IS NOT NULL" ]; + if ( $this->stage & SCHEMA_COMPAT_READ_NEW ) { + if ( $actors ) { + if ( isset( self::$tempTables[$key] ) ) { + $t = self::$tempTables[$key]; + $alias = "temp_$key"; + $tables[$alias] = $t['table']; + $joins[$alias] = [ 'JOIN', "{$alias}.{$t['pk']} = {$t['joinPK']}" ]; + $joinField = "{$alias}.{$t['field']}"; + } else { + $joinField = $actor; + } + $conds['actor'] = $db->makeList( [ $joinField => $actors ], IDatabase::LIST_AND ); } } else { - $joinField = $actor; - $actorEmpty = [ $joinField => 0 ]; - } - - if ( $actors ) { - $conds['actor'] = $db->makeList( - $actorNotEmpty + [ $joinField => $actors ], IDatabase::LIST_AND - ); - } - if ( $this->stage < MIGRATION_NEW && $ids ) { - $conds['userid'] = $db->makeList( - $actorEmpty + [ $key => $ids ], IDatabase::LIST_AND - ); - } - if ( $this->stage < MIGRATION_NEW && $names ) { - $conds['username'] = $db->makeList( - $actorEmpty + [ $text => $names ], IDatabase::LIST_AND - ); + if ( $ids ) { + $conds['userid'] = $db->makeList( [ $key => $ids ], IDatabase::LIST_AND ); + } + if ( $names ) { + $conds['username'] = $db->makeList( [ $text => $names ], IDatabase::LIST_AND ); + } } return [