31 'revision.rev_user_text',
32 'archive.ar_user_text',
33 'ipblocks.ipb_by_text',
34 'image.img_user_text',
35 'oldimage.oi_user_text',
36 'filearchive.fa_user_text',
37 'recentchanges.rc_user_text',
38 'logging.log_user_text',
45 public function run() {
49 $table = $this->params[
'table'];
50 $column = $this->params[
'column'];
54 if ( in_array(
"$table.$column", self::$actorMigratedColumns,
true ) ) {
60 "Ignoring job {$this->toString()}, column $table.$column actor migration stage = $stage\n"
68 if ( !$dbw->tableExists( $table, __METHOD__ ) ) {
70 "Ignoring job {$this->toString()}, table $table does not exist\n"
73 } elseif ( !$dbw->fieldExists( $table, $column, __METHOD__ ) ) {
75 "Ignoring job {$this->toString()}, column $table.$column does not exist\n"
80 $oldname = $this->params[
'oldname'];
81 $newname = $this->params[
'newname'];
82 $count = $this->params[
'count'];
83 if ( isset( $this->params[
'userID'] ) ) {
84 $userID = $this->params[
'userID'];
85 $uidColumn = $this->params[
'uidColumn'];
90 if ( isset( $this->params[
'timestampColumn'] ) ) {
91 $timestampColumn = $this->params[
'timestampColumn'];
92 $minTimestamp = $this->params[
'minTimestamp'];
93 $maxTimestamp = $this->params[
'maxTimestamp'];
95 $timestampColumn =
null;
99 $uniqueKey = isset( $this->params[
'uniqueKey'] ) ? $this->params[
'uniqueKey'] :
null;
100 $keyId = isset( $this->params[
'keyId'] ) ? $this->params[
'keyId'] :
null;
101 $logId = isset( $this->params[
'logId'] ) ? $this->params[
'logId'] :
null;
104 # Block until the transaction that inserted this job commits.
105 # The atomic section is for sanity as FOR UPDATE does not lock in auto-commit mode
106 # per http://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html.
107 $dbw->startAtomic( __METHOD__ );
108 $committed = $dbw->selectField(
'logging',
110 [
'log_id' => $logId ],
114 $dbw->endAtomic( __METHOD__ );
115 # If the transaction inserting this job was rolled back, detect that
116 if ( $committed ===
false ) {
117 throw new LogicException(
'Cannot run job if the account rename failed.' );
121 # Flush any state snapshot data (and release the lock above)
122 $dbw->commit( __METHOD__,
'flush' );
124 # Conditions like "*_user_text = 'x'
125 $conds = [ $column => $oldname ];
126 # If user ID given, add that to condition to avoid rename collisions
127 if ( $userID !==
null ) {
128 $conds[$uidColumn] = $userID;
130 # Bound by timestamp if given
131 if ( $timestampColumn !==
null ) {
132 $conds[] =
"$timestampColumn >= " . $dbw->addQuotes( $minTimestamp );
133 $conds[] =
"$timestampColumn <= " . $dbw->addQuotes( $maxTimestamp );
134 # Bound by unique key if given (B/C)
135 } elseif ( $uniqueKey !==
null && $keyId !==
null ) {
136 $conds[$uniqueKey] = $keyId;
138 throw new InvalidArgumentException(
'Expected ID batch or time range' );
142 # Actually update the rows for this job...
143 if ( $uniqueKey !==
null ) {
144 # Select the rows to update by PRIMARY KEY
145 $ids = $dbw->selectFieldValues( $table, $uniqueKey, $conds, __METHOD__ );
146 # Update these rows by PRIMARY KEY to avoid slave lag
148 $dbw->commit( __METHOD__,
'flush' );
151 $dbw->update( $table,
152 [ $column => $newname ],
153 [ $column => $oldname, $uniqueKey =>
$batch ],
156 $affectedCount += $dbw->affectedRows();
159 # Update the chunk of rows directly
160 $dbw->update( $table,
161 [ $column => $newname ],
165 $affectedCount += $dbw->affectedRows();
168 # Special case: revisions may be deleted while renaming...
169 if ( $affectedCount < $count && $table ===
'revision' && $timestampColumn !==
null ) {
170 # If some revisions were not renamed, they may have been deleted.
171 # Do a pass on the archive table to get these straglers...
172 $ids = $dbw->selectFieldValues(
176 'ar_user_text' => $oldname,
177 'ar_user' => $userID,
180 "ar_timestamp >= '$minTimestamp'",
181 "ar_timestamp <= '$maxTimestamp'"
186 $dbw->commit( __METHOD__,
'flush' );
191 [
'ar_user_text' => $newname ],
192 [
'ar_user_text' => $oldname,
'ar_id' =>
$batch ],
197 # Special case: revisions may be restored while renaming...
198 if ( $affectedCount < $count && $table ===
'archive' && $timestampColumn !==
null ) {
199 # If some revisions were not renamed, they may have been restored.
200 # Do a pass on the revision table to get these straglers...
201 $ids = $dbw->selectFieldValues(
205 'rev_user_text' => $oldname,
206 'rev_user' => $userID,
209 "rev_timestamp >= '$minTimestamp'",
210 "rev_timestamp <= '$maxTimestamp'"
215 $dbw->commit( __METHOD__,
'flush' );
220 [
'rev_user_text' => $newname ],
221 [
'rev_user_text' => $oldname,
'rev_id' =>
$batch ],