Migrate Database.php to use QueryBuilders everywhere

Bug: T350977
Change-Id: I864c1e4880876b329ba0e8102e6c0f335a149491
This commit is contained in:
Isabelle Hurbain-Palatin 2023-12-15 13:43:53 +01:00
parent 91ff1af06b
commit 24155905cd

View file

@ -173,7 +173,7 @@ class Database {
* @param LintError $error
* @return array
*/
private function serializeError( LintError $error ) {
private function buildErrorRow( LintError $error ) {
$mwServices = MediaWikiServices::getInstance();
$config = $mwServices->getMainConfig();
@ -246,11 +246,11 @@ class Database {
$toInsert = array_values( $errors );
$toDelete = [];
} elseif ( $previous && !$errors ) {
$dbw->delete(
'linter',
[ 'linter_page' => $this->pageId ],
__METHOD__
);
$dbw->newDeleteQueryBuilder()
->deleteFrom( 'linter' )
->where( [ 'linter_page' => $this->pageId ] )
->caller( __METHOD__ )
->execute();
return [ 'deleted' => $this->countByCat( $previous ), 'added' => [] ];
} else {
$toInsert = [];
@ -273,22 +273,22 @@ class Database {
$ids[] = $lintError->lintId;
}
}
$dbw->delete(
'linter',
[ 'linter_id' => $ids ],
__METHOD__
);
$dbw->newDeleteQueryBuilder()
->deleteFrom( 'linter' )
->where( [ 'linter_id' => $ids ] )
->caller( __METHOD__ )
->execute();
}
if ( $toInsert ) {
// Insert into db, ignoring any duplicate key errors
// since they're the same lint error
$dbw->insert(
'linter',
array_map( [ $this, 'serializeError' ], $toInsert ),
__METHOD__,
[ 'IGNORE' ]
);
$dbw->newInsertQueryBuilder()
->insertInto( 'linter' )
->ignore()
->rows( array_map( [ $this, 'buildErrorRow' ], $toInsert ) )
->caller( __METHOD__ )
->execute();
}
return [
@ -297,13 +297,6 @@ class Database {
];
}
/**
* @return int[]
*/
public function getTotalsForPage() {
return $this->getTotalsAccurate( [ 'linter_page' => $this->pageId ] );
}
/**
* Get an estimate of how many rows are there for the
* specified category with EXPLAIN SELECT COUNT(*).
@ -315,20 +308,20 @@ class Database {
* @return int
*/
private function getTotalsEstimate( $catId ) {
$dbr = self::getDBConnectionRef( DB_REPLICA );
$dbr = self::getReplicaDBConnection();
// First see if there are no rows, or a moderate number
// within the limit specified by the MAX_ACCURATE_COUNT.
// The distinction between 0, a few and a lot is important
// to determine first, as estimateRowCount seem to never
// return 0 or accurate low error counts.
$rows = $dbr->selectRowCount(
'linter',
'*',
[ 'linter_cat' => $catId ],
__METHOD__,
$rows = $dbr->newSelectQueryBuilder()
->select( '*' )
->from( 'linter' )
->where( [ 'linter_cat' => $catId ] )
// Select 1 more so we can see if we're over the max limit
[ 'LIMIT' => self::MAX_ACCURATE_COUNT + 1 ]
);
->limit( self::MAX_ACCURATE_COUNT + 1 )
->caller( __METHOD__ )
->fetchRowCount();
// Return an accurate count if the number of errors is
// below the maximum accurate count limit
if ( $rows <= self::MAX_ACCURATE_COUNT ) {
@ -336,27 +329,25 @@ class Database {
}
// Now we can just estimate if the maximum accurate count limit
// was returned, which isn't the actual count but the limit reached
return $dbr->estimateRowCount(
'linter',
'*',
[ 'linter_cat' => $catId ],
__METHOD__
);
return $dbr->newSelectQueryBuilder()
->select( '*' )
->from( 'linter' )
->where( [ 'linter_cat' => $catId ] )
->caller( __METHOD__ )
->estimateRowCount();
}
/**
*
* This uses COUNT(*), which is accurate, but can be significantly
* slower depending upon how many rows are in the database.
*
* @param array $conds
*
* @return int[]
*/
private function getTotalsAccurate( $conds = [] ) {
public function getTotalsForPage(): array {
$rows = self::getReplicaDBConnection()->newSelectQueryBuilder()
->select( [ 'linter_cat', 'COUNT(*) AS count' ] )
->from( 'linter' )
->where( $conds )
->where( [ 'linter_page' => $this->pageId ] )
->caller( __METHOD__ )
->groupBy( 'linter_cat' )
->fetchResultSet();
@ -482,15 +473,16 @@ class Database {
// Gather some unique pageId values in linter table records into an array
$linterPages = [];
$queryLinterTable = new SelectQueryBuilder( $dbw );
$queryLinterTable
->select( 'DISTINCT linter_page' )
$result = $dbw->newSelectQueryBuilder()
->select( 'linter_page' )
->distinct()
->from( 'linter' )
->where( [ 'linter_namespace IS NULL', 'linter_page > ' . $lastElement ] )
->where( $dbw->expr( 'linter_page', '>', $lastElement ) )
->andWhere( [ 'linter_namespace' => null ] )
->orderBy( 'linter_page' )
->limit( $linterBatchSize )
->caller( __METHOD__ );
$result = $queryLinterTable->fetchResultSet();
->caller( __METHOD__ )
->fetchResultSet();
foreach ( $result as $row ) {
$lastElement = intval( $row->linter_page );
@ -504,14 +496,12 @@ class Database {
if ( count( $pageIdBatch ) > 0 ) {
$queryPageTable = new SelectQueryBuilder( $dbread );
$queryPageTable
->fields( [ 'page_id', 'page_namespace' ] )
$pageResults = $dbread->newSelectQueryBuilder()
->select( [ 'page_id', 'page_namespace' ] )
->from( 'page' )
->where( [ 'page_id' => $pageIdBatch ] )
->caller( __METHOD__ );
$pageResults = $queryPageTable->fetchResultSet();
->caller( __METHOD__ )
->fetchResultSet();
foreach ( $pageResults as $pageRow ) {
$pageId = intval( $pageRow->page_id );
@ -519,15 +509,16 @@ class Database {
// If a record about to be updated has been removed by another process,
// the update will not error, and continue updating the existing records.
$dbw->update(
'linter',
[
'linter_namespace' => $namespaceID
],
[ 'linter_namespace IS NULL', 'linter_page = ' . $pageId ],
__METHOD__
);
$updated++;
$dbw->newUpdateQueryBuilder()
->update( 'linter' )
->set( [ 'linter_namespace' => $namespaceID ] )
->where( [
'linter_namespace' => null,
'linter_page' => $pageId
] )
->caller( __METHOD__ )
->execute();
$updated += $dbw->affectedRows();
}
// Sleep between batches for replication to catch up
@ -587,16 +578,18 @@ class Database {
$updated = 0;
$lastElement = 0;
do {
$queryLinterTable = new SelectQueryBuilder( $dbw );
$queryLinterTable
->table( 'linter' )
->fields( [ 'linter_id', 'linter_params', 'linter_template', 'linter_tag' ] )
->where( [ 'linter_params != \'[]\'', 'linter_params IS NOT NULL', 'linter_id > ' . $lastElement ] )
$results = $dbw->newSelectQueryBuilder()
->select( [ 'linter_id', 'linter_params', 'linter_template', 'linter_tag' ] )
->from( 'linter' )
->where( [
$dbw->expr( "linter_params", '!=', '[]' ),
$dbw->expr( "linter_params", '!=', null ),
$dbw->expr( "linter_id", '>', $lastElement )
] )
->orderBy( 'linter_id', selectQueryBuilder::SORT_ASC )
->limit( $batchSize )
->caller( __METHOD__ );
$results = $queryLinterTable->fetchResultSet();
->caller( __METHOD__ )
->fetchResultSet();
$linterBatchLength = 0;
foreach ( $results as $row ) {
@ -626,15 +619,13 @@ class Database {
if ( $templateInfo != $row->linter_template || $tagInfo != $row->linter_tag ) {
// If the record about to be updated has been removed by another process,
// the update will not do anything and just return with no records updated.
$dbw->update(
'linter',
[
'linter_template' => $templateInfo, 'linter_tag' => $tagInfo
],
[ 'linter_id' => $linter_id ],
__METHOD__
);
$updated++;
$dbw->newUpdateQueryBuilder()
->update( 'linter' )
->set( [ 'linter_template' => $templateInfo, 'linter_tag' => $tagInfo, ] )
->where( [ 'linter_id' => $linter_id ] )
->caller( __METHOD__ )
->execute();
$updated += $dbw->affectedRows();
}
$linterBatchLength++;
}