26 require_once __DIR__ .
'/Maintenance.php';
36 parent::__construct();
37 $this->
addDescription(
'Migrates actors from pre-1.31 columns to the \'actor\' table' );
50 "...cannot update while \$wgActorTableSchemaMigrationStage < MIGRATION_WRITE_NEW\n"
55 $this->
output(
"Creating actor entries for all registered users\n" );
58 $max = $dbw->selectField(
'user',
'MAX(user_id)',
'', __METHOD__ );
60 while ( $end < $max ) {
62 $end = min( $start + $this->mBatchSize, $max );
63 $this->
output(
"... $start - $end\n" );
67 [
'actor_user' =>
'user_id',
'actor_name' =>
'user_name' ],
68 [
"user_id >= $start",
"user_id <= $end" ],
71 [
'ORDER BY' => [
'user_id' ] ]
73 $count += $dbw->affectedRows();
76 $this->
output(
"Completed actor creation, added $count new actor(s)\n" );
80 'revision',
'rev_id', [
'revactor_timestamp' =>
'rev_timestamp',
'revactor_page' =>
'rev_page' ],
81 'rev_user',
'rev_user_text',
'revactor_rev',
'revactor_actor'
83 $errors += $this->
migrate(
'archive',
'ar_id',
'ar_user',
'ar_user_text',
'ar_actor' );
84 $errors += $this->
migrate(
'ipblocks',
'ipb_id',
'ipb_by',
'ipb_by_text',
'ipb_by_actor' );
85 $errors += $this->
migrate(
'image',
'img_name',
'img_user',
'img_user_text',
'img_actor' );
87 'oldimage', [
'oi_name',
'oi_timestamp' ],
'oi_user',
'oi_user_text',
'oi_actor'
89 $errors += $this->
migrate(
'filearchive',
'fa_id',
'fa_user',
'fa_user_text',
'fa_actor' );
90 $errors += $this->
migrate(
'recentchanges',
'rc_id',
'rc_user',
'rc_user_text',
'rc_actor' );
91 $errors += $this->
migrate(
'logging',
'log_id',
'log_user',
'log_user_text',
'log_actor' );
108 for ( $i =
count( $primaryKey ) - 1; $i >= 0; $i-- ) {
109 $field = $primaryKey[$i];
110 $display[] = $field .
'=' . $row->$field;
111 $value = $dbw->addQuotes( $row->$field );
112 if ( $next ===
'' ) {
113 $next =
"$field > $value";
115 $next =
"$field > $value OR $field = $value AND ($next)";
118 $display = implode(
' ', array_reverse( $display ) );
119 return [ $next, $display ];
138 foreach (
$rows as $index => $row ) {
139 $keep[$index] =
true;
140 if ( $row->actor_id ===
null ) {
144 $name = $row->$nameField;
146 if ( !isset( $complainedAboutUsers[
$name] ) ) {
147 $complainedAboutUsers[
$name] =
true;
149 "User name \"$name\" is usable, cannot create an anonymous actor for it."
150 .
" Run maintenance/cleanupUsersWithNoId.php to fix this situation.\n"
153 unset( $keep[$index] );
156 $needActors[
$name] = 0;
165 array_map(
function ( $v ) {
169 }, array_keys( $needActors ) ),
176 [
'actor_id',
'actor_name' ],
177 [
'actor_name' => array_keys( $needActors ) ],
180 foreach (
$res as $row ) {
181 $needActors[$row->actor_name] = $row->actor_id;
184 if ( $row->actor_id ===
null ) {
185 $row->actor_id = $needActors[$row->$nameField];
206 protected function migrate( $table, $primaryKey, $userField, $nameField, $actorField ) {
207 $complainedAboutUsers = [];
209 $primaryKey = (
array)$primaryKey;
210 $pkFilter = array_flip( $primaryKey );
212 "Beginning migration of $table.$userField and $table.$nameField to $table.$actorField\n"
225 array_merge( $primaryKey, [ $userField, $nameField,
'actor_id' ] ),
232 'ORDER BY' => $primaryKey,
233 'LIMIT' => $this->mBatchSize,
238 "$userField != 0 AND actor_user = $userField OR "
239 .
"($userField = 0 OR $userField IS NULL) AND actor_name = $nameField"
243 if ( !
$res->numRows() ) {
249 $lastRow = end(
$rows );
251 $dbw, $nameField,
$rows, $complainedAboutUsers, $countErrors
256 if ( !$row->actor_id ) {
259 "Could not make actor for row with $display "
260 .
"$userField={$row->$userField} $nameField={$row->$nameField}\n"
268 $actorField => $row->actor_id,
271 array_intersect_key( (
array)$row, $pkFilter ) + [
276 $countUpdated += $dbw->affectedRows();
279 list( $next, $display ) = $this->
makeNextCond( $dbw, $primaryKey, $lastRow );
280 $this->
output(
"... $display\n" );
285 "Completed migration, updated $countUpdated row(s) with $countActors new actor(s), "
286 .
"$countErrors error(s)\n"
308 $table, $primaryKey, $extra, $userField, $nameField, $newPrimaryKey, $actorField
310 $complainedAboutUsers = [];
312 $newTable = $table .
'_actor_temp';
314 "Beginning migration of $table.$userField and $table.$nameField to $newTable.$actorField\n"
326 [ $table, $newTable,
'actor' ],
327 [ $primaryKey, $userField, $nameField,
'actor_id' ] + $extra,
328 [ $newPrimaryKey =>
null ] + $next,
331 'ORDER BY' => $primaryKey,
332 'LIMIT' => $this->mBatchSize,
335 $newTable => [
'LEFT JOIN',
"{$primaryKey}={$newPrimaryKey}" ],
338 "$userField != 0 AND actor_user = $userField OR "
339 .
"($userField = 0 OR $userField IS NULL) AND actor_name = $nameField"
343 if ( !
$res->numRows() ) {
349 $lastRow = end(
$rows );
351 $dbw, $nameField,
$rows, $complainedAboutUsers, $countErrors
359 if ( !$row->actor_id ) {
362 "Could not make actor for row with $display "
363 .
"$userField={$row->$userField} $nameField={$row->$nameField}\n"
369 $newPrimaryKey => $row->$primaryKey,
370 $actorField => $row->actor_id,
372 foreach ( $extra
as $to => $from ) {
373 $ins[$to] = $row->$to;
376 $updates[] = $row->$primaryKey;
379 $dbw->insert( $newTable, $inserts, __METHOD__ );
380 $dbw->update( $table, [ $nameField =>
'' ], [ $primaryKey => $updates ], __METHOD__ );
381 $countUpdated += $dbw->affectedRows();
386 list( $n, $display ) = $this->
makeNextCond( $dbw, [ $primaryKey ], $lastRow );
388 $this->
output(
"... $display\n" );
392 "Completed migration, updated $countUpdated row(s) with $countActors new actor(s), "
393 .
"$countErrors error(s)\n"
403 $complainedAboutUsers = [];
405 $primaryKey = [
'ls_field',
'ls_value' ];
406 $pkFilter = array_flip( $primaryKey );
407 $this->
output(
"Beginning migration of log_search\n" );
419 [
'log_search',
'actor' ],
420 [
'ls_field',
'ls_value',
'actor_id' ],
422 'ls_field' =>
'target_author_id',
428 'ORDER BY' => [
'ls_value' ],
429 'LIMIT' => $this->mBatchSize,
431 [
'actor' => [
'LEFT JOIN',
'ls_value = ' . $dbw->buildStringCast(
'actor_user' ) ] ]
433 if ( !
$res->numRows() ) {
439 foreach (
$res as $row ) {
441 if ( !$row->actor_id ) {
443 $this->
error(
"No actor for row with $display\n" );
450 'ls_field' =>
'target_author_actor',
451 'ls_value' => $row->actor_id,
454 'ls_field' => $row->ls_field,
455 'ls_value' => $row->ls_value,
460 $countUpdated += $dbw->affectedRows();
461 $del[] = $row->ls_value;
465 'log_search', [
'ls_field' =>
'target_author_id',
'ls_value' => $del ], __METHOD__
467 $countUpdated += $dbw->affectedRows();
470 list( $next, $display ) = $this->
makeNextCond( $dbw, $primaryKey, $lastRow );
471 $this->
output(
"... $display\n" );
479 [
'log_search',
'actor' ],
480 [
'ls_field',
'ls_value',
'actor_id' ],
482 'ls_field' =>
'target_author_ip',
488 'ORDER BY' => [
'ls_value' ],
489 'LIMIT' => $this->mBatchSize,
491 [
'actor' => [
'LEFT JOIN',
'ls_value = actor_name' ] ]
493 if ( !
$res->numRows() ) {
499 $lastRow = end(
$rows );
501 $dbw,
'ls_value',
$rows, $complainedAboutUsers, $countErrors
507 if ( !$row->actor_id ) {
509 $this->
error(
"Could not make actor for row with $display\n" );
516 'ls_field' =>
'target_author_actor',
517 'ls_value' => $row->actor_id,
520 'ls_field' => $row->ls_field,
521 'ls_value' => $row->ls_value,
526 $countUpdated += $dbw->affectedRows();
527 $del[] = $row->ls_value;
531 'log_search', [
'ls_field' =>
'target_author_ip',
'ls_value' => $del ], __METHOD__
533 $countUpdated += $dbw->affectedRows();
536 list( $next, $display ) = $this->
makeNextCond( $dbw, $primaryKey, $lastRow );
537 $this->
output(
"... $display\n" );
542 "Completed migration, updated $countUpdated row(s) with $countActors new actor(s), "
543 .
"$countErrors error(s)\n"