Page MenuHomeWickedGov Phorge

UpdateAutoBlockParentIdColumn.php
No OneTemporary

Size
4 KB
Referenced Files
None
Subscribers
None

UpdateAutoBlockParentIdColumn.php

<?php
namespace MediaWiki\Extension\GlobalBlocking\Maintenance;
use MediaWiki\Maintenance\LoggedUpdateMaintenance;
use Wikimedia\Rdbms\IMaintainableDatabase;
use Wikimedia\Rdbms\SelectQueryBuilder;
// @codeCoverageIgnoreStart
$IP = getenv( 'MW_INSTALL_PATH' );
if ( $IP === false ) {
$IP = __DIR__ . '/../../..';
}
require_once "$IP/maintenance/Maintenance.php";
// @codeCoverageIgnoreEnd
/**
* Maintenance script for updating gb_autoblock_parent_id to replace NULL values with 0.
*/
class UpdateAutoBlockParentIdColumn extends LoggedUpdateMaintenance {
public function __construct() {
parent::__construct();
$this->addDescription(
"Used to update the values of NULL for gb_autoblock_parent_id to 0 (T376340). Necessary because " .
"the gb_autoblock_parent_id is used in a unique index which does not work as intended with NULL values. " .
"If you use a central globalblocks table, you only need to run this script once for the wikis which " .
"use the central table."
);
$this->requireExtension( 'GlobalBlocking' );
}
/** @inheritDoc */
public function getUpdateKey() {
return __CLASS__;
}
/** @inheritDoc */
public function doDbUpdates() {
$connectionProvider = $this->getServiceContainer()->getConnectionProvider();
$dbr = $connectionProvider->getReplicaDatabase( 'virtual-globalblocking' );
if ( !( $dbr instanceof IMaintainableDatabase ) ) {
throw new \RuntimeException( 'Wrong database class' );
}
$autoBlockParentIdFieldInfo = $dbr->fieldInfo( 'globalblocks', 'gb_autoblock_parent_id' );
if ( !$autoBlockParentIdFieldInfo || !$autoBlockParentIdFieldInfo->isNullable() ) {
$this->output( "The field globalblocks.gb_autoblock_parent_id is not nullable, nothing to do.\n" );
return true;
}
$hasRowsToUpdate = $dbr->newSelectQueryBuilder()
->select( '1' )
->from( 'globalblocks' )
->where( [ 'gb_autoblock_parent_id' => null ] )
->caller( __METHOD__ )
->fetchField();
if ( !$hasRowsToUpdate ) {
$this->output( "The globalblocks table has no rows to update.\n" );
return true;
}
$success = 0;
$failed = 0;
$lastProcessedRowId = 0;
$dbw = $connectionProvider->getPrimaryDatabase( 'virtual-globalblocking' );
do {
// Fetch a batch of rows with gb_autoblock_parent_id as NULL
$batchToProcess = $dbr->newSelectQueryBuilder()
->select( 'gb_id' )
->from( 'globalblocks' )
->where( [
'gb_autoblock_parent_id' => null,
$dbr->expr( 'gb_id', '>', $lastProcessedRowId ),
] )
->orderBy( 'gb_id', SelectQueryBuilder::SORT_ASC )
->limit( $this->getBatchSize() )
->caller( __METHOD__ )
->fetchFieldValues();
if ( count( $batchToProcess ) ) {
$lastId = end( $batchToProcess );
$firstId = reset( $batchToProcess );
$this->output( "Now processing global blocks with id between $firstId and $lastId...\n" );
foreach ( $batchToProcess as $id ) {
// Check if the gb_address used by this globalblocks row is used for any other globalblocks
// row where the gb_autoblock_parent_id is 0. If it is, then we cannot update the row with ID
// $id because it would cause a unique index constrant violation.
// We cannot use an UPDATE IGNORE for this as postgres will still throw an error.
$targetForRow = $dbr->newSelectQueryBuilder()
->select( 'gb_address' )
->from( 'globalblocks' )
->where( [ 'gb_id' => $id ] )
->caller( __METHOD__ )
->fetchField();
$collidingRowExists = $dbw->newSelectQueryBuilder()
->select( '1' )
->from( 'globalblocks' )
->where( [ 'gb_address' => $targetForRow, 'gb_autoblock_parent_id' => 0 ] )
->fetchField();
if ( !$collidingRowExists ) {
$dbw->newUpdateQueryBuilder()
->update( 'globalblocks' )
->set( [ 'gb_autoblock_parent_id' => 0 ] )
->where( [ 'gb_id' => $id ] )
->caller( __METHOD__ )
->execute();
}
$newValue = $dbw->newSelectQueryBuilder()
->select( 'gb_autoblock_parent_id' )
->from( 'globalblocks' )
->where( [ 'gb_id' => $id ] )
->fetchField();
if ( $newValue !== null ) {
$success += 1;
} else {
$this->output( "...Failed to update row with ID $id.\n" );
$failed += 1;
}
}
$lastProcessedRowId = end( $batchToProcess );
$this->waitForReplication();
}
} while ( count( $batchToProcess ) === $this->getBatchSize() );
$this->output( "Completed migration, updated $success row(s), failed to update $failed row(s).\n" );
return true;
}
}
// @codeCoverageIgnoreStart
$maintClass = UpdateAutoBlockParentIdColumn::class;
require_once RUN_MAINTENANCE_IF_MAIN;
// @codeCoverageIgnoreEnd

File Metadata

Mime Type
text/x-php
Expires
Wed, Aug 19, 13:47 (3 w, 3 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ee/85/4a026f2c0b501e1104bdbc6624c0
Default Alt Text
UpdateAutoBlockParentIdColumn.php (4 KB)

Event Timeline