Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
84.00% covered (warning)
84.00%
42 / 50
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
AttachLatest
84.00% covered (warning)
84.00%
42 / 50
50.00% covered (danger)
50.00%
1 / 2
8.26
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 execute
82.22% covered (warning)
82.22%
37 / 45
0.00% covered (danger)
0.00%
0 / 1
7.28
1<?php
2/**
3 * Corrects wrong values in the `page_latest` field in the database.
4 *
5 * Copyright © 2005 Brooke Vibber <bvibber@wikimedia.org>
6 * https://www.mediawiki.org/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * http://www.gnu.org/copyleft/gpl.html
22 *
23 * @file
24 * @ingroup Maintenance
25 */
26
27use MediaWiki\Maintenance\Maintenance;
28use MediaWiki\Title\Title;
29use Wikimedia\Rdbms\IDBAccessObject;
30
31// @codeCoverageIgnoreStart
32require_once __DIR__ . '/Maintenance.php';
33// @codeCoverageIgnoreEnd
34
35/**
36 * Maintenance script to correct wrong values in the `page_latest` field
37 * in the database.
38 *
39 * @ingroup Maintenance
40 */
41class AttachLatest extends Maintenance {
42    public function __construct() {
43        parent::__construct();
44        $this->addOption( "fix", "Actually fix the entries, will dry run otherwise" );
45        $this->addOption( "regenerate-all",
46            "Regenerate the page_latest field for all records in table page" );
47        $this->addDescription( 'Fix page_latest entries in the page table' );
48    }
49
50    public function execute() {
51        $this->output( "Looking for pages with page_latest set to 0...\n" );
52        $dbw = $this->getPrimaryDB();
53        $conds = [ 'page_latest' => 0 ];
54        if ( $this->hasOption( 'regenerate-all' ) ) {
55            $conds = [];
56        }
57        $result = $dbw->newSelectQueryBuilder()
58            ->select( [ 'page_id', 'page_namespace', 'page_title' ] )
59            ->from( 'page' )
60            ->where( $conds )
61            ->caller( __METHOD__ )
62            ->fetchResultSet();
63
64        $services = $this->getServiceContainer();
65        $dbDomain = $services->getDBLoadBalancerFactory()->getLocalDomainID();
66        $wikiPageFactory = $services->getWikiPageFactory();
67        $revisionLookup = $services->getRevisionLookup();
68
69        $n = 0;
70        foreach ( $result as $row ) {
71            $pageId = intval( $row->page_id );
72            $title = Title::makeTitle( $row->page_namespace, $row->page_title );
73            $name = $title->getPrefixedText();
74            $latestTime = $dbw->newSelectQueryBuilder()
75                ->select( 'MAX(rev_timestamp)' )
76                ->from( 'revision' )
77                ->where( [ 'rev_page' => $pageId ] )
78                ->caller( __METHOD__ )
79                ->fetchField();
80            if ( !$latestTime ) {
81                $this->output( "$dbDomain $pageId [[$name]] can't find latest rev time?!\n" );
82                continue;
83            }
84
85            $revRecord = $revisionLookup->getRevisionByTimestamp( $title, $latestTime, IDBAccessObject::READ_LATEST );
86            if ( $revRecord === null ) {
87                $this->output(
88                    "$dbDomain $pageId [[$name]] latest time $latestTime, can't find revision id\n"
89                );
90                continue;
91            }
92
93            $id = $revRecord->getId();
94            $this->output( "$dbDomain $pageId [[$name]] latest time $latestTime, rev id $id\n" );
95            if ( $this->hasOption( 'fix' ) ) {
96                $page = $wikiPageFactory->newFromTitle( $title );
97                $page->updateRevisionOn( $dbw, $revRecord );
98                $this->waitForReplication();
99            }
100            $n++;
101        }
102        $this->output( "Done! Processed $n pages.\n" );
103        if ( !$this->hasOption( 'fix' ) ) {
104            $this->output( "This was a dry run; rerun with --fix to update page_latest.\n" );
105        }
106    }
107}
108
109// @codeCoverageIgnoreStart
110$maintClass = AttachLatest::class;
111require_once RUN_MAINTENANCE_IF_MAIN;
112// @codeCoverageIgnoreEnd