MediaWiki master
fixAutoblockLogTitles.php
Go to the documentation of this file.
1<?php
2
4
8
9// @codeCoverageIgnoreStart
10require_once __DIR__ . '/Maintenance.php';
11// @codeCoverageIgnoreEnd
12
14
15 public function __construct() {
16 parent::__construct();
17 $this->addDescription(
18 'Finds and fixes unblock log rows in the logging table where the log_title starts with the ' .
19 'prefix "User:#". These rows are broken because the target is an autoblock and code expects the "#" ' .
20 'character to be the first character in the title (T373929).'
21 );
22 $this->setBatchSize( 200 );
23 }
24
25 protected function doDBUpdates() {
26 $this->output( "Fixing log entries with log_title starting with 'User:#'\n" );
27
28 $dbr = $this->getReplicaDB();
29 $dbw = $this->getPrimaryDB();
30
31 $totalRowsFixed = 0;
32 $lastProcessedLogId = 0;
33 do {
34 // Get a batch of "unblock" log entries from the logging table. The check for the log_title being broken
35 // needs to be performed in batches, as it is expensive when run on the whole logging table on large wikis.
36 $logIds = $dbr->newSelectQueryBuilder()
37 ->select( 'log_id' )
38 ->from( 'logging' )
39 ->where( [
40 'log_type' => 'block',
41 'log_action' => 'unblock',
42 $dbr->expr( 'log_id', '>', $lastProcessedLogId ),
43 ] )
44 ->limit( $this->getBatchSize() )
45 ->orderBy( 'log_id', SelectQueryBuilder::SORT_ASC )
46 ->caller( __METHOD__ )
47 ->fetchFieldValues();
48
49 if ( count( $logIds ) ) {
50 $lastId = end( $logIds );
51 $firstId = reset( $logIds );
52 $this->output( "...Processing unblock rows with IDs $firstId to $lastId\n" );
53
54 // Apply the LIKE query to find the rows with broken log_title values on the batch of log IDs.
55 // If any rows are found, then fix the log_title value.
56 $matchingRows = $dbr->newSelectQueryBuilder()
57 ->select( [ 'log_id', 'log_title' ] )
58 ->from( 'logging' )
59 ->where( $dbr->expr(
60 'log_title',
61 IExpression::LIKE,
62 new LikeValue( 'User:#', $dbr->anyString() )
63 ) )
64 ->andWhere( [ 'log_id' => $logIds ] )
65 ->limit( $this->getBatchSize() )
66 ->caller( __METHOD__ )
67 ->fetchResultSet();
68
69 foreach ( $matchingRows as $row ) {
70 $dbw->newUpdateQueryBuilder()
71 ->update( 'logging' )
72 ->set( [ 'log_title' => substr( $row->log_title, strlen( 'User:' ) ) ] )
73 ->where( [ 'log_id' => $row->log_id ] )
74 ->caller( __METHOD__ )
75 ->execute();
76 $totalRowsFixed += $dbw->affectedRows();
77 }
78
79 $this->waitForReplication();
80 }
81
82 $lastProcessedLogId = end( $logIds );
83 } while ( count( $logIds ) );
84
85 // Say we are done. Only output the total rows fixed if we found rows to fix, otherwise it may be confusing
86 // to see that no rows were fixed (and might imply that there are still rows to fix).
87 $this->output( "done." );
88 if ( $totalRowsFixed ) {
89 $this->output( " Fixed $totalRowsFixed rows." );
90 }
91 $this->output( "\n" );
92
93 return true;
94 }
95
96 protected function getUpdateKey() {
97 return __CLASS__;
98 }
99}
100
101// @codeCoverageIgnoreStart
102$maintClass = FixAutoblockLogTitles::class;
103require_once RUN_MAINTENANCE_IF_MAIN;
104// @codeCoverageIgnoreEnd
getUpdateKey()
Get the update key name to go in the update log table.
Class for scripts that perform database maintenance and want to log the update in updatelog so we can...
getBatchSize()
Returns batch size.
output( $out, $channel=null)
Throw some output to the user.
waitForReplication()
Wait for replica DB servers to catch up.
addDescription( $text)
Set the description text.
Content of like value.
Definition LikeValue.php:14
Build SELECT queries with a fluent interface.