33 public function run() {
36 $table = $this->params[
'table'];
37 $column = $this->params[
'column'];
38 $oldname = $this->params[
'oldname'];
39 $newname = $this->params[
'newname'];
40 $count = $this->params[
'count'];
41 if ( isset( $this->params[
'userID'] ) ) {
42 $userID = $this->params[
'userID'];
43 $uidColumn = $this->params[
'uidColumn'];
48 if ( isset( $this->params[
'timestampColumn'] ) ) {
49 $timestampColumn = $this->params[
'timestampColumn'];
50 $minTimestamp = $this->params[
'minTimestamp'];
51 $maxTimestamp = $this->params[
'maxTimestamp'];
53 $timestampColumn =
null;
57 $uniqueKey = isset( $this->params[
'uniqueKey'] ) ? $this->params[
'uniqueKey'] :
null;
58 $keyId = isset( $this->params[
'keyId'] ) ? $this->params[
'keyId'] :
null;
59 $logId = isset( $this->params[
'logId'] ) ? $this->params[
'logId'] :
null;
63 # Block until the transaction that inserted this job commits.
64 # The atomic section is for sanity as FOR UPDATE does not lock in auto-commit mode
65 # per http://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html.
66 $dbw->startAtomic( __METHOD__ );
67 $committed = $dbw->selectField(
'logging',
69 [
'log_id' => $logId ],
73 $dbw->endAtomic( __METHOD__ );
74 # If the transaction inserting this job was rolled back, detect that
75 if ( $committed ===
false ) {
76 throw new LogicException(
'Cannot run job if the account rename failed.' );
80 # Flush any state snapshot data (and release the lock above)
81 $dbw->commit( __METHOD__,
'flush' );
83 # Conditions like "*_user_text = 'x'
84 $conds = [ $column => $oldname ];
85 # If user ID given, add that to condition to avoid rename collisions
86 if ( $userID !==
null ) {
87 $conds[$uidColumn] = $userID;
89 # Bound by timestamp if given
90 if ( $timestampColumn !==
null ) {
91 $conds[] =
"$timestampColumn >= " . $dbw->addQuotes( $minTimestamp );
92 $conds[] =
"$timestampColumn <= " . $dbw->addQuotes( $maxTimestamp );
93 # Bound by unique key if given (B/C)
94 } elseif ( $uniqueKey !==
null && $keyId !==
null ) {
95 $conds[$uniqueKey] = $keyId;
97 throw new InvalidArgumentException(
'Expected ID batch or time range' );
101 # Actually update the rows for this job...
102 if ( $uniqueKey !==
null ) {
103 # Select the rows to update by PRIMARY KEY
104 $ids = $dbw->selectFieldValues( $table, $uniqueKey, $conds, __METHOD__ );
105 # Update these rows by PRIMARY KEY to avoid slave lag
107 $dbw->commit( __METHOD__,
'flush' );
110 $dbw->update( $table,
111 [ $column => $newname ],
112 [ $column => $oldname, $uniqueKey =>
$batch ],
115 $affectedCount += $dbw->affectedRows();
118 # Update the chunk of rows directly
119 $dbw->update( $table,
120 [ $column => $newname ],
124 $affectedCount += $dbw->affectedRows();
127 # Special case: revisions may be deleted while renaming...
128 if ( $affectedCount < $count && $table ===
'revision' && $timestampColumn !==
null ) {
129 # If some revisions were not renamed, they may have been deleted.
130 # Do a pass on the archive table to get these straglers...
131 $ids = $dbw->selectFieldValues(
135 'ar_user_text' => $oldname,
136 'ar_user' => $userID,
139 "ar_timestamp >= '$minTimestamp'",
140 "ar_timestamp <= '$maxTimestamp'"
145 $dbw->commit( __METHOD__,
'flush' );
150 [
'ar_user_text' => $newname ],
151 [
'ar_user_text' => $oldname,
'ar_id' =>
$batch ],
156 # Special case: revisions may be restored while renaming...
157 if ( $affectedCount < $count && $table ===
'archive' && $timestampColumn !==
null ) {
158 # If some revisions were not renamed, they may have been restored.
159 # Do a pass on the revision table to get these straglers...
160 $ids = $dbw->selectFieldValues(
164 'rev_user_text' => $oldname,
165 'rev_user' => $userID,
168 "rev_timestamp >= '$minTimestamp'",
169 "rev_timestamp <= '$maxTimestamp'"
174 $dbw->commit( __METHOD__,
'flush' );
179 [
'rev_user_text' => $newname ],
180 [
'rev_user_text' => $oldname,
'rev_id' =>
$batch ],