Title: [261892] trunk/Source/WebKit
Revision
261892
Author
katherine_che...@apple.com
Date
2020-05-19 15:55:49 -0700 (Tue, 19 May 2020)

Log Message

ITP database should finalize all prepared statements before closing
https://bugs.webkit.org/show_bug.cgi?id=211929
<rdar://problem/63246945>

Reviewed by John Wilander.

No new tests, behavior confirmed by existing tests.

Convert all SQLite statement objects to be unique pointers to better
manage the lifetime of each statement object. Only initialize and
prepare an object when it is needed instead of preparing all objects
at once. Set each statement to null before closing the database
because ~SQLiteStatement() will finalize the statement.

This patch removes all reset() commands now that we initialize
each statement using SQLiteStatementAutoResetScope.

* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
(WebKit::ResourceLoadStatisticsDatabaseStore::ResourceLoadStatisticsDatabaseStore):
(WebKit::ResourceLoadStatisticsDatabaseStore::close):
(WebKit::ResourceLoadStatisticsDatabaseStore::getScopedStatement const):
Function to initialize and prepare a statement.

(WebKit::ResourceLoadStatisticsDatabaseStore::insertDomainRelationship):
This function is not used and can be deleted.

(WebKit::ResourceLoadStatisticsDatabaseStore::checkForMissingTablesInSchema):
(WebKit::ResourceLoadStatisticsDatabaseStore::isMigrationNecessary):
(WebKit::ResourceLoadStatisticsDatabaseStore::openAndUpdateSchemaIfNecessary):
(WebKit::ResourceLoadStatisticsDatabaseStore::isEmpty const):
(WebKit::ResourceLoadStatisticsDatabaseStore::destroyStatements):
(WebKit::ResourceLoadStatisticsDatabaseStore::insertObservedDomain):
(WebKit::ResourceLoadStatisticsDatabaseStore::relationshipExists const):
(WebKit::ResourceLoadStatisticsDatabaseStore::domainID const):
(WebKit::ResourceLoadStatisticsDatabaseStore::merge):
(WebKit::ResourceLoadStatisticsDatabaseStore::mergeStatistic):
(WebKit::CompletionHandler<void):
(WebKit::ResourceLoadStatisticsDatabaseStore::prepareStatements): Deleted.
* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h:
Updated all statement variables to end with "Statement" to follow the
established pattern.

* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
(WebKit::WebResourceLoadStatisticsStore::flushAndDestroyPersistentStore):

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (261891 => 261892)


--- trunk/Source/WebKit/ChangeLog	2020-05-19 22:02:50 UTC (rev 261891)
+++ trunk/Source/WebKit/ChangeLog	2020-05-19 22:55:49 UTC (rev 261892)
@@ -1,3 +1,50 @@
+2020-05-19  Kate Cheney  <katherine_che...@apple.com>
+
+        ITP database should finalize all prepared statements before closing
+        https://bugs.webkit.org/show_bug.cgi?id=211929
+        <rdar://problem/63246945>
+
+        Reviewed by John Wilander.
+
+        No new tests, behavior confirmed by existing tests.
+
+        Convert all SQLite statement objects to be unique pointers to better
+        manage the lifetime of each statement object. Only initialize and
+        prepare an object when it is needed instead of preparing all objects
+        at once. Set each statement to null before closing the database
+        because ~SQLiteStatement() will finalize the statement.
+
+        This patch removes all reset() commands now that we initialize
+        each statement using SQLiteStatementAutoResetScope.
+
+        * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
+        (WebKit::ResourceLoadStatisticsDatabaseStore::ResourceLoadStatisticsDatabaseStore):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::close):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::getScopedStatement const):
+        Function to initialize and prepare a statement.
+
+        (WebKit::ResourceLoadStatisticsDatabaseStore::insertDomainRelationship):
+        This function is not used and can be deleted.
+
+        (WebKit::ResourceLoadStatisticsDatabaseStore::checkForMissingTablesInSchema):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::isMigrationNecessary):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::openAndUpdateSchemaIfNecessary):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::isEmpty const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::destroyStatements):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::insertObservedDomain):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::relationshipExists const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::domainID const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::merge):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::mergeStatistic):
+        (WebKit::CompletionHandler<void):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::prepareStatements): Deleted.
+        * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h:
+        Updated all statement variables to end with "Statement" to follow the
+        established pattern.
+
+        * NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
+        (WebKit::WebResourceLoadStatisticsStore::flushAndDestroyPersistentStore):
+
 2020-05-19  Per Arne Vollan  <pvol...@apple.com>
 
         [iOS] Fix message filter sandbox violation

Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp (261891 => 261892)


--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp	2020-05-19 22:02:50 UTC (rev 261891)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp	2020-05-19 22:55:49 UTC (rev 261892)
@@ -275,44 +275,6 @@
 ResourceLoadStatisticsDatabaseStore::ResourceLoadStatisticsDatabaseStore(WebResourceLoadStatisticsStore& store, WorkQueue& workQueue, ShouldIncludeLocalhost shouldIncludeLocalhost, const String& storageDirectoryPath, PAL::SessionID sessionID)
     : ResourceLoadStatisticsStore(store, workQueue, shouldIncludeLocalhost)
     , m_storageDirectoryPath(storageDirectoryPath + "/observations.db")
-    , m_observedDomainCount(m_database, observedDomainCountQuery)
-    , m_insertObservedDomainStatement(m_database, insertObservedDomainQuery)
-    , m_insertTopLevelDomainStatement(m_database, insertTopLevelDomainQuery)
-    , m_domainIDFromStringStatement(m_database, domainIDFromStringQuery)
-    , m_topFrameLinkDecorationsFromExists(m_database, topFrameLinkDecorationsFromExistsQuery)
-    , m_topFrameLoadedThirdPartyScriptsExists(m_database, topFrameLoadedThirdPartyScriptsExistsQuery)
-    , m_subframeUnderTopFrameDomainExists(m_database, subframeUnderTopFrameDomainExistsQuery)
-    , m_subresourceUnderTopFrameDomainExists(m_database, subresourceUnderTopFrameDomainExistsQuery)
-    , m_subresourceUniqueRedirectsToExists(m_database, subresourceUniqueRedirectsToExistsQuery)
-    , m_mostRecentUserInteractionStatement(m_database, mostRecentUserInteractionQuery)
-    , m_updateLastSeenStatement(m_database, updateLastSeenQuery)
-    , m_updateDataRecordsRemovedStatement(m_database, updateDataRecordsRemovedQuery)
-    , m_updatePrevalentResourceStatement(m_database, updatePrevalentResourceQuery)
-    , m_isPrevalentResourceStatement(m_database, isPrevalentResourceQuery)
-    , m_updateVeryPrevalentResourceStatement(m_database, updateVeryPrevalentResourceQuery)
-    , m_isVeryPrevalentResourceStatement(m_database, isVeryPrevalentResourceQuery)
-    , m_clearPrevalentResourceStatement(m_database, clearPrevalentResourceQuery)
-    , m_hadUserInteractionStatement(m_database, hadUserInteractionQuery)
-    , m_updateGrandfatheredStatement(m_database, updateGrandfatheredQuery)
-    , m_updateIsScheduledForAllButCookieDataRemovalStatement(m_database, updateIsScheduledForAllButCookieDataRemovalQuery)
-    , m_isGrandfatheredStatement(m_database, isGrandfatheredQuery)
-    , m_findExpiredUserInteractionStatement(m_database, findExpiredUserInteractionQuery)
-    , m_countPrevalentResourcesStatement(m_database, countPrevalentResourcesQuery)
-    , m_countPrevalentResourcesWithUserInteractionStatement(m_database, countPrevalentResourcesWithUserInteractionQuery)
-    , m_countPrevalentResourcesWithoutUserInteractionStatement(m_database, countPrevalentResourcesWithoutUserInteractionQuery)
-    , m_getResourceDataByDomainNameStatement(m_database, getResourceDataByDomainNameQuery)
-    , m_getAllDomainsStatement(m_database, getAllDomainsQuery)
-    , m_domainStringFromDomainIDStatement(m_database, domainStringFromDomainIDQuery)
-    , m_getAllSubStatisticsStatement(m_database, getAllSubStatisticsUnderDomainQuery)
-    , m_storageAccessExistsStatement(m_database, storageAccessExistsQuery)
-    , m_getMostRecentlyUpdatedTimestampStatement(m_database, getMostRecentlyUpdatedTimestampQuery)
-    , m_linkDecorationExistsStatement(m_database, linkDecorationExistsQuery)
-    , m_scriptLoadExistsStatement(m_database, scriptLoadExistsQuery)
-    , m_subFrameExistsStatement(m_database, subFrameExistsQuery)
-    , m_subResourceExistsStatement(m_database, subResourceExistsQuery)
-    , m_uniqueRedirectExistsStatement(m_database, uniqueRedirectExistsQuery)
-    , m_observedDomainsExistsStatement(m_database, observedDomainsExistsQuery)
-    , m_removeAllDataStatement(m_database, removeAllDataQuery)
     , m_sessionID(sessionID)
 {
     ASSERT(!RunLoop::isMain());
@@ -326,12 +288,6 @@
     if (!m_database.turnOnIncrementalAutoVacuum())
         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::turnOnIncrementalAutoVacuum failed, error message: %" PUBLIC_LOG_STRING, this, m_database.lastErrorMsg());
 
-    if (!prepareStatements()) {
-        RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::prepareStatements failed, error message: %" PUBLIC_LOG_STRING ", database path: %" PUBLIC_LOG_STRING, this, m_database.lastErrorMsg(), m_storageDirectoryPath.utf8().data());
-        ASSERT_NOT_REACHED();
-        return;
-    }
-
     workQueue.dispatchAfter(5_s, [weakThis = makeWeakPtr(*this)] {
         if (weakThis)
             weakThis->calculateAndSubmitTelemetry();
@@ -338,6 +294,18 @@
     });
 }
 
+ResourceLoadStatisticsDatabaseStore::~ResourceLoadStatisticsDatabaseStore()
+{
+    close();
+}
+
+void ResourceLoadStatisticsDatabaseStore::close()
+{
+    destroyStatements();
+    if (m_database.isOpen())
+        m_database.close();
+}
+
 void ResourceLoadStatisticsDatabaseStore::openITPDatabase()
 {
     if (!FileSystem::fileExists(m_storageDirectoryPath))
@@ -366,12 +334,6 @@
     }
 }
 
-static void resetStatement(SQLiteStatement& statement)
-{
-    int resetResult = statement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
-}
-
 Optional<Vector<String>> ResourceLoadStatisticsDatabaseStore::checkForMissingTablesInSchema()
 {
     Vector<String> missingTables;
@@ -390,7 +352,6 @@
             RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::checkForMissingTablesInSchema schema is missing table: %s", this, table.ascii().data());
             missingTables.append(String(table));
         }
-        resetStatement(statement);
     }
     if (missingTables.isEmpty())
         return WTF::nullopt;
@@ -421,7 +382,7 @@
     // If there is no table at all, or there is an error executing the fetch, delete and reopen the file.
     if (statement.step() != SQLITE_ROW) {
         LOG_ERROR("Error executing statement to fetch schema.");
-        m_database.close();
+        close();
         FileSystem::deleteFile(m_storageDirectoryPath);
         openITPDatabase();
         return false;
@@ -519,7 +480,7 @@
         // If there is no ObservedDomains table at all, or there is an error executing the fetch, delete the file.
         if (statement.step() != SQLITE_ROW) {
             LOG_ERROR("Error executing statement to fetch schema for the Observed Domains table.");
-            m_database.close();
+            close();
             FileSystem::deleteFile(m_storageDirectoryPath);
             openITPDatabase();
             return;
@@ -533,7 +494,7 @@
     // If the ObservedDomains schema in the ResourceLoadStatistics directory is not the current schema, delete the database file.
     // FIXME: Migrate old ObservedDomains data to new table schema.
     if (currentSchema != ObservedDomainsTableSchemaV1() && currentSchema != ObservedDomainsTableSchemaV1Alternate()) {
-        m_database.close();
+        close();
         FileSystem::deleteFile(m_storageDirectoryPath);
         openITPDatabase();
     } else
@@ -540,18 +501,31 @@
         migrateDataToNewTablesIfNecessary();
 }
 
+SQLiteStatementAutoResetScope ResourceLoadStatisticsDatabaseStore::scopedStatement(std::unique_ptr<WebCore::SQLiteStatement>& statement, const String& query, const String& logString) const
+{
+    if (!statement) {
+        statement = makeUnique<WebCore::SQLiteStatement>(m_database, query);
+        ASSERT(m_database.isOpen());
+        if (statement->prepare() != SQLITE_OK) {
+            RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::%s failed to prepare statement, error message: %" PUBLIC_LOG_STRING, this, logString.ascii().data(), m_database.lastErrorMsg());
+            ASSERT_NOT_REACHED();
+        }
+    }
+    return SQLiteStatementAutoResetScope { statement.get() };
+}
+
 bool ResourceLoadStatisticsDatabaseStore::isEmpty() const
 {
     ASSERT(!RunLoop::isMain());
     
-    bool result = false;
-    if (m_observedDomainCount.step() == SQLITE_ROW)
-        result = !m_observedDomainCount.getColumnInt(0);
-    
-    int resetResult = m_observedDomainCount.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
-    
-    return result;
+    auto scopedStatement = this->scopedStatement(m_observedDomainCountStatement, observedDomainCountQuery, "isEmpty"_s);
+    if (!scopedStatement
+        || scopedStatement->step() != SQLITE_ROW) {
+        RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::isEmpty failed to step, error message: %{private}s", this, m_database.lastErrorMsg());
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+    return !scopedStatement->getColumnInt(0);
 }
 
 bool ResourceLoadStatisticsDatabaseStore::createUniqueIndices()
@@ -642,55 +616,48 @@
     return true;
 }
 
-bool ResourceLoadStatisticsDatabaseStore::prepareStatements()
+void ResourceLoadStatisticsDatabaseStore::destroyStatements()
 {
     ASSERT(!RunLoop::isMain());
-        
-    if (m_observedDomainCount.prepare() != SQLITE_OK
-        || m_insertObservedDomainStatement.prepare() != SQLITE_OK
-        || m_insertTopLevelDomainStatement.prepare() != SQLITE_OK
-        || m_domainIDFromStringStatement.prepare() != SQLITE_OK
-        || m_subframeUnderTopFrameDomainExists.prepare() != SQLITE_OK
-        || m_subresourceUnderTopFrameDomainExists.prepare() != SQLITE_OK
-        || m_subresourceUniqueRedirectsToExists.prepare() != SQLITE_OK
-        || m_updateLastSeenStatement.prepare() != SQLITE_OK
-        || m_updateDataRecordsRemovedStatement.prepare() != SQLITE_OK
-        || m_mostRecentUserInteractionStatement.prepare() != SQLITE_OK
-        || m_updatePrevalentResourceStatement.prepare() != SQLITE_OK
-        || m_isPrevalentResourceStatement.prepare() != SQLITE_OK
-        || m_updateVeryPrevalentResourceStatement.prepare() != SQLITE_OK
-        || m_isVeryPrevalentResourceStatement.prepare() != SQLITE_OK
-        || m_clearPrevalentResourceStatement.prepare() != SQLITE_OK
-        || m_hadUserInteractionStatement.prepare() != SQLITE_OK
-        || m_updateGrandfatheredStatement.prepare() != SQLITE_OK
-        || m_updateIsScheduledForAllButCookieDataRemovalStatement.prepare() != SQLITE_OK
-        || m_isGrandfatheredStatement.prepare() != SQLITE_OK
-        || m_findExpiredUserInteractionStatement.prepare() != SQLITE_OK
-        || m_topFrameLinkDecorationsFromExists.prepare() != SQLITE_OK
-        || m_topFrameLoadedThirdPartyScriptsExists.prepare() != SQLITE_OK
-        || m_countPrevalentResourcesStatement.prepare() != SQLITE_OK
-        || m_countPrevalentResourcesWithUserInteractionStatement.prepare() != SQLITE_OK
-        || m_countPrevalentResourcesWithoutUserInteractionStatement.prepare() != SQLITE_OK
-        || m_getResourceDataByDomainNameStatement.prepare() != SQLITE_OK
-        || m_getAllDomainsStatement.prepare() != SQLITE_OK
-        || m_domainStringFromDomainIDStatement.prepare() != SQLITE_OK
-        || m_getAllSubStatisticsStatement.prepare() != SQLITE_OK
-        || m_storageAccessExistsStatement.prepare() != SQLITE_OK
-        || m_getMostRecentlyUpdatedTimestampStatement.prepare() != SQLITE_OK
-        || m_linkDecorationExistsStatement.prepare() != SQLITE_OK
-        || m_scriptLoadExistsStatement.prepare() != SQLITE_OK
-        || m_subFrameExistsStatement.prepare() != SQLITE_OK
-        || m_subResourceExistsStatement.prepare() != SQLITE_OK
-        || m_uniqueRedirectExistsStatement.prepare() != SQLITE_OK
-        || m_observedDomainsExistsStatement.prepare() != SQLITE_OK
-        || m_removeAllDataStatement.prepare() != SQLITE_OK
-        ) {
-        RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::prepareStatements failed to prepare, error message: %" PUBLIC_LOG_STRING, this, m_database.lastErrorMsg());
-        ASSERT_NOT_REACHED();
-        return false;
-    }
 
-    return true;
+    m_observedDomainCountStatement = nullptr;
+    m_insertObservedDomainStatement = nullptr;
+    m_insertTopLevelDomainStatement = nullptr;
+    m_domainIDFromStringStatement = nullptr;
+    m_subframeUnderTopFrameDomainExistsStatement = nullptr;
+    m_subresourceUnderTopFrameDomainExistsStatement = nullptr;
+    m_subresourceUniqueRedirectsToExistsStatement = nullptr;
+    m_updateLastSeenStatement = nullptr;
+    m_updateDataRecordsRemovedStatement = nullptr;
+    m_mostRecentUserInteractionStatement = nullptr;
+    m_updatePrevalentResourceStatement = nullptr;
+    m_isPrevalentResourceStatement = nullptr;
+    m_updateVeryPrevalentResourceStatement = nullptr;
+    m_isVeryPrevalentResourceStatement = nullptr;
+    m_clearPrevalentResourceStatement = nullptr;
+    m_hadUserInteractionStatement = nullptr;
+    m_updateGrandfatheredStatement = nullptr;
+    m_updateIsScheduledForAllButCookieDataRemovalStatement = nullptr;
+    m_isGrandfatheredStatement = nullptr;
+    m_findExpiredUserInteractionStatement = nullptr;
+    m_topFrameLinkDecorationsFromExistsStatement = nullptr;
+    m_topFrameLoadedThirdPartyScriptsExistsStatement = nullptr;
+    m_countPrevalentResourcesStatement = nullptr;
+    m_countPrevalentResourcesWithUserInteractionStatement = nullptr;
+    m_countPrevalentResourcesWithoutUserInteractionStatement = nullptr;
+    m_getResourceDataByDomainNameStatement = nullptr;
+    m_getAllDomainsStatement = nullptr;
+    m_domainStringFromDomainIDStatement = nullptr;
+    m_getAllSubStatisticsStatement = nullptr;
+    m_storageAccessExistsStatement = nullptr;
+    m_getMostRecentlyUpdatedTimestampStatement = nullptr;
+    m_linkDecorationExistsStatement = nullptr;
+    m_scriptLoadExistsStatement = nullptr;
+    m_subFrameExistsStatement = nullptr;
+    m_subResourceExistsStatement = nullptr;
+    m_uniqueRedirectExistsStatement = nullptr;
+    m_observedDomainsExistsStatement = nullptr;
+    m_removeAllDataStatement = nullptr;
 }
 
 bool ResourceLoadStatisticsDatabaseStore::insertObservedDomain(const ResourceLoadStatistics& loadStatistics)
@@ -702,36 +669,33 @@
         ASSERT_NOT_REACHED();
         return false;
     }
-
-    if (m_insertObservedDomainStatement.bindText(RegistrableDomainIndex, loadStatistics.registrableDomain.string()) != SQLITE_OK
-        || m_insertObservedDomainStatement.bindDouble(LastSeenIndex, loadStatistics.lastSeen.secondsSinceEpoch().value()) != SQLITE_OK
-        || m_insertObservedDomainStatement.bindInt(HadUserInteractionIndex, loadStatistics.hadUserInteraction) != SQLITE_OK
-        || m_insertObservedDomainStatement.bindDouble(MostRecentUserInteractionTimeIndex, loadStatistics.mostRecentUserInteractionTime.secondsSinceEpoch().value()) != SQLITE_OK
-        || m_insertObservedDomainStatement.bindInt(GrandfatheredIndex, loadStatistics.grandfathered) != SQLITE_OK
-        || m_insertObservedDomainStatement.bindInt(IsPrevalentIndex, loadStatistics.isPrevalentResource) != SQLITE_OK
-        || m_insertObservedDomainStatement.bindInt(IsVeryPrevalentIndex, loadStatistics.isVeryPrevalentResource) != SQLITE_OK
-        || m_insertObservedDomainStatement.bindInt(DataRecordsRemovedIndex, loadStatistics.dataRecordsRemoved) != SQLITE_OK
-        || m_insertObservedDomainStatement.bindInt(TimesAccessedAsFirstPartyDueToUserInteractionIndex, loadStatistics.timesAccessedAsFirstPartyDueToUserInteraction) != SQLITE_OK
-        || m_insertObservedDomainStatement.bindInt(TimesAccessedAsFirstPartyDueToStorageAccessAPIIndex, loadStatistics.timesAccessedAsFirstPartyDueToStorageAccessAPI) != SQLITE_OK
-        || m_insertObservedDomainStatement.bindInt(IsScheduledForAllButCookieDataRemovalIndex, loadStatistics.gotLinkDecorationFromPrevalentResource) != SQLITE_OK) {
+    auto scopedStatement = this->scopedStatement(m_insertObservedDomainStatement, insertObservedDomainQuery, "insertObservedDomain"_s);
+    if (!scopedStatement
+        || scopedStatement->bindText(RegistrableDomainIndex, loadStatistics.registrableDomain.string()) != SQLITE_OK
+        || scopedStatement->bindDouble(LastSeenIndex, loadStatistics.lastSeen.secondsSinceEpoch().value()) != SQLITE_OK
+        || scopedStatement->bindInt(HadUserInteractionIndex, loadStatistics.hadUserInteraction) != SQLITE_OK
+        || scopedStatement->bindDouble(MostRecentUserInteractionTimeIndex, loadStatistics.mostRecentUserInteractionTime.secondsSinceEpoch().value()) != SQLITE_OK
+        || scopedStatement->bindInt(GrandfatheredIndex, loadStatistics.grandfathered) != SQLITE_OK
+        || scopedStatement->bindInt(IsPrevalentIndex, loadStatistics.isPrevalentResource) != SQLITE_OK
+        || scopedStatement->bindInt(IsVeryPrevalentIndex, loadStatistics.isVeryPrevalentResource) != SQLITE_OK
+        || scopedStatement->bindInt(DataRecordsRemovedIndex, loadStatistics.dataRecordsRemoved) != SQLITE_OK
+        || scopedStatement->bindInt(TimesAccessedAsFirstPartyDueToUserInteractionIndex, loadStatistics.timesAccessedAsFirstPartyDueToUserInteraction) != SQLITE_OK
+        || scopedStatement->bindInt(TimesAccessedAsFirstPartyDueToStorageAccessAPIIndex, loadStatistics.timesAccessedAsFirstPartyDueToStorageAccessAPI) != SQLITE_OK
+        || scopedStatement->bindInt(IsScheduledForAllButCookieDataRemovalIndex, loadStatistics.gotLinkDecorationFromPrevalentResource) != SQLITE_OK) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::insertObservedDomain failed to bind, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return false;
     }
 
-    if (m_insertObservedDomainStatement.step() != SQLITE_DONE) {
+    if (scopedStatement->step() != SQLITE_DONE) {
         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::insertObservedDomain failed to commit, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return false;
     }
-
-    int resetResult = m_insertObservedDomainStatement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
-
     return true;
 }
 
-bool ResourceLoadStatisticsDatabaseStore::relationshipExists(WebCore::SQLiteStatement& statement, Optional<unsigned> firstDomainID, const RegistrableDomain& secondDomain) const
+bool ResourceLoadStatisticsDatabaseStore::relationshipExists(SQLiteStatementAutoResetScope& statement, Optional<unsigned> firstDomainID, const RegistrableDomain& secondDomain) const
 {
     if (!firstDomainID)
         return false;
@@ -738,62 +702,32 @@
     
     ASSERT(!RunLoop::isMain());
 
-    if (statement.bindInt(1, *firstDomainID) != SQLITE_OK
-        || statement.bindText(2, secondDomain.string()) != SQLITE_OK
-        || statement.step() != SQLITE_ROW) {
+    if (!statement
+        || statement->bindInt(1, *firstDomainID) != SQLITE_OK
+        || statement->bindText(2, secondDomain.string()) != SQLITE_OK
+        || statement->step() != SQLITE_ROW) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::relationshipExists failed to bind, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return false;
     }
-    bool relationshipExists = !!statement.getColumnInt(0);
-
-    int resetResult = statement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
-    
-    return relationshipExists;
+    return !!statement->getColumnInt(0);
 }
 
-bool ResourceLoadStatisticsDatabaseStore::insertDomainRelationship(WebCore::SQLiteStatement& statement, unsigned domainID, const RegistrableDomain& topFrame)
-{
-    ASSERT(!RunLoop::isMain());
-
-    if (statement.bindInt(1, domainID) != SQLITE_OK
-        || statement.bindText(2, topFrame.string()) != SQLITE_OK
-        || statement.step() != SQLITE_DONE) {
-        RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::m_insertDomainRelationshipStatement failed to bind, error message: %{private}s", this, m_database.lastErrorMsg());
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-
-    int resetResult = statement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
-    
-    return true;
-}
-
 Optional<unsigned> ResourceLoadStatisticsDatabaseStore::domainID(const RegistrableDomain& domain) const
 {
     ASSERT(!RunLoop::isMain());
 
-    unsigned domainID = 0;
-
-    if (m_domainIDFromStringStatement.bindText(1, domain.string()) != SQLITE_OK) {
+    auto scopedStatement = this->scopedStatement(m_domainIDFromStringStatement, domainIDFromStringQuery, "domainID"_s);
+    if (!scopedStatement
+        || scopedStatement->bindText(1, domain.string()) != SQLITE_OK) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::domainIDFromString failed, error message: %{private}s", this, m_database.lastErrorMsg());
         return WTF::nullopt;
     }
     
-    if (m_domainIDFromStringStatement.step() != SQLITE_ROW) {
-        int resetResult = m_domainIDFromStringStatement.reset();
-        ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
+    if (scopedStatement->step() != SQLITE_ROW)
         return WTF::nullopt;
-    }
 
-    domainID = m_domainIDFromStringStatement.getColumnInt(0);
-
-    int resetResult = m_domainIDFromStringStatement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
-    
-    return domainID;
+    return scopedStatement->getColumnInt(0);
 }
 
 String ResourceLoadStatisticsDatabaseStore::ensureAndMakeDomainList(const HashSet<RegistrableDomain>& domainList)
@@ -884,18 +818,18 @@
         insertDomainRelationships(statistic.value);
 }
 
-void ResourceLoadStatisticsDatabaseStore::merge(WebCore::SQLiteStatement& current, const ResourceLoadStatistics& other)
+void ResourceLoadStatisticsDatabaseStore::merge(WebCore::SQLiteStatement* current, const ResourceLoadStatistics& other)
 {
     ASSERT(!RunLoop::isMain());
 
-    auto currentRegistrableDomain = current.getColumnText(RegistrableDomainIndex);
-    auto currentLastSeen = current.getColumnDouble(LastSeenIndex);
-    auto currentMostRecentUserInteraction = current.getColumnDouble(MostRecentUserInteractionTimeIndex);
-    bool currentGrandfathered = current.getColumnInt(GrandfatheredIndex);
-    bool currentIsPrevalent = current.getColumnInt(IsPrevalentIndex);
-    bool currentIsVeryPrevalent = current.getColumnInt(IsVeryPrevalentIndex);
-    unsigned currentDataRecordsRemoved = current.getColumnInt(DataRecordsRemovedIndex);
-    bool currentIsScheduledForAllButCookieDataRemoval = current.getColumnInt(IsScheduledForAllButCookieDataRemovalIndex);
+    auto currentRegistrableDomain = current->getColumnText(RegistrableDomainIndex);
+    auto currentLastSeen = current->getColumnDouble(LastSeenIndex);
+    auto currentMostRecentUserInteraction = current->getColumnDouble(MostRecentUserInteractionTimeIndex);
+    bool currentGrandfathered = current->getColumnInt(GrandfatheredIndex);
+    bool currentIsPrevalent = current->getColumnInt(IsPrevalentIndex);
+    bool currentIsVeryPrevalent = current->getColumnInt(IsVeryPrevalentIndex);
+    unsigned currentDataRecordsRemoved = current->getColumnInt(DataRecordsRemovedIndex);
+    bool currentIsScheduledForAllButCookieDataRemoval = current->getColumnInt(IsScheduledForAllButCookieDataRemovalIndex);
 
     ASSERT(currentRegistrableDomain == other.registrableDomain.string());
 
@@ -925,15 +859,16 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    if (m_getResourceDataByDomainNameStatement.bindText(1, statistic.registrableDomain.string()) != SQLITE_OK
-        || m_getResourceDataByDomainNameStatement.step() != SQLITE_ROW) {
+    auto scopedStatement = this->scopedStatement(m_getResourceDataByDomainNameStatement, getResourceDataByDomainNameQuery, "mergeStatistic"_s);
+    if (!scopedStatement
+        || scopedStatement->bindText(1, statistic.registrableDomain.string()) != SQLITE_OK
+        || scopedStatement->step() != SQLITE_ROW) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::mergeStatistic. Statement failed to bind or domain was not found, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return;
     }
 
-    merge(m_getResourceDataByDomainNameStatement, statistic);
-    resetStatement(m_getResourceDataByDomainNameStatement);
+    merge(scopedStatement.get(), statistic);
 }
 
 void ResourceLoadStatisticsDatabaseStore::mergeStatistics(Vector<ResourceLoadStatistics>&& statistics)
@@ -987,18 +922,19 @@
 
 Vector<WebResourceLoadStatisticsStore::ThirdPartyDataForSpecificFirstParty> ResourceLoadStatisticsDatabaseStore::getThirdPartyDataForSpecificFirstPartyDomains(unsigned thirdPartyDomainID, const RegistrableDomain& thirdPartyDomain) const
 {
-    if (m_getAllSubStatisticsStatement.bindInt(1, thirdPartyDomainID) != SQLITE_OK
-        || m_getAllSubStatisticsStatement.bindInt(2, thirdPartyDomainID) != SQLITE_OK
-        || m_getAllSubStatisticsStatement.bindInt(3, thirdPartyDomainID) != SQLITE_OK) {
+    auto scopedStatement = this->scopedStatement(m_getAllSubStatisticsStatement, getAllSubStatisticsUnderDomainQuery, "getThirdPartyDataForSpecificFirstPartyDomains"_s);
+    if (!scopedStatement
+        || scopedStatement->bindInt(1, thirdPartyDomainID) != SQLITE_OK
+        || scopedStatement->bindInt(2, thirdPartyDomainID) != SQLITE_OK
+        || scopedStatement->bindInt(3, thirdPartyDomainID) != SQLITE_OK) {
         RELEASE_LOG_ERROR(Network, "ResourceLoadStatisticsDatabaseStore::getThirdPartyDataForSpecificFirstPartyDomain, error message: %" PUBLIC_LOG_STRING, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
     }
     Vector<WebResourceLoadStatisticsStore::ThirdPartyDataForSpecificFirstParty> thirdPartyDataForSpecificFirstPartyDomains;
-    while (m_getAllSubStatisticsStatement.step() == SQLITE_ROW) {
-        RegistrableDomain firstPartyDomain = RegistrableDomain::uncheckedCreateFromRegistrableDomainString(getDomainStringFromDomainID(m_getAllSubStatisticsStatement.getColumnInt(0)));
+    while (scopedStatement->step() == SQLITE_ROW) {
+        RegistrableDomain firstPartyDomain = RegistrableDomain::uncheckedCreateFromRegistrableDomainString(getDomainStringFromDomainID(m_getAllSubStatisticsStatement->getColumnInt(0)));
         thirdPartyDataForSpecificFirstPartyDomains.appendIfNotContains(WebResourceLoadStatisticsStore::ThirdPartyDataForSpecificFirstParty { firstPartyDomain, hasStorageAccess(firstPartyDomain, thirdPartyDomain), getMostRecentlyUpdatedTimestamp(thirdPartyDomain, firstPartyDomain) });
     }
-    resetStatement(m_getAllSubStatisticsStatement);
     return thirdPartyDataForSpecificFirstPartyDomains;
 }
 
@@ -1120,7 +1056,11 @@
 
 unsigned ResourceLoadStatisticsDatabaseStore::getNumberOfPrevalentResources() const
 {
-    auto stepValue = m_countPrevalentResourcesStatement.step();
+    auto scopedStatement = this->scopedStatement(m_countPrevalentResourcesStatement, countPrevalentResourcesQuery, "getNumberOfPrevalentResources"_s);
+    if (!scopedStatement)
+        return 0;
+    
+    auto stepValue = scopedStatement->step();
     if (stepValue != SQLITE_ROW && stepValue != SQLITE_DONE) {
         RELEASE_LOG_ERROR(Network, "ResourceLoadStatisticsDatabaseStore::getNumberOfPrevalentResources failed to step, error message: %" PUBLIC_LOG_STRING, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
@@ -1127,24 +1067,20 @@
         return 0;
     }
     if (stepValue == SQLITE_ROW) {
-        unsigned prevalentResourceCount = m_countPrevalentResourcesStatement.getColumnInt(0);
-        if (prevalentResourceCount >= minimumPrevalentResourcesForTelemetry) {
-            resetStatement(m_countPrevalentResourcesStatement);
+        unsigned prevalentResourceCount = scopedStatement->getColumnInt(0);
+        if (prevalentResourceCount >= minimumPrevalentResourcesForTelemetry)
             return prevalentResourceCount;
-        }
     }
-    resetStatement(m_countPrevalentResourcesStatement);
     return 0;
 }
 
 unsigned ResourceLoadStatisticsDatabaseStore::getNumberOfPrevalentResourcesWithUI() const
 {
-    if (m_countPrevalentResourcesWithUserInteractionStatement.step() == SQLITE_ROW) {
-        int count = m_countPrevalentResourcesWithUserInteractionStatement.getColumnInt(0);
-        resetStatement(m_countPrevalentResourcesWithUserInteractionStatement);
+    auto scopedStatement = this->scopedStatement(m_countPrevalentResourcesWithUserInteractionStatement, countPrevalentResourcesWithUserInteractionQuery, "getNumberOfPrevalentResourcesWithUI"_s);
+    if (scopedStatement && scopedStatement->step() == SQLITE_ROW) {
+        int count = scopedStatement->getColumnInt(0);
         return count;
     }
-    resetStatement(m_countPrevalentResourcesWithUserInteractionStatement);
     return 0;
 }
 
@@ -1258,12 +1194,11 @@
 
 unsigned ResourceLoadStatisticsDatabaseStore::getNumberOfPrevalentResourcesWithoutUI() const
 {
-    if (m_countPrevalentResourcesWithoutUserInteractionStatement.step() == SQLITE_ROW) {
-        int count = m_countPrevalentResourcesWithoutUserInteractionStatement.getColumnInt(0);
-        resetStatement(m_countPrevalentResourcesWithoutUserInteractionStatement);
+    auto scopedStatement = this->scopedStatement(m_countPrevalentResourcesWithoutUserInteractionStatement, countPrevalentResourcesWithoutUserInteractionQuery, "getNumberOfPrevalentResourcesWithoutUI"_s);
+    if (scopedStatement && scopedStatement->step() == SQLITE_ROW) {
+        int count = m_countPrevalentResourcesWithoutUserInteractionStatement->getColumnInt(0);
         return count;
     }
-    resetStatement(m_countPrevalentResourcesWithoutUserInteractionStatement);
     return 0;
 }
 
@@ -1519,7 +1454,8 @@
 
 bool ResourceLoadStatisticsDatabaseStore::hasStorageAccess(const TopFrameDomain& topFrameDomain, const SubFrameDomain& subFrameDomain) const
 {
-    return relationshipExists(m_storageAccessExistsStatement, domainID(subFrameDomain), topFrameDomain);
+    auto scopedStatement = this->scopedStatement(m_storageAccessExistsStatement, storageAccessExistsQuery, "hasStorageAccess"_s);
+    return relationshipExists(scopedStatement, domainID(subFrameDomain), topFrameDomain);
 }
 
 void ResourceLoadStatisticsDatabaseStore::hasStorageAccess(const SubFrameDomain& subFrameDomain, const TopFrameDomain& topFrameDomain, Optional<FrameIdentifier> frameID, PageIdentifier pageID, CompletionHandler<void(bool)>&& completionHandler)
@@ -1841,18 +1777,17 @@
 void ResourceLoadStatisticsDatabaseStore::setUserInteraction(const RegistrableDomain& domain, bool hadUserInteraction, WallTime mostRecentInteraction)
 {
     ASSERT(!RunLoop::isMain());
-
-    if (m_mostRecentUserInteractionStatement.bindInt(1, hadUserInteraction) != SQLITE_OK
-        || m_mostRecentUserInteractionStatement.bindDouble(2, mostRecentInteraction.secondsSinceEpoch().value()) != SQLITE_OK
-        || m_mostRecentUserInteractionStatement.bindText(3, domain.string()) != SQLITE_OK
-        || m_mostRecentUserInteractionStatement.step() != SQLITE_DONE) {
+    
+    auto scopedStatement = this->scopedStatement(m_mostRecentUserInteractionStatement, mostRecentUserInteractionQuery, "setUserInteraction"_s);
+    if (!scopedStatement
+        || scopedStatement->bindInt(1, hadUserInteraction) != SQLITE_OK
+        || scopedStatement->bindDouble(2, mostRecentInteraction.secondsSinceEpoch().value()) != SQLITE_OK
+        || scopedStatement->bindText(3, domain.string()) != SQLITE_OK
+        || scopedStatement->step() != SQLITE_DONE) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setUserInteraction, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return;
     }
-
-    int resetResult = m_mostRecentUserInteractionStatement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
 }
 
 void ResourceLoadStatisticsDatabaseStore::logUserInteraction(const TopFrameDomain& domain, CompletionHandler<void()>&& completionHandler)
@@ -1901,24 +1836,20 @@
 bool ResourceLoadStatisticsDatabaseStore::hasHadUserInteraction(const RegistrableDomain& domain, OperatingDatesWindow operatingDatesWindow)
 {
     ASSERT(!RunLoop::isMain());
-
-    if (m_hadUserInteractionStatement.bindText(1, domain.string()) != SQLITE_OK
-        || m_hadUserInteractionStatement.step() != SQLITE_ROW) {
+    
+    auto scopedStatement = this->scopedStatement(m_hadUserInteractionStatement, hadUserInteractionQuery, "hasHadUserInteraction"_s);
+    if (!scopedStatement
+        || scopedStatement->bindText(1, domain.string()) != SQLITE_OK
+        || scopedStatement->step() != SQLITE_ROW) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::m_hadUserInteractionStatement failed, error message: %{private}s", this, m_database.lastErrorMsg());
-
-        int resetResult = m_hadUserInteractionStatement.reset();
-        ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
         return false;
     }
 
-    bool hadUserInteraction = !!m_hadUserInteractionStatement.getColumnInt(0);
-    if (!hadUserInteraction) {
-        int resetResult = m_hadUserInteractionStatement.reset();
-        ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
+    bool hadUserInteraction = !!scopedStatement->getColumnInt(0);
+    if (!hadUserInteraction)
         return false;
-    }
     
-    WallTime mostRecentUserInteractionTime = WallTime::fromRawSeconds(m_hadUserInteractionStatement.getColumnDouble(1));
+    WallTime mostRecentUserInteractionTime = WallTime::fromRawSeconds(scopedStatement->getColumnDouble(1));
 
     if (hasStatisticsExpired(mostRecentUserInteractionTime, operatingDatesWindow)) {
         // Drop privacy sensitive data because we no longer need it.
@@ -1927,10 +1858,6 @@
         clearUserInteraction(domain, [] { });
         hadUserInteraction = false;
     }
-    
-    int resetResult = m_hadUserInteractionStatement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
-
     return hadUserInteraction;
 }
 
@@ -1940,28 +1867,26 @@
     if (shouldSkip(domain))
         return;
 
-    if (m_updatePrevalentResourceStatement.bindInt(1, 1) != SQLITE_OK
-        || m_updatePrevalentResourceStatement.bindText(2, domain.string()) != SQLITE_OK
-        || m_updatePrevalentResourceStatement.step() != SQLITE_DONE) {
+    auto scopedUpdatePrevalentResourceStatement = this->scopedStatement(m_updatePrevalentResourceStatement, updatePrevalentResourceQuery, "setPrevalentResource"_s);
+    if (!scopedUpdatePrevalentResourceStatement
+        || scopedUpdatePrevalentResourceStatement->bindInt(1, 1) != SQLITE_OK
+        || scopedUpdatePrevalentResourceStatement->bindText(2, domain.string()) != SQLITE_OK
+        || scopedUpdatePrevalentResourceStatement->step() != SQLITE_DONE) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::m_updatePrevalentResourceStatement failed, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return;
     }
-    
-    int resetResult = m_updatePrevalentResourceStatement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
 
+    auto scopedUpdateVeryPrevalentResourceStatement = this->scopedStatement(m_updateVeryPrevalentResourceStatement, updateVeryPrevalentResourceQuery, "setPrevalentResource updateVeryPrevalentResource"_s);
     if (newPrevalence == ResourceLoadPrevalence::VeryHigh) {
-        if (m_updateVeryPrevalentResourceStatement.bindInt(1, 1) != SQLITE_OK
-            || m_updateVeryPrevalentResourceStatement.bindText(2, domain.string()) != SQLITE_OK
-            || m_updateVeryPrevalentResourceStatement.step() != SQLITE_DONE) {
+        if (!scopedUpdateVeryPrevalentResourceStatement
+            || scopedUpdateVeryPrevalentResourceStatement->bindInt(1, 1) != SQLITE_OK
+            || scopedUpdateVeryPrevalentResourceStatement->bindText(2, domain.string()) != SQLITE_OK
+            || scopedUpdateVeryPrevalentResourceStatement->step() != SQLITE_DONE) {
             RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::m_updateVeryPrevalentResourceStatement failed, error message: %{private}s", this, m_database.lastErrorMsg());
             ASSERT_NOT_REACHED();
             return;
         }
-
-        int resetResult = m_updateVeryPrevalentResourceStatement.reset();
-        ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
     }
 
     StdSet<unsigned> nonPrevalentRedirectionSources;
@@ -1992,9 +1917,13 @@
         return;
     }
 
+    auto scopedStatement = this->scopedStatement(m_getAllDomainsStatement, getAllDomainsQuery, "dumpResourceLoadStatistics"_s);
+    if (!scopedStatement)
+        return;
+    
     Vector<String> domains;
-    while (m_getAllDomainsStatement.step() == SQLITE_ROW)
-        domains.append(m_getAllDomainsStatement.getColumnText(0));
+    while (scopedStatement->step() == SQLITE_ROW)
+        domains.append(scopedStatement->getColumnText(0));
     std::sort(domains.begin(), domains.end(), WTF::codePointCompareLessThan);
 
     StringBuilder result;
@@ -2010,28 +1939,20 @@
             result.append('\n');
         }
     }
-    resetStatement(m_getAllDomainsStatement);
     completionHandler(result.toString());
 }
 
-bool ResourceLoadStatisticsDatabaseStore::predicateValueForDomain(WebCore::SQLiteStatement& predicateStatement, const RegistrableDomain& domain) const
+bool ResourceLoadStatisticsDatabaseStore::predicateValueForDomain(SQLiteStatementAutoResetScope& predicateStatement, const RegistrableDomain& domain) const
 {
     ASSERT(!RunLoop::isMain());
-    
-    if (predicateStatement.bindText(1, domain.string()) != SQLITE_OK
-        || predicateStatement.step() != SQLITE_ROW) {
 
-        int resetResult = predicateStatement.reset();
-        ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
-
+    if (!predicateStatement
+        || predicateStatement->bindText(1, domain.string()) != SQLITE_OK
+        || predicateStatement->step() != SQLITE_ROW) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::predicateValueForDomain failed to bind, error message: %{private}s", this, m_database.lastErrorMsg());
         return false;
     }
-
-    bool result = !!predicateStatement.getColumnInt(0);
-    int resetResult = predicateStatement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
-    return result;
+    return !!predicateStatement->getColumnInt(0);
 }
 
 bool ResourceLoadStatisticsDatabaseStore::isPrevalentResource(const RegistrableDomain& domain) const
@@ -2041,7 +1962,8 @@
     if (shouldSkip(domain))
         return false;
 
-    return predicateValueForDomain(m_isPrevalentResourceStatement, domain);
+    auto scopedStatement = this->scopedStatement(m_isPrevalentResourceStatement, isPrevalentResourceQuery, "isPrevalentResource"_s);
+    return predicateValueForDomain(scopedStatement, domain);
 }
 
 bool ResourceLoadStatisticsDatabaseStore::isVeryPrevalentResource(const RegistrableDomain& domain) const
@@ -2051,7 +1973,8 @@
     if (shouldSkip(domain))
         return false;
 
-    return predicateValueForDomain(m_isVeryPrevalentResourceStatement, domain);
+    auto scopedStatement = this->scopedStatement(m_isVeryPrevalentResourceStatement, isVeryPrevalentResourceQuery, "isVeryPrevalentResource"_s);
+    return predicateValueForDomain(scopedStatement, domain);
 }
 
 bool ResourceLoadStatisticsDatabaseStore::isRegisteredAsSubresourceUnder(const SubResourceDomain& subresourceDomain, const TopFrameDomain& topFrameDomain) const
@@ -2058,14 +1981,16 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    return relationshipExists(m_subresourceUnderTopFrameDomainExists, domainID(subresourceDomain), topFrameDomain);
+    auto scopedStatement = this->scopedStatement(m_subresourceUnderTopFrameDomainExistsStatement, subresourceUnderTopFrameDomainExistsQuery, "isRegisteredAsSubresourceUnder"_s);
+    return relationshipExists(scopedStatement, domainID(subresourceDomain), topFrameDomain);
 }
 
 bool ResourceLoadStatisticsDatabaseStore::isRegisteredAsSubFrameUnder(const SubFrameDomain& subFrameDomain, const TopFrameDomain& topFrameDomain) const
 {
     ASSERT(!RunLoop::isMain());
-
-    return relationshipExists(m_subframeUnderTopFrameDomainExists, domainID(subFrameDomain), topFrameDomain);
+    
+    auto scopedStatement = this->scopedStatement(m_subframeUnderTopFrameDomainExistsStatement, subframeUnderTopFrameDomainExistsQuery, "isRegisteredAsSubFrameUnder"_s);
+    return relationshipExists(scopedStatement, domainID(subFrameDomain), topFrameDomain);
 }
 
 bool ResourceLoadStatisticsDatabaseStore::isRegisteredAsRedirectingTo(const RedirectedFromDomain& redirectedFromDomain, const RedirectedToDomain& redirectedToDomain) const
@@ -2072,7 +1997,8 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    return relationshipExists(m_subresourceUniqueRedirectsToExists, domainID(redirectedFromDomain), redirectedToDomain);
+    auto scopedStatement = this->scopedStatement(m_subresourceUniqueRedirectsToExistsStatement, subresourceUniqueRedirectsToExistsQuery, "isRegisteredAsRedirectingTo"_s);
+    return relationshipExists(scopedStatement, domainID(redirectedFromDomain), redirectedToDomain);
 }
 
 void ResourceLoadStatisticsDatabaseStore::clearPrevalentResource(const RegistrableDomain& domain)
@@ -2084,15 +2010,16 @@
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearPrevalentResource was not completed due to failed insert attempt", this);
         return;
     }
-    if (m_clearPrevalentResourceStatement.bindText(1, domain.string()) != SQLITE_OK
-        || m_clearPrevalentResourceStatement.step() != SQLITE_DONE) {
+    
+    auto scopedStatement = this->scopedStatement(m_clearPrevalentResourceStatement, clearPrevalentResourceQuery, "clearPrevalentResource"_s);
+    
+    if (!scopedStatement
+        || scopedStatement->bindText(1, domain.string()) != SQLITE_OK
+        || scopedStatement->step() != SQLITE_DONE) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearPrevalentResource, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return;
     }
-    
-    int resetResult = m_clearPrevalentResourceStatement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
 }
 
 void ResourceLoadStatisticsDatabaseStore::setGrandfathered(const RegistrableDomain& domain, bool value)
@@ -2104,16 +2031,15 @@
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setGrandfathered was not completed due to failed insert attempt", this);
         return;
     }
-    if (m_updateGrandfatheredStatement.bindInt(1, value) != SQLITE_OK
-        || m_updateGrandfatheredStatement.bindText(2, domain.string()) != SQLITE_OK
-        || m_updateGrandfatheredStatement.step() != SQLITE_DONE) {
+    
+    auto scopedStatement = this->scopedStatement(m_updateGrandfatheredStatement, updateGrandfatheredQuery, "setGrandfathered"_s);
+    if (!scopedStatement
+        || scopedStatement->bindInt(1, value) != SQLITE_OK
+        || scopedStatement->bindText(2, domain.string()) != SQLITE_OK
+        || scopedStatement->step() != SQLITE_DONE) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setGrandfathered failed to bind, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
-        return;
     }
-    
-    int resetResult = m_updateGrandfatheredStatement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
 }
 
 void ResourceLoadStatisticsDatabaseStore::setIsScheduledForAllButCookieDataRemoval(const RegistrableDomain& domain, bool value)
@@ -2125,16 +2051,17 @@
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setIsScheduledForAllButCookieDataRemoval was not completed due to failed insert attempt", this);
         return;
     }
-    if (m_updateIsScheduledForAllButCookieDataRemovalStatement.bindInt(1, value) != SQLITE_OK
-        || m_updateIsScheduledForAllButCookieDataRemovalStatement.bindText(2, domain.string()) != SQLITE_OK
-        || m_updateIsScheduledForAllButCookieDataRemovalStatement.step() != SQLITE_DONE) {
+    
+    auto scopedStatement = this->scopedStatement(m_updateIsScheduledForAllButCookieDataRemovalStatement, updateIsScheduledForAllButCookieDataRemovalQuery, "setIsScheduledForAllButCookieDataRemoval"_s);
+    if (!scopedStatement
+        || scopedStatement->bindInt(1, value) != SQLITE_OK
+        || scopedStatement->bindText(2, domain.string()) != SQLITE_OK
+        || scopedStatement->step() != SQLITE_DONE) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setIsScheduledForAllButCookieDataRemoval failed to bind, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
-        return;
     }
+}
 
-    resetStatement(m_updateIsScheduledForAllButCookieDataRemovalStatement);
-}
 Seconds ResourceLoadStatisticsDatabaseStore::getMostRecentlyUpdatedTimestamp(const RegistrableDomain& subDomain, const TopFrameDomain& topFrameDomain) const
 {
     ASSERT(!RunLoop::isMain());
@@ -2144,26 +2071,25 @@
 
     if (!subFrameDomainID || !topFrameDomainID)
         return Seconds { ResourceLoadStatistics::NoExistingTimestamp };
-
-    if (m_getMostRecentlyUpdatedTimestampStatement.bindInt(1, *subFrameDomainID) != SQLITE_OK
-        || m_getMostRecentlyUpdatedTimestampStatement.bindInt(2, *topFrameDomainID) != SQLITE_OK
-        || m_getMostRecentlyUpdatedTimestampStatement.bindInt(3, *subFrameDomainID) != SQLITE_OK
-        || m_getMostRecentlyUpdatedTimestampStatement.bindInt(4, *topFrameDomainID) != SQLITE_OK
-        || m_getMostRecentlyUpdatedTimestampStatement.bindInt(5, *subFrameDomainID) != SQLITE_OK
-        || m_getMostRecentlyUpdatedTimestampStatement.bindInt(6, *topFrameDomainID) != SQLITE_OK
-        || m_getMostRecentlyUpdatedTimestampStatement.bindInt(7, *subFrameDomainID) != SQLITE_OK
-        || m_getMostRecentlyUpdatedTimestampStatement.bindInt(8, *topFrameDomainID) != SQLITE_OK) {
+    
+    auto scopedStatement = this->scopedStatement(m_getMostRecentlyUpdatedTimestampStatement, getMostRecentlyUpdatedTimestampQuery, "getMostRecentlyUpdatedTimestamp"_s);
+    if (!scopedStatement
+        || scopedStatement->bindInt(1, *subFrameDomainID) != SQLITE_OK
+        || scopedStatement->bindInt(2, *topFrameDomainID) != SQLITE_OK
+        || scopedStatement->bindInt(3, *subFrameDomainID) != SQLITE_OK
+        || scopedStatement->bindInt(4, *topFrameDomainID) != SQLITE_OK
+        || scopedStatement->bindInt(5, *subFrameDomainID) != SQLITE_OK
+        || scopedStatement->bindInt(6, *topFrameDomainID) != SQLITE_OK
+        || scopedStatement->bindInt(7, *subFrameDomainID) != SQLITE_OK
+        || scopedStatement->bindInt(8, *topFrameDomainID) != SQLITE_OK) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::getMostRecentlyUpdatedTimestamp failed to bind, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return Seconds { ResourceLoadStatistics::NoExistingTimestamp  };
     }
-    if (m_getMostRecentlyUpdatedTimestampStatement.step() != SQLITE_ROW) {
-        resetStatement(m_getMostRecentlyUpdatedTimestampStatement);
+    if (scopedStatement->step() != SQLITE_ROW)
         return Seconds { ResourceLoadStatistics::NoExistingTimestamp  };
-    }
-    double mostRecentlyUpdatedTimestamp = m_getMostRecentlyUpdatedTimestampStatement.getColumnDouble(0);
-    resetStatement(m_getMostRecentlyUpdatedTimestampStatement);
-    return Seconds { mostRecentlyUpdatedTimestamp };
+
+    return Seconds { scopedStatement->getColumnDouble(0) };
 }
 
 bool ResourceLoadStatisticsDatabaseStore::isGrandfathered(const RegistrableDomain& domain) const
@@ -2170,7 +2096,8 @@
 {
     ASSERT(!RunLoop::isMain());
 
-    return predicateValueForDomain(m_isGrandfatheredStatement, domain);
+    auto scopedStatement = this->scopedStatement(m_isGrandfatheredStatement, isGrandfatheredQuery, "isGrandfathered"_s);
+    return predicateValueForDomain(scopedStatement, domain);
 }
 
 void ResourceLoadStatisticsDatabaseStore::setSubframeUnderTopFrameDomain(const SubFrameDomain& subFrameDomain, const TopFrameDomain& topFrameDomain)
@@ -2255,24 +2182,20 @@
 std::pair<ResourceLoadStatisticsDatabaseStore::AddedRecord, Optional<unsigned>> ResourceLoadStatisticsDatabaseStore::ensureResourceStatisticsForRegistrableDomain(const RegistrableDomain& domain)
 {
     ASSERT(!RunLoop::isMain());
-
-    if (m_domainIDFromStringStatement.bindText(1, domain.string()) != SQLITE_OK) {
+    
+    auto scopedStatement = this->scopedStatement(m_domainIDFromStringStatement, domainIDFromStringQuery, "ensureResourceStatisticsForRegistrableDomain"_s);
+    if (!scopedStatement
+        || scopedStatement->bindText(1, domain.string()) != SQLITE_OK) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::ensureResourceStatisticsForRegistrableDomain failed, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return { AddedRecord::No, 0 };
     }
     
-    if (m_domainIDFromStringStatement.step() == SQLITE_ROW) {
-        unsigned domainID = m_domainIDFromStringStatement.getColumnInt(0);
-
-        int resetResult = m_domainIDFromStringStatement.reset();
-        ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
+    if (scopedStatement->step() == SQLITE_ROW) {
+        unsigned domainID = scopedStatement->getColumnInt(0);
         return { AddedRecord::No, domainID };
     }
 
-    int resetResult = m_domainIDFromStringStatement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
-
     ResourceLoadStatistics newObservation(domain);
     auto result = insertObservedDomain(newObservation);
 
@@ -2301,14 +2224,14 @@
     auto domainIDToRemove = domainID(domain);
     if (!domainIDToRemove)
         return;
-
-    if (m_removeAllDataStatement.bindInt(1, *domainIDToRemove) != SQLITE_OK
-        || m_removeAllDataStatement.step() != SQLITE_DONE) {
+    
+    auto scopedStatement = this->scopedStatement(m_removeAllDataStatement, removeAllDataQuery, "removeDataForDomain"_s);
+    if (!scopedStatement
+        || scopedStatement->bindInt(1, *domainIDToRemove) != SQLITE_OK
+        || scopedStatement->step() != SQLITE_DONE) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::removeDataForDomain failed, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
     }
-    
-    resetStatement(m_removeAllDataStatement);
 }
 
 void ResourceLoadStatisticsDatabaseStore::clear(CompletionHandler<void()>&& completionHandler)
@@ -2490,16 +2413,15 @@
     Optional<Seconds> expirationDateTime = statisticsEpirationTime();
     if (!expirationDateTime)
         return results;
-
-    if (m_findExpiredUserInteractionStatement.bindDouble(1, expirationDateTime.value().value()) != SQLITE_OK)
+    
+    auto scopedStatement = this->scopedStatement(m_findExpiredUserInteractionStatement, findExpiredUserInteractionQuery, "findExpiredUserInteractions"_s);
+    if (!scopedStatement
+        || scopedStatement->bindDouble(1, expirationDateTime.value().value()) != SQLITE_OK)
         return results;
 
-    while (m_findExpiredUserInteractionStatement.step() == SQLITE_ROW)
-        results.append(m_findExpiredUserInteractionStatement.getColumnInt(0));
+    while (scopedStatement->step() == SQLITE_ROW)
+        results.append(scopedStatement->getColumnInt(0));
 
-    int resetResult = m_findExpiredUserInteractionStatement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
-
     return results;
 }
 
@@ -2659,12 +2581,13 @@
     ASSERT(!RunLoop::isMain());
 
     unsigned count = 0;
-    if (m_observedDomainCount.step() == SQLITE_ROW)
-        count = m_observedDomainCount.getColumnInt(0);
+    auto scopedStatement = this->scopedStatement(m_observedDomainCountStatement, observedDomainCountQuery, "pruneStatisticsIfNeeded"_s);
+    if (!scopedStatement)
+        return;
+    
+    if (scopedStatement->step() == SQLITE_ROW)
+        count = scopedStatement->getColumnInt(0);
 
-    int resetResult = m_observedDomainCount.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
-
     if (count <= parameters().maxStatisticsEntries)
         return;
 
@@ -2699,17 +2622,16 @@
 void ResourceLoadStatisticsDatabaseStore::updateLastSeen(const RegistrableDomain& domain, WallTime lastSeen)
 {
     ASSERT(!RunLoop::isMain());
-
-    if (m_updateLastSeenStatement.bindDouble(1, lastSeen.secondsSinceEpoch().value()) != SQLITE_OK
-        || m_updateLastSeenStatement.bindText(2, domain.string()) != SQLITE_OK
-        || m_updateLastSeenStatement.step() != SQLITE_DONE) {
+    
+    auto scopedStatement = this->scopedStatement(m_updateLastSeenStatement, updateLastSeenQuery, "updateLastSeen"_s);
+    if (!scopedStatement
+        || scopedStatement->bindDouble(1, lastSeen.secondsSinceEpoch().value()) != SQLITE_OK
+        || scopedStatement->bindText(2, domain.string()) != SQLITE_OK
+        || scopedStatement->step() != SQLITE_DONE) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::updateLastSeen failed to bind, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return;
     }
-    
-    int resetResult = m_updateLastSeenStatement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
 }
 
 void ResourceLoadStatisticsDatabaseStore::setLastSeen(const RegistrableDomain& domain, Seconds seconds)
@@ -2760,17 +2682,16 @@
 void ResourceLoadStatisticsDatabaseStore::updateDataRecordsRemoved(const RegistrableDomain& domain, int value)
 {
     ASSERT(!RunLoop::isMain());
-
-    if (m_updateDataRecordsRemovedStatement.bindInt(1, value) != SQLITE_OK
-        || m_updateDataRecordsRemovedStatement.bindText(2, domain.string()) != SQLITE_OK
-        || m_updateDataRecordsRemovedStatement.step() != SQLITE_DONE) {
+    
+    auto scopedStatement = this->scopedStatement(m_updateDataRecordsRemovedStatement, updateDataRecordsRemovedQuery, "updateDataRecordsRemoved"_s);
+    if (!scopedStatement
+        || scopedStatement->bindInt(1, value) != SQLITE_OK
+        || scopedStatement->bindText(2, domain.string()) != SQLITE_OK
+        || scopedStatement->step() != SQLITE_DONE) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::updateDataRecordsRemoved failed to bind, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return;
     }
-
-    int resetResult = m_updateDataRecordsRemovedStatement.reset();
-    ASSERT_UNUSED(resetResult, resetResult == SQLITE_OK);
 }
 
 bool ResourceLoadStatisticsDatabaseStore::isCorrectSubStatisticsCount(const RegistrableDomain& subframeDomain, const TopFrameDomain& topFrameDomain)
@@ -2825,16 +2746,17 @@
 {
     auto result = emptyString();
     
-    if (m_domainStringFromDomainIDStatement.bindInt(1, domainID) != SQLITE_OK) {
+    auto scopedStatement = this->scopedStatement(m_domainStringFromDomainIDStatement, domainStringFromDomainIDQuery, "getDomainStringFromDomainID"_s);
+    if (!scopedStatement
+        || scopedStatement->bindInt(1, domainID) != SQLITE_OK) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::getDomainStringFromDomainID. Statement failed to prepare or bind, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return result;
     }
     
-    if (m_domainStringFromDomainIDStatement.step() == SQLITE_ROW)
-        result = m_domainStringFromDomainIDStatement.getColumnText(0);
+    if (scopedStatement->step() == SQLITE_ROW)
+        result = m_domainStringFromDomainIDStatement->getColumnText(0);
     
-    resetStatement(m_domainStringFromDomainIDStatement);
     return result;
 }
 
@@ -2901,8 +2823,10 @@
 
 void ResourceLoadStatisticsDatabaseStore::resourceToString(StringBuilder& builder, const String& domain) const
 {
-    if (m_getResourceDataByDomainNameStatement.bindText(1, domain) != SQLITE_OK
-        || m_getResourceDataByDomainNameStatement.step() != SQLITE_ROW) {
+    auto scopedStatement = this->scopedStatement(m_getResourceDataByDomainNameStatement, getResourceDataByDomainNameQuery, "resourceToString"_s);
+    if (!scopedStatement
+        || scopedStatement->bindText(1, domain) != SQLITE_OK
+        || scopedStatement->step() != SQLITE_ROW) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::resourceToString. Statement failed to bind or domain was not found, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return;
@@ -2913,15 +2837,15 @@
     builder.append('\n');
     
     // User interaction
-    appendBoolean(builder, "hadUserInteraction", m_getResourceDataByDomainNameStatement.getColumnInt(HadUserInteractionIndex));
+    appendBoolean(builder, "hadUserInteraction", m_getResourceDataByDomainNameStatement->getColumnInt(HadUserInteractionIndex));
     builder.append('\n');
     builder.appendLiteral("    mostRecentUserInteraction: ");
-    if (hasHadRecentUserInteraction(Seconds(m_getResourceDataByDomainNameStatement.getColumnDouble(MostRecentUserInteractionTimeIndex))))
+    if (hasHadRecentUserInteraction(Seconds(m_getResourceDataByDomainNameStatement->getColumnDouble(MostRecentUserInteractionTimeIndex))))
         builder.appendLiteral("within 24 hours");
     else
         builder.appendLiteral("-1");
     builder.append('\n');
-    appendBoolean(builder, "grandfathered", m_getResourceDataByDomainNameStatement.getColumnInt(GrandfatheredIndex));
+    appendBoolean(builder, "grandfathered", m_getResourceDataByDomainNameStatement->getColumnInt(GrandfatheredIndex));
     builder.append('\n');
 
     // Storage access
@@ -2934,7 +2858,7 @@
     appendSubStatisticList(builder, "TopFrameLinkDecorationsFrom", domain);
     appendSubStatisticList(builder, "TopFrameLoadedThirdPartyScripts", domain);
 
-    appendBoolean(builder, "IsScheduledForAllButCookieDataRemoval", m_getResourceDataByDomainNameStatement.getColumnInt(IsScheduledForAllButCookieDataRemovalIndex));
+    appendBoolean(builder, "IsScheduledForAllButCookieDataRemoval", m_getResourceDataByDomainNameStatement->getColumnInt(IsScheduledForAllButCookieDataRemovalIndex));
     builder.append('\n');
 
     // Subframe stats
@@ -2946,54 +2870,58 @@
     appendSubStatisticList(builder, "SubresourceUniqueRedirectsFrom", domain);
 
     // Prevalent Resource
-    appendBoolean(builder, "isPrevalentResource", m_getResourceDataByDomainNameStatement.getColumnInt(IsPrevalentIndex));
+    appendBoolean(builder, "isPrevalentResource", m_getResourceDataByDomainNameStatement->getColumnInt(IsPrevalentIndex));
     builder.append('\n');
-    appendBoolean(builder, "isVeryPrevalentResource", m_getResourceDataByDomainNameStatement.getColumnInt(IsVeryPrevalentIndex));
+    appendBoolean(builder, "isVeryPrevalentResource", m_getResourceDataByDomainNameStatement->getColumnInt(IsVeryPrevalentIndex));
     builder.append('\n');
     builder.appendLiteral("    dataRecordsRemoved: ");
-    builder.appendNumber(m_getResourceDataByDomainNameStatement.getColumnInt(DataRecordsRemovedIndex));
+    builder.appendNumber(m_getResourceDataByDomainNameStatement->getColumnInt(DataRecordsRemovedIndex));
     builder.append('\n');
-
-    resetStatement(m_getResourceDataByDomainNameStatement);
 }
 
 bool ResourceLoadStatisticsDatabaseStore::domainIDExistsInDatabase(int domainID)
 {
-    if (m_linkDecorationExistsStatement.bindInt(1, domainID) != SQLITE_OK
-        || m_linkDecorationExistsStatement.bindInt(2, domainID) != SQLITE_OK
-        || m_scriptLoadExistsStatement.bindInt(1, domainID) != SQLITE_OK
-        || m_scriptLoadExistsStatement.bindInt(2, domainID) != SQLITE_OK
-        || m_subFrameExistsStatement.bindInt(1, domainID) != SQLITE_OK
-        || m_subFrameExistsStatement.bindInt(2, domainID) != SQLITE_OK
-        || m_subResourceExistsStatement.bindInt(1, domainID) != SQLITE_OK
-        || m_subResourceExistsStatement.bindInt(2, domainID) != SQLITE_OK
-        || m_uniqueRedirectExistsStatement.bindInt(1, domainID) != SQLITE_OK
-        || m_uniqueRedirectExistsStatement.bindInt(2, domainID) != SQLITE_OK
-        || m_observedDomainsExistsStatement.bindInt(1, domainID) != SQLITE_OK) {
+    auto scopedLinkDecorationExistsStatement = this->scopedStatement(m_linkDecorationExistsStatement, linkDecorationExistsQuery, "domainIDExistsInDatabase"_s);
+    auto scopedScriptLoadExistsStatement = this->scopedStatement(m_scriptLoadExistsStatement, scriptLoadExistsQuery, "domainIDExistsInDatabase linkDecorationExistsStatement"_s);
+    auto scopedSubFrameExistsStatement = this->scopedStatement(m_subFrameExistsStatement, subFrameExistsQuery, "domainIDExistsInDatabase subFrameExistsStatement"_s);
+    auto scopedSubResourceExistsStatement = this->scopedStatement(m_subResourceExistsStatement, subResourceExistsQuery, "domainIDExistsInDatabase subResourceExistsStatement"_s);
+    auto scopedUniqueRedirectExistsStatement = this->scopedStatement(m_uniqueRedirectExistsStatement, uniqueRedirectExistsQuery, "domainIDExistsInDatabase uniqueRedirectExistsStatement"_s);
+    auto scopedObservedDomainsExistsStatement = this->scopedStatement(m_observedDomainsExistsStatement, observedDomainsExistsQuery, "domainIDExistsInDatabase observedDomainsExistsStatement"_s);
+    
+    if (!scopedLinkDecorationExistsStatement
+        || !scopedScriptLoadExistsStatement
+        || !scopedSubFrameExistsStatement
+        || !scopedSubResourceExistsStatement
+        || !scopedUniqueRedirectExistsStatement
+        || !scopedObservedDomainsExistsStatement
+        || m_linkDecorationExistsStatement->bindInt(1, domainID) != SQLITE_OK
+        || m_linkDecorationExistsStatement->bindInt(2, domainID) != SQLITE_OK
+        || m_scriptLoadExistsStatement->bindInt(1, domainID) != SQLITE_OK
+        || m_scriptLoadExistsStatement->bindInt(2, domainID) != SQLITE_OK
+        || m_subFrameExistsStatement->bindInt(1, domainID) != SQLITE_OK
+        || m_subFrameExistsStatement->bindInt(2, domainID) != SQLITE_OK
+        || m_subResourceExistsStatement->bindInt(1, domainID) != SQLITE_OK
+        || m_subResourceExistsStatement->bindInt(2, domainID) != SQLITE_OK
+        || m_uniqueRedirectExistsStatement->bindInt(1, domainID) != SQLITE_OK
+        || m_uniqueRedirectExistsStatement->bindInt(2, domainID) != SQLITE_OK
+        || m_observedDomainsExistsStatement->bindInt(1, domainID) != SQLITE_OK) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::domainIDExistsInDatabase failed to bind, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return false;
     }
 
-    if (m_linkDecorationExistsStatement.step() != SQLITE_ROW
-        || m_scriptLoadExistsStatement.step() != SQLITE_ROW
-        || m_subFrameExistsStatement.step() != SQLITE_ROW
-        || m_subResourceExistsStatement.step() != SQLITE_ROW
-        || m_uniqueRedirectExistsStatement.step() != SQLITE_ROW
-        || m_observedDomainsExistsStatement.step() != SQLITE_ROW) {
+    if (m_linkDecorationExistsStatement->step() != SQLITE_ROW
+        || m_scriptLoadExistsStatement->step() != SQLITE_ROW
+        || m_subFrameExistsStatement->step() != SQLITE_ROW
+        || m_subResourceExistsStatement->step() != SQLITE_ROW
+        || m_uniqueRedirectExistsStatement->step() != SQLITE_ROW
+        || m_observedDomainsExistsStatement->step() != SQLITE_ROW) {
         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::domainIDExistsInDatabase failed to step, error message: %{private}s", this, m_database.lastErrorMsg());
         ASSERT_NOT_REACHED();
         return false;
     }
-    
-    resetStatement(m_linkDecorationExistsStatement);
-    resetStatement(m_scriptLoadExistsStatement);
-    resetStatement(m_subFrameExistsStatement);
-    resetStatement(m_subResourceExistsStatement);
-    resetStatement(m_uniqueRedirectExistsStatement);
-    resetStatement(m_observedDomainsExistsStatement);
 
-    return m_linkDecorationExistsStatement.getColumnInt(0) || m_scriptLoadExistsStatement.getColumnInt(0) || m_subFrameExistsStatement.getColumnInt(0) || m_subResourceExistsStatement.getColumnInt(0) || m_uniqueRedirectExistsStatement.getColumnInt(0) || m_observedDomainsExistsStatement.getColumnInt(0);
+    return m_linkDecorationExistsStatement->getColumnInt(0) || m_scriptLoadExistsStatement->getColumnInt(0) || m_subFrameExistsStatement->getColumnInt(0) || m_subResourceExistsStatement->getColumnInt(0) || m_uniqueRedirectExistsStatement->getColumnInt(0) || m_observedDomainsExistsStatement->getColumnInt(0);
 }
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h (261891 => 261892)


--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h	2020-05-19 22:02:50 UTC (rev 261891)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h	2020-05-19 22:55:49 UTC (rev 261892)
@@ -31,6 +31,7 @@
 #include "WebResourceLoadStatisticsStore.h"
 #include <WebCore/SQLiteDatabase.h>
 #include <WebCore/SQLiteStatement.h>
+#include <WebCore/SQLiteStatementAutoResetScope.h>
 #include <pal/SessionID.h>
 #include <wtf/CompletionHandler.h>
 #include <wtf/StdSet.h>
@@ -79,11 +80,12 @@
 class ResourceLoadStatisticsDatabaseStore final : public ResourceLoadStatisticsStore {
 public:
     ResourceLoadStatisticsDatabaseStore(WebResourceLoadStatisticsStore&, WorkQueue&, ShouldIncludeLocalhost, const String& storageDirectoryPath, PAL::SessionID);
-
+    ~ResourceLoadStatisticsDatabaseStore();
     void populateFromMemoryStore(const ResourceLoadStatisticsMemoryStore&);
     void mergeStatistics(Vector<ResourceLoadStatistics>&&) override;
     void clear(CompletionHandler<void()>&&) override;
     bool isEmpty() const override;
+    void close();
 
     Vector<WebResourceLoadStatisticsStore::ThirdPartyData> aggregatedThirdPartyData() const override;
     void updateCookieBlocking(CompletionHandler<void()>&&) override;
@@ -148,6 +150,9 @@
     void enableForeignKeys();
     bool isMigrationNecessary();
     void migrateDataToNewTablesIfNecessary();
+    void destroyStatements();
+    WebCore::SQLiteStatementAutoResetScope scopedStatement(std::unique_ptr<WebCore::SQLiteStatement>&, const String&, const String&) const;
+
     bool hasStorageAccess(const TopFrameDomain&, const SubFrameDomain&) const;
     Vector<WebResourceLoadStatisticsStore::ThirdPartyDataForSpecificFirstParty> getThirdPartyDataForSpecificFirstPartyDomains(unsigned, const RegistrableDomain&) const;
     void openAndUpdateSchemaIfNecessary();
@@ -155,7 +160,7 @@
     String getSubStatisticStatement(const String&) const;
     void appendSubStatisticList(StringBuilder&, const String& tableName, const String& domain) const;
     void mergeStatistic(const ResourceLoadStatistics&);
-    void merge(WebCore::SQLiteStatement&, const ResourceLoadStatistics&);
+    void merge(WebCore::SQLiteStatement*, const ResourceLoadStatistics&);
     void clearDatabaseContents();
     unsigned getNumberOfPrevalentResources() const;
     unsigned getNumberOfPrevalentResourcesWithUI() const;
@@ -167,8 +172,7 @@
     bool insertObservedDomain(const ResourceLoadStatistics&) WARN_UNUSED_RETURN;
     void insertDomainRelationships(const ResourceLoadStatistics&);
     void insertDomainRelationshipList(const String&, const HashSet<RegistrableDomain>&, unsigned);
-    bool insertDomainRelationship(WebCore::SQLiteStatement&, unsigned domainID, const RegistrableDomain& topFrameDomain);
-    bool relationshipExists(WebCore::SQLiteStatement&, Optional<unsigned> firstDomainID, const RegistrableDomain& secondDomain) const;
+    bool relationshipExists(WebCore::SQLiteStatementAutoResetScope&, Optional<unsigned> firstDomainID, const RegistrableDomain& secondDomain) const;
     Optional<unsigned> domainID(const RegistrableDomain&) const;
     bool domainExists(const RegistrableDomain&) const;
     void updateLastSeen(const RegistrableDomain&, WallTime);
@@ -206,7 +210,7 @@
     };
     HashMap<unsigned, NotVeryPrevalentResources> findNotVeryPrevalentResources();
 
-    bool predicateValueForDomain(WebCore::SQLiteStatement&, const RegistrableDomain&) const;
+    bool predicateValueForDomain(WebCore::SQLiteStatementAutoResetScope&, const RegistrableDomain&) const;
 
     bool areAllThirdPartyCookiesBlockedUnder(const TopFrameDomain&) override;
     CookieAccess cookieAccess(const SubResourceDomain&, const TopFrameDomain&);
@@ -229,50 +233,48 @@
 
     bool createUniqueIndices();
     bool createSchema();
-    bool prepareStatements();
     String ensureAndMakeDomainList(const HashSet<RegistrableDomain>&);
-
     
     const String m_storageDirectoryPath;
     mutable WebCore::SQLiteDatabase m_database;
-    mutable WebCore::SQLiteStatement m_observedDomainCount;
-    WebCore::SQLiteStatement m_insertObservedDomainStatement;
-    WebCore::SQLiteStatement m_insertTopLevelDomainStatement;
-    mutable WebCore::SQLiteStatement m_domainIDFromStringStatement;
-    mutable WebCore::SQLiteStatement m_topFrameLinkDecorationsFromExists;
-    mutable WebCore::SQLiteStatement m_topFrameLoadedThirdPartyScriptsExists;
-    mutable WebCore::SQLiteStatement m_subframeUnderTopFrameDomainExists;
-    mutable WebCore::SQLiteStatement m_subresourceUnderTopFrameDomainExists;
-    mutable WebCore::SQLiteStatement m_subresourceUniqueRedirectsToExists;
-    WebCore::SQLiteStatement m_mostRecentUserInteractionStatement;
-    WebCore::SQLiteStatement m_updateLastSeenStatement;
-    mutable WebCore::SQLiteStatement m_updateDataRecordsRemovedStatement;
-    WebCore::SQLiteStatement m_updatePrevalentResourceStatement;
-    mutable WebCore::SQLiteStatement m_isPrevalentResourceStatement;
-    WebCore::SQLiteStatement m_updateVeryPrevalentResourceStatement;
-    mutable WebCore::SQLiteStatement m_isVeryPrevalentResourceStatement;
-    WebCore::SQLiteStatement m_clearPrevalentResourceStatement;
-    mutable WebCore::SQLiteStatement m_hadUserInteractionStatement;
-    WebCore::SQLiteStatement m_updateGrandfatheredStatement;
-    mutable WebCore::SQLiteStatement m_updateIsScheduledForAllButCookieDataRemovalStatement;
-    mutable WebCore::SQLiteStatement m_isGrandfatheredStatement;
-    mutable WebCore::SQLiteStatement m_findExpiredUserInteractionStatement;
-    mutable WebCore::SQLiteStatement m_countPrevalentResourcesStatement;
-    mutable WebCore::SQLiteStatement m_countPrevalentResourcesWithUserInteractionStatement;
-    mutable WebCore::SQLiteStatement m_countPrevalentResourcesWithoutUserInteractionStatement;
-    mutable WebCore::SQLiteStatement m_getResourceDataByDomainNameStatement;
-    mutable WebCore::SQLiteStatement m_getAllDomainsStatement;
-    mutable WebCore::SQLiteStatement m_domainStringFromDomainIDStatement;
-    mutable WebCore::SQLiteStatement m_getAllSubStatisticsStatement;
-    mutable WebCore::SQLiteStatement m_storageAccessExistsStatement;
-    mutable WebCore::SQLiteStatement m_getMostRecentlyUpdatedTimestampStatement;
-    mutable WebCore::SQLiteStatement m_linkDecorationExistsStatement;
-    mutable WebCore::SQLiteStatement m_scriptLoadExistsStatement;
-    mutable WebCore::SQLiteStatement m_subFrameExistsStatement;
-    mutable WebCore::SQLiteStatement m_subResourceExistsStatement;
-    mutable WebCore::SQLiteStatement m_uniqueRedirectExistsStatement;
-    mutable WebCore::SQLiteStatement m_observedDomainsExistsStatement;
-    mutable WebCore::SQLiteStatement m_removeAllDataStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_observedDomainCountStatement;
+    std::unique_ptr<WebCore::SQLiteStatement> m_insertObservedDomainStatement;
+    std::unique_ptr<WebCore::SQLiteStatement> m_insertTopLevelDomainStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_domainIDFromStringStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_topFrameLinkDecorationsFromExistsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_topFrameLoadedThirdPartyScriptsExistsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_subframeUnderTopFrameDomainExistsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_subresourceUnderTopFrameDomainExistsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_subresourceUniqueRedirectsToExistsStatement;
+    std::unique_ptr<WebCore::SQLiteStatement> m_mostRecentUserInteractionStatement;
+    std::unique_ptr<WebCore::SQLiteStatement> m_updateLastSeenStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_updateDataRecordsRemovedStatement;
+    std::unique_ptr<WebCore::SQLiteStatement> m_updatePrevalentResourceStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_isPrevalentResourceStatement;
+    std::unique_ptr<WebCore::SQLiteStatement> m_updateVeryPrevalentResourceStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_isVeryPrevalentResourceStatement;
+    std::unique_ptr<WebCore::SQLiteStatement> m_clearPrevalentResourceStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_hadUserInteractionStatement;
+    std::unique_ptr<WebCore::SQLiteStatement> m_updateGrandfatheredStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_updateIsScheduledForAllButCookieDataRemovalStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_isGrandfatheredStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_findExpiredUserInteractionStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_countPrevalentResourcesStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_countPrevalentResourcesWithUserInteractionStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_countPrevalentResourcesWithoutUserInteractionStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_getResourceDataByDomainNameStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_getAllDomainsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_domainStringFromDomainIDStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_getAllSubStatisticsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_storageAccessExistsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_getMostRecentlyUpdatedTimestampStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_linkDecorationExistsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_scriptLoadExistsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_subFrameExistsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_subResourceExistsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_uniqueRedirectExistsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_observedDomainsExistsStatement;
+    mutable std::unique_ptr<WebCore::SQLiteStatement> m_removeAllDataStatement;
     PAL::SessionID m_sessionID;
     bool m_isNewResourceLoadStatisticsDatabaseFile { false };
 };
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to