diff --git a/includes/Database.php b/includes/Database.php index e88fc137..eb840948 100644 --- a/includes/Database.php +++ b/includes/Database.php @@ -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++; }