protected $key = null;
/**
- * @var int One of the MIGRATION_* constants
+ * @var int One of the MIGRATION_* constants, or an appropriate combination
+ * of SCHEMA_COMPAT_* constants.
* @todo Deprecate and remove once extensions seem unlikely to need to use
* it for migration anymore.
*/
/**
* @param Language $lang Language to use for comment truncation. Defaults
* to content language.
- * @param int $migrationStage One of the MIGRATION_* constants. Always
- * MIGRATION_NEW for MediaWiki core since 1.33.
+ * @param int $stage One of the MIGRATION_* constants, or an appropriate
+ * combination of SCHEMA_COMPAT_* constants. Always MIGRATION_NEW for
+ * MediaWiki core since 1.33.
*/
- public function __construct( Language $lang, $migrationStage ) {
- $this->stage = $migrationStage;
+ public function __construct( Language $lang, $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' );
+ }
+
+ $this->stage = $stage;
$this->lang = $lang;
}
public function getFields( $key = null ) {
$key = $this->getKey( $key );
$fields = [];
- if ( $this->stage === MIGRATION_OLD ) {
+ if ( ( $this->stage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_OLD ) {
$fields["{$key}_text"] = $key;
$fields["{$key}_data"] = 'NULL';
$fields["{$key}_cid"] = 'NULL';
- } else {
- if ( $this->stage < MIGRATION_NEW ) {
+ } else { // READ_BOTH or READ_NEW
+ if ( $this->stage & SCHEMA_COMPAT_READ_OLD ) {
$fields["{$key}_old"] = $key;
}
$tempTableStage = isset( $this->tempTables[$key] )
? $this->tempTables[$key]['stage'] : MIGRATION_NEW;
- if ( $tempTableStage < MIGRATION_NEW ) {
+ if ( $tempTableStage & SCHEMA_COMPAT_READ_OLD ) {
$fields["{$key}_pk"] = $this->tempTables[$key]['joinPK'];
}
- if ( $tempTableStage > MIGRATION_OLD ) {
+ if ( $tempTableStage & SCHEMA_COMPAT_READ_NEW ) {
$fields["{$key}_id"] = "{$key}_id";
}
}
$fields = [];
$joins = [];
- if ( $this->stage === MIGRATION_OLD ) {
+ if ( ( $this->stage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_OLD ) {
$fields["{$key}_text"] = $key;
$fields["{$key}_data"] = 'NULL';
$fields["{$key}_cid"] = 'NULL';
- } else {
- $join = $this->stage === MIGRATION_NEW ? 'JOIN' : 'LEFT JOIN';
+ } else { // READ_BOTH or READ_NEW
+ $join = ( $this->stage & SCHEMA_COMPAT_READ_OLD ) ? 'LEFT JOIN' : 'JOIN';
$tempTableStage = isset( $this->tempTables[$key] )
? $this->tempTables[$key]['stage'] : MIGRATION_NEW;
- if ( $tempTableStage < MIGRATION_NEW ) {
+ if ( $tempTableStage & SCHEMA_COMPAT_READ_OLD ) {
$t = $this->tempTables[$key];
$alias = "temp_$key";
$tables[$alias] = $t['table'];
$joins[$alias] = [ $join, "{$alias}.{$t['pk']} = {$t['joinPK']}" ];
- if ( $tempTableStage === MIGRATION_OLD ) {
+ if ( ( $tempTableStage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_OLD ) {
$joinField = "{$alias}.{$t['field']}";
} else {
// Nothing hits this code path for now, but will in the future when we set
$tables[$alias] = 'comment';
$joins[$alias] = [ $join, "{$alias}.comment_id = {$joinField}" ];
- if ( $this->stage === MIGRATION_NEW ) {
+ if ( ( $this->stage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_NEW ) {
$fields["{$key}_text"] = "{$alias}.comment_text";
} else {
$fields["{$key}_text"] = "COALESCE( {$alias}.comment_text, $key )";
$cid = $row["{$key}_cid"] ?? null;
$text = $row["{$key}_text"];
$data = $row["{$key}_data"];
- } elseif ( $this->stage === MIGRATION_OLD ) {
+ } elseif ( ( $this->stage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_OLD ) {
$cid = null;
if ( $fallback && isset( $row[$key] ) ) {
wfLogWarning( "Using deprecated fallback handling for comment $key" );
$text = $row[$key];
} else {
- wfLogWarning( "Missing {$key}_text and {$key}_data fields in row with MIGRATION_OLD" );
+ wfLogWarning(
+ "Missing {$key}_text and {$key}_data fields in row with MIGRATION_OLD / READ_OLD"
+ );
$text = '';
}
$data = null;
$tempTableStage = isset( $this->tempTables[$key] )
? $this->tempTables[$key]['stage'] : MIGRATION_NEW;
$row2 = null;
- if ( $tempTableStage > MIGRATION_OLD && array_key_exists( "{$key}_id", $row ) ) {
+ if ( ( $tempTableStage & SCHEMA_COMPAT_READ_NEW ) && array_key_exists( "{$key}_id", $row ) ) {
if ( !$db ) {
throw new InvalidArgumentException(
"\$row does not contain fields needed for comment $key and getComment(), but "
__METHOD__
);
}
- if ( !$row2 && $tempTableStage < MIGRATION_NEW && array_key_exists( "{$key}_pk", $row ) ) {
+ if ( !$row2 && ( $tempTableStage & SCHEMA_COMPAT_READ_OLD ) &&
+ array_key_exists( "{$key}_pk", $row )
+ ) {
if ( !$db ) {
throw new InvalidArgumentException(
"\$row does not contain fields needed for comment $key and getComment(), but "
$cid = $row2->comment_id;
$text = $row2->comment_text;
$data = $row2->comment_data;
- } elseif ( $this->stage < MIGRATION_NEW && array_key_exists( "{$key}_old", $row ) ) {
+ } elseif ( ( $this->stage & SCHEMA_COMPAT_READ_OLD ) &&
+ array_key_exists( "{$key}_old", $row )
+ ) {
$cid = null;
$text = $row["{$key}_old"];
$data = null;
# Truncate comment in a Unicode-sensitive manner
$comment->text = $this->lang->truncateForVisual( $comment->text, self::COMMENT_CHARACTER_LIMIT );
- if ( $this->stage > MIGRATION_OLD && !$comment->id ) {
+ if ( ( $this->stage & SCHEMA_COMPAT_WRITE_NEW ) && !$comment->id ) {
$dbData = $comment->data;
if ( !$comment->message instanceof RawMessage ) {
if ( $dbData === null ) {
$comment = $this->createComment( $dbw, $comment, $data );
- if ( $this->stage <= MIGRATION_WRITE_BOTH ) {
+ if ( $this->stage & SCHEMA_COMPAT_WRITE_OLD ) {
$fields[$key] = $this->lang->truncateForDatabase( $comment->text, 255 );
}
- if ( $this->stage >= MIGRATION_WRITE_BOTH ) {
+ if ( $this->stage & SCHEMA_COMPAT_WRITE_NEW ) {
$tempTableStage = isset( $this->tempTables[$key] )
? $this->tempTables[$key]['stage'] : MIGRATION_NEW;
- if ( $tempTableStage <= MIGRATION_WRITE_BOTH ) {
+ if ( $tempTableStage & SCHEMA_COMPAT_WRITE_OLD ) {
$t = $this->tempTables[$key];
$func = __METHOD__;
$commentId = $comment->id;
);
};
}
- if ( $tempTableStage >= MIGRATION_WRITE_BOTH ) {
+ if ( $tempTableStage & SCHEMA_COMPAT_WRITE_NEW ) {
$fields["{$key}_id"] = $comment->id;
}
}
$tempTableStage = isset( $this->tempTables[$key] )
? $this->tempTables[$key]['stage'] : MIGRATION_NEW;
- if ( $tempTableStage < MIGRATION_WRITE_NEW ) {
+ if ( $tempTableStage & SCHEMA_COMPAT_WRITE_OLD ) {
throw new InvalidArgumentException( "Must use insertWithTempTable() for $key" );
}
return $store;
}
+ /**
+ * @dataProvider provideConstructor
+ * @param int $stage
+ * @param string|null $exceptionMsg
+ */
+ public function testConstructor( $stage, $exceptionMsg ) {
+ try {
+ $m = new CommentStore( Language::factory( 'qqx' ), $stage );
+ if ( $exceptionMsg !== null ) {
+ $this->fail( 'Expected exception not thrown' );
+ }
+ $this->assertInstanceOf( CommentStore::class, $m );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame( $exceptionMsg, $ex->getMessage() );
+ }
+ }
+
+ public static function provideConstructor() {
+ return [
+ [ 0, '$stage must include a write mode' ],
+ [ SCHEMA_COMPAT_READ_OLD, '$stage must include a write mode' ],
+ [ SCHEMA_COMPAT_READ_NEW, '$stage must include a write mode' ],
+ [ SCHEMA_COMPAT_READ_BOTH, '$stage must include a write mode' ],
+
+ [ SCHEMA_COMPAT_WRITE_OLD, '$stage must include a read mode' ],
+ [ SCHEMA_COMPAT_WRITE_OLD | SCHEMA_COMPAT_READ_OLD, null ],
+ [ SCHEMA_COMPAT_WRITE_OLD | SCHEMA_COMPAT_READ_NEW, null ],
+ [ SCHEMA_COMPAT_WRITE_OLD | SCHEMA_COMPAT_READ_BOTH, null ],
+
+ [ SCHEMA_COMPAT_WRITE_NEW, '$stage must include a read mode' ],
+ [ SCHEMA_COMPAT_WRITE_NEW | SCHEMA_COMPAT_READ_OLD, null ],
+ [ SCHEMA_COMPAT_WRITE_NEW | SCHEMA_COMPAT_READ_NEW, null ],
+ [ SCHEMA_COMPAT_WRITE_NEW | SCHEMA_COMPAT_READ_BOTH, null ],
+
+ [ SCHEMA_COMPAT_WRITE_BOTH, '$stage must include a read mode' ],
+ [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, null ],
+ [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, null ],
+ [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_BOTH, null ],
+ ];
+ }
+
/**
* @dataProvider provideGetFields
* @param int $stage
MIGRATION_NEW, 'ipb_reason',
[ 'ipb_reason_id' => 'ipb_reason_id' ],
],
+ 'Simple table, write-both/read-old' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'ipb_reason',
+ [ 'ipb_reason_text' => 'ipb_reason', 'ipb_reason_data' => 'NULL', 'ipb_reason_cid' => 'NULL' ],
+ ],
+ 'Simple table, write-both/read-new' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'ipb_reason',
+ [ 'ipb_reason_id' => 'ipb_reason_id' ],
+ ],
'Revision, old' => [
MIGRATION_OLD, 'rev_comment',
MIGRATION_NEW, 'rev_comment',
[ 'rev_comment_pk' => 'rev_id' ],
],
+ 'Revision, write-both/read-old' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rev_comment',
+ [
+ 'rev_comment_text' => 'rev_comment',
+ 'rev_comment_data' => 'NULL',
+ 'rev_comment_cid' => 'NULL',
+ ],
+ ],
+ 'Revision, write-both/read-new' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rev_comment',
+ [ 'rev_comment_pk' => 'rev_id' ],
+ ],
'Image, old' => [
MIGRATION_OLD, 'img_description',
'img_description_id' => 'img_description_id'
],
],
+ 'Image, write-both/read-old' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'img_description',
+ [
+ 'img_description_text' => 'img_description',
+ 'img_description_data' => 'NULL',
+ 'img_description_cid' => 'NULL',
+ ],
+ ],
+ 'Image, write-both/read-new' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'img_description',
+ [
+ 'img_description_id' => 'img_description_id'
+ ],
+ ],
];
}
],
],
],
+ 'Simple table, write-both/read-old' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'ipb_reason', [
+ 'tables' => [],
+ 'fields' => [
+ 'ipb_reason_text' => 'ipb_reason',
+ 'ipb_reason_data' => 'NULL',
+ 'ipb_reason_cid' => 'NULL',
+ ],
+ 'joins' => [],
+ ],
+ ],
+ 'Simple table, write-both/read-new' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'ipb_reason', [
+ 'tables' => [ 'comment_ipb_reason' => 'comment' ],
+ 'fields' => [
+ 'ipb_reason_text' => 'comment_ipb_reason.comment_text',
+ 'ipb_reason_data' => 'comment_ipb_reason.comment_data',
+ 'ipb_reason_cid' => 'comment_ipb_reason.comment_id',
+ ],
+ 'joins' => [
+ 'comment_ipb_reason' => [ 'JOIN', 'comment_ipb_reason.comment_id = ipb_reason_id' ],
+ ],
+ ],
+ ],
'Revision, old' => [
MIGRATION_OLD, 'rev_comment', [
],
],
],
+ 'Revision, write-both/read-old' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rev_comment', [
+ 'tables' => [],
+ 'fields' => [
+ 'rev_comment_text' => 'rev_comment',
+ 'rev_comment_data' => 'NULL',
+ 'rev_comment_cid' => 'NULL',
+ ],
+ 'joins' => [],
+ ],
+ ],
+ 'Revision, write-both/read-new' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rev_comment', [
+ 'tables' => [
+ 'temp_rev_comment' => 'revision_comment_temp',
+ 'comment_rev_comment' => 'comment',
+ ],
+ 'fields' => [
+ 'rev_comment_text' => 'comment_rev_comment.comment_text',
+ 'rev_comment_data' => 'comment_rev_comment.comment_data',
+ 'rev_comment_cid' => 'comment_rev_comment.comment_id',
+ ],
+ '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' ],
+ ],
+ ],
+ ],
'Image, old' => [
MIGRATION_OLD, 'img_description', [
],
],
],
+ 'Image, write-both/read-old' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'img_description', [
+ 'tables' => [],
+ 'fields' => [
+ 'img_description_text' => 'img_description',
+ 'img_description_data' => 'NULL',
+ 'img_description_cid' => 'NULL',
+ ],
+ 'joins' => [],
+ ],
+ ],
+ 'Image, write-both/read-new' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'img_description', [
+ 'tables' => [
+ 'comment_img_description' => 'comment',
+ ],
+ 'fields' => [
+ 'img_description_text' => 'comment_img_description.comment_text',
+ 'img_description_data' => 'comment_img_description.comment_data',
+ 'img_description_cid' => 'comment_img_description.comment_id',
+ ],
+ 'joins' => [
+ 'comment_img_description' => [ 'JOIN',
+ 'comment_img_description.comment_id = img_description_id',
+ ],
+ ],
+ ],
+ ],
];
}
MIGRATION_NEW ],
MIGRATION_WRITE_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW, MIGRATION_NEW ],
MIGRATION_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW, MIGRATION_NEW ],
+
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD => [
+ MIGRATION_OLD, SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, MIGRATION_NEW
+ ],
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW => [
+ MIGRATION_OLD, SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, MIGRATION_NEW
+ ],
];
foreach ( $stages as $writeStage => $possibleReadStages ) {
$fields = $wstore->insert( $this->db, $key, $comment, $data );
}
- if ( $writeStage <= MIGRATION_WRITE_BOTH ) {
+ if ( $writeStage & SCHEMA_COMPAT_WRITE_OLD ) {
$this->assertSame( $expect['text'], $fields[$key], "old field, stage=$writeStage" );
} else {
$this->assertArrayNotHasKey( $key, $fields, "old field, stage=$writeStage" );
}
- if ( $writeStage >= MIGRATION_WRITE_BOTH && !$usesTemp ) {
+ if ( ( $writeStage & SCHEMA_COMPAT_WRITE_NEW ) && !$usesTemp ) {
$this->assertArrayHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
} else {
$this->assertArrayNotHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
$queryInfo['joins']
);
+ $expectForCombination = (
+ ( $writeStage & SCHEMA_COMPAT_WRITE_BOTH ) === SCHEMA_COMPAT_WRITE_OLD ||
+ ( $readStage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_OLD
+ ) ? $expectOld : $expect;
$this->assertComment(
- $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
+ $expectForCombination,
$rstore->getCommentLegacy( $this->db, $key, $fieldRow ),
"w=$writeStage, r=$readStage, from getFields()"
);
$this->assertComment(
- $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
+ $expectForCombination,
$rstore->getComment( $key, $joinRow ),
"w=$writeStage, r=$readStage, from getJoin()"
);
MIGRATION_NEW ],
MIGRATION_WRITE_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW, MIGRATION_NEW ],
MIGRATION_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW, MIGRATION_NEW ],
+
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD => [
+ MIGRATION_OLD, SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, MIGRATION_NEW
+ ],
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW => [
+ MIGRATION_OLD, SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, MIGRATION_NEW
+ ],
];
foreach ( $stages as $writeStage => $possibleReadStages ) {
$fields = $wstore->insert( $this->db, $comment, $data );
}
- if ( $writeStage <= MIGRATION_WRITE_BOTH ) {
+ if ( $writeStage & SCHEMA_COMPAT_WRITE_OLD ) {
$this->assertSame( $expect['text'], $fields[$key], "old field, stage=$writeStage" );
} else {
$this->assertArrayNotHasKey( $key, $fields, "old field, stage=$writeStage" );
}
- if ( $writeStage >= MIGRATION_WRITE_BOTH && !$usesTemp ) {
+ if ( ( $writeStage & SCHEMA_COMPAT_WRITE_NEW ) && !$usesTemp ) {
$this->assertArrayHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
} else {
$this->assertArrayNotHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
$queryInfo['joins']
);
+ $expectForCombination = (
+ ( $writeStage & SCHEMA_COMPAT_WRITE_BOTH ) === SCHEMA_COMPAT_WRITE_OLD ||
+ ( $readStage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_OLD
+ ) ? $expectOld : $expect;
$this->assertComment(
- $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
+ $expectForCombination,
$rstore->getCommentLegacy( $this->db, $fieldRow ),
"w=$writeStage, r=$readStage, from getFields()"
);
$this->assertComment(
- $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
+ $expectForCombination,
$rstore->getComment( $joinRow ),
"w=$writeStage, r=$readStage, from getJoin()"
);
'MIGRATION_WRITE_BOTH' => [ MIGRATION_WRITE_BOTH ],
'MIGRATION_WRITE_NEW' => [ MIGRATION_WRITE_NEW ],
'MIGRATION_NEW' => [ MIGRATION_NEW ],
+
+ 'SCHEMA_COMPAT write-both/read-old' => [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD ],
+ 'SCHEMA_COMPAT write-both/read-new' => [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW ],
];
}