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 * @license GPL-2.0-or-later
9 * @file
10 * @ingroup Maintenance
11 */
12
13use MediaWiki\Maintenance\Maintenance;
14use MediaWiki\Title\Title;
15use Wikimedia\Rdbms\IDBAccessObject;
16
17// @codeCoverageIgnoreStart
18require_once __DIR__ . '/Maintenance.php';
19// @codeCoverageIgnoreEnd
20
21/**
22 * Maintenance script to correct wrong values in the `page_latest` field
23 * in the database.
24 *
25 * @ingroup Maintenance
26 */
27class AttachLatest extends Maintenance {
28    public function __construct() {
29        parent::__construct();
30        $this->addOption( "fix", "Actually fix the entries, will dry run otherwise" );
31        $this->addOption( "regenerate-all",
32            "Regenerate the page_latest field for all records in table page" );
33        $this->addDescription( 'Fix page_latest entries in the page table' );
34    }
35
36    public function execute() {
37        $this->output( "Looking for pages with page_latest set to 0...\n" );
38        $dbw = $this->getPrimaryDB();
39        $conds = [ 'page_latest' => 0 ];
40        if ( $this->hasOption( 'regenerate-all' ) ) {
41            $conds = [];
42        }
43        $result = $dbw->newSelectQueryBuilder()
44            ->select( [ 'page_id', 'page_namespace', 'page_title' ] )
45            ->from( 'page' )
46            ->where( $conds )
47            ->caller( __METHOD__ )
48            ->fetchResultSet();
49
50        $services = $this->getServiceContainer();
51        $dbDomain = $services->getDBLoadBalancerFactory()->getLocalDomainID();
52        $wikiPageFactory = $services->getWikiPageFactory();
53        $revisionLookup = $services->getRevisionLookup();
54
55        $n = 0;
56        foreach ( $result as $row ) {
57            $pageId = intval( $row->page_id );
58            $title = Title::makeTitle( $row->page_namespace, $row->page_title );
59            $name = $title->getPrefixedText();
60            $latestTime = $dbw->newSelectQueryBuilder()
61                ->select( 'MAX(rev_timestamp)' )
62                ->from( 'revision' )
63                ->where( [ 'rev_page' => $pageId ] )
64                ->caller( __METHOD__ )
65                ->fetchField();
66            if ( !$latestTime ) {
67                $this->output( "$dbDomain $pageId [[$name]] can't find latest rev time?!\n" );
68                continue;
69            }
70
71            $revRecord = $revisionLookup->getRevisionByTimestamp( $title, $latestTime, IDBAccessObject::READ_LATEST );
72            if ( $revRecord === null ) {
73                $this->output(
74                    "$dbDomain $pageId [[$name]] latest time $latestTime, can't find revision id\n"
75                );
76                continue;
77            }
78
79            $id = $revRecord->getId();
80            $this->output( "$dbDomain $pageId [[$name]] latest time $latestTime, rev id $id\n" );
81            if ( $this->hasOption( 'fix' ) ) {
82                $page = $wikiPageFactory->newFromTitle( $title );
83                $page->updateRevisionOn( $dbw, $revRecord );
84                $this->waitForReplication();
85            }
86            $n++;
87        }
88        $this->output( "Done! Processed $n pages.\n" );
89        if ( !$this->hasOption( 'fix' ) ) {
90            $this->output( "This was a dry run; rerun with --fix to update page_latest.\n" );
91        }
92    }
93}
94
95// @codeCoverageIgnoreStart
96$maintClass = AttachLatest::class;
97require_once RUN_MAINTENANCE_IF_MAIN;
98// @codeCoverageIgnoreEnd