Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
PopulateFRRevTimestamp
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 4
210
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 populateFRRevTimestamp
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 1
90
 lastPosFile
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * @ingroup Maintenance
4 */
5
6use MediaWiki\Maintenance\Maintenance;
7use MediaWiki\WikiMap\WikiMap;
8
9// @codeCoverageIgnoreStart
10if ( getenv( 'MW_INSTALL_PATH' ) ) {
11    $IP = getenv( 'MW_INSTALL_PATH' );
12} else {
13    $IP = __DIR__ . '/../../..';
14}
15
16require_once "$IP/maintenance/Maintenance.php";
17// @codeCoverageIgnoreEnd
18
19class PopulateFRRevTimestamp extends Maintenance {
20
21    public function __construct() {
22        parent::__construct();
23        $this->addDescription( 'Populates fr_rev_timestamp column in the flaggedrevs table.' );
24        $this->addOption( 'startrev', 'The ID of the starting rev', false, true );
25        $this->setBatchSize( 1000 );
26        $this->requireExtension( 'FlaggedRevs' );
27    }
28
29    /**
30     * @inheritDoc
31     */
32    public function execute() {
33        $startRev = $this->getOption( 'startrev' );
34        if ( $startRev === 'prev' ) {
35            $startRev = file_get_contents( $this->lastPosFile() );
36        }
37        if ( $startRev !== null ) {
38            $startRev = (int)$startRev;
39        }
40        $this->populateFRRevTimestamp( $startRev );
41    }
42
43    /**
44     * @param int|null $start Revision ID
45     */
46    private function populateFRRevTimestamp( $start = null ) {
47        $this->output( "Populating and correcting flaggedrevs columns from $start\n" );
48
49        $db = $this->getPrimaryDB();
50
51        if ( $start === null ) {
52            $start = $db->newSelectQueryBuilder()
53                ->select( 'MIN(fr_rev_id)' )
54                ->from( 'flaggedrevs' )
55                ->caller( __METHOD__ )
56                ->fetchField();
57        }
58        $end = $db->newSelectQueryBuilder()
59            ->select( 'MAX(fr_rev_id)' )
60            ->from( 'flaggedrevs' )
61            ->caller( __METHOD__ )
62            ->fetchField();
63        if ( $start === null || $end === null ) {
64            $this->output( "...flaggedrevs table seems to be empty.\n" );
65            return;
66        }
67        # Do remaining chunk
68        $end += $this->mBatchSize - 1;
69        $blockStart = (int)$start;
70        $blockEnd = (int)$start + $this->mBatchSize - 1;
71        $count = 0;
72        $changed = 0;
73
74        while ( $blockEnd <= $end ) {
75            $this->output( "...doing fr_rev_id from $blockStart to $blockEnd\n" );
76            $res = $db->newSelectQueryBuilder()
77                ->select( [ 'fr_rev_id', 'rev_timestamp', 'ar_timestamp' ] )
78                ->from( 'flaggedrevs' )
79                ->leftJoin( 'revision', null, 'rev_id = fr_rev_id' )
80                ->leftJoin( 'archive', null, 'ar_rev_id = fr_rev_id' ) // non-unique but OK
81                ->where( [
82                    $db->expr( 'fr_rev_id', '>=', $blockStart ),
83                    $db->expr( 'fr_rev_id', '<=', $blockEnd ),
84                    'fr_rev_timestamp' => '',
85                ] )
86                ->caller( __METHOD__ )
87                ->fetchResultSet();
88            $db->begin( __METHOD__ );
89            # Go through and clean up missing items
90            foreach ( $res as $row ) {
91                $timestamp = '';
92                if ( $row->rev_timestamp ) {
93                    $timestamp = $row->rev_timestamp;
94                } elseif ( $row->ar_timestamp ) {
95                    $timestamp = $row->ar_timestamp;
96                }
97                if ( $timestamp != '' ) {
98                    # Update the row...
99                    $db->newUpdateQueryBuilder()
100                        ->update( 'flaggedrevs' )
101                        ->set( [ 'fr_rev_timestamp' => $timestamp ] )
102                        ->where( [ 'fr_rev_id' => $row->fr_rev_id ] )
103                        ->caller( __METHOD__ )
104                        ->execute();
105                    $changed++;
106                }
107                $count++;
108            }
109            $db->commit( __METHOD__ );
110            $blockStart += $this->mBatchSize;
111            $blockEnd += $this->mBatchSize;
112            $this->waitForReplication();
113        }
114        file_put_contents( $this->lastPosFile(), $end );
115        $this->output( "fr_rev_timestamp columns update complete ..." .
116            " {$count} rows [{$changed} changed]\n" );
117    }
118
119    /**
120     * @return string
121     */
122    private function lastPosFile() {
123        return __DIR__ . "/popRevTimestampLast-" . WikiMap::getCurrentWikiId();
124    }
125}
126
127// @codeCoverageIgnoreStart
128$maintClass = PopulateFRRevTimestamp::class;
129require_once RUN_MAINTENANCE_IF_MAIN;
130// @codeCoverageIgnoreEnd