<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[277571] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/277571">277571</a></dd>
<dt>Author</dt> <dd>cdumez@apple.com</dd>
<dt>Date</dt> <dd>2021-05-16 10:18:30 -0700 (Sun, 16 May 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Modernize / Optimize SQLiteStatement creation and preparation
https://bugs.webkit.org/show_bug.cgi?id=225791

Reviewed by Sam Weinig.

Source/WebCore:

Modernize / Optimize SQLiteStatement creation and preparation:
- The SQLiteStatement constructor is now private so that we never have a
  SQLiteStatement that has not been "prepared". Only the SQLiteDatabase
  can now construct SQLiteStatement objects. We already needed to pass
  a SQLiteDatabase reference when constructing the SQLiteStatement anyway.
- The construct AND prepare a SQLiteStatement, we now call
  SQLiteDatabase::prepareStatement() to get a stack object or
  SQLiteDatabase::prepareHeapStatement() to get a heap one. These functions
  return an Expected<> type so they will either return a "prepared"
  SQLiteStatement or an unexpected SQLite error code.
- The prepare*Statement() functions now avoid String allocations in most
  cases thanks to overloads taking in the query as an ASCIILiteral.
- Drop finalize() function on SQLiteStatement so SQLiteStatement objects
  are always valid. It simplifies the implementation of SQLiteStatement
  member functions. The SQLiteStatement destructor "finalizes" the statement
  so users can simply destroy the SQLiteStatement if they need the object
  to be finalize at a certain point (e.g. before closing a database).
- Drop the prepare() & prepareAndStep() SQLiteStatement member functions now
  that SQLiteStatement are always prepared.
- Stop storing the SQL query as a String data member in SQLiteStatement class.
  This is no longer needed now that they is no separe prepare step after the
  construction. This makes the SQLiteStatement a bit smaller.

* Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
(WebCore::IDBServer::createOrMigrateRecordsTableIfNecessary):
(WebCore::IDBServer::SQLiteIDBBackingStore::ensureValidBlobTables):
(WebCore::IDBServer::SQLiteIDBBackingStore::ensureValidIndexRecordsTable):
(WebCore::IDBServer::SQLiteIDBBackingStore::ensureValidIndexRecordsIndex):
(WebCore::IDBServer::SQLiteIDBBackingStore::ensureValidIndexRecordsRecordIndex):
(WebCore::IDBServer::SQLiteIDBBackingStore::createAndPopulateInitialDatabaseInfo):
(WebCore::IDBServer::SQLiteIDBBackingStore::ensureValidObjectStoreInfoTable):
(WebCore::IDBServer::SQLiteIDBBackingStore::migrateIndexInfoTableForIDUpdate):
(WebCore::IDBServer::SQLiteIDBBackingStore::migrateIndexRecordsTableForIDUpdate):
(WebCore::IDBServer::SQLiteIDBBackingStore::extractExistingDatabaseInfo):
(WebCore::IDBServer::SQLiteIDBBackingStore::databaseNameAndVersionFromFile):
(WebCore::IDBServer::SQLiteIDBBackingStore::beginTransaction):
(WebCore::IDBServer::SQLiteIDBBackingStore::deleteBackingStore):
(WebCore::IDBServer::SQLiteIDBBackingStore::cachedStatement):
* Modules/indexeddb/server/SQLiteIDBCursor.cpp:
(WebCore::IDBServer::SQLiteIDBCursor::createSQLiteStatement):
(WebCore::IDBServer::SQLiteIDBCursor::resetAndRebindPreIndexStatementIfNecessary):
(WebCore::IDBServer::SQLiteIDBCursor::internalFetchNextRecord):
* Modules/webdatabase/Database.cpp:
(WebCore::setTextValueInDatabase):
(WebCore::retrieveTextResultFromDatabase):
(WebCore::Database::performGetTableNames):
* Modules/webdatabase/DatabaseTracker.cpp:
(WebCore::DatabaseTracker::hasEntryForOriginNoLock):
(WebCore::DatabaseTracker::hasEntryForDatabase):
(WebCore::DatabaseTracker::fullPathForDatabaseNoLock):
(WebCore::DatabaseTracker::origins):
(WebCore::DatabaseTracker::databaseNamesNoLock):
(WebCore::DatabaseTracker::detailsForNameAndOrigin):
(WebCore::DatabaseTracker::setDatabaseDetails):
(WebCore::DatabaseTracker::quotaNoLock):
(WebCore::DatabaseTracker::setQuota):
(WebCore::DatabaseTracker::addDatabase):
(WebCore::DatabaseTracker::deleteOrigin):
(WebCore::DatabaseTracker::deleteDatabase):
(WebCore::DatabaseTracker::removeDeletedOpenedDatabases):
(WebCore::DatabaseTracker::deleteDatabaseFileIfEmpty):
* Modules/webdatabase/SQLStatement.cpp:
(WebCore::SQLStatement::execute):
* loader/appcache/ApplicationCacheStorage.cpp:
(WebCore::ApplicationCacheStorage::loadCacheGroup):
(WebCore::ApplicationCacheStorage::loadManifestHostHashes):
(WebCore::ApplicationCacheStorage::cacheGroupForURL):
(WebCore::ApplicationCacheStorage::fallbackCacheGroupForURL):
(WebCore::ApplicationCacheStorage::calculateQuotaForOrigin):
(WebCore::ApplicationCacheStorage::calculateUsageForOrigin):
(WebCore::ApplicationCacheStorage::calculateRemainingSizeForOriginExcludingCache):
(WebCore::ApplicationCacheStorage::storeUpdatedQuotaForOrigin):
(WebCore::ApplicationCacheStorage::verifySchemaVersion):
(WebCore::ApplicationCacheStorage::executeStatement):
(WebCore::ApplicationCacheStorage::store):
(WebCore::ApplicationCacheStorage::storeUpdatedType):
(WebCore::ApplicationCacheStorage::ensureOriginRecord):
(WebCore::ApplicationCacheStorage::storeNewestCache):
(WebCore::ApplicationCacheStorage::loadCache):
(WebCore::ApplicationCacheStorage::remove):
(WebCore::ApplicationCacheStorage::manifestURLs):
(WebCore::ApplicationCacheStorage::deleteCacheGroupRecord):
(WebCore::ApplicationCacheStorage::checkForDeletedResources):
(WebCore::ApplicationCacheStorage::flatFileAreaSize):
* platform/network/curl/CookieJarDB.cpp:
(WebCore::CookieJarDB::verifySchemaVersion):
(WebCore::CookieJarDB::checkDatabaseValidity):
(WebCore::CookieJarDB::searchCookies):
(WebCore::CookieJarDB::getAllCookies):
(WebCore::CookieJarDB::allDomains):
(WebCore::CookieJarDB::createPrepareStatement):
(WebCore::CookieJarDB::executeSql):
* platform/sql/SQLiteDatabase.cpp:
(WebCore::SQLiteDatabase::open):
(WebCore::SQLiteDatabase::useWALJournalMode):
(WebCore::SQLiteDatabase::maximumSize):
(WebCore::SQLiteDatabase::setMaximumSize):
(WebCore::SQLiteDatabase::pageSize):
(WebCore::SQLiteDatabase::freeSpaceSize):
(WebCore::SQLiteDatabase::totalSize):
(WebCore::SQLiteDatabase::executeCommand):
(WebCore::SQLiteDatabase::returnsAtLeastOneResult):
(WebCore::SQLiteDatabase::tableExists):
(WebCore::SQLiteDatabase::clearAllTables):
(WebCore::SQLiteDatabase::turnOnIncrementalAutoVacuum):
(WebCore::constructAndPrepareStatement):
(WebCore::SQLiteDatabase::prepareStatement):
(WebCore::SQLiteDatabase::prepareHeapStatement):
* platform/sql/SQLiteDatabase.h:
* platform/sql/SQLiteStatement.cpp:
(WebCore::SQLiteStatement::SQLiteStatement):
(WebCore::SQLiteStatement::~SQLiteStatement):
(WebCore::SQLiteStatement::step):
(WebCore::SQLiteStatement::reset):
(WebCore::SQLiteStatement::executeCommand):
(WebCore::SQLiteStatement::returnsAtLeastOneResult):
(WebCore::SQLiteStatement::bindBlob):
(WebCore::SQLiteStatement::bindText):
(WebCore::SQLiteStatement::bindInt):
(WebCore::SQLiteStatement::bindInt64):
(WebCore::SQLiteStatement::bindDouble):
(WebCore::SQLiteStatement::bindNull):
(WebCore::SQLiteStatement::bindParameterCount const):
(WebCore::SQLiteStatement::columnCount):
(WebCore::SQLiteStatement::isColumnNull):
(WebCore::SQLiteStatement::isColumnDeclaredAsBlob):
(WebCore::SQLiteStatement::getColumnName):
(WebCore::SQLiteStatement::getColumnValue):
(WebCore::SQLiteStatement::getColumnText):
(WebCore::SQLiteStatement::getColumnDouble):
(WebCore::SQLiteStatement::getColumnInt):
(WebCore::SQLiteStatement::getColumnInt64):
(WebCore::SQLiteStatement::getColumnBlobAsString):
(WebCore::SQLiteStatement::getColumnBlobAsVector):
(WebCore::SQLiteStatement::returnTextResults):
(WebCore::SQLiteStatement::returnIntResults):
(WebCore::SQLiteStatement::returnInt64Results):
(WebCore::SQLiteStatement::returnDoubleResults):
* platform/sql/SQLiteStatement.h:
* platform/win/SearchPopupMenuDB.cpp:
(WebCore::SearchPopupMenuDB::checkDatabaseValidity):
(WebCore::SearchPopupMenuDB::verifySchemaVersion):
(WebCore::SearchPopupMenuDB::executeSimpleSql):
(WebCore::SearchPopupMenuDB::createPreparedStatement):
* workers/service/server/RegistrationDatabase.cpp:
(WebCore::RegistrationDatabase::ensureValidRecordsTable):
(WebCore::RegistrationDatabase::doPushChanges):
(WebCore::RegistrationDatabase::importRecords):

Source/WebKit:

Update code base now that the SQLiteDatabase & SQLiteStatement API has changed.
Also use more ASCIILiterals.

* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
(WebKit::ResourceLoadStatisticsDatabaseStore::openITPDatabase):
(WebKit::ResourceLoadStatisticsDatabaseStore::checkForMissingTablesInSchema):
(WebKit::ResourceLoadStatisticsDatabaseStore::enableForeignKeys):
(WebKit::ResourceLoadStatisticsDatabaseStore::currentTableAndIndexQueries):
(WebKit::ResourceLoadStatisticsDatabaseStore::missingUniqueIndices):
(WebKit::ResourceLoadStatisticsDatabaseStore::migrateDataToNewTablesIfNecessary):
(WebKit::ResourceLoadStatisticsDatabaseStore::columnsForTable):
(WebKit::ResourceLoadStatisticsDatabaseStore::addMissingColumnsToTable):
(WebKit::ResourceLoadStatisticsDatabaseStore::renameColumnInTable):
(WebKit::ResourceLoadStatisticsDatabaseStore::openAndUpdateSchemaIfNecessary):
(WebKit::ResourceLoadStatisticsDatabaseStore::scopedStatement const):
(WebKit::ResourceLoadStatisticsDatabaseStore::insertDomainRelationshipList):
(WebKit::ResourceLoadStatisticsDatabaseStore::aggregatedThirdPartyData const):
(WebKit::ResourceLoadStatisticsDatabaseStore::incrementRecordsDeletedCountForDomains):
(WebKit::ResourceLoadStatisticsDatabaseStore::recursivelyFindNonPrevalentDomainsThatRedirectedToThisDomain):
(WebKit::ResourceLoadStatisticsDatabaseStore::markAsPrevalentIfHasRedirectedToPrevalent):
(WebKit::ResourceLoadStatisticsDatabaseStore::findNotVeryPrevalentResources):
(WebKit::ResourceLoadStatisticsDatabaseStore::requestStorageAccess):
(WebKit::ResourceLoadStatisticsDatabaseStore::grandfatherDataForDomains):
(WebKit::ResourceLoadStatisticsDatabaseStore::clearTopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement):
(WebKit::ResourceLoadStatisticsDatabaseStore::clearUserInteraction):
(WebKit::ResourceLoadStatisticsDatabaseStore::setDomainsAsPrevalent):
(WebKit::ResourceLoadStatisticsDatabaseStore::cookieAccess):
(WebKit::ResourceLoadStatisticsDatabaseStore::hasUserGrantedStorageAccessThroughPrompt):
(WebKit::ResourceLoadStatisticsDatabaseStore::domainsToBlockAndDeleteCookiesFor const):
(WebKit::ResourceLoadStatisticsDatabaseStore::domainsToBlockButKeepCookiesFor const):
(WebKit::ResourceLoadStatisticsDatabaseStore::domainsWithUserInteractionAsFirstParty const):
(WebKit::ResourceLoadStatisticsDatabaseStore::domainsWithStorageAccess const):
(WebKit::ResourceLoadStatisticsDatabaseStore::domains const):
(WebKit::ResourceLoadStatisticsDatabaseStore::clearGrandfathering):
(WebKit::ResourceLoadStatisticsDatabaseStore::pruneStatisticsIfNeeded):
(WebKit::ResourceLoadStatisticsDatabaseStore::isCorrectSubStatisticsCount):
(WebKit::ResourceLoadStatisticsDatabaseStore::appendSubStatisticList const):
(WebKit::ResourceLoadStatisticsDatabaseStore::updateOperatingDatesParameters):
(WebKit::ResourceLoadStatisticsDatabaseStore::includeTodayAsOperatingDateIfNecessary):
(WebKit::ResourceLoadStatisticsDatabaseStore::insertExpiredStatisticForTesting):
(WebKit::ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement):
(WebKit::ResourceLoadStatisticsDatabaseStore::privateClickMeasurementToString):
(WebKit::ResourceLoadStatisticsDatabaseStore::clearSentAttribution):
(WebKit::ResourceLoadStatisticsDatabaseStore::markAttributedPrivateClickMeasurementsAsExpiredForTesting):
* NetworkProcess/WebStorage/LocalStorageDatabase.cpp:
(WebKit::LocalStorageDatabase::migrateItemTableIfNeeded):
(WebKit::LocalStorageDatabase::databaseIsEmpty const):
(WebKit::LocalStorageDatabase::scopedStatement const):
* NetworkProcess/WebStorage/LocalStorageDatabase.h:
* UIProcess/API/glib/IconDatabase.cpp:
(WebKit::IconDatabase::IconDatabase):
(WebKit::IconDatabase::populatePageURLToIconURLMap):
(WebKit::IconDatabase::pruneTimerFired):
(WebKit::IconDatabase::iconIDForIconURL):
(WebKit::IconDatabase::setIconIDForPageURL):
(WebKit::IconDatabase::iconData):
(WebKit::IconDatabase::addIcon):
(WebKit::IconDatabase::updateIconTimestamp):
(WebKit::IconDatabase::deleteIcon):

Source/WebKitLegacy:

Update code base now that the SQLiteDatabase & SQLiteStatement API has changed.
Also use more ASCIILiterals.

* Storage/StorageAreaSync.cpp:
(WebKit::StorageAreaSync::migrateItemTableIfNeeded):
(WebKit::StorageAreaSync::performImport):
(WebKit::StorageAreaSync::sync):
(WebKit::StorageAreaSync::deleteEmptyDatabase):
* Storage/StorageTracker.cpp:
(WebKit::StorageTracker::syncImportOriginIdentifiers):
(WebKit::StorageTracker::syncSetOriginDetails):
(WebKit::StorageTracker::syncDeleteAllOrigins):
(WebKit::StorageTracker::syncDeleteOrigin):
(WebKit::StorageTracker::databasePathForOrigin):

Source/WTF:

Allow constructing a UniqueRef<> from a C++ reference. std::unique_ptr<>() can be constructed
using a raw pointer and we can construct a UniqueRef<> from a std::unique_ptr<>() so I see
no reason not to allow that.

The reason I needed this is that I want to prevent call sites from allocating SQLiteStatement
without going through the SQLiteDatabase. As a result, I made the SQLiteStatement constructor
private and marked SQLiteDatabase as a friend class. SQLiteDatabase has to heap-allocate
a SQLiteStatement via new and then construct a UniqueRef<> for it. SQLiteDatabase cannot use
makeUniqueRef() because the SQLiteStatement constructor is private. I also cannot mark
makeUniqueRef() as a friend function of SQLiteStatement or anybody could heap allocate a
SQLiteStatement via makeUniqueRef (not just the SQLiteDatabase).

* wtf/UniqueRef.h:
(WTF::UniqueRef::UniqueRef):

Tools:

Update code base now that the SQLiteDatabase & SQLiteStatement API has changed.
Also use more ASCIILiterals.

* TestWebKitAPI/Tests/WebCore/cocoa/DatabaseTrackerTest.mm:
(TestWebKitAPI::addToDatabasesTable):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfUniqueRefh">trunk/Source/WTF/wtf/UniqueRef.h</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverSQLiteIDBBackingStorecpp">trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverSQLiteIDBBackingStoreh">trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverSQLiteIDBCursorcpp">trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp</a></li>
<li><a href="#trunkSourceWebCoreModuleswebdatabaseDatabasecpp">trunk/Source/WebCore/Modules/webdatabase/Database.cpp</a></li>
<li><a href="#trunkSourceWebCoreModuleswebdatabaseDatabaseTrackercpp">trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.cpp</a></li>
<li><a href="#trunkSourceWebCoreModuleswebdatabaseSQLStatementcpp">trunk/Source/WebCore/Modules/webdatabase/SQLStatement.cpp</a></li>
<li><a href="#trunkSourceWebCoreloaderappcacheApplicationCacheStoragecpp">trunk/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworkcurlCookieJarDBcpp">trunk/Source/WebCore/platform/network/curl/CookieJarDB.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformsqlSQLiteDatabasecpp">trunk/Source/WebCore/platform/sql/SQLiteDatabase.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformsqlSQLiteDatabaseh">trunk/Source/WebCore/platform/sql/SQLiteDatabase.h</a></li>
<li><a href="#trunkSourceWebCoreplatformsqlSQLiteStatementcpp">trunk/Source/WebCore/platform/sql/SQLiteStatement.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformsqlSQLiteStatementh">trunk/Source/WebCore/platform/sql/SQLiteStatement.h</a></li>
<li><a href="#trunkSourceWebCoreplatformwinSearchPopupMenuDBcpp">trunk/Source/WebCore/platform/win/SearchPopupMenuDB.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformwinSearchPopupMenuDBh">trunk/Source/WebCore/platform/win/SearchPopupMenuDB.h</a></li>
<li><a href="#trunkSourceWebCoreworkersserviceserverRegistrationDatabasecpp">trunk/Source/WebCore/workers/service/server/RegistrationDatabase.cpp</a></li>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsDatabaseStorecpp">trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsDatabaseStoreh">trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessWebStorageLocalStorageDatabasecpp">trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessWebStorageLocalStorageDatabaseh">trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPIglibIconDatabasecpp">trunk/Source/WebKit/UIProcess/API/glib/IconDatabase.cpp</a></li>
<li><a href="#trunkSourceWebKitLegacyChangeLog">trunk/Source/WebKitLegacy/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitLegacyStorageStorageAreaSynccpp">trunk/Source/WebKitLegacy/Storage/StorageAreaSync.cpp</a></li>
<li><a href="#trunkSourceWebKitLegacyStorageStorageTrackercpp">trunk/Source/WebKitLegacy/Storage/StorageTracker.cpp</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebCorecocoaDatabaseTrackerTestmm">trunk/Tools/TestWebKitAPI/Tests/WebCore/cocoa/DatabaseTrackerTest.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog       2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WTF/ChangeLog  2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -1,3 +1,25 @@
</span><ins>+2021-05-16  Chris Dumez  <cdumez@apple.com>
+
+        Modernize / Optimize SQLiteStatement creation and preparation
+        https://bugs.webkit.org/show_bug.cgi?id=225791
+
+        Reviewed by Sam Weinig.
+
+        Allow constructing a UniqueRef<> from a C++ reference. std::unique_ptr<>() can be constructed
+        using a raw pointer and we can construct a UniqueRef<> from a std::unique_ptr<>() so I see
+        no reason not to allow that.
+
+        The reason I needed this is that I want to prevent call sites from allocating SQLiteStatement
+        without going through the SQLiteDatabase. As a result, I made the SQLiteStatement constructor
+        private and marked SQLiteDatabase as a friend class. SQLiteDatabase has to heap-allocate
+        a SQLiteStatement via new and then construct a UniqueRef<> for it. SQLiteDatabase cannot use
+        makeUniqueRef() because the SQLiteStatement constructor is private. I also cannot mark
+        makeUniqueRef() as a friend function of SQLiteStatement or anybody could heap allocate a
+        SQLiteStatement via makeUniqueRef (not just the SQLiteDatabase).
+
+        * wtf/UniqueRef.h:
+        (WTF::UniqueRef::UniqueRef):
+
</ins><span class="cx"> 2021-05-15  Ryosuke Niwa  <rniwa@webkit.org>
</span><span class="cx"> 
</span><span class="cx">         Delete WebSQL code from WebKit2
</span></span></pre></div>
<a id="trunkSourceWTFwtfUniqueRefh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/UniqueRef.h (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/UniqueRef.h 2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WTF/wtf/UniqueRef.h    2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -61,6 +61,12 @@
</span><span class="cx">         ASSERT(m_ref);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    explicit UniqueRef(T& other)
+        : m_ref(&other)
+    {
+        ASSERT(m_ref);
+    }
+
</ins><span class="cx">     T& get() { ASSERT(m_ref); return *m_ref; }
</span><span class="cx">     const T& get() const { ASSERT(m_ref); return *m_ref; }
</span><span class="cx"> 
</span><span class="lines">@@ -80,12 +86,6 @@
</span><span class="cx">     template<class U> friend UniqueRef<U> makeUniqueRefFromNonNullUniquePtr(std::unique_ptr<U>);
</span><span class="cx">     template<class U> friend class UniqueRef;
</span><span class="cx"> 
</span><del>-    UniqueRef(T& other)
-        : m_ref(&other)
-    {
-        ASSERT(m_ref);
-    }
-
</del><span class="cx">     std::unique_ptr<T> m_ref;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/ChangeLog      2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -1,3 +1,159 @@
</span><ins>+2021-05-16  Chris Dumez  <cdumez@apple.com>
+
+        Modernize / Optimize SQLiteStatement creation and preparation
+        https://bugs.webkit.org/show_bug.cgi?id=225791
+
+        Reviewed by Sam Weinig.
+
+        Modernize / Optimize SQLiteStatement creation and preparation:
+        - The SQLiteStatement constructor is now private so that we never have a
+          SQLiteStatement that has not been "prepared". Only the SQLiteDatabase
+          can now construct SQLiteStatement objects. We already needed to pass
+          a SQLiteDatabase reference when constructing the SQLiteStatement anyway.
+        - The construct AND prepare a SQLiteStatement, we now call
+          SQLiteDatabase::prepareStatement() to get a stack object or
+          SQLiteDatabase::prepareHeapStatement() to get a heap one. These functions
+          return an Expected<> type so they will either return a "prepared"
+          SQLiteStatement or an unexpected SQLite error code.
+        - The prepare*Statement() functions now avoid String allocations in most
+          cases thanks to overloads taking in the query as an ASCIILiteral.
+        - Drop finalize() function on SQLiteStatement so SQLiteStatement objects
+          are always valid. It simplifies the implementation of SQLiteStatement
+          member functions. The SQLiteStatement destructor "finalizes" the statement
+          so users can simply destroy the SQLiteStatement if they need the object
+          to be finalize at a certain point (e.g. before closing a database).
+        - Drop the prepare() & prepareAndStep() SQLiteStatement member functions now
+          that SQLiteStatement are always prepared.
+        - Stop storing the SQL query as a String data member in SQLiteStatement class.
+          This is no longer needed now that they is no separe prepare step after the
+          construction. This makes the SQLiteStatement a bit smaller.
+
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
+        (WebCore::IDBServer::createOrMigrateRecordsTableIfNecessary):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::ensureValidBlobTables):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::ensureValidIndexRecordsTable):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::ensureValidIndexRecordsIndex):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::ensureValidIndexRecordsRecordIndex):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::createAndPopulateInitialDatabaseInfo):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::ensureValidObjectStoreInfoTable):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::migrateIndexInfoTableForIDUpdate):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::migrateIndexRecordsTableForIDUpdate):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::extractExistingDatabaseInfo):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::databaseNameAndVersionFromFile):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::beginTransaction):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::deleteBackingStore):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::cachedStatement):
+        * Modules/indexeddb/server/SQLiteIDBCursor.cpp:
+        (WebCore::IDBServer::SQLiteIDBCursor::createSQLiteStatement):
+        (WebCore::IDBServer::SQLiteIDBCursor::resetAndRebindPreIndexStatementIfNecessary):
+        (WebCore::IDBServer::SQLiteIDBCursor::internalFetchNextRecord):
+        * Modules/webdatabase/Database.cpp:
+        (WebCore::setTextValueInDatabase):
+        (WebCore::retrieveTextResultFromDatabase):
+        (WebCore::Database::performGetTableNames):
+        * Modules/webdatabase/DatabaseTracker.cpp:
+        (WebCore::DatabaseTracker::hasEntryForOriginNoLock):
+        (WebCore::DatabaseTracker::hasEntryForDatabase):
+        (WebCore::DatabaseTracker::fullPathForDatabaseNoLock):
+        (WebCore::DatabaseTracker::origins):
+        (WebCore::DatabaseTracker::databaseNamesNoLock):
+        (WebCore::DatabaseTracker::detailsForNameAndOrigin):
+        (WebCore::DatabaseTracker::setDatabaseDetails):
+        (WebCore::DatabaseTracker::quotaNoLock):
+        (WebCore::DatabaseTracker::setQuota):
+        (WebCore::DatabaseTracker::addDatabase):
+        (WebCore::DatabaseTracker::deleteOrigin):
+        (WebCore::DatabaseTracker::deleteDatabase):
+        (WebCore::DatabaseTracker::removeDeletedOpenedDatabases):
+        (WebCore::DatabaseTracker::deleteDatabaseFileIfEmpty):
+        * Modules/webdatabase/SQLStatement.cpp:
+        (WebCore::SQLStatement::execute):
+        * loader/appcache/ApplicationCacheStorage.cpp:
+        (WebCore::ApplicationCacheStorage::loadCacheGroup):
+        (WebCore::ApplicationCacheStorage::loadManifestHostHashes):
+        (WebCore::ApplicationCacheStorage::cacheGroupForURL):
+        (WebCore::ApplicationCacheStorage::fallbackCacheGroupForURL):
+        (WebCore::ApplicationCacheStorage::calculateQuotaForOrigin):
+        (WebCore::ApplicationCacheStorage::calculateUsageForOrigin):
+        (WebCore::ApplicationCacheStorage::calculateRemainingSizeForOriginExcludingCache):
+        (WebCore::ApplicationCacheStorage::storeUpdatedQuotaForOrigin):
+        (WebCore::ApplicationCacheStorage::verifySchemaVersion):
+        (WebCore::ApplicationCacheStorage::executeStatement):
+        (WebCore::ApplicationCacheStorage::store):
+        (WebCore::ApplicationCacheStorage::storeUpdatedType):
+        (WebCore::ApplicationCacheStorage::ensureOriginRecord):
+        (WebCore::ApplicationCacheStorage::storeNewestCache):
+        (WebCore::ApplicationCacheStorage::loadCache):
+        (WebCore::ApplicationCacheStorage::remove):
+        (WebCore::ApplicationCacheStorage::manifestURLs):
+        (WebCore::ApplicationCacheStorage::deleteCacheGroupRecord):
+        (WebCore::ApplicationCacheStorage::checkForDeletedResources):
+        (WebCore::ApplicationCacheStorage::flatFileAreaSize):
+        * platform/network/curl/CookieJarDB.cpp:
+        (WebCore::CookieJarDB::verifySchemaVersion):
+        (WebCore::CookieJarDB::checkDatabaseValidity):
+        (WebCore::CookieJarDB::searchCookies):
+        (WebCore::CookieJarDB::getAllCookies):
+        (WebCore::CookieJarDB::allDomains):
+        (WebCore::CookieJarDB::createPrepareStatement):
+        (WebCore::CookieJarDB::executeSql):
+        * platform/sql/SQLiteDatabase.cpp:
+        (WebCore::SQLiteDatabase::open):
+        (WebCore::SQLiteDatabase::useWALJournalMode):
+        (WebCore::SQLiteDatabase::maximumSize):
+        (WebCore::SQLiteDatabase::setMaximumSize):
+        (WebCore::SQLiteDatabase::pageSize):
+        (WebCore::SQLiteDatabase::freeSpaceSize):
+        (WebCore::SQLiteDatabase::totalSize):
+        (WebCore::SQLiteDatabase::executeCommand):
+        (WebCore::SQLiteDatabase::returnsAtLeastOneResult):
+        (WebCore::SQLiteDatabase::tableExists):
+        (WebCore::SQLiteDatabase::clearAllTables):
+        (WebCore::SQLiteDatabase::turnOnIncrementalAutoVacuum):
+        (WebCore::constructAndPrepareStatement):
+        (WebCore::SQLiteDatabase::prepareStatement):
+        (WebCore::SQLiteDatabase::prepareHeapStatement):
+        * platform/sql/SQLiteDatabase.h:
+        * platform/sql/SQLiteStatement.cpp:
+        (WebCore::SQLiteStatement::SQLiteStatement):
+        (WebCore::SQLiteStatement::~SQLiteStatement):
+        (WebCore::SQLiteStatement::step):
+        (WebCore::SQLiteStatement::reset):
+        (WebCore::SQLiteStatement::executeCommand):
+        (WebCore::SQLiteStatement::returnsAtLeastOneResult):
+        (WebCore::SQLiteStatement::bindBlob):
+        (WebCore::SQLiteStatement::bindText):
+        (WebCore::SQLiteStatement::bindInt):
+        (WebCore::SQLiteStatement::bindInt64):
+        (WebCore::SQLiteStatement::bindDouble):
+        (WebCore::SQLiteStatement::bindNull):
+        (WebCore::SQLiteStatement::bindParameterCount const):
+        (WebCore::SQLiteStatement::columnCount):
+        (WebCore::SQLiteStatement::isColumnNull):
+        (WebCore::SQLiteStatement::isColumnDeclaredAsBlob):
+        (WebCore::SQLiteStatement::getColumnName):
+        (WebCore::SQLiteStatement::getColumnValue):
+        (WebCore::SQLiteStatement::getColumnText):
+        (WebCore::SQLiteStatement::getColumnDouble):
+        (WebCore::SQLiteStatement::getColumnInt):
+        (WebCore::SQLiteStatement::getColumnInt64):
+        (WebCore::SQLiteStatement::getColumnBlobAsString):
+        (WebCore::SQLiteStatement::getColumnBlobAsVector):
+        (WebCore::SQLiteStatement::returnTextResults):
+        (WebCore::SQLiteStatement::returnIntResults):
+        (WebCore::SQLiteStatement::returnInt64Results):
+        (WebCore::SQLiteStatement::returnDoubleResults):
+        * platform/sql/SQLiteStatement.h:
+        * platform/win/SearchPopupMenuDB.cpp:
+        (WebCore::SearchPopupMenuDB::checkDatabaseValidity):
+        (WebCore::SearchPopupMenuDB::verifySchemaVersion):
+        (WebCore::SearchPopupMenuDB::executeSimpleSql):
+        (WebCore::SearchPopupMenuDB::createPreparedStatement):
+        * workers/service/server/RegistrationDatabase.cpp:
+        (WebCore::RegistrationDatabase::ensureValidRecordsTable):
+        (WebCore::RegistrationDatabase::doPushChanges):
+        (WebCore::RegistrationDatabase::importRecords):
+
</ins><span class="cx"> 2021-05-16  Alan Bujtas  <zalan@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [LFC] Cleanup FormattingContext class
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverSQLiteIDBBackingStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp  2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp     2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -263,13 +263,13 @@
</span><span class="cx">     String currentSchema;
</span><span class="cx">     {
</span><span class="cx">         // Fetch the schema for an existing records table.
</span><del>-        SQLiteStatement statement(database, "SELECT type, sql FROM sqlite_master WHERE tbl_name='Records'");
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = database.prepareStatement("SELECT type, sql FROM sqlite_master WHERE tbl_name='Records'"_s);
+        if (!statement) {
</ins><span class="cx">             LOG_ERROR("Unable to prepare statement to fetch schema for the Records table.");
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        int sqliteResult = statement.step();
</del><ins>+        int sqliteResult = statement->step();
</ins><span class="cx"> 
</span><span class="cx">         // If there is no Records table at all, create it and then bail.
</span><span class="cx">         if (sqliteResult == SQLITE_DONE) {
</span><span class="lines">@@ -286,7 +286,7 @@
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        currentSchema = statement.getColumnText(1);
</del><ins>+        currentSchema = statement->getColumnText(1);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT(!currentSchema.isEmpty());
</span><span class="lines">@@ -338,13 +338,13 @@
</span><span class="cx">     String currentSchema;
</span><span class="cx">     {
</span><span class="cx">         // Fetch the schema for an existing blob record table.
</span><del>-        SQLiteStatement statement(*m_sqliteDB, "SELECT type, sql FROM sqlite_master WHERE tbl_name='BlobRecords'");
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = m_sqliteDB->prepareStatement("SELECT type, sql FROM sqlite_master WHERE tbl_name='BlobRecords'"_s);
+        if (!statement) {
</ins><span class="cx">             LOG_ERROR("Unable to prepare statement to fetch schema for the BlobRecords table.");
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        int sqliteResult = statement.step();
</del><ins>+        int sqliteResult = statement->step();
</ins><span class="cx"> 
</span><span class="cx">         // If there is no BlobRecords table at all, create it..
</span><span class="cx">         if (sqliteResult == SQLITE_DONE) {
</span><span class="lines">@@ -358,7 +358,7 @@
</span><span class="cx">             LOG_ERROR("Error executing statement to fetch schema for the BlobRecords table.");
</span><span class="cx">             return false;
</span><span class="cx">         } else
</span><del>-            currentSchema = statement.getColumnText(1);
</del><ins>+            currentSchema = statement->getColumnText(1);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (currentSchema != blobRecordsTableSchema() && currentSchema != blobRecordsTableSchemaAlternate()) {
</span><span class="lines">@@ -368,13 +368,13 @@
</span><span class="cx"> 
</span><span class="cx">     {
</span><span class="cx">         // Fetch the schema for an existing blob file table.
</span><del>-        SQLiteStatement statement(*m_sqliteDB, "SELECT type, sql FROM sqlite_master WHERE tbl_name='BlobFiles'");
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = m_sqliteDB->prepareStatement("SELECT type, sql FROM sqlite_master WHERE tbl_name='BlobFiles'"_s);
+        if (!statement) {
</ins><span class="cx">             LOG_ERROR("Unable to prepare statement to fetch schema for the BlobFiles table.");
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        int sqliteResult = statement.step();
</del><ins>+        int sqliteResult = statement->step();
</ins><span class="cx"> 
</span><span class="cx">         // If there is no BlobFiles table at all, create it and then bail.
</span><span class="cx">         if (sqliteResult == SQLITE_DONE) {
</span><span class="lines">@@ -391,7 +391,7 @@
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        currentSchema = statement.getColumnText(1);
</del><ins>+        currentSchema = statement->getColumnText(1);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (currentSchema != blobFilesTableSchema() && currentSchema != blobFilesTableSchemaAlternate()) {
</span><span class="lines">@@ -428,13 +428,13 @@
</span><span class="cx">     String currentSchema;
</span><span class="cx">     {
</span><span class="cx">         // Fetch the schema for an existing index record table.
</span><del>-        SQLiteStatement statement(*m_sqliteDB, "SELECT type, sql FROM sqlite_master WHERE tbl_name='IndexRecords'");
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = m_sqliteDB->prepareStatement("SELECT type, sql FROM sqlite_master WHERE tbl_name='IndexRecords'"_s);
+        if (!statement) {
</ins><span class="cx">             LOG_ERROR("Unable to prepare statement to fetch schema for the IndexRecords table.");
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        int sqliteResult = statement.step();
</del><ins>+        int sqliteResult = statement->step();
</ins><span class="cx"> 
</span><span class="cx">         // If there is no IndexRecords table at all, create it and then bail.
</span><span class="cx">         if (sqliteResult == SQLITE_DONE) {
</span><span class="lines">@@ -451,7 +451,7 @@
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        currentSchema = statement.getColumnText(1);
</del><ins>+        currentSchema = statement->getColumnText(1);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT(!currentSchema.isEmpty());
</span><span class="lines">@@ -503,13 +503,13 @@
</span><span class="cx">     String currentSchema;
</span><span class="cx">     {
</span><span class="cx">         // Fetch the schema for an existing index record index.
</span><del>-        SQLiteStatement statement(*m_sqliteDB, "SELECT sql FROM sqlite_master WHERE name='IndexRecordsIndex'");
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = m_sqliteDB->prepareStatement("SELECT sql FROM sqlite_master WHERE name='IndexRecordsIndex'"_s);
+        if (!statement) {
</ins><span class="cx">             LOG_ERROR("Unable to prepare statement to fetch schema for the IndexRecordsIndex index.");
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        int sqliteResult = statement.step();
</del><ins>+        int sqliteResult = statement->step();
</ins><span class="cx"> 
</span><span class="cx">         // If there is no IndexRecordsIndex index at all, create it and then bail.
</span><span class="cx">         if (sqliteResult == SQLITE_DONE) {
</span><span class="lines">@@ -526,7 +526,7 @@
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        currentSchema = statement.getColumnText(0);
</del><ins>+        currentSchema = statement->getColumnText(0);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT(!currentSchema.isEmpty());
</span><span class="lines">@@ -561,13 +561,13 @@
</span><span class="cx"> 
</span><span class="cx">     String currentSchema;
</span><span class="cx">     {
</span><del>-        SQLiteStatement statement(*m_sqliteDB, "SELECT sql FROM sqlite_master WHERE name='IndexRecordsRecordIndex'");
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = m_sqliteDB->prepareStatement("SELECT sql FROM sqlite_master WHERE name='IndexRecordsRecordIndex'"_s);
+        if (!statement) {
</ins><span class="cx">             LOG_ERROR("Unable to prepare statement to fetch schema for the IndexRecordsRecordIndex index.");
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        int sqliteResult = statement.step();
</del><ins>+        int sqliteResult = statement->step();
</ins><span class="cx"> 
</span><span class="cx">         if (sqliteResult == SQLITE_DONE) {
</span><span class="cx">             if (!m_sqliteDB->executeCommand(v1IndexRecordsRecordIndexSchema)) {
</span><span class="lines">@@ -583,7 +583,7 @@
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        currentSchema = statement.getColumnText(0);
</del><ins>+        currentSchema = statement->getColumnText(0);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT(!currentSchema.isEmpty());
</span><span class="lines">@@ -624,10 +624,10 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     {
</span><del>-        SQLiteStatement sql(*m_sqliteDB, "INSERT INTO IDBDatabaseInfo VALUES ('MetadataVersion', ?);"_s);
-        if (sql.prepare() != SQLITE_OK
-            || sql.bindInt(1, currentMetadataVersion) != SQLITE_OK
-            || sql.step() != SQLITE_DONE) {
</del><ins>+        auto sql = m_sqliteDB->prepareStatement("INSERT INTO IDBDatabaseInfo VALUES ('MetadataVersion', ?);"_s);
+        if (!sql
+            || sql->bindInt(1, currentMetadataVersion) != SQLITE_OK
+            || sql->step() != SQLITE_DONE) {
</ins><span class="cx">             LOG_ERROR("Could not insert database metadata version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
</span><span class="cx">             closeSQLiteDB();
</span><span class="cx">             return nullptr;
</span><span class="lines">@@ -634,10 +634,10 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     {
</span><del>-        SQLiteStatement sql(*m_sqliteDB, "INSERT INTO IDBDatabaseInfo VALUES ('DatabaseName', ?);"_s);
-        if (sql.prepare() != SQLITE_OK
-            || sql.bindText(1, m_identifier.databaseName()) != SQLITE_OK
-            || sql.step() != SQLITE_DONE) {
</del><ins>+        auto sql = m_sqliteDB->prepareStatement("INSERT INTO IDBDatabaseInfo VALUES ('DatabaseName', ?);"_s);
+        if (!sql
+            || sql->bindText(1, m_identifier.databaseName()) != SQLITE_OK
+            || sql->step() != SQLITE_DONE) {
</ins><span class="cx">             LOG_ERROR("Could not insert database name into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
</span><span class="cx">             closeSQLiteDB();
</span><span class="cx">             return nullptr;
</span><span class="lines">@@ -646,10 +646,10 @@
</span><span class="cx">     {
</span><span class="cx">         // Database versions are defined to be a uin64_t in the spec but sqlite3 doesn't support native binding of unsigned integers.
</span><span class="cx">         // Therefore we'll store the version as a String.
</span><del>-        SQLiteStatement sql(*m_sqliteDB, "INSERT INTO IDBDatabaseInfo VALUES ('DatabaseVersion', ?);"_s);
-        if (sql.prepare() != SQLITE_OK
-            || sql.bindText(1, String::number(0)) != SQLITE_OK
-            || sql.step() != SQLITE_DONE) {
</del><ins>+        auto sql = m_sqliteDB->prepareStatement("INSERT INTO IDBDatabaseInfo VALUES ('DatabaseVersion', ?);"_s);
+        if (!sql
+            || sql->bindText(1, String::number(0)) != SQLITE_OK
+            || sql->step() != SQLITE_DONE) {
</ins><span class="cx">             LOG_ERROR("Could not insert default version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
</span><span class="cx">             closeSQLiteDB();
</span><span class="cx">             return nullptr;
</span><span class="lines">@@ -674,19 +674,19 @@
</span><span class="cx">     String currentSchema;
</span><span class="cx">     {
</span><span class="cx">         // Fetch the schema for ObjectStoreInfo table.
</span><del>-        SQLiteStatement statement(*m_sqliteDB, "SELECT sql FROM sqlite_master WHERE tbl_name='ObjectStoreInfo'");
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = m_sqliteDB->prepareStatement("SELECT sql FROM sqlite_master WHERE tbl_name='ObjectStoreInfo'"_s);
+        if (!statement) {
</ins><span class="cx">             LOG_ERROR("Unable to prepare statement to fetch schema for the ObjectStoreInfo table.");
</span><span class="cx">             return WTF::nullopt;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        int sqliteResult = statement.step();
</del><ins>+        int sqliteResult = statement->step();
</ins><span class="cx">         if (sqliteResult != SQLITE_ROW) {
</span><span class="cx">             LOG_ERROR("Error executing statement to fetch schema for the ObjectStoreInfo table.");
</span><span class="cx">             return WTF::nullopt;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        currentSchema = statement.getColumnText(0);
</del><ins>+        currentSchema = statement->getColumnText(0);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT(!currentSchema.isEmpty());
</span><span class="lines">@@ -739,22 +739,22 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     {
</span><del>-        SQLiteStatement statement(database, "SELECT id, name, objectStoreID, keyPath, isUnique, multiEntry FROM IndexInfo;"_s);
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = database.prepareStatement("SELECT id, name, objectStoreID, keyPath, isUnique, multiEntry FROM IndexInfo;"_s);
+        if (!statement) {
</ins><span class="cx">             LOG_ERROR("Error preparing statement to fetch records from IndexInfo table (%i) - %s", database.lastError(), database.lastErrorMsg());
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        int result = statement.step();
</del><ins>+        int result = statement->step();
</ins><span class="cx">         while (result == SQLITE_ROW) {
</span><del>-            uint64_t id = statement.getColumnInt64(0);
-            String name = statement.getColumnText(1);
-            uint64_t objectStoreID = statement.getColumnInt64(2);
</del><ins>+            uint64_t id = statement->getColumnInt64(0);
+            String name = statement->getColumnText(1);
+            uint64_t objectStoreID = statement->getColumnInt64(2);
</ins><span class="cx">             uint64_t newID = indexIDMap.get({ objectStoreID, id });
</span><span class="cx">             Vector<uint8_t> keyPathBuffer;
</span><del>-            statement.getColumnBlobAsVector(3, keyPathBuffer);
-            bool unique = statement.getColumnInt(4);
-            bool multiEntry = statement.getColumnInt(5);
</del><ins>+            statement->getColumnBlobAsVector(3, keyPathBuffer);
+            bool unique = statement->getColumnInt(4);
+            bool multiEntry = statement->getColumnInt(5);
</ins><span class="cx"> 
</span><span class="cx">             auto sql = cachedStatement(SQL::CreateTempIndexInfo, "INSERT INTO _Temp_IndexInfo VALUES (?, ?, ?, ?, ?, ?);"_s);
</span><span class="cx">             if (!sql
</span><span class="lines">@@ -769,7 +769,7 @@
</span><span class="cx">                 return false;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            result = statement.step();
</del><ins>+            result = statement->step();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (result != SQLITE_DONE) {
</span><span class="lines">@@ -804,22 +804,22 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     {
</span><del>-        SQLiteStatement statement(database, "SELECT indexID, objectStoreID, key, value, objectStoreRecordID FROM IndexRecords;"_s);
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = database.prepareStatement("SELECT indexID, objectStoreID, key, value, objectStoreRecordID FROM IndexRecords;"_s);
+        if (!statement) {
</ins><span class="cx">             LOG_ERROR("Error preparing statement to fetch records from the IndexRecords table (%i) - %s", database.lastError(), database.lastErrorMsg());
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        int result = statement.step();
</del><ins>+        int result = statement->step();
</ins><span class="cx">         while (result == SQLITE_ROW) {
</span><del>-            uint64_t id = statement.getColumnInt64(0);
-            uint64_t objectStoreID = statement.getColumnInt64(1);
</del><ins>+            uint64_t id = statement->getColumnInt64(0);
+            uint64_t objectStoreID = statement->getColumnInt64(1);
</ins><span class="cx">             uint64_t newID = indexIDMap.get({ objectStoreID, id });
</span><span class="cx">             Vector<uint8_t> keyBuffer;
</span><del>-            statement.getColumnBlobAsVector(2, keyBuffer);
</del><ins>+            statement->getColumnBlobAsVector(2, keyBuffer);
</ins><span class="cx">             Vector<uint8_t> valueBuffer;
</span><del>-            statement.getColumnBlobAsVector(3, valueBuffer);
-            uint64_t recordID = statement.getColumnInt64(4);
</del><ins>+            statement->getColumnBlobAsVector(3, valueBuffer);
+            uint64_t recordID = statement->getColumnInt64(4);
</ins><span class="cx"> 
</span><span class="cx">             auto sql = cachedStatement(SQL::PutTempIndexRecord, "INSERT INTO _Temp_IndexRecords VALUES (?, ?, CAST(? AS TEXT), CAST(? AS TEXT), ?);"_s);
</span><span class="cx">             if (!sql
</span><span class="lines">@@ -833,7 +833,7 @@
</span><span class="cx">                 return false;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            result = statement.step();
</del><ins>+            result = statement->step();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (result != SQLITE_DONE) {
</span><span class="lines">@@ -989,10 +989,10 @@
</span><span class="cx"> 
</span><span class="cx">     String databaseName;
</span><span class="cx">     {
</span><del>-        SQLiteStatement sql(*m_sqliteDB, "SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseName';");
-        if (sql.isColumnNull(0))
</del><ins>+        auto sql = m_sqliteDB->prepareStatement("SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseName';"_s);
+        if (sql->isColumnNull(0))
</ins><span class="cx">             return nullptr;
</span><del>-        databaseName = sql.getColumnText(0);
</del><ins>+        databaseName = sql->getColumnText(0);
</ins><span class="cx">         if (databaseName != m_identifier.databaseName()) {
</span><span class="cx">             LOG_ERROR("Database name in the info database ('%s') does not match the expected name ('%s')", databaseName.utf8().data(), m_identifier.databaseName().utf8().data());
</span><span class="cx">             return nullptr;
</span><span class="lines">@@ -1000,10 +1000,10 @@
</span><span class="cx">     }
</span><span class="cx">     uint64_t databaseVersion;
</span><span class="cx">     {
</span><del>-        SQLiteStatement sql(*m_sqliteDB, "SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseVersion';"_s);
-        if (sql.isColumnNull(0))
</del><ins>+        auto sql = m_sqliteDB->prepareStatement("SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseVersion';"_s);
+        if (sql->isColumnNull(0))
</ins><span class="cx">             return nullptr;
</span><del>-        String stringVersion = sql.getColumnText(0);
</del><ins>+        String stringVersion = sql->getColumnText(0);
</ins><span class="cx">         auto parsedVersion = parseInteger<uint64_t>(stringVersion);
</span><span class="cx">         if (!parsedVersion) {
</span><span class="cx">             LOG_ERROR("Database version on disk ('%s') does not cleanly convert to an unsigned 64-bit integer version", stringVersion.utf8().data());
</span><span class="lines">@@ -1021,17 +1021,17 @@
</span><span class="cx">     bool shouldUpdateIndexID = (result.value() == IsSchemaUpgraded::Yes);
</span><span class="cx"> 
</span><span class="cx">     {
</span><del>-        SQLiteStatement sql(*m_sqliteDB, "SELECT id, name, keyPath, autoInc FROM ObjectStoreInfo;"_s);
-        if (sql.prepare() != SQLITE_OK)
</del><ins>+        auto sql = m_sqliteDB->prepareStatement("SELECT id, name, keyPath, autoInc FROM ObjectStoreInfo;"_s);
+        if (!sql)
</ins><span class="cx">             return nullptr;
</span><span class="cx"> 
</span><del>-        int result = sql.step();
</del><ins>+        int result = sql->step();
</ins><span class="cx">         while (result == SQLITE_ROW) {
</span><del>-            uint64_t objectStoreID = sql.getColumnInt64(0);
-            String objectStoreName = sql.getColumnText(1);
</del><ins>+            uint64_t objectStoreID = sql->getColumnInt64(0);
+            String objectStoreName = sql->getColumnText(1);
</ins><span class="cx"> 
</span><span class="cx">             Vector<char> keyPathBuffer;
</span><del>-            sql.getColumnBlobAsVector(2, keyPathBuffer);
</del><ins>+            sql->getColumnBlobAsVector(2, keyPathBuffer);
</ins><span class="cx"> 
</span><span class="cx">             Optional<IDBKeyPath> objectStoreKeyPath;
</span><span class="cx">             if (!deserializeIDBKeyPath(reinterpret_cast<const uint8_t*>(keyPathBuffer.data()), keyPathBuffer.size(), objectStoreKeyPath)) {
</span><span class="lines">@@ -1039,11 +1039,11 @@
</span><span class="cx">                 return nullptr;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            bool autoIncrement = sql.getColumnInt(3);
</del><ins>+            bool autoIncrement = sql->getColumnInt(3);
</ins><span class="cx"> 
</span><span class="cx">             databaseInfo->addExistingObjectStore({ objectStoreID, objectStoreName, WTFMove(objectStoreKeyPath), autoIncrement });
</span><span class="cx"> 
</span><del>-            result = sql.step();
</del><ins>+            result = sql->step();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (result != SQLITE_DONE) {
</span><span class="lines">@@ -1056,20 +1056,20 @@
</span><span class="cx">     HashMap<std::pair<uint64_t, uint64_t>, uint64_t> indexIDMap;
</span><span class="cx">     HashMap<uint64_t, Vector<IDBIndexInfo>> indexInfoMap;
</span><span class="cx">     {
</span><del>-        SQLiteStatement sql(*m_sqliteDB, "SELECT id, name, objectStoreID, keyPath, isUnique, multiEntry FROM IndexInfo;"_s);
-        if (sql.prepare() != SQLITE_OK) {
</del><ins>+        auto sql = m_sqliteDB->prepareStatement("SELECT id, name, objectStoreID, keyPath, isUnique, multiEntry FROM IndexInfo;"_s);
+        if (!sql) {
</ins><span class="cx">             LOG_ERROR("Unable to prepare statement to fetch records from the IndexInfo table.");
</span><span class="cx">             return nullptr;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        int result = sql.step();
</del><ins>+        int result = sql->step();
</ins><span class="cx">         while (result == SQLITE_ROW) {
</span><del>-            uint64_t indexID = sql.getColumnInt64(0);
-            String indexName = sql.getColumnText(1);
-            uint64_t objectStoreID = sql.getColumnInt64(2);
</del><ins>+            uint64_t indexID = sql->getColumnInt64(0);
+            String indexName = sql->getColumnText(1);
+            uint64_t objectStoreID = sql->getColumnInt64(2);
</ins><span class="cx"> 
</span><span class="cx">             Vector<char> keyPathBuffer;
</span><del>-            sql.getColumnBlobAsVector(3, keyPathBuffer);
</del><ins>+            sql->getColumnBlobAsVector(3, keyPathBuffer);
</ins><span class="cx"> 
</span><span class="cx">             Optional<IDBKeyPath> indexKeyPath;
</span><span class="cx">             if (!deserializeIDBKeyPath(reinterpret_cast<const uint8_t*>(keyPathBuffer.data()), keyPathBuffer.size(), indexKeyPath)) {
</span><span class="lines">@@ -1081,8 +1081,8 @@
</span><span class="cx">                 return nullptr;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            bool unique = sql.getColumnInt(4);
-            bool multiEntry = sql.getColumnInt(5);
</del><ins>+            bool unique = sql->getColumnInt(4);
+            bool multiEntry = sql->getColumnInt(5);
</ins><span class="cx"> 
</span><span class="cx">             auto objectStore = databaseInfo->infoForExistingObjectStore(objectStoreID);
</span><span class="cx">             if (!objectStore) {
</span><span class="lines">@@ -1106,7 +1106,7 @@
</span><span class="cx">             objectStore->addExistingIndex(indexInfo);
</span><span class="cx">             maxIndexID = maxIndexID < indexID ? indexID : maxIndexID;
</span><span class="cx"> 
</span><del>-            result = sql.step();
</del><ins>+            result = sql->step();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (result != SQLITE_DONE) {
</span><span class="lines">@@ -1162,11 +1162,15 @@
</span><span class="cx">         return WTF::nullopt;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement namesql(database, "SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseName';");
-    auto databaseName = namesql.getColumnText(0);
</del><ins>+    auto namesql = database.prepareStatement("SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseName';"_s);
+    if (!namesql) {
+        LOG_ERROR("Could not prepare statement to get database name(%i) - %s", database.lastError(), database.lastErrorMsg());
+        return WTF::nullopt;
+    }
+    auto databaseName = namesql->getColumnText(0);
</ins><span class="cx"> 
</span><del>-    SQLiteStatement versql(database, "SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseVersion';"_s);
-    String stringVersion = versql.getColumnText(0);
</del><ins>+    auto versql = database.prepareStatement("SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseVersion';"_s);
+    String stringVersion = versql ? versql->getColumnText(0) : String();
</ins><span class="cx">     auto databaseVersion = parseInteger<uint64_t>(stringVersion);
</span><span class="cx">     if (!databaseVersion) {
</span><span class="cx">         LOG_ERROR("Database version on disk ('%s') does not cleanly convert to an unsigned 64-bit integer version", stringVersion.utf8().data());
</span><span class="lines">@@ -1310,10 +1314,10 @@
</span><span class="cx">     if (error.isNull() && info.mode() == IDBTransactionMode::Versionchange) {
</span><span class="cx">         m_originalDatabaseInfoBeforeVersionChange = makeUnique<IDBDatabaseInfo>(*m_databaseInfo);
</span><span class="cx"> 
</span><del>-        SQLiteStatement sql(*m_sqliteDB, "UPDATE IDBDatabaseInfo SET value = ? where key = 'DatabaseVersion';"_s);
-        if (sql.prepare() != SQLITE_OK
-            || sql.bindText(1, String::number(info.newVersion())) != SQLITE_OK
-            || sql.step() != SQLITE_DONE) {
</del><ins>+        auto sql = m_sqliteDB->prepareStatement("UPDATE IDBDatabaseInfo SET value = ? where key = 'DatabaseVersion';"_s);
+        if (!sql
+            || sql->bindText(1, String::number(info.newVersion())) != SQLITE_OK
+            || sql->step() != SQLITE_DONE) {
</ins><span class="cx">             error = IDBError { UnknownError, "Failed to store new database version in database"_s };
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -2347,16 +2351,6 @@
</span><span class="cx">     int64_t recordID = 0;
</span><span class="cx">     ThreadSafeDataBuffer keyResultBuffer, valueResultBuffer;
</span><span class="cx">     {
</span><del>-        static const char* const lowerOpenUpperOpen = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
-        static const char* const lowerOpenUpperClosed = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
-        static const char* const lowerClosedUpperOpen = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
-        static const char* const lowerClosedUpperClosed = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
-
-        static const char* const lowerOpenUpperOpenKeyOnly = "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
-        static const char* const lowerOpenUpperClosedKeyOnly = "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
-        static const char* const lowerClosedUpperOpenKeyOnly = "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
-        static const char* const lowerClosedUpperClosedKeyOnly = "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
-
</del><span class="cx">         SQLiteStatementAutoResetScope sql;
</span><span class="cx"> 
</span><span class="cx">         switch (type) {
</span><span class="lines">@@ -2363,27 +2357,27 @@
</span><span class="cx">         case IDBGetRecordDataType::KeyAndValue:
</span><span class="cx">             if (keyRange.lowerOpen) {
</span><span class="cx">                 if (keyRange.upperOpen)
</span><del>-                    sql = cachedStatement(SQL::GetValueRecordsLowerOpenUpperOpen, lowerOpenUpperOpen);
</del><ins>+                    sql = cachedStatement(SQL::GetValueRecordsLowerOpenUpperOpen, "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;"_s);
</ins><span class="cx">                 else
</span><del>-                    sql = cachedStatement(SQL::GetValueRecordsLowerOpenUpperClosed, lowerOpenUpperClosed);
</del><ins>+                    sql = cachedStatement(SQL::GetValueRecordsLowerOpenUpperClosed, "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;"_s);
</ins><span class="cx">             } else {
</span><span class="cx">                 if (keyRange.upperOpen)
</span><del>-                    sql = cachedStatement(SQL::GetValueRecordsLowerClosedUpperOpen, lowerClosedUpperOpen);
</del><ins>+                    sql = cachedStatement(SQL::GetValueRecordsLowerClosedUpperOpen, "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;"_s);
</ins><span class="cx">                 else
</span><del>-                    sql = cachedStatement(SQL::GetValueRecordsLowerClosedUpperClosed, lowerClosedUpperClosed);
</del><ins>+                    sql = cachedStatement(SQL::GetValueRecordsLowerClosedUpperClosed, "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;"_s);
</ins><span class="cx">             }
</span><span class="cx">             break;
</span><span class="cx">         case IDBGetRecordDataType::KeyOnly:
</span><span class="cx">             if (keyRange.lowerOpen) {
</span><span class="cx">                 if (keyRange.upperOpen)
</span><del>-                    sql = cachedStatement(SQL::GetKeyRecordsLowerOpenUpperOpen, lowerOpenUpperOpenKeyOnly);
</del><ins>+                    sql = cachedStatement(SQL::GetKeyRecordsLowerOpenUpperOpen, "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;"_s);
</ins><span class="cx">                 else
</span><del>-                    sql = cachedStatement(SQL::GetKeyRecordsLowerOpenUpperClosed, lowerOpenUpperClosedKeyOnly);
</del><ins>+                    sql = cachedStatement(SQL::GetKeyRecordsLowerOpenUpperClosed, "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;"_s);
</ins><span class="cx">             } else {
</span><span class="cx">                 if (keyRange.upperOpen)
</span><del>-                    sql = cachedStatement(SQL::GetKeyRecordsLowerClosedUpperOpen, lowerClosedUpperOpenKeyOnly);
</del><ins>+                    sql = cachedStatement(SQL::GetKeyRecordsLowerClosedUpperOpen, "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;"_s);
</ins><span class="cx">                 else
</span><del>-                    sql = cachedStatement(SQL::GetKeyRecordsLowerClosedUpperClosed, lowerClosedUpperClosedKeyOnly);
</del><ins>+                    sql = cachedStatement(SQL::GetKeyRecordsLowerClosedUpperClosed, "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;"_s);
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -2455,36 +2449,27 @@
</span><span class="cx"> 
</span><span class="cx"> SQLiteStatementAutoResetScope SQLiteIDBBackingStore::cachedStatementForGetAllObjectStoreRecords(const IDBGetAllRecordsData& getAllRecordsData)
</span><span class="cx"> {
</span><del>-    static const char* const lowerOpenUpperOpenKey ="SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
-    static const char* const lowerOpenUpperClosedKey = "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
-    static const char* const lowerClosedUpperOpenKey = "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
-    static const char* const lowerClosedUpperClosedKey = "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
-    static const char* const lowerOpenUpperOpenValue = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
-    static const char* const lowerOpenUpperClosedValue = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
-    static const char* const lowerClosedUpperOpenValue = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
-    static const char* const lowerClosedUpperClosedValue = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
-
</del><span class="cx">     if (getAllRecordsData.getAllType == IndexedDB::GetAllType::Keys) {
</span><span class="cx">         if (getAllRecordsData.keyRangeData.lowerOpen) {
</span><span class="cx">             if (getAllRecordsData.keyRangeData.upperOpen)
</span><del>-                return cachedStatement(SQL::GetAllKeyRecordsLowerOpenUpperOpen, lowerOpenUpperOpenKey);
-            return cachedStatement(SQL::GetAllKeyRecordsLowerOpenUpperClosed, lowerOpenUpperClosedKey);
</del><ins>+                return cachedStatement(SQL::GetAllKeyRecordsLowerOpenUpperOpen, "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;"_s);
+            return cachedStatement(SQL::GetAllKeyRecordsLowerOpenUpperClosed, "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;"_s);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (getAllRecordsData.keyRangeData.upperOpen)
</span><del>-            return cachedStatement(SQL::GetAllKeyRecordsLowerClosedUpperOpen, lowerClosedUpperOpenKey);
-        return cachedStatement(SQL::GetAllKeyRecordsLowerClosedUpperClosed, lowerClosedUpperClosedKey);
</del><ins>+            return cachedStatement(SQL::GetAllKeyRecordsLowerClosedUpperOpen, "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;"_s);
+        return cachedStatement(SQL::GetAllKeyRecordsLowerClosedUpperClosed, "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;"_s);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (getAllRecordsData.keyRangeData.lowerOpen) {
</span><span class="cx">         if (getAllRecordsData.keyRangeData.upperOpen)
</span><del>-            return cachedStatement(SQL::GetValueRecordsLowerOpenUpperOpen, lowerOpenUpperOpenValue);
-        return cachedStatement(SQL::GetValueRecordsLowerOpenUpperClosed, lowerOpenUpperClosedValue);
</del><ins>+            return cachedStatement(SQL::GetValueRecordsLowerOpenUpperOpen, "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;"_s);
+        return cachedStatement(SQL::GetValueRecordsLowerOpenUpperClosed, "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;"_s);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (getAllRecordsData.keyRangeData.upperOpen)
</span><del>-        return cachedStatement(SQL::GetValueRecordsLowerClosedUpperOpen, lowerClosedUpperOpenValue);
-    return cachedStatement(SQL::GetValueRecordsLowerClosedUpperClosed, lowerClosedUpperClosedValue);
</del><ins>+        return cachedStatement(SQL::GetValueRecordsLowerClosedUpperOpen, "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;"_s);
+    return cachedStatement(SQL::GetValueRecordsLowerClosedUpperClosed, "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;"_s);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> IDBError SQLiteIDBBackingStore::getAllObjectStoreRecords(const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData& getAllRecordsData, IDBGetAllResult& result)
</span><span class="lines">@@ -2758,19 +2743,14 @@
</span><span class="cx">     SQLiteStatementAutoResetScope statement;
</span><span class="cx"> 
</span><span class="cx">     if (!indexIdentifier) {
</span><del>-        static const char* const countLowerOpenUpperOpenRecords = "SELECT COUNT(*) FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT);";
-        static const char* const countLowerOpenUpperClosedRecords = "SELECT COUNT(*) FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT);";
-        static const char* const countLowerClosedUpperOpenRecords = "SELECT COUNT(*) FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT);";
-        static const char* const countLowerClosedUpperClosedRecords = "SELECT COUNT(*) FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT);";
-
</del><span class="cx">         if (range.lowerOpen && range.upperOpen)
</span><del>-            statement = cachedStatement(SQL::CountRecordsLowerOpenUpperOpen, countLowerOpenUpperOpenRecords);
</del><ins>+            statement = cachedStatement(SQL::CountRecordsLowerOpenUpperOpen, "SELECT COUNT(*) FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT);"_s);
</ins><span class="cx">         else if (range.lowerOpen && !range.upperOpen)
</span><del>-            statement = cachedStatement(SQL::CountRecordsLowerOpenUpperClosed, countLowerOpenUpperClosedRecords);
</del><ins>+            statement = cachedStatement(SQL::CountRecordsLowerOpenUpperClosed, "SELECT COUNT(*) FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT);"_s);
</ins><span class="cx">         else if (!range.lowerOpen && range.upperOpen)
</span><del>-            statement = cachedStatement(SQL::CountRecordsLowerClosedUpperOpen, countLowerClosedUpperOpenRecords);
</del><ins>+            statement = cachedStatement(SQL::CountRecordsLowerClosedUpperOpen, "SELECT COUNT(*) FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT);"_s);
</ins><span class="cx">         else
</span><del>-            statement = cachedStatement(SQL::CountRecordsLowerClosedUpperClosed, countLowerClosedUpperClosedRecords);
</del><ins>+            statement = cachedStatement(SQL::CountRecordsLowerClosedUpperClosed, "SELECT COUNT(*) FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT);"_s);
</ins><span class="cx">         
</span><span class="cx">         if (!statement
</span><span class="cx">             || statement->bindInt64(1, objectStoreIdentifier) != SQLITE_OK
</span><span class="lines">@@ -2780,19 +2760,14 @@
</span><span class="cx">             return IDBError { UnknownError, "Unable to count records in object store due to binding failure"_s };
</span><span class="cx">         }
</span><span class="cx">     } else {
</span><del>-        static const char* const countLowerOpenUpperOpenIndexRecords = "SELECT COUNT(*) FROM IndexRecords WHERE indexID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT);";
-        static const char* const countLowerOpenUpperClosedIndexRecords = "SELECT COUNT(*) FROM IndexRecords WHERE indexID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT);";
-        static const char* const countLowerClosedUpperOpenIndexRecords = "SELECT COUNT(*) FROM IndexRecords WHERE indexID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT);";
-        static const char* const countLowerClosedUpperClosedIndexRecords = "SELECT COUNT(*) FROM IndexRecords WHERE indexID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT);";
-        
</del><span class="cx">         if (range.lowerOpen && range.upperOpen)
</span><del>-            statement = cachedStatement(SQL::CountIndexRecordsLowerOpenUpperOpen, countLowerOpenUpperOpenIndexRecords);
</del><ins>+            statement = cachedStatement(SQL::CountIndexRecordsLowerOpenUpperOpen, "SELECT COUNT(*) FROM IndexRecords WHERE indexID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT);"_s);
</ins><span class="cx">         else if (range.lowerOpen && !range.upperOpen)
</span><del>-            statement = cachedStatement(SQL::CountIndexRecordsLowerOpenUpperClosed, countLowerOpenUpperClosedIndexRecords);
</del><ins>+            statement = cachedStatement(SQL::CountIndexRecordsLowerOpenUpperClosed, "SELECT COUNT(*) FROM IndexRecords WHERE indexID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT);"_s);
</ins><span class="cx">         else if (!range.lowerOpen && range.upperOpen)
</span><del>-            statement = cachedStatement(SQL::CountIndexRecordsLowerClosedUpperOpen, countLowerClosedUpperOpenIndexRecords);
</del><ins>+            statement = cachedStatement(SQL::CountIndexRecordsLowerClosedUpperOpen, "SELECT COUNT(*) FROM IndexRecords WHERE indexID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT);"_s);
</ins><span class="cx">         else
</span><del>-            statement = cachedStatement(SQL::CountIndexRecordsLowerClosedUpperClosed, countLowerClosedUpperClosedIndexRecords);
</del><ins>+            statement = cachedStatement(SQL::CountIndexRecordsLowerClosedUpperClosed, "SELECT COUNT(*) FROM IndexRecords WHERE indexID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT);"_s);
</ins><span class="cx"> 
</span><span class="cx">         if (!statement
</span><span class="cx">             || statement->bindInt64(1, indexIdentifier) != SQLITE_OK
</span><span class="lines">@@ -3017,12 +2992,12 @@
</span><span class="cx">         bool errored = true;
</span><span class="cx"> 
</span><span class="cx">         if (m_sqliteDB) {
</span><del>-            SQLiteStatement sql(*m_sqliteDB, "SELECT fileName FROM BlobFiles;"_s);
-            if (sql.prepare() == SQLITE_OK) {
-                int result = sql.step();
</del><ins>+            auto sql = m_sqliteDB->prepareStatement("SELECT fileName FROM BlobFiles;"_s);
+            if (sql) {
+                int result = sql->step();
</ins><span class="cx">                 while (result == SQLITE_ROW) {
</span><del>-                    blobFiles.append(sql.getColumnText(0));
-                    result = sql.step();
</del><ins>+                    blobFiles.append(sql->getColumnText(0));
+                    result = sql->step();
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 if (result == SQLITE_DONE)
</span><span class="lines">@@ -3054,7 +3029,7 @@
</span><span class="cx">     m_cursors.remove(cursor.identifier());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-SQLiteStatementAutoResetScope SQLiteIDBBackingStore::cachedStatement(SQLiteIDBBackingStore::SQL sql, const char* statement)
</del><ins>+SQLiteStatementAutoResetScope SQLiteIDBBackingStore::cachedStatement(SQLiteIDBBackingStore::SQL sql, ASCIILiteral query)
</ins><span class="cx"> {
</span><span class="cx">     if (sql >= SQL::Invalid) {
</span><span class="cx">         LOG_ERROR("Invalid SQL statement ID passed to cachedStatement()");
</span><span class="lines">@@ -3061,14 +3036,13 @@
</span><span class="cx">         return SQLiteStatementAutoResetScope { };
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (m_cachedStatements[static_cast<size_t>(sql)]) {
</del><ins>+    if (m_cachedStatements[static_cast<size_t>(sql)])
</ins><span class="cx">         return SQLiteStatementAutoResetScope { m_cachedStatements[static_cast<size_t>(sql)].get() };
</span><del>-    }
</del><span class="cx"> 
</span><span class="cx">     if (m_sqliteDB) {
</span><del>-        m_cachedStatements[static_cast<size_t>(sql)] = makeUnique<SQLiteStatement>(*m_sqliteDB, statement);
-        if (m_cachedStatements[static_cast<size_t>(sql)]->prepare() != SQLITE_OK)
-            m_cachedStatements[static_cast<size_t>(sql)] = nullptr;
</del><ins>+        auto statement = m_sqliteDB->prepareHeapStatement(query);
+        if (statement)
+            m_cachedStatements[static_cast<size_t>(sql)] = statement.value().moveToUniquePtr();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return SQLiteStatementAutoResetScope { m_cachedStatements[static_cast<size_t>(sql)].get() };
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverSQLiteIDBBackingStoreh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h    2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h       2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -204,7 +204,7 @@
</span><span class="cx">         Invalid,
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    SQLiteStatementAutoResetScope cachedStatement(SQL, const char*);
</del><ins>+    SQLiteStatementAutoResetScope cachedStatement(SQL, ASCIILiteral);
</ins><span class="cx">     SQLiteStatementAutoResetScope cachedStatementForGetAllObjectStoreRecords(const IDBGetAllRecordsData&);
</span><span class="cx"> 
</span><span class="cx">     std::unique_ptr<SQLiteStatement> m_cachedStatements[static_cast<int>(SQL::Invalid)];
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverSQLiteIDBCursorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp        2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp   2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -235,12 +235,12 @@
</span><span class="cx">     ASSERT(!m_currentUpperKey.isNull());
</span><span class="cx">     ASSERT(m_transaction->sqliteTransaction());
</span><span class="cx"> 
</span><del>-    m_statement = makeUnique<SQLiteStatement>(m_transaction->sqliteTransaction()->database(), sql);
-
-    if (m_statement->prepare() != SQLITE_OK) {
</del><ins>+    auto statement = m_transaction->sqliteTransaction()->database().prepareHeapStatement(sql);
+    if (!statement) {
</ins><span class="cx">         LOG_ERROR("Could not create cursor statement (prepare/id) - '%s'", m_transaction->sqliteTransaction()->database().lastErrorMsg());
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><ins>+    m_statement = statement.value().moveToUniquePtr();
</ins><span class="cx"> 
</span><span class="cx">     return bindArguments();
</span><span class="cx"> }
</span><span class="lines">@@ -341,12 +341,12 @@
</span><span class="cx"> 
</span><span class="cx">     auto& database = m_transaction->sqliteTransaction()->database();
</span><span class="cx">     if (!m_preIndexStatement) {
</span><del>-        m_preIndexStatement = makeUnique<SQLiteStatement>(database, buildPreIndexStatement(isDirectionNext()));
-
-        if (m_preIndexStatement->prepare() != SQLITE_OK) {
</del><ins>+        auto preIndexStatement = database.prepareHeapStatement(buildPreIndexStatement(isDirectionNext()));
+        if (!preIndexStatement) {
</ins><span class="cx">             LOG_ERROR("Could not prepare pre statement - '%s'", database.lastErrorMsg());
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><ins>+        m_preIndexStatement = preIndexStatement.value().moveToUniquePtr();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (m_preIndexStatement->reset() != SQLITE_OK) {
</span><span class="lines">@@ -588,9 +588,8 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (!m_cachedObjectStoreStatement || m_cachedObjectStoreStatement->reset() != SQLITE_OK) {
</span><del>-            m_cachedObjectStoreStatement = makeUnique<SQLiteStatement>(database, "SELECT value FROM Records WHERE key = CAST(? AS TEXT) and objectStoreID = ?;");
-            if (m_cachedObjectStoreStatement->prepare() != SQLITE_OK)
-                m_cachedObjectStoreStatement = nullptr;
</del><ins>+            if (auto cachedObjectStoreStatement = database.prepareHeapStatement("SELECT value FROM Records WHERE key = CAST(? AS TEXT) and objectStoreID = ?;"_s))
+                m_cachedObjectStoreStatement = cachedObjectStoreStatement.value().moveToUniquePtr();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (!m_cachedObjectStoreStatement
</span></span></pre></div>
<a id="trunkSourceWebCoreModuleswebdatabaseDatabasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/webdatabase/Database.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/webdatabase/Database.cpp    2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/Modules/webdatabase/Database.cpp       2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -113,18 +113,15 @@
</span><span class="cx"> 
</span><span class="cx"> static bool setTextValueInDatabase(SQLiteDatabase& db, const String& query, const String& value)
</span><span class="cx"> {
</span><del>-    SQLiteStatement statement(db, query);
-    int result = statement.prepare();
-
-    if (result != SQLITE_OK) {
</del><ins>+    auto statement = db.prepareStatement(query);
+    if (!statement) {
</ins><span class="cx">         LOG_ERROR("Failed to prepare statement to set value in database (%s)", query.ascii().data());
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    statement.bindText(1, value);
</del><ins>+    statement->bindText(1, value);
</ins><span class="cx"> 
</span><del>-    result = statement.step();
-    if (result != SQLITE_DONE) {
</del><ins>+    if (statement->step() != SQLITE_DONE) {
</ins><span class="cx">         LOG_ERROR("Failed to step statement to set value in database (%s)", query.ascii().data());
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="lines">@@ -134,17 +131,15 @@
</span><span class="cx"> 
</span><span class="cx"> static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& query, String& resultString)
</span><span class="cx"> {
</span><del>-    SQLiteStatement statement(db, query);
-    int result = statement.prepare();
-
-    if (result != SQLITE_OK) {
-        LOG_ERROR("Error (%i) preparing statement to read text result from database (%s)", result, query.ascii().data());
</del><ins>+    auto statement = db.prepareStatement(query);
+    if (!statement) {
+        LOG_ERROR("Error (%i) preparing statement to read text result from database (%s)", statement.error(), query.ascii().data());
</ins><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    result = statement.step();
</del><ins>+    int result = statement->step();
</ins><span class="cx">     if (result == SQLITE_ROW) {
</span><del>-        resultString = statement.getColumnText(0);
</del><ins>+        resultString = statement->getColumnText(0);
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx">     if (result == SQLITE_DONE) {
</span><span class="lines">@@ -714,8 +709,8 @@
</span><span class="cx"> {
</span><span class="cx">     disableAuthorizer();
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(sqliteDatabase(), "SELECT name FROM sqlite_master WHERE type='table';");
-    if (statement.prepare() != SQLITE_OK) {
</del><ins>+    auto statement = sqliteDatabase().prepareStatement("SELECT name FROM sqlite_master WHERE type='table';"_s);
+    if (!statement) {
</ins><span class="cx">         LOG_ERROR("Unable to retrieve list of tables for database %s", databaseDebugName().ascii().data());
</span><span class="cx">         enableAuthorizer();
</span><span class="cx">         return Vector<String>();
</span><span class="lines">@@ -723,8 +718,8 @@
</span><span class="cx"> 
</span><span class="cx">     Vector<String> tableNames;
</span><span class="cx">     int result;
</span><del>-    while ((result = statement.step()) == SQLITE_ROW) {
-        String name = statement.getColumnText(0);
</del><ins>+    while ((result = statement->step()) == SQLITE_ROW) {
+        String name = statement->getColumnText(0);
</ins><span class="cx">         if (name != unqualifiedInfoTableName)
</span><span class="cx">             tableNames.append(name);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebCoreModuleswebdatabaseDatabaseTrackercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.cpp     2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.cpp        2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -235,15 +235,15 @@
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, "SELECT origin FROM Origins where origin=?;");
-    if (statement.prepare() != SQLITE_OK) {
</del><ins>+    auto statement = m_database.prepareStatement("SELECT origin FROM Origins where origin=?;"_s);
+    if (!statement) {
</ins><span class="cx">         LOG_ERROR("Failed to prepare statement.");
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    statement.bindText(1, origin.databaseIdentifier());
</del><ins>+    statement->bindText(1, origin.databaseIdentifier());
</ins><span class="cx"> 
</span><del>-    return statement.step() == SQLITE_ROW;
</del><ins>+    return statement->step() == SQLITE_ROW;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool DatabaseTracker::hasEntryForDatabase(const SecurityOriginData& origin, const String& databaseIdentifier)
</span><span class="lines">@@ -256,15 +256,15 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // We've got a tracker database. Set up a query to ask for the db of interest:
</span><del>-    SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE origin=? AND name=?;");
</del><ins>+    auto statement = m_database.prepareStatement("SELECT guid FROM Databases WHERE origin=? AND name=?;"_s);
</ins><span class="cx"> 
</span><del>-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    if (!statement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    statement.bindText(1, origin.databaseIdentifier());
-    statement.bindText(2, databaseIdentifier);
</del><ins>+    statement->bindText(1, origin.databaseIdentifier());
+    statement->bindText(2, databaseIdentifier);
</ins><span class="cx"> 
</span><del>-    return statement.step() == SQLITE_ROW;
</del><ins>+    return statement->step() == SQLITE_ROW;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> uint64_t DatabaseTracker::maximumSize(Database& database)
</span><span class="lines">@@ -325,26 +325,26 @@
</span><span class="cx">     // See if we have a path for this database yet
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return String();
</span><del>-    SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;");
</del><span class="cx"> 
</span><del>-    if (statement.prepare() != SQLITE_OK)
-        return String();
</del><ins>+    {
+        auto statement = m_database.prepareStatement("SELECT path FROM Databases WHERE origin=? AND name=?;"_s);
+        if (!statement)
+            return String();
</ins><span class="cx"> 
</span><del>-    statement.bindText(1, originIdentifier);
-    statement.bindText(2, name);
</del><ins>+        statement->bindText(1, originIdentifier);
+        statement->bindText(2, name);
</ins><span class="cx"> 
</span><del>-    int result = statement.step();
</del><ins>+        int result = statement->step();
+        if (result == SQLITE_ROW)
+            return SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, statement->getColumnText(0));
+        if (!createIfNotExists)
+            return String();
</ins><span class="cx"> 
</span><del>-    if (result == SQLITE_ROW)
-        return SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, statement.getColumnText(0));
-    if (!createIfNotExists)
-        return String();
-
-    if (result != SQLITE_DONE) {
-        LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", originIdentifier.utf8().data(), name.utf8().data());
-        return String();
</del><ins>+        if (result != SQLITE_DONE) {
+            LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", originIdentifier.utf8().data(), name.utf8().data());
+            return String();
+        }
</ins><span class="cx">     }
</span><del>-    statement.finalize();
</del><span class="cx"> 
</span><span class="cx">     String fileName = generateDatabaseFileName();
</span><span class="cx"> 
</span><span class="lines">@@ -372,8 +372,8 @@
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return { };
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, "SELECT origin FROM Origins");
-    if (statement.prepare() != SQLITE_OK) {
</del><ins>+    auto statement = m_database.prepareStatement("SELECT origin FROM Origins"_s);
+    if (!statement) {
</ins><span class="cx">         LOG_ERROR("Failed to prepare statement.");
</span><span class="cx">         return { };
</span><span class="cx">     }
</span><span class="lines">@@ -380,8 +380,8 @@
</span><span class="cx"> 
</span><span class="cx">     Vector<SecurityOriginData> origins;
</span><span class="cx">     int stepResult;
</span><del>-    while ((stepResult = statement.step()) == SQLITE_ROW)
-        origins.append(SecurityOriginData::fromDatabaseIdentifier(statement.getColumnText(0))->isolatedCopy());
</del><ins>+    while ((stepResult = statement->step()) == SQLITE_ROW)
+        origins.append(SecurityOriginData::fromDatabaseIdentifier(statement->getColumnText(0))->isolatedCopy());
</ins><span class="cx">     origins.shrinkToFit();
</span><span class="cx"> 
</span><span class="cx">     if (stepResult != SQLITE_DONE)
</span><span class="lines">@@ -397,16 +397,16 @@
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return { };
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, "SELECT name FROM Databases where origin=?;");
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT name FROM Databases where origin=?;"_s);
+    if (!statement)
</ins><span class="cx">         return { };
</span><span class="cx"> 
</span><del>-    statement.bindText(1, origin.databaseIdentifier());
</del><ins>+    statement->bindText(1, origin.databaseIdentifier());
</ins><span class="cx"> 
</span><span class="cx">     Vector<String> names;
</span><span class="cx">     int result;
</span><del>-    while ((result = statement.step()) == SQLITE_ROW)
-        names.append(statement.getColumnText(0));
</del><ins>+    while ((result = statement->step()) == SQLITE_ROW)
+        names.append(statement->getColumnText(0));
</ins><span class="cx">     names.shrinkToFit();
</span><span class="cx"> 
</span><span class="cx">     if (result != SQLITE_DONE) {
</span><span class="lines">@@ -439,14 +439,14 @@
</span><span class="cx">         openTrackerDatabase(DontCreateIfDoesNotExist);
</span><span class="cx">         if (!m_database.isOpen())
</span><span class="cx">             return DatabaseDetails();
</span><del>-        SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize FROM Databases WHERE origin=? AND name=?");
-        if (statement.prepare() != SQLITE_OK)
</del><ins>+        auto statement = m_database.prepareStatement("SELECT displayName, estimatedSize FROM Databases WHERE origin=? AND name=?"_s);
+        if (!statement)
</ins><span class="cx">             return DatabaseDetails();
</span><span class="cx"> 
</span><del>-        statement.bindText(1, originIdentifier);
-        statement.bindText(2, name);
</del><ins>+        statement->bindText(1, originIdentifier);
+        statement->bindText(2, name);
</ins><span class="cx"> 
</span><del>-        int result = statement.step();
</del><ins>+        int result = statement->step();
</ins><span class="cx">         if (result == SQLITE_DONE)
</span><span class="cx">             return DatabaseDetails();
</span><span class="cx"> 
</span><span class="lines">@@ -454,8 +454,8 @@
</span><span class="cx">             LOG_ERROR("Error retrieving details for database %s in origin %s from tracker database", name.utf8().data(), originIdentifier.utf8().data());
</span><span class="cx">             return DatabaseDetails();
</span><span class="cx">         }
</span><del>-        displayName = statement.getColumnText(0);
-        expectedUsage = statement.getColumnInt64(1);
</del><ins>+        displayName = statement->getColumnText(0);
+        expectedUsage = statement->getColumnInt64(1);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     String path = fullPathForDatabase(origin, name, false);
</span><span class="lines">@@ -474,39 +474,41 @@
</span><span class="cx">     openTrackerDatabase(CreateIfDoesNotExist);
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return;
</span><del>-    SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE origin=? AND name=?");
-    if (statement.prepare() != SQLITE_OK)
-        return;
</del><span class="cx"> 
</span><del>-    statement.bindText(1, originIdentifier);
-    statement.bindText(2, name);
</del><ins>+    {
+        auto statement = m_database.prepareStatement("SELECT guid FROM Databases WHERE origin=? AND name=?"_s);
+        if (!statement)
+            return;
</ins><span class="cx"> 
</span><del>-    int result = statement.step();
-    if (result == SQLITE_ROW)
-        guid = statement.getColumnInt64(0);
-    statement.finalize();
</del><ins>+        statement->bindText(1, originIdentifier);
+        statement->bindText(2, name);
</ins><span class="cx"> 
</span><del>-    if (guid == 0) {
-        if (result != SQLITE_DONE)
-            LOG_ERROR("Error to determing existence of database %s in origin %s in tracker database", name.utf8().data(), originIdentifier.utf8().data());
-        else {
-            // This case should never occur - we should never be setting database details for a database that doesn't already exist in the tracker
-            // But since the tracker file is an external resource not under complete control of our code, it's somewhat invalid to make this an ASSERT case
-            // So we'll print an error instead
-            LOG_ERROR("Could not retrieve guid for database %s in origin %s from the tracker database - it is invalid to set database details on a database that doesn't already exist in the tracker", name.utf8().data(), originIdentifier.utf8().data());
</del><ins>+        int result = statement->step();
+        if (result == SQLITE_ROW)
+            guid = statement->getColumnInt64(0);
+
+        if (!guid) {
+            if (result != SQLITE_DONE)
+                LOG_ERROR("Error to determing existence of database %s in origin %s in tracker database", name.utf8().data(), originIdentifier.utf8().data());
+            else {
+                // This case should never occur - we should never be setting database details for a database that doesn't already exist in the tracker
+                // But since the tracker file is an external resource not under complete control of our code, it's somewhat invalid to make this an ASSERT case
+                // So we'll print an error instead
+                LOG_ERROR("Could not retrieve guid for database %s in origin %s from the tracker database - it is invalid to set database details on a database that doesn't already exist in the tracker", name.utf8().data(), originIdentifier.utf8().data());
+            }
+            return;
</ins><span class="cx">         }
</span><del>-        return;
</del><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement updateStatement(m_database, "UPDATE Databases SET displayName=?, estimatedSize=? WHERE guid=?");
-    if (updateStatement.prepare() != SQLITE_OK)
</del><ins>+    auto updateStatement = m_database.prepareStatement("UPDATE Databases SET displayName=?, estimatedSize=? WHERE guid=?"_s);
+    if (!updateStatement)
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    updateStatement.bindText(1, displayName);
-    updateStatement.bindInt64(2, estimatedSize);
-    updateStatement.bindInt64(3, guid);
</del><ins>+    updateStatement->bindText(1, displayName);
+    updateStatement->bindInt64(2, estimatedSize);
+    updateStatement->bindInt64(3, guid);
</ins><span class="cx"> 
</span><del>-    if (updateStatement.step() != SQLITE_DONE) {
</del><ins>+    if (updateStatement->step() != SQLITE_DONE) {
</ins><span class="cx">         LOG_ERROR("Failed to update details for database %s in origin %s", name.utf8().data(), originIdentifier.utf8().data());
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -671,15 +673,15 @@
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return quota;
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, "SELECT quota FROM Origins where origin=?;");
-    if (statement.prepare() != SQLITE_OK) {
</del><ins>+    auto statement = m_database.prepareStatement("SELECT quota FROM Origins where origin=?;"_s);
+    if (!statement) {
</ins><span class="cx">         LOG_ERROR("Failed to prepare statement.");
</span><span class="cx">         return quota;
</span><span class="cx">     }
</span><del>-    statement.bindText(1, origin.databaseIdentifier());
</del><ins>+    statement->bindText(1, origin.databaseIdentifier());
</ins><span class="cx"> 
</span><del>-    if (statement.step() == SQLITE_ROW)
-        quota = statement.getColumnInt64(0);
</del><ins>+    if (statement->step() == SQLITE_ROW)
+        quota = statement->getColumnInt64(0);
</ins><span class="cx"> 
</span><span class="cx">     return quota;
</span><span class="cx"> }
</span><span class="lines">@@ -705,26 +707,26 @@
</span><span class="cx"> 
</span><span class="cx">     bool originEntryExists = hasEntryForOriginNoLock(origin);
</span><span class="cx">     if (!originEntryExists) {
</span><del>-        SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)");
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = m_database.prepareStatement("INSERT INTO Origins VALUES (?, ?)"_s);
+        if (!statement) {
</ins><span class="cx">             LOG_ERROR("Unable to establish origin %s in the tracker", origin.databaseIdentifier().utf8().data());
</span><span class="cx">         } else {
</span><del>-            statement.bindText(1, origin.databaseIdentifier());
-            statement.bindInt64(2, quota);
</del><ins>+            statement->bindText(1, origin.databaseIdentifier());
+            statement->bindInt64(2, quota);
</ins><span class="cx"> 
</span><del>-            if (statement.step() != SQLITE_DONE)
</del><ins>+            if (statement->step() != SQLITE_DONE)
</ins><span class="cx">                 LOG_ERROR("Unable to establish origin %s in the tracker", origin.databaseIdentifier().utf8().data());
</span><span class="cx">             else
</span><span class="cx">                 insertedNewOrigin = true;
</span><span class="cx">         }
</span><span class="cx">     } else {
</span><del>-        SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
-        bool error = statement.prepare() != SQLITE_OK;
</del><ins>+        auto statement = m_database.prepareStatement("UPDATE Origins SET quota=? WHERE origin=?"_s);
+        bool error = !statement;
</ins><span class="cx">         if (!error) {
</span><del>-            statement.bindInt64(1, quota);
-            statement.bindText(2, origin.databaseIdentifier());
</del><ins>+            statement->bindInt64(1, quota);
+            statement->bindText(2, origin.databaseIdentifier());
</ins><span class="cx"> 
</span><del>-            error = !statement.executeCommand();
</del><ins>+            error = !statement->executeCommand();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (error)
</span><span class="lines">@@ -748,16 +750,16 @@
</span><span class="cx">     // New database should never be added until the origin has been established
</span><span class="cx">     ASSERT(hasEntryForOriginNoLock(origin));
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, "INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);");
</del><ins>+    auto statement = m_database.prepareStatement("INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);"_s);
</ins><span class="cx"> 
</span><del>-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    if (!statement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    statement.bindText(1, origin.databaseIdentifier());
-    statement.bindText(2, name);
-    statement.bindText(3, path);
</del><ins>+    statement->bindText(1, origin.databaseIdentifier());
+    statement->bindText(2, name);
+    statement->bindText(3, path);
</ins><span class="cx"> 
</span><del>-    if (!statement.executeCommand()) {
</del><ins>+    if (!statement->executeCommand()) {
</ins><span class="cx">         LOG_ERROR("Failed to add database %s to origin %s: %s\n", name.utf8().data(), origin.databaseIdentifier().utf8().data(), m_database.lastErrorMsg());
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="lines">@@ -881,28 +883,28 @@
</span><span class="cx">         SQLiteTransaction transaction(m_database);
</span><span class="cx">         transaction.begin();
</span><span class="cx"> 
</span><del>-        SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?");
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = m_database.prepareStatement("DELETE FROM Databases WHERE origin=?"_s);
+        if (!statement) {
</ins><span class="cx">             LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin.databaseIdentifier().utf8().data());
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        statement.bindText(1, origin.databaseIdentifier());
</del><ins>+        statement->bindText(1, origin.databaseIdentifier());
</ins><span class="cx"> 
</span><del>-        if (!statement.executeCommand()) {
</del><ins>+        if (!statement->executeCommand()) {
</ins><span class="cx">             LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin.databaseIdentifier().utf8().data());
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?");
-        if (originStatement.prepare() != SQLITE_OK) {
</del><ins>+        auto originStatement = m_database.prepareStatement("DELETE FROM Origins WHERE origin=?"_s);
+        if (!originStatement) {
</ins><span class="cx">             LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin.databaseIdentifier().utf8().data());
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        originStatement.bindText(1, origin.databaseIdentifier());
</del><ins>+        originStatement->bindText(1, origin.databaseIdentifier());
</ins><span class="cx"> 
</span><del>-        if (!originStatement.executeCommand()) {
</del><ins>+        if (!originStatement->executeCommand()) {
</ins><span class="cx">             LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin.databaseIdentifier().utf8().data());
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="lines">@@ -915,10 +917,10 @@
</span><span class="cx"> 
</span><span class="cx">         openTrackerDatabase(DontCreateIfDoesNotExist);
</span><span class="cx">         if (m_database.isOpen()) {
</span><del>-            SQLiteStatement statement(m_database, "SELECT origin FROM Origins");
-            if (statement.prepare() != SQLITE_OK)
</del><ins>+            auto statement = m_database.prepareStatement("SELECT origin FROM Origins"_s);
+            if (!statement)
</ins><span class="cx">                 LOG_ERROR("Failed to prepare statement.");
</span><del>-            else if (statement.step() == SQLITE_ROW)
</del><ins>+            else if (statement->step() == SQLITE_ROW)
</ins><span class="cx">                 isEmpty = false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -1081,17 +1083,17 @@
</span><span class="cx"> 
</span><span class="cx">     LockHolder lockDatabase(m_databaseGuard);
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=? AND name=?");
-    if (statement.prepare() != SQLITE_OK) {
</del><ins>+    auto statement = m_database.prepareStatement("DELETE FROM Databases WHERE origin=? AND name=?"_s);
+    if (!statement) {
</ins><span class="cx">         LOG_ERROR("Unable to prepare deletion of database %s from origin %s from tracker", name.utf8().data(), origin.databaseIdentifier().utf8().data());
</span><span class="cx">         doneDeletingDatabase(origin, name);
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    statement.bindText(1, origin.databaseIdentifier());
-    statement.bindText(2, name);
</del><ins>+    statement->bindText(1, origin.databaseIdentifier());
+    statement->bindText(2, name);
</ins><span class="cx"> 
</span><del>-    if (!statement.executeCommand()) {
</del><ins>+    if (!statement->executeCommand()) {
</ins><span class="cx">         LOG_ERROR("Unable to execute deletion of database %s from origin %s from tracker", name.utf8().data(), origin.databaseIdentifier().utf8().data());
</span><span class="cx">         doneDeletingDatabase(origin, name);
</span><span class="cx">         return false;
</span><span class="lines">@@ -1197,13 +1199,11 @@
</span><span class="cx">                 for (auto& databases : *databaseNameMap) {
</span><span class="cx">                     String databaseName = databases.key;
</span><span class="cx">                     String databaseFileName;
</span><del>-                    SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;");
-                    if (statement.prepare() == SQLITE_OK) {
-                        statement.bindText(1, origin.databaseIdentifier());
-                        statement.bindText(2, databaseName);
-                        if (statement.step() == SQLITE_ROW)
-                            databaseFileName = statement.getColumnText(0);
-                        statement.finalize();
</del><ins>+                    if (auto statement = m_database.prepareStatement("SELECT path FROM Databases WHERE origin=? AND name=?;"_s)) {
+                        statement->bindText(1, origin.databaseIdentifier());
+                        statement->bindText(2, databaseName);
+                        if (statement->step() == SQLITE_ROW)
+                            databaseFileName = statement->getColumnText(0);
</ins><span class="cx">                     }
</span><span class="cx">                     
</span><span class="cx">                     bool foundDeletedDatabase = false;
</span><span class="lines">@@ -1258,13 +1258,14 @@
</span><span class="cx">     
</span><span class="cx">     // Specify that we want the exclusive locking mode, so after the next write,
</span><span class="cx">     // we'll be holding the lock to this database file.
</span><del>-    SQLiteStatement lockStatement(database, "PRAGMA locking_mode=EXCLUSIVE;");
-    if (lockStatement.prepare() != SQLITE_OK)
-        return false;
-    int result = lockStatement.step();
-    if (result != SQLITE_ROW && result != SQLITE_DONE)
-        return false;
-    lockStatement.finalize();
</del><ins>+    {
+        auto lockStatement = database.prepareStatement("PRAGMA locking_mode=EXCLUSIVE;"_s);
+        if (!lockStatement)
+            return false;
+        int result = lockStatement->step();
+        if (result != SQLITE_ROW && result != SQLITE_DONE)
+            return false;
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (!database.executeCommand("BEGIN EXCLUSIVE TRANSACTION;"))
</span><span class="cx">         return false;
</span></span></pre></div>
<a id="trunkSourceWebCoreModuleswebdatabaseSQLStatementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/webdatabase/SQLStatement.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/webdatabase/SQLStatement.cpp        2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/Modules/webdatabase/SQLStatement.cpp   2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -112,21 +112,19 @@
</span><span class="cx"> 
</span><span class="cx">     SQLiteDatabase& database = db.sqliteDatabase();
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(database, m_statement);
-    int result = statement.prepare();
-
-    if (result != SQLITE_OK) {
-        LOG(StorageAPI, "Unable to verify correctness of statement %s - error %i (%s)", m_statement.ascii().data(), result, database.lastErrorMsg());
-        if (result == SQLITE_INTERRUPT)
-            m_error = SQLError::create(SQLError::DATABASE_ERR, "could not prepare statement", result, "interrupted");
</del><ins>+    auto statement = database.prepareStatement(m_statement);
+    if (!statement) {
+        LOG(StorageAPI, "Unable to verify correctness of statement %s - error %i (%s)", m_statement.ascii().data(), statement.error(), database.lastErrorMsg());
+        if (statement.error() == SQLITE_INTERRUPT)
+            m_error = SQLError::create(SQLError::DATABASE_ERR, "could not prepare statement", statement.error(), "interrupted");
</ins><span class="cx">         else
</span><del>-            m_error = SQLError::create(SQLError::SYNTAX_ERR, "could not prepare statement", result, database.lastErrorMsg());
</del><ins>+            m_error = SQLError::create(SQLError::SYNTAX_ERR, "could not prepare statement", statement.error(), database.lastErrorMsg());
</ins><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // FIXME: If the statement uses the ?### syntax supported by sqlite, the bind parameter count is very likely off from the number of question marks.
</span><span class="cx">     // If this is the case, they might be trying to do something fishy or malicious
</span><del>-    if (statement.bindParameterCount() != m_arguments.size()) {
</del><ins>+    if (statement->bindParameterCount() != m_arguments.size()) {
</ins><span class="cx">         LOG(StorageAPI, "Bind parameter count doesn't match number of question marks");
</span><span class="cx">         m_error = SQLError::create(SQLError::SYNTAX_ERR, "number of '?'s in statement string does not match argument count");
</span><span class="cx">         return false;
</span><span class="lines">@@ -133,7 +131,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     for (unsigned i = 0; i < m_arguments.size(); ++i) {
</span><del>-        result = statement.bindValue(i + 1, m_arguments[i]);
</del><ins>+        int result = statement->bindValue(i + 1, m_arguments[i]);
</ins><span class="cx">         if (result == SQLITE_FULL) {
</span><span class="cx">             setFailureDueToQuota();
</span><span class="cx">             return false;
</span><span class="lines">@@ -149,20 +147,20 @@
</span><span class="cx">     auto resultSet = SQLResultSet::create();
</span><span class="cx"> 
</span><span class="cx">     // Step so we can fetch the column names.
</span><del>-    result = statement.step();
</del><ins>+    int result = statement->step();
</ins><span class="cx">     switch (result) {
</span><span class="cx">     case SQLITE_ROW: {
</span><del>-        int columnCount = statement.columnCount();
</del><ins>+        int columnCount = statement->columnCount();
</ins><span class="cx">         auto& rows = resultSet->rows();
</span><span class="cx"> 
</span><span class="cx">         for (int i = 0; i < columnCount; i++)
</span><del>-            rows.addColumn(statement.getColumnName(i));
</del><ins>+            rows.addColumn(statement->getColumnName(i));
</ins><span class="cx"> 
</span><span class="cx">         do {
</span><span class="cx">             for (int i = 0; i < columnCount; i++)
</span><del>-                rows.addResult(statement.getColumnValue(i));
</del><ins>+                rows.addResult(statement->getColumnValue(i));
</ins><span class="cx"> 
</span><del>-            result = statement.step();
</del><ins>+            result = statement->step();
</ins><span class="cx">         } while (result == SQLITE_ROW);
</span><span class="cx"> 
</span><span class="cx">         if (result != SQLITE_DONE) {
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderappcacheApplicationCacheStoragecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp 2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp    2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -98,13 +98,13 @@
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL AND manifestURL=?");
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL AND manifestURL=?"_s);
+    if (!statement)
</ins><span class="cx">         return nullptr;
</span><span class="cx">     
</span><del>-    statement.bindText(1, manifestURL.string());
</del><ins>+    statement->bindText(1, manifestURL.string());
</ins><span class="cx">    
</span><del>-    int result = statement.step();
</del><ins>+    int result = statement->step();
</ins><span class="cx">     if (result == SQLITE_DONE)
</span><span class="cx">         return nullptr;
</span><span class="cx">     
</span><span class="lines">@@ -113,7 +113,7 @@
</span><span class="cx">         return nullptr;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    unsigned newestCacheStorageID = static_cast<unsigned>(statement.getColumnInt64(2));
</del><ins>+    unsigned newestCacheStorageID = static_cast<unsigned>(statement->getColumnInt64(2));
</ins><span class="cx"> 
</span><span class="cx">     auto cache = loadCache(newestCacheStorageID);
</span><span class="cx">     if (!cache)
</span><span class="lines">@@ -120,7 +120,7 @@
</span><span class="cx">         return nullptr;
</span><span class="cx">         
</span><span class="cx">     auto& group = *new ApplicationCacheGroup(*this, manifestURL);
</span><del>-    group.setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
</del><ins>+    group.setStorageID(static_cast<unsigned>(statement->getColumnInt64(0)));
</ins><span class="cx">     group.setNewestCache(cache.releaseNonNull());
</span><span class="cx">     return &group;
</span><span class="cx"> }    
</span><span class="lines">@@ -171,12 +171,12 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     // Fetch the host hashes.
</span><del>-    SQLiteStatement statement(m_database, "SELECT manifestHostHash FROM CacheGroups");    
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT manifestHostHash FROM CacheGroups"_s);
+    if (!statement)
</ins><span class="cx">         return;
</span><span class="cx">     
</span><del>-    while (statement.step() == SQLITE_ROW)
-        m_cacheHostSet.add(static_cast<unsigned>(statement.getColumnInt64(0)));
</del><ins>+    while (statement->step() == SQLITE_ROW)
+        m_cacheHostSet.add(static_cast<unsigned>(statement->getColumnInt64(0)));
</ins><span class="cx"> }    
</span><span class="cx"> 
</span><span class="cx"> ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const URL& url)
</span><span class="lines">@@ -212,13 +212,13 @@
</span><span class="cx">     SQLiteTransactionInProgressAutoCounter transactionCounter;
</span><span class="cx"> 
</span><span class="cx">     // Check the database. Look for all cache groups with a newest cache.
</span><del>-    SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL");
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL"_s);
+    if (!statement)
</ins><span class="cx">         return nullptr;
</span><span class="cx">     
</span><span class="cx">     int result;
</span><del>-    while ((result = statement.step()) == SQLITE_ROW) {
-        URL manifestURL = URL({ }, statement.getColumnText(1));
</del><ins>+    while ((result = statement->step()) == SQLITE_ROW) {
+        URL manifestURL = URL({ }, statement->getColumnText(1));
</ins><span class="cx"> 
</span><span class="cx">         if (m_cachesInMemory.contains(manifestURL.string()))
</span><span class="cx">             continue;
</span><span class="lines">@@ -228,7 +228,7 @@
</span><span class="cx"> 
</span><span class="cx">         // We found a cache group that matches. Now check if the newest cache has a resource with
</span><span class="cx">         // a matching URL.
</span><del>-        unsigned newestCacheID = static_cast<unsigned>(statement.getColumnInt64(2));
</del><ins>+        unsigned newestCacheID = static_cast<unsigned>(statement->getColumnInt64(2));
</ins><span class="cx">         auto cache = loadCache(newestCacheID);
</span><span class="cx">         if (!cache)
</span><span class="cx">             continue;
</span><span class="lines">@@ -240,7 +240,7 @@
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><span class="cx">         auto& group = *new ApplicationCacheGroup(*this, manifestURL);
</span><del>-        group.setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
</del><ins>+        group.setStorageID(static_cast<unsigned>(statement->getColumnInt64(0)));
</ins><span class="cx">         group.setNewestCache(cache.releaseNonNull());
</span><span class="cx">         m_cachesInMemory.set(group.manifestURL().string(), &group);
</span><span class="cx"> 
</span><span class="lines">@@ -279,13 +279,13 @@
</span><span class="cx">         return nullptr;
</span><span class="cx">         
</span><span class="cx">     // Check the database. Look for all cache groups with a newest cache.
</span><del>-    SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL");
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL"_s);
+    if (!statement)
</ins><span class="cx">         return nullptr;
</span><span class="cx">     
</span><span class="cx">     int result;
</span><del>-    while ((result = statement.step()) == SQLITE_ROW) {
-        URL manifestURL = URL({ }, statement.getColumnText(1));
</del><ins>+    while ((result = statement->step()) == SQLITE_ROW) {
+        URL manifestURL = URL({ }, statement->getColumnText(1));
</ins><span class="cx"> 
</span><span class="cx">         if (m_cachesInMemory.contains(manifestURL.string()))
</span><span class="cx">             continue;
</span><span class="lines">@@ -296,7 +296,7 @@
</span><span class="cx"> 
</span><span class="cx">         // We found a cache group that matches. Now check if the newest cache has a resource with
</span><span class="cx">         // a matching fallback namespace.
</span><del>-        unsigned newestCacheID = static_cast<unsigned>(statement.getColumnInt64(2));
</del><ins>+        unsigned newestCacheID = static_cast<unsigned>(statement->getColumnInt64(2));
</ins><span class="cx">         auto cache = loadCache(newestCacheID);
</span><span class="cx"> 
</span><span class="cx">         URL fallbackURL;
</span><span class="lines">@@ -308,7 +308,7 @@
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><span class="cx">         auto& group = *new ApplicationCacheGroup(*this, manifestURL);
</span><del>-        group.setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
</del><ins>+        group.setStorageID(static_cast<unsigned>(statement->getColumnInt64(0)));
</ins><span class="cx">         group.setNewestCache(cache.releaseNonNull());
</span><span class="cx"> 
</span><span class="cx">         m_cachesInMemory.set(group.manifestURL().string(), &group);
</span><span class="lines">@@ -416,17 +416,17 @@
</span><span class="cx">     // If an Origin record doesn't exist, then the COUNT will be 0 and quota will be 0.
</span><span class="cx">     // Using the count to determine if a record existed or not is a safe way to determine
</span><span class="cx">     // if a quota of 0 is real, from the record, or from null.
</span><del>-    SQLiteStatement statement(m_database, "SELECT COUNT(quota), quota FROM Origins WHERE origin=?");
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT COUNT(quota), quota FROM Origins WHERE origin=?"_s);
+    if (!statement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    statement.bindText(1, origin.data().databaseIdentifier());
-    int result = statement.step();
</del><ins>+    statement->bindText(1, origin.data().databaseIdentifier());
+    int result = statement->step();
</ins><span class="cx"> 
</span><span class="cx">     // Return the quota, or if it was null the default.
</span><span class="cx">     if (result == SQLITE_ROW) {
</span><del>-        bool wasNoRecord = statement.getColumnInt64(0) == 0;
-        quota = wasNoRecord ? m_defaultOriginQuota : statement.getColumnInt64(1);
</del><ins>+        bool wasNoRecord = !statement->getColumnInt64(0);
+        quota = wasNoRecord ? m_defaultOriginQuota : statement->getColumnInt64(1);
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -440,19 +440,19 @@
</span><span class="cx"> 
</span><span class="cx">     // If an Origins record doesn't exist, then the SUM will be null,
</span><span class="cx">     // which will become 0, as expected, when converting to a number.
</span><del>-    SQLiteStatement statement(m_database, "SELECT SUM(Caches.size)"
-                                          "  FROM CacheGroups"
-                                          " INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
-                                          " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
-                                          " WHERE Origins.origin=?");
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT SUM(Caches.size)"
+                                                 " FROM CacheGroups"
+                                                 " INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
+                                                 " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
+                                                 " WHERE Origins.origin=?"_s);
+    if (!statement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    statement.bindText(1, origin.databaseIdentifier());
-    int result = statement.step();
</del><ins>+    statement->bindText(1, origin.databaseIdentifier());
+    int result = statement->step();
</ins><span class="cx"> 
</span><span class="cx">     if (result == SQLITE_ROW) {
</span><del>-        usage = statement.getColumnInt64(0);
</del><ins>+        usage = statement->getColumnInt64(0);
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -470,40 +470,40 @@
</span><span class="cx"> 
</span><span class="cx">     // Remaining size = total origin quota - size of all caches with origin excluding the provided cache.
</span><span class="cx">     // Keep track of the number of caches so we can tell if the result was a calculation or not.
</span><del>-    const char* query;
</del><span class="cx">     int64_t excludingCacheIdentifier = cache ? cache->storageID() : 0;
</span><del>-    if (excludingCacheIdentifier != 0) {
-        query = "SELECT COUNT(Caches.size), Origins.quota - SUM(Caches.size)"
-                "  FROM CacheGroups"
-                " INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
-                " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
-                " WHERE Origins.origin=?"
-                "   AND Caches.id!=?";
-    } else {
-        query = "SELECT COUNT(Caches.size), Origins.quota - SUM(Caches.size)"
-                "  FROM CacheGroups"
-                " INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
-                " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
-                " WHERE Origins.origin=?";
-    }
</del><ins>+    auto query = [excludingCacheIdentifier]() {
+        if (excludingCacheIdentifier) {
+            return "SELECT COUNT(Caches.size), Origins.quota - SUM(Caches.size)"
+                    "  FROM CacheGroups"
+                    " INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
+                    " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
+                    " WHERE Origins.origin=?"
+                    "   AND Caches.id!=?"_s;
+        }
+        return "SELECT COUNT(Caches.size), Origins.quota - SUM(Caches.size)"
+               "  FROM CacheGroups"
+               " INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
+               " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
+               " WHERE Origins.origin=?"_s;
+    }();
</ins><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, query);
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement(query);
+    if (!statement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    statement.bindText(1, origin.data().databaseIdentifier());
</del><ins>+    statement->bindText(1, origin.data().databaseIdentifier());
</ins><span class="cx">     if (excludingCacheIdentifier != 0)
</span><del>-        statement.bindInt64(2, excludingCacheIdentifier);
-    int result = statement.step();
</del><ins>+        statement->bindInt64(2, excludingCacheIdentifier);
+    int result = statement->step();
</ins><span class="cx"> 
</span><span class="cx">     // If the count was 0 that then we have to query the origin table directly
</span><span class="cx">     // for its quota. Otherwise we can use the calculated value.
</span><span class="cx">     if (result == SQLITE_ROW) {
</span><del>-        int64_t numberOfCaches = statement.getColumnInt64(0);
</del><ins>+        int64_t numberOfCaches = statement->getColumnInt64(0);
</ins><span class="cx">         if (numberOfCaches == 0)
</span><span class="cx">             calculateQuotaForOrigin(origin, remainingSize);
</span><span class="cx">         else
</span><del>-            remainingSize = statement.getColumnInt64(1);
</del><ins>+            remainingSize = statement->getColumnInt64(1);
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -522,14 +522,14 @@
</span><span class="cx">     if (!ensureOriginRecord(origin))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    SQLiteStatement updateStatement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
-    if (updateStatement.prepare() != SQLITE_OK)
</del><ins>+    auto updateStatement = m_database.prepareStatement("UPDATE Origins SET quota=? WHERE origin=?"_s);
+    if (!updateStatement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    updateStatement.bindInt64(1, quota);
-    updateStatement.bindText(2, origin->data().databaseIdentifier());
</del><ins>+    updateStatement->bindInt64(1, quota);
+    updateStatement->bindText(2, origin->data().databaseIdentifier());
</ins><span class="cx"> 
</span><del>-    return executeStatement(updateStatement);
</del><ins>+    return executeStatement(updateStatement.value());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool ApplicationCacheStorage::executeSQLCommand(const String& sql)
</span><span class="lines">@@ -554,7 +554,8 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
</span><span class="cx"> 
</span><del>-    int version = SQLiteStatement(m_database, "PRAGMA user_version").getColumnInt(0);
</del><ins>+    auto versionStatement = m_database.prepareStatement("PRAGMA user_version"_s);
+    int version = versionStatement ? versionStatement->getColumnInt(0) : 0;
</ins><span class="cx">     if (version == schemaVersion)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="lines">@@ -570,11 +571,11 @@
</span><span class="cx">     int unusedNumBytes = snprintf(userVersionSQL, sizeof(userVersionSQL), "PRAGMA user_version=%d", schemaVersion);
</span><span class="cx">     ASSERT_UNUSED(unusedNumBytes, static_cast<int>(sizeof(userVersionSQL)) >= unusedNumBytes);
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, userVersionSQL);
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement(userVersionSQL);
+    if (!statement)
</ins><span class="cx">         return;
</span><span class="cx">     
</span><del>-    executeStatement(statement);
</del><ins>+    executeStatement(statement.value());
</ins><span class="cx">     setDatabaseVersion.commit();
</span><span class="cx"> }
</span><span class="cx">     
</span><span class="lines">@@ -652,8 +653,7 @@
</span><span class="cx">     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
</span><span class="cx">     bool result = statement.executeCommand();
</span><span class="cx">     if (!result)
</span><del>-        LOG_ERROR("Application Cache Storage: failed to execute statement \"%s\" error \"%s\"", 
-                  statement.query().utf8().data(), m_database.lastErrorMsg());
</del><ins>+        LOG_ERROR("Application Cache Storage: failed to execute statement, error \"%s\"", m_database.lastErrorMsg());
</ins><span class="cx">     
</span><span class="cx">     return result;
</span><span class="cx"> }    
</span><span class="lines">@@ -670,15 +670,15 @@
</span><span class="cx">     // a way to repair it.
</span><span class="cx">     deleteCacheGroupRecord(group->manifestURL().string());
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, "INSERT INTO CacheGroups (manifestHostHash, manifestURL, origin) VALUES (?, ?, ?)");
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("INSERT INTO CacheGroups (manifestHostHash, manifestURL, origin) VALUES (?, ?, ?)"_s);
+    if (!statement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    statement.bindInt64(1, urlHostHash(group->manifestURL()));
-    statement.bindText(2, group->manifestURL().string());
-    statement.bindText(3, group->origin().data().databaseIdentifier());
</del><ins>+    statement->bindInt64(1, urlHostHash(group->manifestURL()));
+    statement->bindText(2, group->manifestURL().string());
+    statement->bindText(3, group->origin().data().databaseIdentifier());
</ins><span class="cx"> 
</span><del>-    if (!executeStatement(statement))
</del><ins>+    if (!executeStatement(statement.value()))
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     unsigned groupStorageID = static_cast<unsigned>(m_database.lastInsertRowID());
</span><span class="lines">@@ -698,14 +698,14 @@
</span><span class="cx">     ASSERT(cache->group()->storageID() != 0);
</span><span class="cx">     ASSERT(storageIDJournal);
</span><span class="cx">     
</span><del>-    SQLiteStatement statement(m_database, "INSERT INTO Caches (cacheGroup, size) VALUES (?, ?)");
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("INSERT INTO Caches (cacheGroup, size) VALUES (?, ?)"_s);
+    if (!statement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    statement.bindInt64(1, cache->group()->storageID());
-    statement.bindInt64(2, cache->estimatedSizeInStorage());
</del><ins>+    statement->bindInt64(1, cache->group()->storageID());
+    statement->bindInt64(2, cache->estimatedSizeInStorage());
</ins><span class="cx"> 
</span><del>-    if (!executeStatement(statement))
</del><ins>+    if (!executeStatement(statement.value()))
</ins><span class="cx">         return false;
</span><span class="cx">     
</span><span class="cx">     unsigned cacheStorageID = static_cast<unsigned>(m_database.lastInsertRowID());
</span><span class="lines">@@ -725,13 +725,14 @@
</span><span class="cx">     const Vector<URL>& onlineAllowlist = cache->onlineAllowlist();
</span><span class="cx">     {
</span><span class="cx">         for (auto& allowlistURL : onlineAllowlist) {
</span><del>-            SQLiteStatement statement(m_database, "INSERT INTO CacheWhitelistURLs (url, cache) VALUES (?, ?)");
-            statement.prepare();
</del><ins>+            auto statement = m_database.prepareStatement("INSERT INTO CacheWhitelistURLs (url, cache) VALUES (?, ?)"_s);
+            if (!statement)
+                return false;
</ins><span class="cx"> 
</span><del>-            statement.bindText(1, allowlistURL.string());
-            statement.bindInt64(2, cacheStorageID);
</del><ins>+            statement->bindText(1, allowlistURL.string());
+            statement->bindInt64(2, cacheStorageID);
</ins><span class="cx"> 
</span><del>-            if (!executeStatement(statement))
</del><ins>+            if (!executeStatement(statement.value()))
</ins><span class="cx">                 return false;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -738,13 +739,14 @@
</span><span class="cx"> 
</span><span class="cx">     // Store online allowlist wildcard flag.
</span><span class="cx">     {
</span><del>-        SQLiteStatement statement(m_database, "INSERT INTO CacheAllowsAllNetworkRequests (wildcard, cache) VALUES (?, ?)");
-        statement.prepare();
</del><ins>+        auto statement = m_database.prepareStatement("INSERT INTO CacheAllowsAllNetworkRequests (wildcard, cache) VALUES (?, ?)"_s);
+        if (!statement)
+            return false;
</ins><span class="cx"> 
</span><del>-        statement.bindInt64(1, cache->allowsAllNetworkRequests());
-        statement.bindInt64(2, cacheStorageID);
</del><ins>+        statement->bindInt64(1, cache->allowsAllNetworkRequests());
+        statement->bindInt64(2, cacheStorageID);
</ins><span class="cx"> 
</span><del>-        if (!executeStatement(statement))
</del><ins>+        if (!executeStatement(statement.value()))
</ins><span class="cx">             return false;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -752,14 +754,15 @@
</span><span class="cx">     const FallbackURLVector& fallbackURLs = cache->fallbackURLs();
</span><span class="cx">     {
</span><span class="cx">         for (auto& fallbackURL : fallbackURLs) {
</span><del>-            SQLiteStatement statement(m_database, "INSERT INTO FallbackURLs (namespace, fallbackURL, cache) VALUES (?, ?, ?)");
-            statement.prepare();
</del><ins>+            auto statement = m_database.prepareStatement("INSERT INTO FallbackURLs (namespace, fallbackURL, cache) VALUES (?, ?, ?)"_s);
+            if (!statement)
+                return false;
</ins><span class="cx"> 
</span><del>-            statement.bindText(1, fallbackURL.first.string());
-            statement.bindText(2, fallbackURL.second.string());
-            statement.bindInt64(3, cacheStorageID);
</del><ins>+            statement->bindText(1, fallbackURL.first.string());
+            statement->bindText(2, fallbackURL.second.string());
+            statement->bindInt64(3, cacheStorageID);
</ins><span class="cx"> 
</span><del>-            if (!executeStatement(statement))
</del><ins>+            if (!executeStatement(statement.value()))
</ins><span class="cx">                 return false;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -781,14 +784,14 @@
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     // First, insert the data
</span><del>-    SQLiteStatement dataStatement(m_database, "INSERT INTO CacheResourceData (data, path) VALUES (?, ?)");
-    if (dataStatement.prepare() != SQLITE_OK)
</del><ins>+    auto dataStatement = m_database.prepareStatement("INSERT INTO CacheResourceData (data, path) VALUES (?, ?)"_s);
+    if (!dataStatement)
</ins><span class="cx">         return false;
</span><span class="cx">     
</span><span class="cx"> 
</span><span class="cx">     String fullPath;
</span><span class="cx">     if (!resource->path().isEmpty())
</span><del>-        dataStatement.bindText(2, FileSystem::pathFileName(resource->path()));
</del><ins>+        dataStatement->bindText(2, FileSystem::pathFileName(resource->path()));
</ins><span class="cx">     else if (shouldStoreResourceAsFlatFile(resource)) {
</span><span class="cx">         // First, check to see if creating the flat file would violate the maximum total quota. We don't need
</span><span class="cx">         // to check the per-origin quota here, as it was already checked in storeNewestCache().
</span><span class="lines">@@ -813,13 +816,13 @@
</span><span class="cx">         
</span><span class="cx">         fullPath = FileSystem::pathByAppendingComponent(flatFileDirectory, path);
</span><span class="cx">         resource->setPath(fullPath);
</span><del>-        dataStatement.bindText(2, path);
</del><ins>+        dataStatement->bindText(2, path);
</ins><span class="cx">     } else {
</span><span class="cx">         if (resource->data().size())
</span><del>-            dataStatement.bindBlob(1, resource->data().data(), resource->data().size());
</del><ins>+            dataStatement->bindBlob(1, resource->data().data(), resource->data().size());
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    if (!dataStatement.executeCommand()) {
</del><ins>+    if (!dataStatement->executeCommand()) {
</ins><span class="cx">         // Clean up the file which we may have written to:
</span><span class="cx">         if (!fullPath.isEmpty())
</span><span class="cx">             FileSystem::deleteFile(fullPath);
</span><span class="lines">@@ -843,36 +846,36 @@
</span><span class="cx">     
</span><span class="cx">     String headers = stringBuilder.toString();
</span><span class="cx">     
</span><del>-    SQLiteStatement resourceStatement(m_database, "INSERT INTO CacheResources (url, statusCode, responseURL, headers, data, mimeType, textEncodingName) VALUES (?, ?, ?, ?, ?, ?, ?)");
-    if (resourceStatement.prepare() != SQLITE_OK)
</del><ins>+    auto resourceStatement = m_database.prepareStatement("INSERT INTO CacheResources (url, statusCode, responseURL, headers, data, mimeType, textEncodingName) VALUES (?, ?, ?, ?, ?, ?, ?)"_s);
+    if (!resourceStatement)
</ins><span class="cx">         return false;
</span><span class="cx">     
</span><span class="cx">     // The same ApplicationCacheResource are used in ApplicationCacheResource::size()
</span><span class="cx">     // to calculate the approximate size of an ApplicationCacheResource object. If
</span><span class="cx">     // you change the code below, please also change ApplicationCacheResource::size().
</span><del>-    resourceStatement.bindText(1, resource->url().string());
-    resourceStatement.bindInt64(2, resource->response().httpStatusCode());
-    resourceStatement.bindText(3, resource->response().url().string());
-    resourceStatement.bindText(4, headers);
-    resourceStatement.bindInt64(5, dataId);
-    resourceStatement.bindText(6, resource->response().mimeType());
-    resourceStatement.bindText(7, resource->response().textEncodingName());
</del><ins>+    resourceStatement->bindText(1, resource->url().string());
+    resourceStatement->bindInt64(2, resource->response().httpStatusCode());
+    resourceStatement->bindText(3, resource->response().url().string());
+    resourceStatement->bindText(4, headers);
+    resourceStatement->bindInt64(5, dataId);
+    resourceStatement->bindText(6, resource->response().mimeType());
+    resourceStatement->bindText(7, resource->response().textEncodingName());
</ins><span class="cx"> 
</span><del>-    if (!executeStatement(resourceStatement))
</del><ins>+    if (!executeStatement(resourceStatement.value()))
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     unsigned resourceId = static_cast<unsigned>(m_database.lastInsertRowID());
</span><span class="cx">     
</span><span class="cx">     // Finally, insert the cache entry
</span><del>-    SQLiteStatement entryStatement(m_database, "INSERT INTO CacheEntries (cache, type, resource) VALUES (?, ?, ?)");
-    if (entryStatement.prepare() != SQLITE_OK)
</del><ins>+    auto entryStatement = m_database.prepareStatement("INSERT INTO CacheEntries (cache, type, resource) VALUES (?, ?, ?)"_s);
+    if (!entryStatement)
</ins><span class="cx">         return false;
</span><span class="cx">     
</span><del>-    entryStatement.bindInt64(1, cacheStorageID);
-    entryStatement.bindInt64(2, resource->type());
-    entryStatement.bindInt64(3, resourceId);
</del><ins>+    entryStatement->bindInt64(1, cacheStorageID);
+    entryStatement->bindInt64(2, resource->type());
+    entryStatement->bindInt64(3, resourceId);
</ins><span class="cx">     
</span><del>-    if (!executeStatement(entryStatement))
</del><ins>+    if (!executeStatement(entryStatement.value()))
</ins><span class="cx">         return false;
</span><span class="cx">     
</span><span class="cx">     // Did we successfully write the resource data to a file? If so,
</span><span class="lines">@@ -893,14 +896,14 @@
</span><span class="cx">     ASSERT(resource->storageID());
</span><span class="cx"> 
</span><span class="cx">     // First, insert the data
</span><del>-    SQLiteStatement entryStatement(m_database, "UPDATE CacheEntries SET type=? WHERE resource=?");
-    if (entryStatement.prepare() != SQLITE_OK)
</del><ins>+    auto entryStatement = m_database.prepareStatement("UPDATE CacheEntries SET type=? WHERE resource=?"_s);
+    if (!entryStatement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    entryStatement.bindInt64(1, resource->type());
-    entryStatement.bindInt64(2, resource->storageID());
</del><ins>+    entryStatement->bindInt64(1, resource->type());
+    entryStatement->bindInt64(2, resource->storageID());
</ins><span class="cx"> 
</span><del>-    return executeStatement(entryStatement);
</del><ins>+    return executeStatement(entryStatement.value());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, ApplicationCache* cache)
</span><span class="lines">@@ -926,14 +929,14 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // A resource was added to the cache. Update the total data size for the cache.
</span><del>-    SQLiteStatement sizeUpdateStatement(m_database, "UPDATE Caches SET size=size+? WHERE id=?");
-    if (sizeUpdateStatement.prepare() != SQLITE_OK)
</del><ins>+    auto sizeUpdateStatement = m_database.prepareStatement("UPDATE Caches SET size=size+? WHERE id=?"_s);
+    if (!sizeUpdateStatement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    sizeUpdateStatement.bindInt64(1, resource->estimatedSizeInStorage());
-    sizeUpdateStatement.bindInt64(2, cache->storageID());
</del><ins>+    sizeUpdateStatement->bindInt64(1, resource->estimatedSizeInStorage());
+    sizeUpdateStatement->bindInt64(2, cache->storageID());
</ins><span class="cx"> 
</span><del>-    if (!executeStatement(sizeUpdateStatement))
</del><ins>+    if (!executeStatement(sizeUpdateStatement.value()))
</ins><span class="cx">         return false;
</span><span class="cx">     
</span><span class="cx">     storeResourceTransaction.commit();
</span><span class="lines">@@ -943,13 +946,13 @@
</span><span class="cx"> bool ApplicationCacheStorage::ensureOriginRecord(const SecurityOrigin* origin)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
</span><del>-    SQLiteStatement insertOriginStatement(m_database, "INSERT INTO Origins (origin, quota) VALUES (?, ?)");
-    if (insertOriginStatement.prepare() != SQLITE_OK)
</del><ins>+    auto insertOriginStatement = m_database.prepareStatement("INSERT INTO Origins (origin, quota) VALUES (?, ?)"_s);
+    if (!insertOriginStatement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    insertOriginStatement.bindText(1, origin->data().databaseIdentifier());
-    insertOriginStatement.bindInt64(2, m_defaultOriginQuota);
-    if (!executeStatement(insertOriginStatement))
</del><ins>+    insertOriginStatement->bindText(1, origin->data().databaseIdentifier());
+    insertOriginStatement->bindInt64(2, m_defaultOriginQuota);
+    if (!executeStatement(insertOriginStatement.value()))
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     return true;
</span><span class="lines">@@ -1026,16 +1029,16 @@
</span><span class="cx">     
</span><span class="cx">     // Update the newest cache in the group.
</span><span class="cx">     
</span><del>-    SQLiteStatement statement(m_database, "UPDATE CacheGroups SET newestCache=? WHERE id=?");
-    if (statement.prepare() != SQLITE_OK) {
</del><ins>+    auto statement = m_database.prepareStatement("UPDATE CacheGroups SET newestCache=? WHERE id=?"_s);
+    if (!statement) {
</ins><span class="cx">         failureReason = DiskOrOperationFailure;
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    statement.bindInt64(1, group.newestCache()->storageID());
-    statement.bindInt64(2, group.storageID());
</del><ins>+    statement->bindInt64(1, group.newestCache()->storageID());
+    statement->bindInt64(2, group.storageID());
</ins><span class="cx">     
</span><del>-    if (!executeStatement(statement)) {
</del><ins>+    if (!executeStatement(statement.value())) {
</ins><span class="cx">         failureReason = DiskOrOperationFailure;
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="lines">@@ -1093,15 +1096,15 @@
</span><span class="cx"> RefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storageID)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
</span><del>-    SQLiteStatement cacheStatement(m_database,
-                                   "SELECT url, statusCode, type, mimeType, textEncodingName, headers, CacheResourceData.data, CacheResourceData.path FROM CacheEntries INNER JOIN CacheResources ON CacheEntries.resource=CacheResources.id "
-                                   "INNER JOIN CacheResourceData ON CacheResourceData.id=CacheResources.data WHERE CacheEntries.cache=?");
-    if (cacheStatement.prepare() != SQLITE_OK) {
</del><ins>+    auto cacheStatement = m_database.prepareStatement(
+        "SELECT url, statusCode, type, mimeType, textEncodingName, headers, CacheResourceData.data, CacheResourceData.path FROM CacheEntries INNER JOIN CacheResources ON CacheEntries.resource=CacheResources.id "
+        "INNER JOIN CacheResourceData ON CacheResourceData.id=CacheResources.data WHERE CacheEntries.cache=?"_s);
+    if (!cacheStatement) {
</ins><span class="cx">         LOG_ERROR("Could not prepare cache statement, error \"%s\"", m_database.lastErrorMsg());
</span><span class="cx">         return nullptr;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    cacheStatement.bindInt64(1, storageID);
</del><ins>+    cacheStatement->bindInt64(1, storageID);
</ins><span class="cx"> 
</span><span class="cx">     auto cache = ApplicationCache::create();
</span><span class="cx"> 
</span><span class="lines">@@ -1108,19 +1111,19 @@
</span><span class="cx">     String flatFileDirectory = FileSystem::pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName);
</span><span class="cx"> 
</span><span class="cx">     int result;
</span><del>-    while ((result = cacheStatement.step()) == SQLITE_ROW) {
-        URL url({ }, cacheStatement.getColumnText(0));
</del><ins>+    while ((result = cacheStatement->step()) == SQLITE_ROW) {
+        URL url({ }, cacheStatement->getColumnText(0));
</ins><span class="cx">         
</span><del>-        int httpStatusCode = cacheStatement.getColumnInt(1);
</del><ins>+        int httpStatusCode = cacheStatement->getColumnInt(1);
</ins><span class="cx"> 
</span><del>-        unsigned type = static_cast<unsigned>(cacheStatement.getColumnInt64(2));
</del><ins>+        unsigned type = static_cast<unsigned>(cacheStatement->getColumnInt64(2));
</ins><span class="cx"> 
</span><span class="cx">         Vector<char> blob;
</span><del>-        cacheStatement.getColumnBlobAsVector(6, blob);
</del><ins>+        cacheStatement->getColumnBlobAsVector(6, blob);
</ins><span class="cx">         
</span><span class="cx">         auto data = SharedBuffer::create(WTFMove(blob));
</span><span class="cx">         
</span><del>-        String path = cacheStatement.getColumnText(7);
</del><ins>+        String path = cacheStatement->getColumnText(7);
</ins><span class="cx">         long long size = 0;
</span><span class="cx">         if (path.isEmpty())
</span><span class="cx">             size = data->size();
</span><span class="lines">@@ -1129,13 +1132,13 @@
</span><span class="cx">             size = FileSystem::fileSize(path).valueOr(0);
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        String mimeType = cacheStatement.getColumnText(3);
-        String textEncodingName = cacheStatement.getColumnText(4);
</del><ins>+        String mimeType = cacheStatement->getColumnText(3);
+        String textEncodingName = cacheStatement->getColumnText(4);
</ins><span class="cx">         
</span><span class="cx">         ResourceResponse response(url, mimeType, size, textEncodingName);
</span><span class="cx">         response.setHTTPStatusCode(httpStatusCode);
</span><span class="cx"> 
</span><del>-        String headers = cacheStatement.getColumnText(5);
</del><ins>+        String headers = cacheStatement->getColumnText(5);
</ins><span class="cx">         parseHeaders(headers, response);
</span><span class="cx">         
</span><span class="cx">         auto resource = ApplicationCacheResource::create(url, response, type, WTFMove(data), path);
</span><span class="lines">@@ -1155,14 +1158,14 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Load the online allowlist
</span><del>-    SQLiteStatement allowlistStatement(m_database, "SELECT url FROM CacheWhitelistURLs WHERE cache=?");
-    if (allowlistStatement.prepare() != SQLITE_OK)
</del><ins>+    auto allowlistStatement = m_database.prepareStatement("SELECT url FROM CacheWhitelistURLs WHERE cache=?"_s);
+    if (!allowlistStatement)
</ins><span class="cx">         return nullptr;
</span><del>-    allowlistStatement.bindInt64(1, storageID);
</del><ins>+    allowlistStatement->bindInt64(1, storageID);
</ins><span class="cx">     
</span><span class="cx">     Vector<URL> allowlist;
</span><del>-    while ((result = allowlistStatement.step()) == SQLITE_ROW)
-        allowlist.append(URL({ }, allowlistStatement.getColumnText(0)));
</del><ins>+    while ((result = allowlistStatement->step()) == SQLITE_ROW)
+        allowlist.append(URL({ }, allowlistStatement->getColumnText(0)));
</ins><span class="cx"> 
</span><span class="cx">     if (result != SQLITE_DONE)
</span><span class="cx">         LOG_ERROR("Could not load cache online allowlist, error \"%s\"", m_database.lastErrorMsg());
</span><span class="lines">@@ -1170,29 +1173,29 @@
</span><span class="cx">     cache->setOnlineAllowlist(allowlist);
</span><span class="cx"> 
</span><span class="cx">     // Load online allowlist wildcard flag.
</span><del>-    SQLiteStatement allowlistWildcardStatement(m_database, "SELECT wildcard FROM CacheAllowsAllNetworkRequests WHERE cache=?");
-    if (allowlistWildcardStatement.prepare() != SQLITE_OK)
</del><ins>+    auto allowlistWildcardStatement = m_database.prepareStatement("SELECT wildcard FROM CacheAllowsAllNetworkRequests WHERE cache=?"_s);
+    if (!allowlistWildcardStatement)
</ins><span class="cx">         return nullptr;
</span><del>-    allowlistWildcardStatement.bindInt64(1, storageID);
</del><ins>+    allowlistWildcardStatement->bindInt64(1, storageID);
</ins><span class="cx">     
</span><del>-    result = allowlistWildcardStatement.step();
</del><ins>+    result = allowlistWildcardStatement->step();
</ins><span class="cx">     if (result != SQLITE_ROW)
</span><span class="cx">         LOG_ERROR("Could not load cache online allowlist wildcard flag, error \"%s\"", m_database.lastErrorMsg());
</span><span class="cx"> 
</span><del>-    cache->setAllowsAllNetworkRequests(allowlistWildcardStatement.getColumnInt64(0));
</del><ins>+    cache->setAllowsAllNetworkRequests(allowlistWildcardStatement->getColumnInt64(0));
</ins><span class="cx"> 
</span><del>-    if (allowlistWildcardStatement.step() != SQLITE_DONE)
</del><ins>+    if (allowlistWildcardStatement->step() != SQLITE_DONE)
</ins><span class="cx">         LOG_ERROR("Too many rows for online allowlist wildcard flag");
</span><span class="cx"> 
</span><span class="cx">     // Load fallback URLs.
</span><del>-    SQLiteStatement fallbackStatement(m_database, "SELECT namespace, fallbackURL FROM FallbackURLs WHERE cache=?");
-    if (fallbackStatement.prepare() != SQLITE_OK)
</del><ins>+    auto fallbackStatement = m_database.prepareStatement("SELECT namespace, fallbackURL FROM FallbackURLs WHERE cache=?"_s);
+    if (!fallbackStatement)
</ins><span class="cx">         return nullptr;
</span><del>-    fallbackStatement.bindInt64(1, storageID);
</del><ins>+    fallbackStatement->bindInt64(1, storageID);
</ins><span class="cx">     
</span><span class="cx">     FallbackURLVector fallbackURLs;
</span><del>-    while ((result = fallbackStatement.step()) == SQLITE_ROW) 
-        fallbackURLs.append(std::make_pair(URL({ }, fallbackStatement.getColumnText(0)), URL({ }, fallbackStatement.getColumnText(1))));
</del><ins>+    while ((result = fallbackStatement->step()) == SQLITE_ROW)
+        fallbackURLs.append(std::make_pair(URL({ }, fallbackStatement->getColumnText(0)), URL({ }, fallbackStatement->getColumnText(1))));
</ins><span class="cx"> 
</span><span class="cx">     if (result != SQLITE_DONE)
</span><span class="cx">         LOG_ERROR("Could not load fallback URLs, error \"%s\"", m_database.lastErrorMsg());
</span><span class="lines">@@ -1219,23 +1222,23 @@
</span><span class="cx">     ASSERT(cache->group()->storageID());
</span><span class="cx"> 
</span><span class="cx">     // All associated data will be deleted by database triggers.
</span><del>-    SQLiteStatement statement(m_database, "DELETE FROM Caches WHERE id=?");
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("DELETE FROM Caches WHERE id=?"_s);
+    if (!statement)
</ins><span class="cx">         return;
</span><span class="cx">     
</span><del>-    statement.bindInt64(1, cache->storageID());
-    executeStatement(statement);
</del><ins>+    statement->bindInt64(1, cache->storageID());
+    executeStatement(statement.value());
</ins><span class="cx"> 
</span><span class="cx">     cache->clearStorageID();
</span><span class="cx"> 
</span><span class="cx">     if (cache->group()->newestCache() == cache) {
</span><span class="cx">         // Currently, there are no triggers on the cache group, which is why the cache had to be removed separately above.
</span><del>-        SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?");
-        if (groupStatement.prepare() != SQLITE_OK)
</del><ins>+        auto groupStatement = m_database.prepareStatement("DELETE FROM CacheGroups WHERE id=?"_s);
+        if (!groupStatement)
</ins><span class="cx">             return;
</span><span class="cx">         
</span><del>-        groupStatement.bindInt64(1, cache->group()->storageID());
-        executeStatement(groupStatement);
</del><ins>+        groupStatement->bindInt64(1, cache->group()->storageID());
+        executeStatement(groupStatement.value());
</ins><span class="cx"> 
</span><span class="cx">         cache->group()->clearStorageID();
</span><span class="cx">     }
</span><span class="lines">@@ -1316,14 +1319,13 @@
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return WTF::nullopt;
</span><span class="cx"> 
</span><del>-    SQLiteStatement selectURLs(m_database, "SELECT manifestURL FROM CacheGroups");
-
-    if (selectURLs.prepare() != SQLITE_OK)
</del><ins>+    auto selectURLs = m_database.prepareStatement("SELECT manifestURL FROM CacheGroups"_s);
+    if (!selectURLs)
</ins><span class="cx">         return WTF::nullopt;
</span><span class="cx"> 
</span><span class="cx">     Vector<URL> urls;
</span><del>-    while (selectURLs.step() == SQLITE_ROW)
-        urls.append(URL({ }, selectURLs.getColumnText(0)));
</del><ins>+    while (selectURLs->step() == SQLITE_ROW)
+        urls.append(URL({ }, selectURLs->getColumnText(0)));
</ins><span class="cx"> 
</span><span class="cx">     return urls;
</span><span class="cx"> }
</span><span class="lines">@@ -1331,30 +1333,30 @@
</span><span class="cx"> bool ApplicationCacheStorage::deleteCacheGroupRecord(const String& manifestURL)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
</span><del>-    SQLiteStatement idStatement(m_database, "SELECT id FROM CacheGroups WHERE manifestURL=?");
-    if (idStatement.prepare() != SQLITE_OK)
</del><ins>+    auto idStatement = m_database.prepareStatement("SELECT id FROM CacheGroups WHERE manifestURL=?"_s);
+    if (!idStatement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    idStatement.bindText(1, manifestURL);
</del><ins>+    idStatement->bindText(1, manifestURL);
</ins><span class="cx"> 
</span><del>-    int result = idStatement.step();
</del><ins>+    int result = idStatement->step();
</ins><span class="cx">     if (result != SQLITE_ROW)
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    int64_t groupId = idStatement.getColumnInt64(0);
</del><ins>+    int64_t groupId = idStatement->getColumnInt64(0);
</ins><span class="cx"> 
</span><del>-    SQLiteStatement cacheStatement(m_database, "DELETE FROM Caches WHERE cacheGroup=?");
-    if (cacheStatement.prepare() != SQLITE_OK)
</del><ins>+    auto cacheStatement = m_database.prepareStatement("DELETE FROM Caches WHERE cacheGroup=?"_s);
+    if (!cacheStatement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?");
-    if (groupStatement.prepare() != SQLITE_OK)
</del><ins>+    auto groupStatement = m_database.prepareStatement("DELETE FROM CacheGroups WHERE id=?"_s);
+    if (!groupStatement)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    cacheStatement.bindInt64(1, groupId);
-    executeStatement(cacheStatement);
-    groupStatement.bindInt64(1, groupId);
-    executeStatement(groupStatement);
</del><ins>+    cacheStatement->bindInt64(1, groupId);
+    executeStatement(cacheStatement.value());
+    groupStatement->bindInt64(1, groupId);
+    executeStatement(groupStatement.value());
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1409,20 +1411,20 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     // Select only the paths in DeletedCacheResources that do not also appear in CacheResourceData:
</span><del>-    SQLiteStatement selectPaths(m_database, "SELECT DeletedCacheResources.path "
</del><ins>+    auto selectPaths = m_database.prepareStatement("SELECT DeletedCacheResources.path "
</ins><span class="cx">         "FROM DeletedCacheResources "
</span><span class="cx">         "LEFT JOIN CacheResourceData "
</span><span class="cx">         "ON DeletedCacheResources.path = CacheResourceData.path "
</span><del>-        "WHERE (SELECT DeletedCacheResources.path == CacheResourceData.path) IS NULL");
</del><ins>+        "WHERE (SELECT DeletedCacheResources.path == CacheResourceData.path) IS NULL"_s);
</ins><span class="cx">     
</span><del>-    if (selectPaths.prepare() != SQLITE_OK)
</del><ins>+    if (!selectPaths)
</ins><span class="cx">         return;
</span><span class="cx">     
</span><del>-    if (selectPaths.step() != SQLITE_ROW)
</del><ins>+    if (selectPaths->step() != SQLITE_ROW)
</ins><span class="cx">         return;
</span><span class="cx">     
</span><span class="cx">     do {
</span><del>-        String path = selectPaths.getColumnText(0);
</del><ins>+        String path = selectPaths->getColumnText(0);
</ins><span class="cx">         if (path.isEmpty())
</span><span class="cx">             continue;
</span><span class="cx">         
</span><span class="lines">@@ -1435,7 +1437,7 @@
</span><span class="cx">             continue;
</span><span class="cx">         
</span><span class="cx">         FileSystem::deleteFile(fullPath);
</span><del>-    } while (selectPaths.step() == SQLITE_ROW);
</del><ins>+    } while (selectPaths->step() == SQLITE_ROW);
</ins><span class="cx">     
</span><span class="cx">     executeSQLCommand("DELETE FROM DeletedCacheResources");
</span><span class="cx"> }
</span><span class="lines">@@ -1446,9 +1448,8 @@
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return 0;
</span><span class="cx">     
</span><del>-    SQLiteStatement selectPaths(m_database, "SELECT path FROM CacheResourceData WHERE path NOT NULL");
-
-    if (selectPaths.prepare() != SQLITE_OK) {
</del><ins>+    auto selectPaths = m_database.prepareStatement("SELECT path FROM CacheResourceData WHERE path NOT NULL"_s);
+    if (!selectPaths) {
</ins><span class="cx">         LOG_ERROR("Could not load flat file cache resource data, error \"%s\"", m_database.lastErrorMsg());
</span><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="lines">@@ -1455,8 +1456,8 @@
</span><span class="cx"> 
</span><span class="cx">     long long totalSize = 0;
</span><span class="cx">     String flatFileDirectory = FileSystem::pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName);
</span><del>-    while (selectPaths.step() == SQLITE_ROW) {
-        auto fullPath = FileSystem::pathByAppendingComponent(flatFileDirectory, selectPaths.getColumnText(0));
</del><ins>+    while (selectPaths->step() == SQLITE_ROW) {
+        auto fullPath = FileSystem::pathByAppendingComponent(flatFileDirectory, selectPaths->getColumnText(0));
</ins><span class="cx">         totalSize += FileSystem::fileSize(fullPath).valueOr(0);
</span><span class="cx">     }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworkcurlCookieJarDBcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/curl/CookieJarDB.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/curl/CookieJarDB.cpp       2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/platform/network/curl/CookieJarDB.cpp  2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -181,8 +181,6 @@
</span><span class="cx"> void CookieJarDB::closeDatabase()
</span><span class="cx"> {
</span><span class="cx">     if (m_database.isOpen()) {
</span><del>-        for (const auto& statement : m_statements)
-            statement.value.get()->finalize();
</del><span class="cx">         m_statements.clear();
</span><span class="cx">         m_database.close();
</span><span class="cx">     }
</span><span class="lines">@@ -193,7 +191,8 @@
</span><span class="cx">     if (isOnMemory())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    int version = SQLiteStatement(m_database, "PRAGMA user_version").getColumnInt(0);
</del><ins>+    auto statement = m_database.prepareStatement("PRAGMA user_version"_s);
+    int version = statement ? statement->getColumnInt(0) : 0;
</ins><span class="cx">     if (version == schemaVersion)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="lines">@@ -273,25 +272,25 @@
</span><span class="cx">     if (!m_database.tableExists("Cookie"))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    SQLiteStatement integrity(m_database, "PRAGMA quick_check;");
-    if (integrity.prepare() != SQLITE_OK) {
</del><ins>+    auto integrity = m_database.prepareStatement("PRAGMA quick_check;"_s);
+    if (!integrity) {
</ins><span class="cx">         LOG_ERROR("Failed to execute database integrity check");
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    int resultCode = integrity.step();
</del><ins>+    int resultCode = integrity->step();
</ins><span class="cx">     if (resultCode != SQLITE_ROW) {
</span><span class="cx">         LOG_ERROR("Integrity quick_check step returned %d", resultCode);
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    int columns = integrity.columnCount();
</del><ins>+    int columns = integrity->columnCount();
</ins><span class="cx">     if (columns != 1) {
</span><span class="cx">         LOG_ERROR("Received %i columns performing integrity check, should be 1", columns);
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    String resultText = integrity.getColumnText(0);
</del><ins>+    String resultText = integrity->getColumnText(0);
</ins><span class="cx"> 
</span><span class="cx">     if (resultText != "ok") {
</span><span class="cx">         LOG_ERROR("Cookie database integrity check failed - %s", resultText.ascii().data());
</span><span class="lines">@@ -386,20 +385,16 @@
</span><span class="cx"> 
</span><span class="cx">     RegistrableDomain registrableDomain { requestUrl };
</span><span class="cx"> 
</span><del>-    const String sql =
-        "SELECT name, value, domain, path, expires, httponly, secure, session FROM Cookie WHERE "\
</del><ins>+    auto pstmt = m_database.prepareStatement("SELECT name, value, domain, path, expires, httponly, secure, session FROM Cookie WHERE "\
</ins><span class="cx">         "(NOT ((session = 0) AND (expires < ?)))"
</span><span class="cx">         "AND (httponly = COALESCE(NULLIF(?, -1), httponly)) "\
</span><span class="cx">         "AND (secure = COALESCE(NULLIF(?, -1), secure)) "\
</span><span class="cx">         "AND (session = COALESCE(NULLIF(?, -1), session)) "\
</span><span class="cx">         "AND ((domain = ?) OR (domain GLOB ?)) "\
</span><del>-        "ORDER BY length(path) DESC, lastupdated";
-
-    auto pstmt = makeUnique<SQLiteStatement>(m_database, sql);
</del><ins>+        "ORDER BY length(path) DESC, lastupdated"_s);
</ins><span class="cx">     if (!pstmt)
</span><span class="cx">         return WTF::nullopt;
</span><span class="cx"> 
</span><del>-    pstmt->prepare();
</del><span class="cx">     pstmt->bindInt64(1, WallTime::now().secondsSinceEpoch().milliseconds());
</span><span class="cx">     pstmt->bindInt(2, httpOnly ? *httpOnly : -1);
</span><span class="cx">     pstmt->bindInt(3, secure ? *secure : -1);
</span><span class="lines">@@ -411,9 +406,6 @@
</span><span class="cx">     else
</span><span class="cx">         pstmt->bindText(6, String("*.") + registrableDomain.string());
</span><span class="cx"> 
</span><del>-    if (!pstmt)
-        return WTF::nullopt;
-
</del><span class="cx">     Vector<Cookie> results;
</span><span class="cx"> 
</span><span class="cx">     while (pstmt->step() == SQLITE_ROW) {
</span><span class="lines">@@ -453,7 +445,6 @@
</span><span class="cx">         cookie.session = cookieSession;
</span><span class="cx">         results.append(WTFMove(cookie));
</span><span class="cx">     }
</span><del>-    pstmt->finalize();
</del><span class="cx"> 
</span><span class="cx">     return results;
</span><span class="cx"> }
</span><span class="lines">@@ -463,11 +454,11 @@
</span><span class="cx">     Vector<Cookie> result;
</span><span class="cx">     if (!isEnabled() || !m_database.isOpen())
</span><span class="cx">         return result;
</span><del>-    const String sql = "SELECT name, value, domain, path, expires, httponly, secure, session FROM Cookie"_s;
-    auto pstmt = makeUnique<SQLiteStatement>(m_database, sql);
</del><ins>+
+    auto pstmt = m_database.prepareStatement("SELECT name, value, domain, path, expires, httponly, secure, session FROM Cookie"_s);
</ins><span class="cx">     if (!pstmt)
</span><span class="cx">         return result;
</span><del>-    pstmt->prepare();
</del><ins>+
</ins><span class="cx">     while (pstmt->step() == SQLITE_ROW) {
</span><span class="cx">         Cookie cookie;
</span><span class="cx">         cookie.name = pstmt->getColumnText(0);
</span><span class="lines">@@ -482,7 +473,6 @@
</span><span class="cx">         cookie.session = (pstmt->getColumnInt(7) == 1);
</span><span class="cx">         result.append(WTFMove(cookie));
</span><span class="cx">     }
</span><del>-    pstmt->finalize();
</del><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -571,16 +561,15 @@
</span><span class="cx"> 
</span><span class="cx"> HashSet<String> CookieJarDB::allDomains()
</span><span class="cx"> {
</span><del>-    SQLiteStatement statement(m_database, SELECT_ALL_DOMAINS_SQL);
-    statement.prepare();
</del><ins>+    auto statement = m_database.prepareStatement(SELECT_ALL_DOMAINS_SQL);
+    if (!statement)
+        return { };
</ins><span class="cx"> 
</span><span class="cx">     HashSet<String> domains;
</span><del>-    while (statement.step() == SQLITE_ROW) {
-        auto domain = statement.getColumnText(0);
</del><ins>+    while (statement->step() == SQLITE_ROW) {
+        auto domain = statement->getColumnText(0);
</ins><span class="cx">         domains.add(domain);
</span><span class="cx">     }
</span><del>-
-    statement.finalize();
</del><span class="cx">     return domains;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -637,10 +626,9 @@
</span><span class="cx"> 
</span><span class="cx"> void CookieJarDB::createPrepareStatement(const String& sql)
</span><span class="cx"> {
</span><del>-    auto statement = makeUnique<SQLiteStatement>(m_database, sql);
-    int ret = statement->prepare();
-    ASSERT_UNUSED(ret, ret == SQLITE_OK);
-    m_statements.add(sql, WTFMove(statement));
</del><ins>+    auto statement = m_database.prepareHeapStatement(sql);
+    ASSERT(statement);
+    m_statements.add(sql, statement.value().moveToUniquePtr());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SQLiteStatement& CookieJarDB::preparedStatement(const String& sql)
</span><span class="lines">@@ -653,10 +641,13 @@
</span><span class="cx"> 
</span><span class="cx"> bool CookieJarDB::executeSql(const String& sql)
</span><span class="cx"> {
</span><del>-    SQLiteStatement statement(m_database, sql);
-    int ret = statement.prepareAndStep();
-    statement.finalize();
</del><ins>+    auto statement = m_database.prepareStatement(sql);
+    if (!statement && !checkSQLiteReturnCode(statement.error())) {
+        LOG_ERROR("Failed to prepare %s error: %s", sql.ascii().data(), m_database.lastErrorMsg());
+        return false;
+    }
</ins><span class="cx"> 
</span><ins>+    int ret = statement->step();
</ins><span class="cx">     if (!checkSQLiteReturnCode(ret)) {
</span><span class="cx">         LOG_ERROR("Failed to execute %s error: %s", sql.ascii().data(), m_database.lastErrorMsg());
</span><span class="cx">         return false;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformsqlSQLiteDatabasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/sql/SQLiteDatabase.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/sql/SQLiteDatabase.cpp     2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/platform/sql/SQLiteDatabase.cpp        2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2006-2021 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
</span><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -142,7 +142,7 @@
</span><span class="cx"> 
</span><span class="cx">     {
</span><span class="cx">         SQLiteTransactionInProgressAutoCounter transactionCounter;
</span><del>-        if (!SQLiteStatement(*this, "PRAGMA temp_store = MEMORY;"_s).executeCommand())
</del><ins>+        if (!executeCommand("PRAGMA temp_store = MEMORY;"_s))
</ins><span class="cx">             LOG_ERROR("SQLite database could not set temp_store to memory");
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -197,10 +197,10 @@
</span><span class="cx"> {
</span><span class="cx">     m_useWAL = true;
</span><span class="cx">     {
</span><del>-        SQLiteStatement walStatement(*this, "PRAGMA journal_mode=WAL;"_s);
-        if (walStatement.prepareAndStep() == SQLITE_ROW) {
</del><ins>+        auto walStatement = prepareStatement("PRAGMA journal_mode=WAL;"_s);
+        if (walStatement && walStatement->step() == SQLITE_ROW) {
</ins><span class="cx"> #ifndef NDEBUG
</span><del>-            String mode = walStatement.getColumnText(0);
</del><ins>+            String mode = walStatement->getColumnText(0);
</ins><span class="cx">             if (!equalLettersIgnoringASCIICase(mode, "wal"))
</span><span class="cx">                 LOG_ERROR("journal_mode of database should be 'WAL', but is '%s'", mode.utf8().data());
</span><span class="cx"> #endif
</span><span class="lines">@@ -210,9 +210,9 @@
</span><span class="cx"> 
</span><span class="cx">     {
</span><span class="cx">         SQLiteTransactionInProgressAutoCounter transactionCounter;
</span><del>-        SQLiteStatement checkpointStatement(*this, "PRAGMA wal_checkpoint(TRUNCATE)"_s);
-        if (checkpointStatement.prepareAndStep() == SQLITE_ROW) {
-            if (checkpointStatement.getColumnInt(0))
</del><ins>+        auto checkpointStatement = prepareStatement("PRAGMA wal_checkpoint(TRUNCATE)"_s);
+        if (checkpointStatement && checkpointStatement->step() == SQLITE_ROW) {
+            if (checkpointStatement->getColumnInt(0))
</ins><span class="cx">                 LOG(SQLDatabase, "SQLite database checkpoint is blocked");
</span><span class="cx">         } else
</span><span class="cx">             LOG_ERROR("SQLite database failed to checkpoint: %s", lastErrorMsg());
</span><span class="lines">@@ -272,8 +272,8 @@
</span><span class="cx">     {
</span><span class="cx">         LockHolder locker(m_authorizerLock);
</span><span class="cx">         enableAuthorizer(false);
</span><del>-        SQLiteStatement statement(*this, "PRAGMA max_page_count"_s);
-        maxPageCount = statement.getColumnInt64(0);
</del><ins>+        auto statement = prepareStatement("PRAGMA max_page_count"_s);
+        maxPageCount = statement ? statement->getColumnInt64(0) : 0;
</ins><span class="cx">         enableAuthorizer(true);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -293,9 +293,8 @@
</span><span class="cx">     LockHolder locker(m_authorizerLock);
</span><span class="cx">     enableAuthorizer(false);
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(*this, makeString("PRAGMA max_page_count = ", newMaxPageCount));
-    statement.prepare();
-    if (statement.step() != SQLITE_ROW)
</del><ins>+    auto statement = prepareStatement(makeString("PRAGMA max_page_count = ", newMaxPageCount));
+    if (!statement || statement->step() != SQLITE_ROW)
</ins><span class="cx">         LOG_ERROR("Failed to set maximum size of database to %lli bytes", static_cast<long long>(size));
</span><span class="cx"> 
</span><span class="cx">     enableAuthorizer(true);
</span><span class="lines">@@ -310,8 +309,8 @@
</span><span class="cx">         LockHolder locker(m_authorizerLock);
</span><span class="cx">         enableAuthorizer(false);
</span><span class="cx">         
</span><del>-        SQLiteStatement statement(*this, "PRAGMA page_size"_s);
-        m_pageSize = statement.getColumnInt(0);
</del><ins>+        auto statement = prepareStatement("PRAGMA page_size"_s);
+        m_pageSize = statement ? statement->getColumnInt(0) : 0;
</ins><span class="cx">         
</span><span class="cx">         enableAuthorizer(true);
</span><span class="cx">     }
</span><span class="lines">@@ -327,8 +326,8 @@
</span><span class="cx">         LockHolder locker(m_authorizerLock);
</span><span class="cx">         enableAuthorizer(false);
</span><span class="cx">         // Note: freelist_count was added in SQLite 3.4.1.
</span><del>-        SQLiteStatement statement(*this, "PRAGMA freelist_count"_s);
-        freelistCount = statement.getColumnInt64(0);
</del><ins>+        auto statement = prepareStatement("PRAGMA freelist_count"_s);
+        freelistCount = statement ? statement->getColumnInt64(0) : 0;
</ins><span class="cx">         enableAuthorizer(true);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -342,8 +341,8 @@
</span><span class="cx">     {
</span><span class="cx">         LockHolder locker(m_authorizerLock);
</span><span class="cx">         enableAuthorizer(false);
</span><del>-        SQLiteStatement statement(*this, "PRAGMA page_count"_s);
-        pageCount = statement.getColumnInt64(0);
</del><ins>+        auto statement = prepareStatement("PRAGMA page_count"_s);
+        pageCount = statement ? statement->getColumnInt64(0) : 0;
</ins><span class="cx">         enableAuthorizer(true);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -371,14 +370,22 @@
</span><span class="cx">         LOG(SQLDatabase, "Busy handler set on non-open database");
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool SQLiteDatabase::executeCommand(const String& sql)
</del><ins>+bool SQLiteDatabase::executeCommand(const String& query)
</ins><span class="cx"> {
</span><del>-    return SQLiteStatement(*this, sql).executeCommand();
</del><ins>+    auto statement = prepareStatement(query);
+    return statement && statement->executeCommand();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool SQLiteDatabase::executeCommand(ASCIILiteral query)
+{
+    auto statement = prepareStatement(query);
+    return statement && statement->executeCommand();
+}
+
</ins><span class="cx"> bool SQLiteDatabase::returnsAtLeastOneResult(const String& sql)
</span><span class="cx"> {
</span><del>-    return SQLiteStatement(*this, sql).returnsAtLeastOneResult();
</del><ins>+    auto statement = prepareStatement(sql);
+    return statement && statement->returnsAtLeastOneResult();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool SQLiteDatabase::tableExists(const String& tablename)
</span><span class="lines">@@ -386,18 +393,15 @@
</span><span class="cx">     if (!isOpen())
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    String statement = "SELECT name FROM sqlite_master WHERE type = 'table' AND name = '" + tablename + "';";
-
-    SQLiteStatement sql(*this, statement);
-    sql.prepare();
-    return sql.step() == SQLITE_ROW;
</del><ins>+    auto statement = prepareStatement("SELECT name FROM sqlite_master WHERE type = 'table' AND name = '" + tablename + "';"_s);
+    return statement && statement->step() == SQLITE_ROW;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SQLiteDatabase::clearAllTables()
</span><span class="cx"> {
</span><del>-    String query = "SELECT name FROM sqlite_master WHERE type='table';"_s;
</del><span class="cx">     Vector<String> tables;
</span><del>-    if (!SQLiteStatement(*this, query).returnTextResults(0, tables)) {
</del><ins>+    auto statement = prepareStatement("SELECT name FROM sqlite_master WHERE type='table';"_s);
+    if (!statement || !statement->returnTextResults(0, tables)) {
</ins><span class="cx">         LOG(SQLDatabase, "Unable to retrieve list of tables from database");
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -583,10 +587,10 @@
</span><span class="cx"> 
</span><span class="cx"> bool SQLiteDatabase::turnOnIncrementalAutoVacuum()
</span><span class="cx"> {
</span><del>-    SQLiteStatement statement(*this, "PRAGMA auto_vacuum"_s);
-    int autoVacuumMode = statement.getColumnInt(0);
</del><ins>+    int autoVacuumMode = 0;
+    if (auto statement = prepareStatement("PRAGMA auto_vacuum"_s))
+        autoVacuumMode = statement->getColumnInt(0);
</ins><span class="cx">     int error = lastError();
</span><del>-    statement.finalize();
</del><span class="cx"> 
</span><span class="cx">     // Check if we got an error while trying to get the value of the auto_vacuum flag.
</span><span class="cx">     // If we got a SQLITE_BUSY error, then there's probably another transaction in
</span><span class="lines">@@ -643,4 +647,76 @@
</span><span class="cx">     sqlite3_db_release_memory(m_db);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static Expected<sqlite3_stmt*, int> constructAndPrepareStatement(SQLiteDatabase& database, const char* query, size_t queryLength)
+{
+    LockHolder databaseLock(database.databaseMutex());
+    LOG(SQLDatabase, "SQL - prepare - %s", query);
+
+    // Pass the length of the string including the null character to sqlite3_prepare_v2;
+    // this lets SQLite avoid an extra string copy.
+    size_t lengthIncludingNullCharacter = queryLength + 1;
+
+    sqlite3_stmt* statement { nullptr };
+    const char* tail = nullptr;
+    int error = sqlite3_prepare_v2(database.sqlite3Handle(), query, lengthIncludingNullCharacter, &statement, &tail);
+    if (error != SQLITE_OK)
+        LOG(SQLDatabase, "sqlite3_prepare16 failed (%i)\n%s\n%s", error, query, sqlite3_errmsg(database.sqlite3Handle()));
+
+    if (tail && *tail)
+        error = SQLITE_ERROR;
+
+    if (error != SQLITE_OK) {
+        sqlite3_finalize(statement);
+        return makeUnexpected(error);
+    }
+
+    // When the query is an empty string, sqlite3_prepare_v2() sets the statement to nullptr and yet doesn't return an error.
+    if (!statement)
+        return makeUnexpected(SQLITE_ERROR);
+
+    return statement;
+}
+
+Expected<SQLiteStatement, int> SQLiteDatabase::prepareStatement(const String& queryString)
+{
+    CString query = queryString.stripWhiteSpace().utf8();
+    auto sqlStatement = constructAndPrepareStatement(*this, query.data(), query.length());
+    if (!sqlStatement) {
+        RELEASE_LOG_ERROR(SQLDatabase, "SQLiteDatabase::prepareStatement: Failed to prepare statement %{public}s", query.data());
+        return makeUnexpected(sqlStatement.error());
+    }
+    return SQLiteStatement { *this, sqlStatement.value() };
+}
+
+Expected<SQLiteStatement, int> SQLiteDatabase::prepareStatement(ASCIILiteral query)
+{
+    auto sqlStatement = constructAndPrepareStatement(*this, query.characters(), query.length());
+    if (!sqlStatement) {
+        RELEASE_LOG_ERROR(SQLDatabase, "SQLiteDatabase::prepareStatement: Failed to prepare statement %{public}s", query.characters());
+        return makeUnexpected(sqlStatement.error());
+    }
+    return SQLiteStatement { *this, sqlStatement.value() };
+}
+
+Expected<UniqueRef<SQLiteStatement>, int> SQLiteDatabase::prepareHeapStatement(const String& queryString)
+{
+    CString query = queryString.stripWhiteSpace().utf8();
+    auto sqlStatement = constructAndPrepareStatement(*this, query.data(), query.length());
+    if (!sqlStatement) {
+        RELEASE_LOG_ERROR(SQLDatabase, "SQLiteDatabase::prepareHeapStatement: Failed to prepare statement %{public}s", query.data());
+        return makeUnexpected(sqlStatement.error());
+    }
+    return UniqueRef<SQLiteStatement>(*new SQLiteStatement(*this, sqlStatement.value()));
+}
+
+Expected<UniqueRef<SQLiteStatement>, int> SQLiteDatabase::prepareHeapStatement(ASCIILiteral query)
+{
+    auto sqlStatement = constructAndPrepareStatement(*this, query.characters(), query.length());
+    if (!sqlStatement) {
+        RELEASE_LOG_ERROR(SQLDatabase, "SQLiteDatabase::prepareHeapStatement: Failed to prepare statement %{public}s", query.characters());
+        return makeUnexpected(sqlStatement.error());
+    }
+    return UniqueRef<SQLiteStatement>(*new SQLiteStatement(*this, sqlStatement.value()));
+}
+
</ins><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformsqlSQLiteDatabaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/sql/SQLiteDatabase.h (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/sql/SQLiteDatabase.h       2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/platform/sql/SQLiteDatabase.h  2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2006-2021 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
</span><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -28,8 +28,10 @@
</span><span class="cx"> 
</span><span class="cx"> #include <functional>
</span><span class="cx"> #include <sqlite3.h>
</span><ins>+#include <wtf/Expected.h>
</ins><span class="cx"> #include <wtf/Lock.h>
</span><span class="cx"> #include <wtf/Threading.h>
</span><ins>+#include <wtf/UniqueRef.h>
</ins><span class="cx"> #include <wtf/text/CString.h>
</span><span class="cx"> #include <wtf/text/WTFString.h>
</span><span class="cx"> 
</span><span class="lines">@@ -61,6 +63,8 @@
</span><span class="cx">     WEBCORE_EXPORT void updateLastChangesCount();
</span><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT bool executeCommand(const String&);
</span><ins>+    WEBCORE_EXPORT bool executeCommand(ASCIILiteral);
+
</ins><span class="cx">     bool returnsAtLeastOneResult(const String&);
</span><span class="cx">     
</span><span class="cx">     WEBCORE_EXPORT bool tableExists(const String&);
</span><span class="lines">@@ -70,6 +74,11 @@
</span><span class="cx">     
</span><span class="cx">     bool transactionInProgress() const { return m_transactionInProgress; }
</span><span class="cx"> 
</span><ins>+    WEBCORE_EXPORT Expected<SQLiteStatement, int> prepareStatement(const String& query);
+    WEBCORE_EXPORT Expected<SQLiteStatement, int> prepareStatement(ASCIILiteral query);
+    WEBCORE_EXPORT Expected<UniqueRef<SQLiteStatement>, int> prepareHeapStatement(const String& query);
+    WEBCORE_EXPORT Expected<UniqueRef<SQLiteStatement>, int> prepareHeapStatement(ASCIILiteral query);
+
</ins><span class="cx">     // Aborts the current database operation. This is thread safe.
</span><span class="cx">     WEBCORE_EXPORT void interrupt();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformsqlSQLiteStatementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/sql/SQLiteStatement.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/sql/SQLiteStatement.cpp    2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/platform/sql/SQLiteStatement.cpp       2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2006-2021 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -41,45 +41,22 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-SQLiteStatement::SQLiteStatement(SQLiteDatabase& db, const String& sql)
</del><ins>+SQLiteStatement::SQLiteStatement(SQLiteDatabase& db, sqlite3_stmt* statement)
</ins><span class="cx">     : m_database(db)
</span><del>-    , m_query(sql)
-    , m_statement(0)
</del><ins>+    , m_statement(statement)
</ins><span class="cx"> {
</span><ins>+    ASSERT(statement);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-SQLiteStatement::~SQLiteStatement()
</del><ins>+SQLiteStatement::SQLiteStatement(SQLiteStatement&& other)
+    : m_database(other.database())
+    , m_statement(std::exchange(other.m_statement, nullptr))
</ins><span class="cx"> {
</span><del>-    finalize();
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-int SQLiteStatement::prepare()
</del><ins>+SQLiteStatement::~SQLiteStatement()
</ins><span class="cx"> {
</span><del>-    ASSERT(!m_isPrepared);
-
-    LockHolder databaseLock(m_database.databaseMutex());
-
-    CString query = m_query.stripWhiteSpace().utf8();
-    
-    LOG(SQLDatabase, "SQL - prepare - %s", query.data());
-
-    // Pass the length of the string including the null character to sqlite3_prepare_v2;
-    // this lets SQLite avoid an extra string copy.
-    size_t lengthIncludingNullCharacter = query.length() + 1;
-
-    const char* tail = nullptr;
-    int error = sqlite3_prepare_v2(m_database.sqlite3Handle(), query.data(), lengthIncludingNullCharacter, &m_statement, &tail);
-
-    if (error != SQLITE_OK)
-        LOG(SQLDatabase, "sqlite3_prepare16 failed (%i)\n%s\n%s", error, query.data(), sqlite3_errmsg(m_database.sqlite3Handle()));
-
-    if (tail && *tail)
-        error = SQLITE_ERROR;
-
-#if ASSERT_ENABLED
-    m_isPrepared = error == SQLITE_OK;
-#endif
-    return error;
</del><ins>+    sqlite3_finalize(m_statement);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> int SQLiteStatement::step()
</span><span class="lines">@@ -86,42 +63,19 @@
</span><span class="cx"> {
</span><span class="cx">     LockHolder databaseLock(m_database.databaseMutex());
</span><span class="cx"> 
</span><del>-    if (!m_statement)
-        return SQLITE_OK;
-
</del><span class="cx">     // The database needs to update its last changes count before each statement
</span><span class="cx">     // in order to compute properly the lastChanges() return value.
</span><span class="cx">     m_database.updateLastChangesCount();
</span><span class="cx"> 
</span><del>-    LOG(SQLDatabase, "SQL - step - %s", m_query.ascii().data());
</del><span class="cx">     int error = sqlite3_step(m_statement);
</span><del>-    if (error != SQLITE_DONE && error != SQLITE_ROW) {
-        LOG(SQLDatabase, "sqlite3_step failed (%i)\nQuery - %s\nError - %s", 
-            error, m_query.ascii().data(), sqlite3_errmsg(m_database.sqlite3Handle()));
-    }
</del><ins>+    if (error != SQLITE_DONE && error != SQLITE_ROW)
+        LOG(SQLDatabase, "sqlite3_step failed (%i)\nError - %s", error, sqlite3_errmsg(m_database.sqlite3Handle()));
</ins><span class="cx"> 
</span><span class="cx">     return error;
</span><span class="cx"> }
</span><del>-    
-int SQLiteStatement::finalize()
-{
-#if ASSERT_ENABLED
-    m_isPrepared = false;
-#endif
-    if (!m_statement)
-        return SQLITE_OK;
-    LOG(SQLDatabase, "SQL - finalize - %s", m_query.ascii().data());
-    int result = sqlite3_finalize(m_statement);
-    m_statement = 0;
-    return result;
-}
</del><span class="cx"> 
</span><span class="cx"> int SQLiteStatement::reset() 
</span><span class="cx"> {
</span><del>-    ASSERT(m_isPrepared);
-    if (!m_statement)
-        return SQLITE_OK;
-    LOG(SQLDatabase, "SQL - reset - %s", m_query.ascii().data());
</del><span class="cx">     int status = sqlite3_reset(m_statement);
</span><span class="cx">     sqlite3_clear_bindings(m_statement);
</span><span class="cx">     return status;
</span><span class="lines">@@ -129,42 +83,21 @@
</span><span class="cx"> 
</span><span class="cx"> bool SQLiteStatement::executeCommand()
</span><span class="cx"> {
</span><del>-    if (!m_statement && prepare() != SQLITE_OK)
-        return false;
-    ASSERT(m_isPrepared);
-    if (step() != SQLITE_DONE) {
-        finalize();
-        return false;
-    }
-    finalize();
-    return true;
</del><ins>+    return step() == SQLITE_DONE;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool SQLiteStatement::returnsAtLeastOneResult()
</span><span class="cx"> {
</span><del>-    if (!m_statement && prepare() != SQLITE_OK)
-        return false;
-    ASSERT(m_isPrepared);
-    if (step() != SQLITE_ROW) {
-        finalize();
-        return false;
-    }
-    finalize();
-    return true;
-
</del><ins>+    return step() == SQLITE_ROW;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> int SQLiteStatement::bindBlob(int index, const void* blob, int size)
</span><span class="cx"> {
</span><del>-    ASSERT(m_isPrepared);
</del><span class="cx">     ASSERT(index > 0);
</span><span class="cx">     ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
</span><span class="cx">     ASSERT(blob || !size);
</span><span class="cx">     ASSERT(size >= 0);
</span><span class="cx"> 
</span><del>-    if (!m_statement)
-        return SQLITE_ERROR;
-
</del><span class="cx">     return sqlite3_bind_blob(m_statement, index, blob, size, SQLITE_TRANSIENT);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -185,7 +118,6 @@
</span><span class="cx"> 
</span><span class="cx"> int SQLiteStatement::bindText(int index, const String& text)
</span><span class="cx"> {
</span><del>-    ASSERT(m_isPrepared);
</del><span class="cx">     ASSERT(index > 0);
</span><span class="cx">     ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
</span><span class="cx"> 
</span><span class="lines">@@ -204,7 +136,6 @@
</span><span class="cx"> 
</span><span class="cx"> int SQLiteStatement::bindInt(int index, int integer)
</span><span class="cx"> {
</span><del>-    ASSERT(m_isPrepared);
</del><span class="cx">     ASSERT(index > 0);
</span><span class="cx">     ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
</span><span class="cx"> 
</span><span class="lines">@@ -213,7 +144,6 @@
</span><span class="cx"> 
</span><span class="cx"> int SQLiteStatement::bindInt64(int index, int64_t integer)
</span><span class="cx"> {
</span><del>-    ASSERT(m_isPrepared);
</del><span class="cx">     ASSERT(index > 0);
</span><span class="cx">     ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
</span><span class="cx"> 
</span><span class="lines">@@ -222,7 +152,6 @@
</span><span class="cx"> 
</span><span class="cx"> int SQLiteStatement::bindDouble(int index, double number)
</span><span class="cx"> {
</span><del>-    ASSERT(m_isPrepared);
</del><span class="cx">     ASSERT(index > 0);
</span><span class="cx">     ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
</span><span class="cx"> 
</span><span class="lines">@@ -231,7 +160,6 @@
</span><span class="cx"> 
</span><span class="cx"> int SQLiteStatement::bindNull(int index)
</span><span class="cx"> {
</span><del>-    ASSERT(m_isPrepared);
</del><span class="cx">     ASSERT(index > 0);
</span><span class="cx">     ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
</span><span class="cx"> 
</span><span class="lines">@@ -249,17 +177,11 @@
</span><span class="cx"> 
</span><span class="cx"> unsigned SQLiteStatement::bindParameterCount() const
</span><span class="cx"> {
</span><del>-    ASSERT(m_isPrepared);
-    if (!m_statement)
-        return 0;
</del><span class="cx">     return sqlite3_bind_parameter_count(m_statement);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> int SQLiteStatement::columnCount()
</span><span class="cx"> {
</span><del>-    ASSERT(m_isPrepared);
-    if (!m_statement)
-        return 0;
</del><span class="cx">     return sqlite3_data_count(m_statement);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -266,9 +188,8 @@
</span><span class="cx"> bool SQLiteStatement::isColumnNull(int col)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(col >= 0);
</span><del>-    if (!m_statement)
-        if (prepareAndStep() != SQLITE_ROW)
-            return false;
</del><ins>+    if (!hasStartedStepping() && step() != SQLITE_ROW)
+        return false;
</ins><span class="cx">     if (columnCount() <= col)
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="lines">@@ -278,10 +199,6 @@
</span><span class="cx"> bool SQLiteStatement::isColumnDeclaredAsBlob(int col)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(col >= 0);
</span><del>-    if (!m_statement) {
-        if (prepare() != SQLITE_OK)
-            return false;
-    }
</del><span class="cx">     return equalLettersIgnoringASCIICase(StringView(sqlite3_column_decltype(m_statement, col)), "blob");
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -288,9 +205,8 @@
</span><span class="cx"> String SQLiteStatement::getColumnName(int col)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(col >= 0);
</span><del>-    if (!m_statement)
-        if (prepareAndStep() != SQLITE_ROW)
-            return String();
</del><ins>+    if (!hasStartedStepping() && step() != SQLITE_ROW)
+        return String();
</ins><span class="cx">     if (columnCount() <= col)
</span><span class="cx">         return String();
</span><span class="cx">     return String(reinterpret_cast<const UChar*>(sqlite3_column_name16(m_statement, col)));
</span><span class="lines">@@ -299,9 +215,8 @@
</span><span class="cx"> SQLValue SQLiteStatement::getColumnValue(int col)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(col >= 0);
</span><del>-    if (!m_statement)
-        if (prepareAndStep() != SQLITE_ROW)
-            return nullptr;
</del><ins>+    if (!hasStartedStepping() && step() != SQLITE_ROW)
+        return nullptr;
</ins><span class="cx">     if (columnCount() <= col)
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><span class="lines">@@ -330,9 +245,8 @@
</span><span class="cx"> String SQLiteStatement::getColumnText(int col)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(col >= 0);
</span><del>-    if (!m_statement)
-        if (prepareAndStep() != SQLITE_ROW)
-            return String();
</del><ins>+    if (!hasStartedStepping() && step() != SQLITE_ROW)
+        return String();
</ins><span class="cx">     if (columnCount() <= col)
</span><span class="cx">         return String();
</span><span class="cx">     return String(reinterpret_cast<const UChar*>(sqlite3_column_text16(m_statement, col)), sqlite3_column_bytes16(m_statement, col) / sizeof(UChar));
</span><span class="lines">@@ -341,9 +255,8 @@
</span><span class="cx"> double SQLiteStatement::getColumnDouble(int col)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(col >= 0);
</span><del>-    if (!m_statement)
-        if (prepareAndStep() != SQLITE_ROW)
-            return 0.0;
</del><ins>+    if (!hasStartedStepping() && step() != SQLITE_ROW)
+        return 0.0;
</ins><span class="cx">     if (columnCount() <= col)
</span><span class="cx">         return 0.0;
</span><span class="cx">     return sqlite3_column_double(m_statement, col);
</span><span class="lines">@@ -352,9 +265,8 @@
</span><span class="cx"> int SQLiteStatement::getColumnInt(int col)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(col >= 0);
</span><del>-    if (!m_statement)
-        if (prepareAndStep() != SQLITE_ROW)
-            return 0;
</del><ins>+    if (!hasStartedStepping() && step() != SQLITE_ROW)
+        return 0;
</ins><span class="cx">     if (columnCount() <= col)
</span><span class="cx">         return 0;
</span><span class="cx">     return sqlite3_column_int(m_statement, col);
</span><span class="lines">@@ -363,9 +275,8 @@
</span><span class="cx"> int64_t SQLiteStatement::getColumnInt64(int col)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(col >= 0);
</span><del>-    if (!m_statement)
-        if (prepareAndStep() != SQLITE_ROW)
-            return 0;
</del><ins>+    if (!hasStartedStepping() && step() != SQLITE_ROW)
+        return 0;
</ins><span class="cx">     if (columnCount() <= col)
</span><span class="cx">         return 0;
</span><span class="cx">     return sqlite3_column_int64(m_statement, col);
</span><span class="lines">@@ -375,7 +286,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(col >= 0);
</span><span class="cx"> 
</span><del>-    if (!m_statement && prepareAndStep() != SQLITE_ROW)
</del><ins>+    if (!hasStartedStepping() && step() != SQLITE_ROW)
</ins><span class="cx">         return String();
</span><span class="cx"> 
</span><span class="cx">     if (columnCount() <= col)
</span><span class="lines">@@ -397,7 +308,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(col >= 0);
</span><span class="cx"> 
</span><del>-    if (!m_statement && prepareAndStep() != SQLITE_ROW) {
</del><ins>+    if (!hasStartedStepping() && step() != SQLITE_ROW) {
</ins><span class="cx">         result.clear();
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -423,7 +334,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(col >= 0);
</span><span class="cx"> 
</span><del>-    if (!m_statement && prepareAndStep() != SQLITE_ROW) {
</del><ins>+    if (!hasStartedStepping() && step() != SQLITE_ROW) {
</ins><span class="cx">         result.clear();
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -451,10 +362,8 @@
</span><span class="cx"> 
</span><span class="cx">     v.clear();
</span><span class="cx"> 
</span><del>-    if (m_statement)
-        finalize();
-    if (prepare() != SQLITE_OK)
-        return false;
</del><ins>+    if (hasStartedStepping())
+        reset();
</ins><span class="cx"> 
</span><span class="cx">     while (step() == SQLITE_ROW)
</span><span class="cx">         v.append(getColumnText(col));
</span><span class="lines">@@ -461,9 +370,8 @@
</span><span class="cx">     bool result = true;
</span><span class="cx">     if (m_database.lastError() != SQLITE_DONE) {
</span><span class="cx">         result = false;
</span><del>-        LOG(SQLDatabase, "Error reading results from database query %s", m_query.ascii().data());
</del><ins>+        LOG(SQLDatabase, "SQLiteStatement::returnTextResults: Error reading results");
</ins><span class="cx">     }
</span><del>-    finalize();
</del><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -471,10 +379,8 @@
</span><span class="cx"> {
</span><span class="cx">     v.clear();
</span><span class="cx"> 
</span><del>-    if (m_statement)
-        finalize();
-    if (prepare() != SQLITE_OK)
-        return false;
</del><ins>+    if (hasStartedStepping())
+        reset();
</ins><span class="cx"> 
</span><span class="cx">     while (step() == SQLITE_ROW)
</span><span class="cx">         v.append(getColumnInt(col));
</span><span class="lines">@@ -481,9 +387,8 @@
</span><span class="cx">     bool result = true;
</span><span class="cx">     if (m_database.lastError() != SQLITE_DONE) {
</span><span class="cx">         result = false;
</span><del>-        LOG(SQLDatabase, "Error reading results from database query %s", m_query.ascii().data());
</del><ins>+        LOG(SQLDatabase, "SQLiteStatement::returnIntResults: Error reading results");
</ins><span class="cx">     }
</span><del>-    finalize();
</del><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -491,10 +396,8 @@
</span><span class="cx"> {
</span><span class="cx">     v.clear();
</span><span class="cx"> 
</span><del>-    if (m_statement)
-        finalize();
-    if (prepare() != SQLITE_OK)
-        return false;
</del><ins>+    if (hasStartedStepping())
+        reset();
</ins><span class="cx"> 
</span><span class="cx">     while (step() == SQLITE_ROW)
</span><span class="cx">         v.append(getColumnInt64(col));
</span><span class="lines">@@ -501,9 +404,8 @@
</span><span class="cx">     bool result = true;
</span><span class="cx">     if (m_database.lastError() != SQLITE_DONE) {
</span><span class="cx">         result = false;
</span><del>-        LOG(SQLDatabase, "Error reading results from database query %s", m_query.ascii().data());
</del><ins>+        LOG(SQLDatabase, "SQLiteStatement::returnInt64Results: Error reading results");
</ins><span class="cx">     }
</span><del>-    finalize();
</del><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -511,10 +413,8 @@
</span><span class="cx"> {
</span><span class="cx">     v.clear();
</span><span class="cx"> 
</span><del>-    if (m_statement)
-        finalize();
-    if (prepare() != SQLITE_OK)
-        return false;
</del><ins>+    if (hasStartedStepping())
+        reset();
</ins><span class="cx"> 
</span><span class="cx">     while (step() == SQLITE_ROW)
</span><span class="cx">         v.append(getColumnDouble(col));
</span><span class="lines">@@ -521,15 +421,14 @@
</span><span class="cx">     bool result = true;
</span><span class="cx">     if (m_database.lastError() != SQLITE_DONE) {
</span><span class="cx">         result = false;
</span><del>-        LOG(SQLDatabase, "Error reading results from database query %s", m_query.ascii().data());
</del><ins>+        LOG(SQLDatabase, "SQLiteStatement::returnDoubleResults: Error reading results");
</ins><span class="cx">     }
</span><del>-    finalize();
</del><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool SQLiteStatement::isExpired()
</del><ins>+bool SQLiteStatement::hasStartedStepping()
</ins><span class="cx"> {
</span><del>-    return !m_statement;
</del><ins>+    return sqlite3_stmt_busy(m_statement);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformsqlSQLiteStatementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/sql/SQLiteStatement.h (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/sql/SQLiteStatement.h      2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/platform/sql/SQLiteStatement.h 2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2006-2021 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -35,10 +35,9 @@
</span><span class="cx"> class SQLiteStatement {
</span><span class="cx">     WTF_MAKE_NONCOPYABLE(SQLiteStatement); WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx"> public:
</span><del>-    WEBCORE_EXPORT SQLiteStatement(SQLiteDatabase&, const String&);
</del><span class="cx">     WEBCORE_EXPORT ~SQLiteStatement();
</span><ins>+    WEBCORE_EXPORT SQLiteStatement(SQLiteStatement&&);
</ins><span class="cx">     
</span><del>-    WEBCORE_EXPORT int prepare();
</del><span class="cx">     WEBCORE_EXPORT int bindBlob(int index, const void* blob, int size);
</span><span class="cx">     WEBCORE_EXPORT int bindBlob(int index, const String&);
</span><span class="cx">     WEBCORE_EXPORT int bindText(int index, const String&);
</span><span class="lines">@@ -50,23 +49,18 @@
</span><span class="cx">     WEBCORE_EXPORT unsigned bindParameterCount() const;
</span><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT int step();
</span><del>-    WEBCORE_EXPORT int finalize();
</del><span class="cx">     WEBCORE_EXPORT int reset();
</span><span class="cx">     
</span><del>-    int prepareAndStep() { if (int error = prepare()) return error; return step(); }
-    
-    // prepares, steps, and finalizes the query.
</del><ins>+    // steps and finalizes the query.
</ins><span class="cx">     // returns true if all 3 steps succeed with step() returning SQLITE_DONE
</span><span class="cx">     // returns false otherwise  
</span><span class="cx">     WEBCORE_EXPORT bool executeCommand();
</span><span class="cx">     
</span><del>-    // prepares, steps, and finalizes.  
</del><ins>+    // steps, and finalizes.
</ins><span class="cx">     // returns true is step() returns SQLITE_ROW
</span><span class="cx">     // returns false otherwise
</span><span class="cx">     bool returnsAtLeastOneResult();
</span><span class="cx"> 
</span><del>-    bool isExpired();
-
</del><span class="cx">     // Returns -1 on last-step failing.  Otherwise, returns number of rows
</span><span class="cx">     // returned in the last step()
</span><span class="cx">     int columnCount();
</span><span class="lines">@@ -90,15 +84,15 @@
</span><span class="cx"> 
</span><span class="cx">     SQLiteDatabase& database() { return m_database; }
</span><span class="cx">     
</span><del>-    const String& query() const { return m_query; }
-    
</del><span class="cx"> private:
</span><ins>+    friend class SQLiteDatabase;
+    SQLiteStatement(SQLiteDatabase&, sqlite3_stmt*);
+
+    // Returns true if the prepared statement has been stepped at least once using step() but has neither run to completion (returned SQLITE_DONE from step()) nor been reset().
+    bool hasStartedStepping();
+
</ins><span class="cx">     SQLiteDatabase& m_database;
</span><del>-    String m_query;
</del><span class="cx">     sqlite3_stmt* m_statement;
</span><del>-#if ASSERT_ENABLED
-    bool m_isPrepared { false };
-#endif
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformwinSearchPopupMenuDBcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/win/SearchPopupMenuDB.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/win/SearchPopupMenuDB.cpp  2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/platform/win/SearchPopupMenuDB.cpp     2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -130,25 +130,25 @@
</span><span class="cx">     if (!m_database.tableExists("Search"))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    SQLiteStatement integrity(m_database, "PRAGMA quick_check;");
-    if (integrity.prepare() != SQLITE_OK) {
</del><ins>+    auto integrity = m_database.prepareStatement("PRAGMA quick_check;"_s);
+    if (!integrity) {
</ins><span class="cx">         LOG_ERROR("Failed to execute database integrity check");
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    int resultCode = integrity.step();
</del><ins>+    int resultCode = integrity->step();
</ins><span class="cx">     if (resultCode != SQLITE_ROW) {
</span><span class="cx">         LOG_ERROR("Integrity quick_check step returned %d", resultCode);
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    int columns = integrity.columnCount();
</del><ins>+    int columns = integrity->columnCount();
</ins><span class="cx">     if (columns != 1) {
</span><span class="cx">         LOG_ERROR("Received %i columns performing integrity check, should be 1", columns);
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    String resultText = integrity.getColumnText(0);
</del><ins>+    String resultText = integrity->getColumnText(0);
</ins><span class="cx"> 
</span><span class="cx">     if (resultText != "ok") {
</span><span class="cx">         LOG_ERROR("Search autosave database integrity check failed - %s", resultText.ascii().data());
</span><span class="lines">@@ -224,17 +224,19 @@
</span><span class="cx"> 
</span><span class="cx"> void SearchPopupMenuDB::closeDatabase()
</span><span class="cx"> {
</span><del>-    if (m_database.isOpen()) {
-        m_loadSearchTermsForNameStatement->finalize();
-        m_insertSearchTermStatement->finalize();
-        m_removeSearchTermsForNameStatement->finalize();
-        m_database.close();
-    }
</del><ins>+    if (!m_database.isOpen())
+        return;
+
+    m_loadSearchTermsForNameStatement = nullptr;
+    m_insertSearchTermStatement = nullptr;
+    m_removeSearchTermsForNameStatement = nullptr;
+    m_database.close();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SearchPopupMenuDB::verifySchemaVersion()
</span><span class="cx"> {
</span><del>-    int version = SQLiteStatement(m_database, "PRAGMA user_version").getColumnInt(0);
</del><ins>+    auto statement = m_database.prepareStatement("PRAGMA user_version"_s);
+    int version = statement ? statement->getColumnInt(0) : 0;
</ins><span class="cx">     if (version == schemaVersion)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="lines">@@ -271,23 +273,25 @@
</span><span class="cx"> 
</span><span class="cx"> int SearchPopupMenuDB::executeSimpleSql(const String& sql, bool ignoreError)
</span><span class="cx"> {
</span><del>-    SQLiteStatement statement(m_database, sql);
-    int ret = statement.prepareAndStep();
-    statement.finalize();
</del><ins>+    auto statement = m_database.prepareStatement(sql);
+    if (!statement) {
+        checkSQLiteReturnCode(statement.error());
+        return statement.error();
+    }
</ins><span class="cx"> 
</span><del>-    checkSQLiteReturnCode(ret);
</del><ins>+    int ret = statement->step();
</ins><span class="cx">     if (ret != SQLITE_OK && ret != SQLITE_DONE && ret != SQLITE_ROW && !ignoreError)
</span><span class="cx">         LOG_ERROR("Failed to execute %s error: %s", sql.ascii().data(), m_database.lastErrorMsg());
</span><del>-
</del><span class="cx">     return ret;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-std::unique_ptr<SQLiteStatement> SearchPopupMenuDB::createPreparedStatement(const String& sql)
</del><ins>+std::unique_ptr<SQLiteStatement> SearchPopupMenuDB::createPreparedStatement(ASCIILiteral sql)
</ins><span class="cx"> {
</span><del>-    auto statement = makeUnique<SQLiteStatement>(m_database, sql);
-    int ret = statement->prepare();
-    ASSERT_UNUSED(ret, ret == SQLITE_OK);
-    return statement;
</del><ins>+    auto statement = m_database.prepareHeapStatement(sql);
+    ASSERT(statement);
+    if (!statement)
+        return nullptr;
+    return statement.value().moveToUniquePtr();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformwinSearchPopupMenuDBh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/win/SearchPopupMenuDB.h (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/win/SearchPopupMenuDB.h    2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/platform/win/SearchPopupMenuDB.h       2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -51,7 +51,7 @@
</span><span class="cx">     void verifySchemaVersion();
</span><span class="cx">     int executeSimpleSql(const String& sql, bool ignoreError = false);
</span><span class="cx">     void checkSQLiteReturnCode(int actual);
</span><del>-    std::unique_ptr<SQLiteStatement> createPreparedStatement(const String& sql);
</del><ins>+    std::unique_ptr<SQLiteStatement> createPreparedStatement(ASCIILiteral sql);
</ins><span class="cx"> 
</span><span class="cx">     String m_databaseFilename;
</span><span class="cx">     SQLiteDatabase m_database;
</span></span></pre></div>
<a id="trunkSourceWebCoreworkersserviceserverRegistrationDatabasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/workers/service/server/RegistrationDatabase.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/workers/service/server/RegistrationDatabase.cpp     2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebCore/workers/service/server/RegistrationDatabase.cpp        2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -285,11 +285,11 @@
</span><span class="cx">     String currentSchema;
</span><span class="cx">     {
</span><span class="cx">         // Fetch the schema for an existing records table.
</span><del>-        SQLiteStatement statement(*m_database, "SELECT type, sql FROM sqlite_master WHERE tbl_name='Records'");
-        if (statement.prepare() != SQLITE_OK)
-            return "Unable to prepare statement to fetch schema for the Records table.";
</del><ins>+        auto statement = m_database->prepareStatement("SELECT type, sql FROM sqlite_master WHERE tbl_name='Records'"_s);
+        if (!statement)
+            return "Unable to prepare statement to fetch schema for the Records table."_s;
</ins><span class="cx"> 
</span><del>-        int sqliteResult = statement.step();
</del><ins>+        int sqliteResult = statement->step();
</ins><span class="cx"> 
</span><span class="cx">         // If there is no Records table at all, create it and then bail.
</span><span class="cx">         if (sqliteResult == SQLITE_DONE) {
</span><span class="lines">@@ -301,7 +301,7 @@
</span><span class="cx">         if (sqliteResult != SQLITE_ROW)
</span><span class="cx">             return "Error executing statement to fetch schema for the Records table.";
</span><span class="cx"> 
</span><del>-        currentSchema = statement.getColumnText(1);
</del><ins>+        currentSchema = statement->getColumnText(1);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT(!currentSchema.isEmpty());
</span><span class="lines">@@ -427,8 +427,8 @@
</span><span class="cx">     SQLiteTransaction transaction(*m_database);
</span><span class="cx">     transaction.begin();
</span><span class="cx"> 
</span><del>-    SQLiteStatement sql(*m_database, "INSERT INTO Records VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"_s);
-    if (sql.prepare() != SQLITE_OK) {
</del><ins>+    auto insertStatement = m_database->prepareStatement("INSERT INTO Records VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"_s);
+    if (!insertStatement) {
</ins><span class="cx">         RELEASE_LOG_ERROR(ServiceWorker, "Failed to prepare statement to store registration data into records table (%i) - %s", m_database->lastError(), m_database->lastErrorMsg());
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="lines">@@ -435,10 +435,10 @@
</span><span class="cx"> 
</span><span class="cx">     auto& scriptStorage = this->scriptStorage();
</span><span class="cx">     for (auto& registration : removedRegistrations) {
</span><del>-        SQLiteStatement sql(*m_database, "DELETE FROM Records WHERE key = ?");
-        if (sql.prepare() != SQLITE_OK
-            || sql.bindText(1, registration.toDatabaseKey()) != SQLITE_OK
-            || sql.step() != SQLITE_DONE) {
</del><ins>+        auto deleteStatement = m_database->prepareStatement("DELETE FROM Records WHERE key = ?"_s);
+        if (!deleteStatement
+            || deleteStatement->bindText(1, registration.toDatabaseKey()) != SQLITE_OK
+            || deleteStatement->step() != SQLITE_DONE) {
</ins><span class="cx">             RELEASE_LOG_ERROR(ServiceWorker, "Failed to remove registration data from records table (%i) - %s", m_database->lastError(), m_database->lastErrorMsg());
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="lines">@@ -457,19 +457,19 @@
</span><span class="cx">         WTF::Persistence::Encoder certificateInfoEncoder;
</span><span class="cx">         certificateInfoEncoder << data.certificateInfo;
</span><span class="cx"> 
</span><del>-        if (sql.bindText(1, data.registration.key.toDatabaseKey()) != SQLITE_OK
-            || sql.bindText(2, data.registration.scopeURL.protocolHostAndPort()) != SQLITE_OK
-            || sql.bindText(3, data.registration.scopeURL.path().toString()) != SQLITE_OK
-            || sql.bindText(4, data.registration.key.topOrigin().databaseIdentifier()) != SQLITE_OK
-            || sql.bindDouble(5, data.registration.lastUpdateTime.secondsSinceEpoch().value()) != SQLITE_OK
-            || sql.bindText(6, updateViaCacheToString(data.registration.updateViaCache)) != SQLITE_OK
-            || sql.bindText(7, data.scriptURL.string()) != SQLITE_OK
-            || sql.bindText(8, workerTypeToString(data.workerType)) != SQLITE_OK
-            || sql.bindBlob(9, cspEncoder.buffer(), cspEncoder.bufferSize()) != SQLITE_OK
-            || sql.bindText(10, data.referrerPolicy) != SQLITE_OK
-            || sql.bindBlob(11, scriptResourceMapEncoder.buffer(), scriptResourceMapEncoder.bufferSize()) != SQLITE_OK
-            || sql.bindBlob(12, certificateInfoEncoder.buffer(), certificateInfoEncoder.bufferSize()) != SQLITE_OK
-            || sql.step() != SQLITE_DONE) {
</del><ins>+        if (insertStatement->bindText(1, data.registration.key.toDatabaseKey()) != SQLITE_OK
+            || insertStatement->bindText(2, data.registration.scopeURL.protocolHostAndPort()) != SQLITE_OK
+            || insertStatement->bindText(3, data.registration.scopeURL.path().toString()) != SQLITE_OK
+            || insertStatement->bindText(4, data.registration.key.topOrigin().databaseIdentifier()) != SQLITE_OK
+            || insertStatement->bindDouble(5, data.registration.lastUpdateTime.secondsSinceEpoch().value()) != SQLITE_OK
+            || insertStatement->bindText(6, updateViaCacheToString(data.registration.updateViaCache)) != SQLITE_OK
+            || insertStatement->bindText(7, data.scriptURL.string()) != SQLITE_OK
+            || insertStatement->bindText(8, workerTypeToString(data.workerType)) != SQLITE_OK
+            || insertStatement->bindBlob(9, cspEncoder.buffer(), cspEncoder.bufferSize()) != SQLITE_OK
+            || insertStatement->bindText(10, data.referrerPolicy) != SQLITE_OK
+            || insertStatement->bindBlob(11, scriptResourceMapEncoder.buffer(), scriptResourceMapEncoder.bufferSize()) != SQLITE_OK
+            || insertStatement->bindBlob(12, certificateInfoEncoder.buffer(), certificateInfoEncoder.bufferSize()) != SQLITE_OK
+            || insertStatement->step() != SQLITE_DONE) {
</ins><span class="cx">             RELEASE_LOG_ERROR(ServiceWorker, "Failed to store registration data into records table (%i) - %s", m_database->lastError(), m_database->lastErrorMsg());
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="lines">@@ -502,26 +502,26 @@
</span><span class="cx">     ASSERT(!isMainThread());
</span><span class="cx"> 
</span><span class="cx">     RELEASE_LOG(ServiceWorker, "RegistrationDatabase::importRecords:");
</span><del>-    SQLiteStatement sql(*m_database, "SELECT * FROM Records;"_s);
-    if (sql.prepare() != SQLITE_OK)
</del><ins>+    auto sql = m_database->prepareStatement("SELECT * FROM Records;"_s);
+    if (!sql)
</ins><span class="cx">         return makeString("Failed to prepare statement to retrieve registrations from records table (", m_database->lastError(), ") - ", m_database->lastErrorMsg());
</span><span class="cx"> 
</span><del>-    int result = sql.step();
</del><ins>+    int result = sql->step();
</ins><span class="cx"> 
</span><del>-    for (; result == SQLITE_ROW; result = sql.step()) {
</del><ins>+    for (; result == SQLITE_ROW; result = sql->step()) {
</ins><span class="cx">         RELEASE_LOG(ServiceWorker, "RegistrationDatabase::importRecords: Importing a registration from the database");
</span><del>-        auto key = ServiceWorkerRegistrationKey::fromDatabaseKey(sql.getColumnText(0));
-        auto originURL = URL { URL(), sql.getColumnText(1) };
-        auto scopePath = sql.getColumnText(2);
</del><ins>+        auto key = ServiceWorkerRegistrationKey::fromDatabaseKey(sql->getColumnText(0));
+        auto originURL = URL { URL(), sql->getColumnText(1) };
+        auto scopePath = sql->getColumnText(2);
</ins><span class="cx">         auto scopeURL = URL { originURL, scopePath };
</span><del>-        auto topOrigin = SecurityOriginData::fromDatabaseIdentifier(sql.getColumnText(3));
-        auto lastUpdateCheckTime = WallTime::fromRawSeconds(sql.getColumnDouble(4));
-        auto updateViaCache = stringToUpdateViaCache(sql.getColumnText(5));
-        auto scriptURL = URL { URL(), sql.getColumnText(6) };
-        auto workerType = stringToWorkerType(sql.getColumnText(7));
</del><ins>+        auto topOrigin = SecurityOriginData::fromDatabaseIdentifier(sql->getColumnText(3));
+        auto lastUpdateCheckTime = WallTime::fromRawSeconds(sql->getColumnDouble(4));
+        auto updateViaCache = stringToUpdateViaCache(sql->getColumnText(5));
+        auto scriptURL = URL { URL(), sql->getColumnText(6) };
+        auto workerType = stringToWorkerType(sql->getColumnText(7));
</ins><span class="cx"> 
</span><span class="cx">         Vector<uint8_t> contentSecurityPolicyData;
</span><del>-        sql.getColumnBlobAsVector(8, contentSecurityPolicyData);
</del><ins>+        sql->getColumnBlobAsVector(8, contentSecurityPolicyData);
</ins><span class="cx">         WTF::Persistence::Decoder cspDecoder(contentSecurityPolicyData.data(), contentSecurityPolicyData.size());
</span><span class="cx">         Optional<ContentSecurityPolicyResponseHeaders> contentSecurityPolicy;
</span><span class="cx">         if (contentSecurityPolicyData.size()) {
</span><span class="lines">@@ -532,10 +532,10 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        auto referrerPolicy = sql.getColumnText(9);
</del><ins>+        auto referrerPolicy = sql->getColumnText(9);
</ins><span class="cx"> 
</span><span class="cx">         Vector<uint8_t> scriptResourceMapData;
</span><del>-        sql.getColumnBlobAsVector(10, scriptResourceMapData);
</del><ins>+        sql->getColumnBlobAsVector(10, scriptResourceMapData);
</ins><span class="cx">         HashMap<URL, ServiceWorkerContextData::ImportedScript> scriptResourceMap;
</span><span class="cx"> 
</span><span class="cx">         WTF::Persistence::Decoder scriptResourceMapDecoder(scriptResourceMapData.data(), scriptResourceMapData.size());
</span><span class="lines">@@ -550,7 +550,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         Vector<uint8_t> certificateInfoData;
</span><del>-        sql.getColumnBlobAsVector(11, certificateInfoData);
</del><ins>+        sql->getColumnBlobAsVector(11, certificateInfoData);
</ins><span class="cx">         Optional<CertificateInfo> certificateInfo;
</span><span class="cx"> 
</span><span class="cx">         WTF::Persistence::Decoder certificateInfoDecoder(certificateInfoData.data(), certificateInfoData.size());
</span></span></pre></div>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog    2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebKit/ChangeLog       2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -1,3 +1,70 @@
</span><ins>+2021-05-16  Chris Dumez  <cdumez@apple.com>
+
+        Modernize / Optimize SQLiteStatement creation and preparation
+        https://bugs.webkit.org/show_bug.cgi?id=225791
+
+        Reviewed by Sam Weinig.
+
+        Update code base now that the SQLiteDatabase & SQLiteStatement API has changed.
+        Also use more ASCIILiterals.
+
+        * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
+        (WebKit::ResourceLoadStatisticsDatabaseStore::openITPDatabase):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::checkForMissingTablesInSchema):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::enableForeignKeys):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::currentTableAndIndexQueries):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::missingUniqueIndices):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::migrateDataToNewTablesIfNecessary):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::columnsForTable):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::addMissingColumnsToTable):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::renameColumnInTable):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::openAndUpdateSchemaIfNecessary):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::scopedStatement const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::insertDomainRelationshipList):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::aggregatedThirdPartyData const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::incrementRecordsDeletedCountForDomains):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::recursivelyFindNonPrevalentDomainsThatRedirectedToThisDomain):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::markAsPrevalentIfHasRedirectedToPrevalent):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::findNotVeryPrevalentResources):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::requestStorageAccess):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::grandfatherDataForDomains):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::clearTopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::clearUserInteraction):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::setDomainsAsPrevalent):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::cookieAccess):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::hasUserGrantedStorageAccessThroughPrompt):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::domainsToBlockAndDeleteCookiesFor const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::domainsToBlockButKeepCookiesFor const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::domainsWithUserInteractionAsFirstParty const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::domainsWithStorageAccess const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::domains const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::clearGrandfathering):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::pruneStatisticsIfNeeded):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::isCorrectSubStatisticsCount):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::appendSubStatisticList const):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::updateOperatingDatesParameters):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::includeTodayAsOperatingDateIfNecessary):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::insertExpiredStatisticForTesting):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::privateClickMeasurementToString):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::clearSentAttribution):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::markAttributedPrivateClickMeasurementsAsExpiredForTesting):
+        * NetworkProcess/WebStorage/LocalStorageDatabase.cpp:
+        (WebKit::LocalStorageDatabase::migrateItemTableIfNeeded):
+        (WebKit::LocalStorageDatabase::databaseIsEmpty const):
+        (WebKit::LocalStorageDatabase::scopedStatement const):
+        * NetworkProcess/WebStorage/LocalStorageDatabase.h:
+        * UIProcess/API/glib/IconDatabase.cpp:
+        (WebKit::IconDatabase::IconDatabase):
+        (WebKit::IconDatabase::populatePageURLToIconURLMap):
+        (WebKit::IconDatabase::pruneTimerFired):
+        (WebKit::IconDatabase::iconIDForIconURL):
+        (WebKit::IconDatabase::setIconIDForPageURL):
+        (WebKit::IconDatabase::iconData):
+        (WebKit::IconDatabase::addIcon):
+        (WebKit::IconDatabase::updateIconTimestamp):
+        (WebKit::IconDatabase::deleteIcon):
+
</ins><span class="cx"> 2021-05-15  Ryosuke Niwa  <rniwa@webkit.org>
</span><span class="cx"> 
</span><span class="cx">         Delete WebSQL code from WebKit2
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsDatabaseStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp    2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp       2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -106,7 +106,7 @@
</span><span class="cx"> constexpr auto storageAccessExistsQuery = "SELECT EXISTS (SELECT 1 FROM StorageAccessUnderTopFrameDomains WHERE domainID = ? AND topLevelDomainID = (SELECT domainID FROM ObservedDomains WHERE registrableDomain = ?))"_s;
</span><span class="cx"> 
</span><span class="cx"> // UPDATE Queries
</span><del>-constexpr auto mostRecentUserInteractionQuery = "UPDATE ObservedDomains SET hadUserInteraction = ?, mostRecentUserInteractionTime = ? "
</del><ins>+constexpr auto mostRecentUserInteractionQuery = "UPDATE ObservedDomains SET hadUserInteraction = ?, mostRecentUserInteractionTime = ? "_s
</ins><span class="cx">     "WHERE registrableDomain = ?"_s;
</span><span class="cx"> constexpr auto updateLastSeenQuery = "UPDATE ObservedDomains SET lastSeen = ? WHERE registrableDomain = ?"_s;
</span><span class="cx"> constexpr auto updateDataRecordsRemovedQuery = "UPDATE ObservedDomains SET dataRecordsRemoved = ? WHERE registrableDomain = ?"_s;
</span><span class="lines">@@ -127,8 +127,8 @@
</span><span class="cx"> constexpr auto hadUserInteractionQuery = "SELECT hadUserInteraction, mostRecentUserInteractionTime FROM ObservedDomains WHERE registrableDomain = ?"_s;
</span><span class="cx"> constexpr auto isGrandfatheredQuery = "SELECT grandfathered FROM ObservedDomains WHERE registrableDomain = ?"_s;
</span><span class="cx"> constexpr auto findExpiredUserInteractionQuery = "SELECT domainID FROM ObservedDomains WHERE hadUserInteraction = 1 AND mostRecentUserInteractionTime < ?"_s;
</span><del>-constexpr auto getResourceDataByDomainNameQuery = "SELECT * FROM ObservedDomains WHERE registrableDomain = ?";
-constexpr auto getMostRecentlyUpdatedTimestampQuery = "SELECT MAX(lastUpdated) FROM (SELECT lastUpdated FROM SubframeUnderTopFrameDomains WHERE subFrameDomainID = ? and topFrameDomainID = ?"
</del><ins>+constexpr auto getResourceDataByDomainNameQuery = "SELECT * FROM ObservedDomains WHERE registrableDomain = ?"_s;
+constexpr auto getMostRecentlyUpdatedTimestampQuery = "SELECT MAX(lastUpdated) FROM (SELECT lastUpdated FROM SubframeUnderTopFrameDomains WHERE subFrameDomainID = ? and topFrameDomainID = ?"_s
</ins><span class="cx">     "UNION ALL SELECT lastUpdated FROM TopFrameLinkDecorationsFrom WHERE toDomainID = ? and fromDomainID = ?"
</span><span class="cx">     "UNION ALL SELECT lastUpdated FROM SubresourceUnderTopFrameDomains WHERE subresourceDomainID = ? and topFrameDomainID = ?"
</span><span class="cx">     "UNION ALL SELECT lastUpdated FROM SubresourceUniqueRedirectsTo WHERE subresourceDomainID = ? and toDomainID = ?)"_s;
</span><span class="lines">@@ -382,8 +382,8 @@
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    SQLiteStatement setBusyTimeout(m_database, "PRAGMA busy_timeout = 5000");
-    if (setBusyTimeout.prepare() != SQLITE_OK || setBusyTimeout.step() != SQLITE_ROW) {
</del><ins>+    auto setBusyTimeout = m_database.prepareStatement("PRAGMA busy_timeout = 5000"_s);
+    if (!setBusyTimeout || setBusyTimeout->step() != SQLITE_ROW) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::setBusyTimeout failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="lines">@@ -401,22 +401,22 @@
</span><span class="cx"> Optional<Vector<String>> ResourceLoadStatisticsDatabaseStore::checkForMissingTablesInSchema()
</span><span class="cx"> {
</span><span class="cx">     Vector<String> missingTables;
</span><del>-    SQLiteStatement statement(m_database, "SELECT 1 from sqlite_master WHERE type='table' and tbl_name=?");
-    if (statement.prepare() != SQLITE_OK) {
</del><ins>+    auto statement = m_database.prepareStatement("SELECT 1 from sqlite_master WHERE type='table' and tbl_name=?"_s);
+    if (!statement) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::checkForMissingTablesInSchema failed to prepare, error message: %" PUBLIC_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         return WTF::nullopt;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     for (auto& table : expectedTableAndIndexQueries().keys()) {
</span><del>-        if (statement.bindText(1, table) != SQLITE_OK) {
</del><ins>+        if (statement->bindText(1, table) != SQLITE_OK) {
</ins><span class="cx">             RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::checkForMissingTablesInSchema failed to bind, error message: %" PUBLIC_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">             return WTF::nullopt;
</span><span class="cx">         }
</span><del>-        if (statement.step() != SQLITE_ROW) {
</del><ins>+        if (statement->step() != SQLITE_ROW) {
</ins><span class="cx">             RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::checkForMissingTablesInSchema schema is missing table: %s", this, table.ascii().data());
</span><span class="cx">             missingTables.append(String(table));
</span><span class="cx">         }
</span><del>-        statement.reset();
</del><ins>+        statement->reset();
</ins><span class="cx">     }
</span><span class="cx">     if (missingTables.isEmpty())
</span><span class="cx">         return WTF::nullopt;
</span><span class="lines">@@ -426,8 +426,8 @@
</span><span class="cx"> 
</span><span class="cx"> void ResourceLoadStatisticsDatabaseStore::enableForeignKeys()
</span><span class="cx"> {
</span><del>-    SQLiteStatement enableForeignKeys(m_database, "PRAGMA foreign_keys = ON");
-    if (enableForeignKeys.prepare() != SQLITE_OK || enableForeignKeys.step() != SQLITE_DONE) {
</del><ins>+    auto enableForeignKeys = m_database.prepareStatement("PRAGMA foreign_keys = ON"_s);
+    if (!enableForeignKeys || enableForeignKeys->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::enableForeignKeys failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="lines">@@ -436,23 +436,23 @@
</span><span class="cx"> 
</span><span class="cx"> TableAndIndexPair ResourceLoadStatisticsDatabaseStore::currentTableAndIndexQueries(const String& tableName)
</span><span class="cx"> {
</span><del>-    SQLiteStatement getTableStatement(m_database, makeString("SELECT sql FROM sqlite_master WHERE tbl_name='", tableName, "' AND type = 'table'"));
-    if (getTableStatement.prepare() != SQLITE_OK) {
</del><ins>+    auto getTableStatement = m_database.prepareStatement(makeString("SELECT sql FROM sqlite_master WHERE tbl_name='", tableName, "' AND type = 'table'"));
+    if (!getTableStatement) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::currentTableAndIndexQueries Unable to prepare statement to fetch schema for the table, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return { };
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (getTableStatement.step() != SQLITE_ROW) {
</del><ins>+    if (getTableStatement->step() != SQLITE_ROW) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::currentTableAndIndexQueries error executing statement to fetch table schema, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return { };
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    String createTableQuery = getTableStatement.getColumnText(0);
</del><ins>+    String createTableQuery = getTableStatement->getColumnText(0);
</ins><span class="cx"> 
</span><del>-    SQLiteStatement getIndexStatement(m_database, makeString("SELECT sql FROM sqlite_master WHERE tbl_name='", tableName, "' AND type = 'index'"));
-    if (getIndexStatement.prepare() != SQLITE_OK) {
</del><ins>+    auto getIndexStatement = m_database.prepareStatement(makeString("SELECT sql FROM sqlite_master WHERE tbl_name='", tableName, "' AND type = 'index'"));
+    if (!getIndexStatement) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::currentTableAndIndexQueries Unable to prepare statement to fetch index for the table, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return { };
</span><span class="lines">@@ -459,8 +459,8 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Optional<String> index;
</span><del>-    if (getIndexStatement.step() == SQLITE_ROW) {
-        auto rawIndex = String(getIndexStatement.getColumnText(0));
</del><ins>+    if (getIndexStatement->step() == SQLITE_ROW) {
+        auto rawIndex = String(getIndexStatement->getColumnText(0));
</ins><span class="cx">         if (!rawIndex.isEmpty())
</span><span class="cx">             index = rawIndex;
</span><span class="cx">     }
</span><span class="lines">@@ -480,20 +480,20 @@
</span><span class="cx"> 
</span><span class="cx"> bool ResourceLoadStatisticsDatabaseStore::missingUniqueIndices()
</span><span class="cx"> {
</span><del>-    SQLiteStatement statement(m_database, makeString("SELECT COUNT(*) FROM sqlite_master WHERE type = 'index'"));
-    if (statement.prepare() != SQLITE_OK) {
</del><ins>+    auto statement = m_database.prepareStatement("SELECT COUNT(*) FROM sqlite_master WHERE type = 'index'"_s);
+    if (!statement) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::missingUniqueIndices Unable to prepare statement to fetch index count, error message: %s", this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return { };
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (statement.step() != SQLITE_ROW) {
</del><ins>+    if (statement->step() != SQLITE_ROW) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::missingUniqueIndices error executing statement to fetch index count, error message: %s", this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return { };
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (statement.getColumnInt(0) < expectedIndexCount)
</del><ins>+    if (statement->getColumnInt(0) < expectedIndexCount)
</ins><span class="cx">         return true;
</span><span class="cx"> 
</span><span class="cx">     return false;
</span><span class="lines">@@ -554,8 +554,8 @@
</span><span class="cx"> 
</span><span class="cx">     for (auto& table : expectedTableAndIndexQueries().keys()) {
</span><span class="cx">         auto query = makeString("ALTER TABLE ", table, " RENAME TO _", table);
</span><del>-        SQLiteStatement alterTable(m_database, query);
-        if (alterTable.prepare() != SQLITE_OK || alterTable.step() != SQLITE_DONE) {
</del><ins>+        auto alterTable = m_database.prepareStatement(query);
+        if (!alterTable || alterTable->step() != SQLITE_DONE) {
</ins><span class="cx">             RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::migrateDataToNewTablesIfNecessary failed to rename table, error message: %s", this, m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">             return;
</span><span class="lines">@@ -570,8 +570,8 @@
</span><span class="cx"> 
</span><span class="cx">     for (auto& table : expectedTableAndIndexQueries().keys()) {
</span><span class="cx">         auto query = insertDistinctValuesInTableQuery(table);
</span><del>-        SQLiteStatement migrateTableData(m_database, query);
-        if (migrateTableData.prepare() != SQLITE_OK || migrateTableData.step() != SQLITE_DONE) {
</del><ins>+        auto migrateTableData = m_database.prepareStatement(query);
+        if (!migrateTableData || migrateTableData->step() != SQLITE_DONE) {
</ins><span class="cx">             RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::migrateDataToNewTablesIfNecessary failed to migrate schema, error message: %s", this, m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">             return;
</span><span class="lines">@@ -578,8 +578,8 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         auto dropQuery = makeString("DROP TABLE _", table);
</span><del>-        SQLiteStatement dropTableQuery(m_database, dropQuery);
-        if (dropTableQuery.prepare() != SQLITE_OK || dropTableQuery.step() != SQLITE_DONE) {
</del><ins>+        auto dropTableQuery = m_database.prepareStatement(dropQuery);
+        if (!dropTableQuery || dropTableQuery->step() != SQLITE_DONE) {
</ins><span class="cx">             RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::migrateDataToNewTablesIfNecessary failed to drop temporary tables, error message: %s", this, m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">             return;
</span><span class="lines">@@ -597,9 +597,9 @@
</span><span class="cx"> 
</span><span class="cx"> Vector<String> ResourceLoadStatisticsDatabaseStore::columnsForTable(const String& tableName)
</span><span class="cx"> {
</span><del>-    SQLiteStatement statement(m_database, makeString("PRAGMA table_info(", tableName, ")"));
</del><ins>+    auto statement = m_database.prepareStatement(makeString("PRAGMA table_info(", tableName, ")"));
</ins><span class="cx"> 
</span><del>-    if (statement.prepare() != SQLITE_OK) {
</del><ins>+    if (!statement) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::getColumnsFromTableInfoStatement Unable to prepare statement to fetch schema for table, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return { };
</span><span class="lines">@@ -606,8 +606,8 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Vector<String> columns;
</span><del>-    while (statement.step() == SQLITE_ROW) {
-        auto name = statement.getColumnText(1);
</del><ins>+    while (statement->step() == SQLITE_ROW) {
+        auto name = statement->getColumnText(1);
</ins><span class="cx">         columns.append(name);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -622,18 +622,18 @@
</span><span class="cx">         if (existingColumns.contains(column))
</span><span class="cx">             continue;
</span><span class="cx">         
</span><del>-        SQLiteStatement statement(m_database, makeString("ALTER TABLE ", tableName, " ADD COLUMN ", column));
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = m_database.prepareStatement(makeString("ALTER TABLE ", tableName, " ADD COLUMN ", column));
+        if (!statement) {
</ins><span class="cx">             RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::addMissingColumnsToTable Unable to prepare statement to add missing columns to table, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        if (statement.step() != SQLITE_DONE) {
</del><ins>+        if (statement->step() != SQLITE_DONE) {
</ins><span class="cx">             RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::addMissingColumnsToTable error executing statement to add missing columns to table, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        statement.reset();
</del><ins>+        statement->reset();
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -648,13 +648,13 @@
</span><span class="cx"> 
</span><span class="cx"> void ResourceLoadStatisticsDatabaseStore::renameColumnInTable(String&& tableName, ExistingColumnName&& existingColumnName, ExpectedColumnName&& expectedColumnName)
</span><span class="cx"> {
</span><del>-    SQLiteStatement statement(m_database, makeString("ALTER TABLE ", tableName, " RENAME COLUMN ", existingColumnName, " TO ", expectedColumnName));
-    if (statement.prepare() != SQLITE_OK) {
</del><ins>+    auto statement = m_database.prepareStatement(makeString("ALTER TABLE ", tableName, " RENAME COLUMN ", existingColumnName, " TO ", expectedColumnName));
+    if (!statement) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::addMissingColumnsToTable Unable to prepare statement to rename column in table, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="cx">     }
</span><del>-    if (statement.step() != SQLITE_DONE) {
</del><ins>+    if (statement->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::addMissingColumnsToTable error executing statement to rename column in table, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="lines">@@ -712,8 +712,8 @@
</span><span class="cx">     String currentSchema;
</span><span class="cx">     {
</span><span class="cx">         // Fetch the schema for an existing Observed Domains table.
</span><del>-        SQLiteStatement statement(m_database, "SELECT type, sql FROM sqlite_master WHERE tbl_name='ObservedDomains'");
-        if (statement.prepare() != SQLITE_OK) {
</del><ins>+        auto statement = m_database.prepareStatement("SELECT type, sql FROM sqlite_master WHERE tbl_name='ObservedDomains'"_s);
+        if (!statement) {
</ins><span class="cx">             LOG_ERROR("Unable to prepare statement to fetch schema for the ObservedDomains table.");
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">             return;
</span><span class="lines">@@ -720,7 +720,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // If there is no ObservedDomains table at all, or there is an error executing the fetch, delete the file.
</span><del>-        if (statement.step() != SQLITE_ROW) {
</del><ins>+        if (statement->step() != SQLITE_ROW) {
</ins><span class="cx">             LOG_ERROR("Error executing statement to fetch schema for the Observed Domains table.");
</span><span class="cx">             close();
</span><span class="cx">             FileSystem::deleteFile(m_storageDirectoryPath);
</span><span class="lines">@@ -728,7 +728,7 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        currentSchema = statement.getColumnText(1);
</del><ins>+        currentSchema = statement->getColumnText(1);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT(!currentSchema.isEmpty());
</span><span class="lines">@@ -748,15 +748,17 @@
</span><span class="cx">     migrateDataToNewTablesIfNecessary();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-SQLiteStatementAutoResetScope ResourceLoadStatisticsDatabaseStore::scopedStatement(std::unique_ptr<WebCore::SQLiteStatement>& statement, const String& query, const String& logString) const
</del><ins>+SQLiteStatementAutoResetScope ResourceLoadStatisticsDatabaseStore::scopedStatement(std::unique_ptr<WebCore::SQLiteStatement>& statement, ASCIILiteral query, const String& logString) const
</ins><span class="cx"> {
</span><span class="cx">     if (!statement) {
</span><del>-        statement = makeUnique<WebCore::SQLiteStatement>(m_database, query);
-        ASSERT(m_database.isOpen());
-        if (statement->prepare() != SQLITE_OK) {
</del><ins>+        auto statementOrError = m_database.prepareHeapStatement(query);
+        if (!statementOrError) {
</ins><span class="cx">             RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::%s failed to prepare statement, error message: %" PUBLIC_LOG_STRING, this, logString.ascii().data(), m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><ins>+            return SQLiteStatementAutoResetScope { };
</ins><span class="cx">         }
</span><ins>+        statement = statementOrError.value().moveToUniquePtr();
+        ASSERT(m_database.isOpen());
</ins><span class="cx">     }
</span><span class="cx">     return SQLiteStatementAutoResetScope { statement.get() };
</span><span class="cx"> }
</span><span class="lines">@@ -1004,9 +1006,8 @@
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     auto scopedStatement = this->scopedStatement(m_domainIDFromStringStatement, domainIDFromStringQuery, "domainID"_s);
</span><del>-    if (!scopedStatement
-        || scopedStatement->bindText(1, domain.string()) != SQLITE_OK) {
-        RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::domainIDFromString failed. Statement: %s. Error message: %" PRIVATE_LOG_STRING, this, scopedStatement->query().utf8().data(), m_database.lastErrorMsg());
</del><ins>+    if (!scopedStatement || scopedStatement->bindText(1, domain.string()) != SQLITE_OK) {
+        RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::domainIDFromString failed. Error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</ins><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return WTF::nullopt;
</span><span class="cx">     }
</span><span class="lines">@@ -1039,16 +1040,16 @@
</span><span class="cx"> 
</span><span class="cx"> void ResourceLoadStatisticsDatabaseStore::insertDomainRelationshipList(const String& statement, const HashSet<RegistrableDomain>& domainList, unsigned domainID)
</span><span class="cx"> {
</span><del>-    SQLiteStatement insertRelationshipStatement(m_database, makeString(statement, ensureAndMakeDomainList(domainList), " );"));
</del><ins>+    auto insertRelationshipStatement = m_database.prepareStatement(makeString(statement, ensureAndMakeDomainList(domainList), " );"));
</ins><span class="cx">     
</span><del>-    if (insertRelationshipStatement.prepare() != SQLITE_OK
-        || insertRelationshipStatement.bindInt(1, domainID) != SQLITE_OK) {
</del><ins>+    if (!insertRelationshipStatement
+        || insertRelationshipStatement->bindInt(1, domainID) != SQLITE_OK) {
</ins><span class="cx">             RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::insertDomainRelationshipList failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (statement.contains("REPLACE")) {
</span><del>-        if (insertRelationshipStatement.bindDouble(2, WallTime::now().secondsSinceEpoch().value()) != SQLITE_OK) {
</del><ins>+        if (insertRelationshipStatement->bindDouble(2, WallTime::now().secondsSinceEpoch().value()) != SQLITE_OK) {
</ins><span class="cx">             RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::insertDomainRelationshipList failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">             return;
</span><span class="lines">@@ -1055,7 +1056,7 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (insertRelationshipStatement.step() != SQLITE_DONE) {
</del><ins>+    if (insertRelationshipStatement->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::insertDomainRelationshipList failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="lines">@@ -1229,17 +1230,17 @@
</span><span class="cx"> 
</span><span class="cx">     Vector<WebResourceLoadStatisticsStore::ThirdPartyData> thirdPartyDataList;
</span><span class="cx">     const auto prevalentDomainsBindParameter = thirdPartyCookieBlockingMode() == ThirdPartyCookieBlockingMode::All ? "%" : "1";
</span><del>-    SQLiteStatement sortedStatistics(m_database, makeString("SELECT ", joinSubStatisticsForSorting()));
-    if (sortedStatistics.prepare() != SQLITE_OK
-        || sortedStatistics.bindText(1, prevalentDomainsBindParameter)
-        || sortedStatistics.bindText(2, "%") != SQLITE_OK) {
</del><ins>+    auto sortedStatistics = m_database.prepareStatement(makeString("SELECT ", joinSubStatisticsForSorting()));
+    if (!sortedStatistics
+        || sortedStatistics->bindText(1, prevalentDomainsBindParameter)
+        || sortedStatistics->bindText(2, "%") != SQLITE_OK) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "ResourceLoadStatisticsDatabaseStore::aggregatedThirdPartyData, error message: %" PUBLIC_LOG_STRING, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return thirdPartyDataList;
</span><span class="cx">     }
</span><del>-    while (sortedStatistics.step() == SQLITE_ROW) {
-        if (hasBeenThirdParty(sortedStatistics.getColumnInt(1))) {
-            auto thirdPartyDomainID = sortedStatistics.getColumnInt(0);
</del><ins>+    while (sortedStatistics->step() == SQLITE_ROW) {
+        if (hasBeenThirdParty(sortedStatistics->getColumnInt(1))) {
+            auto thirdPartyDomainID = sortedStatistics->getColumnInt(0);
</ins><span class="cx">             auto thirdPartyDomain = RegistrableDomain::uncheckedCreateFromRegistrableDomainString(getDomainStringFromDomainID(thirdPartyDomainID));
</span><span class="cx">             thirdPartyDataList.append(WebResourceLoadStatisticsStore::ThirdPartyData { thirdPartyDomain, getThirdPartyDataForSpecificFirstPartyDomains(thirdPartyDomainID, thirdPartyDomain) });
</span><span class="cx">         }
</span><span class="lines">@@ -1265,9 +1266,8 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><del>-    SQLiteStatement domainsToUpdateStatement(m_database, makeString("UPDATE ObservedDomains SET dataRecordsRemoved = dataRecordsRemoved + 1 WHERE registrableDomain IN (", domainsToString(domains), ")"));
-    if (domainsToUpdateStatement.prepare() != SQLITE_OK
-        || domainsToUpdateStatement.step() != SQLITE_DONE) {
</del><ins>+    auto domainsToUpdateStatement = m_database.prepareStatement(makeString("UPDATE ObservedDomains SET dataRecordsRemoved = dataRecordsRemoved + 1 WHERE registrableDomain IN (", domainsToString(domains), ")"));
+    if (!domainsToUpdateStatement || domainsToUpdateStatement->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::incrementStatisticsForDomains failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="lines">@@ -1285,31 +1285,30 @@
</span><span class="cx">     ++numberOfRecursiveCalls;
</span><span class="cx"> 
</span><span class="cx">     StdSet<unsigned> newlyIdentifiedDomains;
</span><del>-    SQLiteStatement findSubresources(m_database, "SELECT SubresourceUniqueRedirectsFrom.fromDomainID from SubresourceUniqueRedirectsFrom INNER JOIN ObservedDomains ON ObservedDomains.domainID = SubresourceUniqueRedirectsFrom.fromDomainID WHERE subresourceDomainID = ? AND ObservedDomains.isPrevalent = 0"_s);
-    if (findSubresources.prepare() != SQLITE_OK
-        || findSubresources.bindInt(1, primaryDomainID) != SQLITE_OK) {
</del><ins>+    auto findSubresources = m_database.prepareStatement("SELECT SubresourceUniqueRedirectsFrom.fromDomainID from SubresourceUniqueRedirectsFrom INNER JOIN ObservedDomains ON ObservedDomains.domainID = SubresourceUniqueRedirectsFrom.fromDomainID WHERE subresourceDomainID = ? AND ObservedDomains.isPrevalent = 0"_s);
+    if (!findSubresources || findSubresources->bindInt(1, primaryDomainID) != SQLITE_OK) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::recursivelyFindNonPrevalentDomainsThatRedirectedToThisDomain failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    while (findSubresources.step() == SQLITE_ROW) {
-        int newDomainID = findSubresources.getColumnInt(0);
</del><ins>+    while (findSubresources->step() == SQLITE_ROW) {
+        int newDomainID = findSubresources->getColumnInt(0);
</ins><span class="cx">         auto insertResult = nonPrevalentRedirectionSources.insert(newDomainID);
</span><span class="cx">         if (insertResult.second)
</span><span class="cx">             newlyIdentifiedDomains.insert(newDomainID);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement findTopFrames(m_database, "SELECT TopFrameUniqueRedirectsFrom.fromDomainID from TopFrameUniqueRedirectsFrom INNER JOIN ObservedDomains ON ObservedDomains.domainID = TopFrameUniqueRedirectsFrom.fromDomainID WHERE targetDomainID = ? AND ObservedDomains.isPrevalent = 0"_s);
-    if (findTopFrames.prepare() != SQLITE_OK
-        || findTopFrames.bindInt(1, primaryDomainID) != SQLITE_OK) {
</del><ins>+    auto findTopFrames = m_database.prepareStatement("SELECT TopFrameUniqueRedirectsFrom.fromDomainID from TopFrameUniqueRedirectsFrom INNER JOIN ObservedDomains ON ObservedDomains.domainID = TopFrameUniqueRedirectsFrom.fromDomainID WHERE targetDomainID = ? AND ObservedDomains.isPrevalent = 0"_s);
+    if (!findTopFrames
+        || findTopFrames->bindInt(1, primaryDomainID) != SQLITE_OK) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::recursivelyFindNonPrevalentDomainsThatRedirectedToThisDomain failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    while (findTopFrames.step() == SQLITE_ROW) {
-        int newDomainID = findTopFrames.getColumnInt(0);
</del><ins>+    while (findTopFrames->step() == SQLITE_ROW) {
+        int newDomainID = findTopFrames->getColumnInt(0);
</ins><span class="cx">         auto insertResult = nonPrevalentRedirectionSources.insert(newDomainID);
</span><span class="cx">         if (insertResult.second)
</span><span class="cx">             newlyIdentifiedDomains.insert(newDomainID);
</span><span class="lines">@@ -1341,21 +1340,20 @@
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     StdSet<unsigned> prevalentDueToRedirect;
</span><del>-    SQLiteStatement subresourceRedirectStatement(m_database, "SELECT DISTINCT SubresourceUniqueRedirectsTo.subresourceDomainID FROM SubresourceUniqueRedirectsTo JOIN ObservedDomains ON ObservedDomains.domainID = SubresourceUniqueRedirectsTo.toDomainID AND ObservedDomains.isPrevalent = 1"_s);
-    if (subresourceRedirectStatement.prepare() == SQLITE_OK) {
-        while (subresourceRedirectStatement.step() == SQLITE_ROW)
-            prevalentDueToRedirect.insert(subresourceRedirectStatement.getColumnInt(0));
</del><ins>+    auto subresourceRedirectStatement = m_database.prepareStatement("SELECT DISTINCT SubresourceUniqueRedirectsTo.subresourceDomainID FROM SubresourceUniqueRedirectsTo JOIN ObservedDomains ON ObservedDomains.domainID = SubresourceUniqueRedirectsTo.toDomainID AND ObservedDomains.isPrevalent = 1"_s);
+    if (subresourceRedirectStatement) {
+        while (subresourceRedirectStatement->step() == SQLITE_ROW)
+            prevalentDueToRedirect.insert(subresourceRedirectStatement->getColumnInt(0));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement topFrameRedirectStatement(m_database, "SELECT DISTINCT TopFrameUniqueRedirectsTo.sourceDomainID FROM TopFrameUniqueRedirectsTo JOIN ObservedDomains ON ObservedDomains.domainID = TopFrameUniqueRedirectsTo.toDomainID AND ObservedDomains.isPrevalent = 1"_s);
-    if (topFrameRedirectStatement.prepare() == SQLITE_OK) {
-        while (topFrameRedirectStatement.step() == SQLITE_ROW)
-            prevalentDueToRedirect.insert(topFrameRedirectStatement.getColumnInt(0));
</del><ins>+    auto topFrameRedirectStatement = m_database.prepareStatement("SELECT DISTINCT TopFrameUniqueRedirectsTo.sourceDomainID FROM TopFrameUniqueRedirectsTo JOIN ObservedDomains ON ObservedDomains.domainID = TopFrameUniqueRedirectsTo.toDomainID AND ObservedDomains.isPrevalent = 1"_s);
+    if (topFrameRedirectStatement) {
+        while (topFrameRedirectStatement->step() == SQLITE_ROW)
+            prevalentDueToRedirect.insert(topFrameRedirectStatement->getColumnInt(0));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement markPrevalentStatement(m_database, makeString("UPDATE ObservedDomains SET isPrevalent = 1 WHERE domainID IN (", buildList(WTF::IteratorRange<StdSet<unsigned>::iterator>(prevalentDueToRedirect.begin(), prevalentDueToRedirect.end())), ")"));
-    if (markPrevalentStatement.prepare() != SQLITE_OK
-        || markPrevalentStatement.step() != SQLITE_DONE) {
</del><ins>+    auto markPrevalentStatement = m_database.prepareStatement(makeString("UPDATE ObservedDomains SET isPrevalent = 1 WHERE domainID IN (", buildList(WTF::IteratorRange<StdSet<unsigned>::iterator>(prevalentDueToRedirect.begin(), prevalentDueToRedirect.end())), ")"));
+    if (!markPrevalentStatement || markPrevalentStatement->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::markAsPrevalentIfHasRedirectedToPrevalent failed to execute, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="lines">@@ -1366,12 +1364,12 @@
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     HashMap<unsigned, NotVeryPrevalentResources> results;
</span><del>-    SQLiteStatement notVeryPrevalentResourcesStatement(m_database, "SELECT domainID, registrableDomain, isPrevalent FROM ObservedDomains WHERE isVeryPrevalent = 0"_s);
-    if (notVeryPrevalentResourcesStatement.prepare() == SQLITE_OK) {
-        while (notVeryPrevalentResourcesStatement.step() == SQLITE_ROW) {
-            unsigned key = static_cast<unsigned>(notVeryPrevalentResourcesStatement.getColumnInt(0));
-            NotVeryPrevalentResources value({ RegistrableDomain::uncheckedCreateFromRegistrableDomainString(notVeryPrevalentResourcesStatement.getColumnText(1))
-                , notVeryPrevalentResourcesStatement.getColumnInt(2) ? ResourceLoadPrevalence::High : ResourceLoadPrevalence::Low
</del><ins>+    auto notVeryPrevalentResourcesStatement = m_database.prepareStatement("SELECT domainID, registrableDomain, isPrevalent FROM ObservedDomains WHERE isVeryPrevalent = 0"_s);
+    if (notVeryPrevalentResourcesStatement) {
+        while (notVeryPrevalentResourcesStatement->step() == SQLITE_ROW) {
+            unsigned key = static_cast<unsigned>(notVeryPrevalentResourcesStatement->getColumnInt(0));
+            NotVeryPrevalentResources value({ RegistrableDomain::uncheckedCreateFromRegistrableDomainString(notVeryPrevalentResourcesStatement->getColumnText(1))
+                , notVeryPrevalentResourcesStatement->getColumnInt(2) ? ResourceLoadPrevalence::High : ResourceLoadPrevalence::Low
</ins><span class="cx">                 , 0, 0, 0, 0 });
</span><span class="cx">             results.add(key, value);
</span><span class="cx">         }
</span><span class="lines">@@ -1386,43 +1384,43 @@
</span><span class="cx"> 
</span><span class="cx">     auto domainIDsOfInterest = builder.toString();
</span><span class="cx"> 
</span><del>-    SQLiteStatement subresourceUnderTopFrameDomainsStatement(m_database, makeString("SELECT subresourceDomainID, COUNT(topFrameDomainID) FROM SubresourceUnderTopFrameDomains WHERE subresourceDomainID IN (", domainIDsOfInterest, ") GROUP BY subresourceDomainID"));
-    if (subresourceUnderTopFrameDomainsStatement.prepare() == SQLITE_OK) {
-        while (subresourceUnderTopFrameDomainsStatement.step() == SQLITE_ROW) {
-            unsigned domainID = static_cast<unsigned>(subresourceUnderTopFrameDomainsStatement.getColumnInt(0));
</del><ins>+    auto subresourceUnderTopFrameDomainsStatement = m_database.prepareStatement(makeString("SELECT subresourceDomainID, COUNT(topFrameDomainID) FROM SubresourceUnderTopFrameDomains WHERE subresourceDomainID IN (", domainIDsOfInterest, ") GROUP BY subresourceDomainID"));
+    if (subresourceUnderTopFrameDomainsStatement) {
+        while (subresourceUnderTopFrameDomainsStatement->step() == SQLITE_ROW) {
+            unsigned domainID = static_cast<unsigned>(subresourceUnderTopFrameDomainsStatement->getColumnInt(0));
</ins><span class="cx">             auto result = results.find(domainID);
</span><span class="cx">             if (result != results.end())
</span><del>-                result->value.subresourceUnderTopFrameDomainsCount = static_cast<unsigned>(subresourceUnderTopFrameDomainsStatement.getColumnInt(1));
</del><ins>+                result->value.subresourceUnderTopFrameDomainsCount = static_cast<unsigned>(subresourceUnderTopFrameDomainsStatement->getColumnInt(1));
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement subresourceUniqueRedirectsToCountStatement(m_database, makeString("SELECT subresourceDomainID, COUNT(toDomainID) FROM SubresourceUniqueRedirectsTo WHERE subresourceDomainID IN (", domainIDsOfInterest, ") GROUP BY subresourceDomainID"));
-    if (subresourceUniqueRedirectsToCountStatement.prepare() == SQLITE_OK) {
-        while (subresourceUniqueRedirectsToCountStatement.step() == SQLITE_ROW) {
-            unsigned domainID = static_cast<unsigned>(subresourceUniqueRedirectsToCountStatement.getColumnInt(0));
</del><ins>+    auto subresourceUniqueRedirectsToCountStatement = m_database.prepareStatement(makeString("SELECT subresourceDomainID, COUNT(toDomainID) FROM SubresourceUniqueRedirectsTo WHERE subresourceDomainID IN (", domainIDsOfInterest, ") GROUP BY subresourceDomainID"));
+    if (subresourceUniqueRedirectsToCountStatement) {
+        while (subresourceUniqueRedirectsToCountStatement->step() == SQLITE_ROW) {
+            unsigned domainID = static_cast<unsigned>(subresourceUniqueRedirectsToCountStatement->getColumnInt(0));
</ins><span class="cx">             auto result = results.find(domainID);
</span><span class="cx">             if (result != results.end())
</span><del>-                result->value.subresourceUniqueRedirectsToCount = static_cast<unsigned>(subresourceUniqueRedirectsToCountStatement.getColumnInt(1));
</del><ins>+                result->value.subresourceUniqueRedirectsToCount = static_cast<unsigned>(subresourceUniqueRedirectsToCountStatement->getColumnInt(1));
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement subframeUnderTopFrameDomainsCountStatement(m_database, makeString("SELECT subframeDomainID, COUNT(topFrameDomainID) FROM SubframeUnderTopFrameDomains WHERE subframeDomainID IN (", domainIDsOfInterest, ") GROUP BY subframeDomainID"));
-    if (subframeUnderTopFrameDomainsCountStatement.prepare() == SQLITE_OK) {
-        while (subframeUnderTopFrameDomainsCountStatement.step() == SQLITE_ROW) {
-            unsigned domainID = static_cast<unsigned>(subframeUnderTopFrameDomainsCountStatement.getColumnInt(0));
</del><ins>+    auto subframeUnderTopFrameDomainsCountStatement = m_database.prepareStatement(makeString("SELECT subframeDomainID, COUNT(topFrameDomainID) FROM SubframeUnderTopFrameDomains WHERE subframeDomainID IN (", domainIDsOfInterest, ") GROUP BY subframeDomainID"));
+    if (subframeUnderTopFrameDomainsCountStatement) {
+        while (subframeUnderTopFrameDomainsCountStatement->step() == SQLITE_ROW) {
+            unsigned domainID = static_cast<unsigned>(subframeUnderTopFrameDomainsCountStatement->getColumnInt(0));
</ins><span class="cx">             auto result = results.find(domainID);
</span><span class="cx">             if (result != results.end())
</span><del>-                result->value.subframeUnderTopFrameDomainsCount = static_cast<unsigned>(subframeUnderTopFrameDomainsCountStatement.getColumnInt(1));
</del><ins>+                result->value.subframeUnderTopFrameDomainsCount = static_cast<unsigned>(subframeUnderTopFrameDomainsCountStatement->getColumnInt(1));
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement topFrameUniqueRedirectsToCountStatement(m_database, makeString("SELECT sourceDomainID, COUNT(toDomainID) FROM TopFrameUniqueRedirectsTo WHERE sourceDomainID IN (", domainIDsOfInterest, ") GROUP BY sourceDomainID"));
-    if (topFrameUniqueRedirectsToCountStatement.prepare() == SQLITE_OK) {
-        while (topFrameUniqueRedirectsToCountStatement.step() == SQLITE_ROW) {
-            unsigned domainID = static_cast<unsigned>(topFrameUniqueRedirectsToCountStatement.getColumnInt(0));
</del><ins>+    auto topFrameUniqueRedirectsToCountStatement = m_database.prepareStatement(makeString("SELECT sourceDomainID, COUNT(toDomainID) FROM TopFrameUniqueRedirectsTo WHERE sourceDomainID IN (", domainIDsOfInterest, ") GROUP BY sourceDomainID"));
+    if (topFrameUniqueRedirectsToCountStatement) {
+        while (topFrameUniqueRedirectsToCountStatement->step() == SQLITE_ROW) {
+            unsigned domainID = static_cast<unsigned>(topFrameUniqueRedirectsToCountStatement->getColumnInt(0));
</ins><span class="cx">             auto result = results.find(domainID);
</span><span class="cx">             if (result != results.end())
</span><del>-                result->value.topFrameUniqueRedirectsToCount = static_cast<unsigned>(topFrameUniqueRedirectsToCountStatement.getColumnInt(1));
</del><ins>+                result->value.topFrameUniqueRedirectsToCount = static_cast<unsigned>(topFrameUniqueRedirectsToCountStatement->getColumnInt(1));
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1549,10 +1547,10 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement incrementStorageAccess(m_database, "UPDATE ObservedDomains SET timesAccessedAsFirstPartyDueToStorageAccessAPI = timesAccessedAsFirstPartyDueToStorageAccessAPI + 1 WHERE domainID = ?");
-    if (incrementStorageAccess.prepare() != SQLITE_OK
-        || incrementStorageAccess.bindInt(1, *subFrameStatus.second) != SQLITE_OK
-        || incrementStorageAccess.step() != SQLITE_DONE) {
</del><ins>+    auto incrementStorageAccess = m_database.prepareStatement("UPDATE ObservedDomains SET timesAccessedAsFirstPartyDueToStorageAccessAPI = timesAccessedAsFirstPartyDueToStorageAccessAPI + 1 WHERE domainID = ?"_s);
+    if (!incrementStorageAccess
+        || incrementStorageAccess->bindInt(1, *subFrameStatus.second) != SQLITE_OK
+        || incrementStorageAccess->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::requestStorageAccess failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="lines">@@ -1646,9 +1644,8 @@
</span><span class="cx">             RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::grandfatherDataForDomains was not completed due to failed insert attempt", this);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement domainsToUpdateStatement(m_database, makeString("UPDATE ObservedDomains SET grandfathered = 1 WHERE registrableDomain IN (", domainsToString(domains), ")"));
-    if (domainsToUpdateStatement.prepare() != SQLITE_OK
-        || domainsToUpdateStatement.step() != SQLITE_DONE) {
</del><ins>+    auto domainsToUpdateStatement = m_database.prepareStatement(makeString("UPDATE ObservedDomains SET grandfathered = 1 WHERE registrableDomain IN (", domainsToString(domains), ")"));
+    if (!domainsToUpdateStatement || domainsToUpdateStatement->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::grandfatherDataForDomains failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="lines">@@ -1776,10 +1773,10 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement removeRedirectsToSinceSameSite(m_database, "DELETE FROM TopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement WHERE sourceDomainID = ?");
-    if (removeRedirectsToSinceSameSite.prepare() != SQLITE_OK
-        || removeRedirectsToSinceSameSite.bindInt(1, *targetResult.second) != SQLITE_OK
-        || removeRedirectsToSinceSameSite.step() != SQLITE_DONE) {
</del><ins>+    auto removeRedirectsToSinceSameSite = m_database.prepareStatement("DELETE FROM TopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement WHERE sourceDomainID = ?"_s);
+    if (!removeRedirectsToSinceSameSite
+        || removeRedirectsToSinceSameSite->bindInt(1, *targetResult.second) != SQLITE_OK
+        || removeRedirectsToSinceSameSite->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearTopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement failed to bind, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="lines">@@ -1832,10 +1829,10 @@
</span><span class="cx">     }
</span><span class="cx">     setUserInteraction(domain, false, { });
</span><span class="cx"> 
</span><del>-    SQLiteStatement removeStorageAccess(m_database, "DELETE FROM StorageAccessUnderTopFrameDomains WHERE domainID = ?");
-    if (removeStorageAccess.prepare() != SQLITE_OK
-        || removeStorageAccess.bindInt(1, *targetResult.second) != SQLITE_OK
-        || removeStorageAccess.step() != SQLITE_DONE) {
</del><ins>+    auto removeStorageAccess = m_database.prepareStatement("DELETE FROM StorageAccessUnderTopFrameDomains WHERE domainID = ?"_s);
+    if (!removeStorageAccess
+        || removeStorageAccess->bindInt(1, *targetResult.second) != SQLITE_OK
+        || removeStorageAccess->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearUserInteraction failed to bind, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="lines">@@ -1918,9 +1915,8 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><del>-    SQLiteStatement domainsToUpdateStatement(m_database, makeString("UPDATE ObservedDomains SET isPrevalent = 1 WHERE domainID IN (", buildList(WTF::IteratorRange<StdSet<unsigned>::iterator>(domains.begin(), domains.end())), ")"));
-    if (domainsToUpdateStatement.prepare() != SQLITE_OK
-        || domainsToUpdateStatement.step() != SQLITE_DONE) {
</del><ins>+    auto domainsToUpdateStatement = m_database.prepareStatement(makeString("UPDATE ObservedDomains SET isPrevalent = 1 WHERE domainID IN (", buildList(WTF::IteratorRange<StdSet<unsigned>::iterator>(domains.begin(), domains.end())), ")"));
+    if (!domainsToUpdateStatement || domainsToUpdateStatement->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::setDomainsAsPrevalent failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="lines">@@ -2301,16 +2297,15 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, "SELECT isPrevalent, hadUserInteraction FROM ObservedDomains WHERE registrableDomain = ?");
-    if (statement.prepare() != SQLITE_OK
-        || statement.bindText(1, subresourceDomain.string()) != SQLITE_OK) {
</del><ins>+    auto statement = m_database.prepareStatement("SELECT isPrevalent, hadUserInteraction FROM ObservedDomains WHERE registrableDomain = ?"_s);
+    if (!statement || statement->bindText(1, subresourceDomain.string()) != SQLITE_OK) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::cookieAccess failed to bind, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    bool hasNoEntry = statement.step() != SQLITE_ROW;
-    bool isPrevalent = !hasNoEntry && !!statement.getColumnInt(0);
-    bool hadUserInteraction = !hasNoEntry && statement.getColumnInt(1) ? true : false;
</del><ins>+    bool hasNoEntry = statement->step() != SQLITE_ROW;
+    bool isPrevalent = !hasNoEntry && !!statement->getColumnInt(0);
+    bool hadUserInteraction = !hasNoEntry && statement->getColumnInt(1) ? true : false;
</ins><span class="cx"> 
</span><span class="cx">     if (!areAllThirdPartyCookiesBlockedUnder(topFrameDomain) && !isPrevalent)
</span><span class="cx">         return CookieAccess::BasedOnCookiePolicy;
</span><span class="lines">@@ -2333,14 +2328,14 @@
</span><span class="cx"> 
</span><span class="cx">     auto firstPartyPrimaryDomainID = *result.second;
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, "SELECT COUNT(*) FROM StorageAccessUnderTopFrameDomains WHERE domainID = ? AND topLevelDomainID = ?");
-    if (statement.prepare() != SQLITE_OK
-        || statement.bindInt(1, requestingDomainID) != SQLITE_OK
-        || statement.bindInt(2, firstPartyPrimaryDomainID) != SQLITE_OK
-        || statement.step() != SQLITE_ROW)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT COUNT(*) FROM StorageAccessUnderTopFrameDomains WHERE domainID = ? AND topLevelDomainID = ?"_s);
+    if (!statement
+        || statement->bindInt(1, requestingDomainID) != SQLITE_OK
+        || statement->bindInt(2, firstPartyPrimaryDomainID) != SQLITE_OK
+        || statement->step() != SQLITE_ROW)
</ins><span class="cx">         return StorageAccessPromptWasShown::No;
</span><span class="cx"> 
</span><del>-    return !!statement.getColumnInt(0) ? StorageAccessPromptWasShown::Yes : StorageAccessPromptWasShown::No;
</del><ins>+    return !!statement->getColumnInt(0) ? StorageAccessPromptWasShown::Yes : StorageAccessPromptWasShown::No;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Vector<RegistrableDomain> ResourceLoadStatisticsDatabaseStore::domainsToBlockAndDeleteCookiesFor() const
</span><span class="lines">@@ -2348,12 +2343,12 @@
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx">     
</span><span class="cx">     Vector<RegistrableDomain> results;
</span><del>-    SQLiteStatement statement(m_database, "SELECT registrableDomain FROM ObservedDomains WHERE isPrevalent = 1 AND hadUserInteraction = 0"_s);
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT registrableDomain FROM ObservedDomains WHERE isPrevalent = 1 AND hadUserInteraction = 0"_s);
+    if (!statement)
</ins><span class="cx">         return results;
</span><span class="cx">     
</span><del>-    while (statement.step() == SQLITE_ROW)
-        results.append(RegistrableDomain::uncheckedCreateFromRegistrableDomainString(statement.getColumnText(0)));
</del><ins>+    while (statement->step() == SQLITE_ROW)
+        results.append(RegistrableDomain::uncheckedCreateFromRegistrableDomainString(statement->getColumnText(0)));
</ins><span class="cx">     
</span><span class="cx">     return results;
</span><span class="cx"> }
</span><span class="lines">@@ -2363,12 +2358,12 @@
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     Vector<RegistrableDomain> results;
</span><del>-    SQLiteStatement statement(m_database, "SELECT registrableDomain FROM ObservedDomains WHERE isPrevalent = 1 AND hadUserInteraction = 1"_s);
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT registrableDomain FROM ObservedDomains WHERE isPrevalent = 1 AND hadUserInteraction = 1"_s);
+    if (!statement)
</ins><span class="cx">         return results;
</span><span class="cx">     
</span><del>-    while (statement.step() == SQLITE_ROW)
-        results.append(RegistrableDomain::uncheckedCreateFromRegistrableDomainString(statement.getColumnText(0)));
</del><ins>+    while (statement->step() == SQLITE_ROW)
+        results.append(RegistrableDomain::uncheckedCreateFromRegistrableDomainString(statement->getColumnText(0)));
</ins><span class="cx"> 
</span><span class="cx">     return results;
</span><span class="cx"> }
</span><span class="lines">@@ -2378,12 +2373,12 @@
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     Vector<RegistrableDomain> results;
</span><del>-    SQLiteStatement statement(m_database, "SELECT registrableDomain FROM ObservedDomains WHERE hadUserInteraction = 1"_s);
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT registrableDomain FROM ObservedDomains WHERE hadUserInteraction = 1"_s);
+    if (!statement)
</ins><span class="cx">         return results;
</span><span class="cx">     
</span><del>-    while (statement.step() == SQLITE_ROW)
-        results.append(RegistrableDomain::uncheckedCreateFromRegistrableDomainString(statement.getColumnText(0)));
</del><ins>+    while (statement->step() == SQLITE_ROW)
+        results.append(RegistrableDomain::uncheckedCreateFromRegistrableDomainString(statement->getColumnText(0)));
</ins><span class="cx"> 
</span><span class="cx">     return results;
</span><span class="cx"> }
</span><span class="lines">@@ -2393,13 +2388,12 @@
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     HashMap<WebCore::RegistrableDomain, WebCore::RegistrableDomain> results;
</span><del>-    SQLiteStatement statement(m_database, "SELECT subFrameDomain, registrableDomain FROM (SELECT o.registrableDomain as subFrameDomain, s.topLevelDomainID as topLevelDomainID FROM ObservedDomains as o INNER JOIN StorageAccessUnderTopFrameDomains as s WHERE o.domainID = s.domainID) as z INNER JOIN ObservedDomains ON domainID = z.topLevelDomainID;"_s);
-
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT subFrameDomain, registrableDomain FROM (SELECT o.registrableDomain as subFrameDomain, s.topLevelDomainID as topLevelDomainID FROM ObservedDomains as o INNER JOIN StorageAccessUnderTopFrameDomains as s WHERE o.domainID = s.domainID) as z INNER JOIN ObservedDomains ON domainID = z.topLevelDomainID;"_s);
+    if (!statement)
</ins><span class="cx">         return results;
</span><span class="cx"> 
</span><del>-    while (statement.step() == SQLITE_ROW)
-        results.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString(statement.getColumnText(1)), RegistrableDomain::uncheckedCreateFromRegistrableDomainString(statement.getColumnText(0)));
</del><ins>+    while (statement->step() == SQLITE_ROW)
+        results.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString(statement->getColumnText(1)), RegistrableDomain::uncheckedCreateFromRegistrableDomainString(statement->getColumnText(0)));
</ins><span class="cx"> 
</span><span class="cx">     return results;
</span><span class="cx"> }
</span><span class="lines">@@ -2445,19 +2439,18 @@
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx">     
</span><span class="cx">     Vector<DomainData> results;
</span><del>-    SQLiteStatement statement(m_database, "SELECT domainID, registrableDomain, mostRecentUserInteractionTime, hadUserInteraction, grandfathered, isScheduledForAllButCookieDataRemoval, countOfTopFrameRedirects FROM ObservedDomains LEFT JOIN (SELECT sourceDomainID, COUNT(*) as countOfTopFrameRedirects from TopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement GROUP BY sourceDomainID) as z ON z.sourceDomainID = domainID"_s);
-
-    if (statement.prepare() != SQLITE_OK)
</del><ins>+    auto statement = m_database.prepareStatement("SELECT domainID, registrableDomain, mostRecentUserInteractionTime, hadUserInteraction, grandfathered, isScheduledForAllButCookieDataRemoval, countOfTopFrameRedirects FROM ObservedDomains LEFT JOIN (SELECT sourceDomainID, COUNT(*) as countOfTopFrameRedirects from TopFrameUniqueRedirectsToSinceSameSiteStrictEnforcement GROUP BY sourceDomainID) as z ON z.sourceDomainID = domainID"_s);
+    if (!statement)
</ins><span class="cx">         return results;
</span><span class="cx">     
</span><del>-    while (statement.step() == SQLITE_ROW) {
-        results.append({ static_cast<unsigned>(statement.getColumnInt(0))
-            , RegistrableDomain::uncheckedCreateFromRegistrableDomainString(statement.getColumnText(1))
-            , WallTime::fromRawSeconds(statement.getColumnDouble(2))
-            , statement.getColumnInt(3) ? true : false
-            , statement.getColumnInt(4) ? true : false
-            , statement.getColumnInt(5) ? true : false
-            , static_cast<unsigned>(statement.getColumnInt(6))
</del><ins>+    while (statement->step() == SQLITE_ROW) {
+        results.append({ static_cast<unsigned>(statement->getColumnInt(0))
+            , RegistrableDomain::uncheckedCreateFromRegistrableDomainString(statement->getColumnText(1))
+            , WallTime::fromRawSeconds(statement->getColumnDouble(2))
+            , statement->getColumnInt(3) ? true : false
+            , statement->getColumnInt(4) ? true : false
+            , statement->getColumnInt(5) ? true : false
+            , static_cast<unsigned>(statement->getColumnInt(6))
</ins><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -2473,11 +2466,11 @@
</span><span class="cx"> 
</span><span class="cx">     auto listToClear = buildList(WTF::IteratorRange<Vector<unsigned>::iterator>(domainIDsToClear.begin(), domainIDsToClear.end()));
</span><span class="cx"> 
</span><del>-    SQLiteStatement clearGrandfatheringStatement(m_database, makeString("UPDATE ObservedDomains SET grandfathered = 0 WHERE domainID IN (", listToClear, ")"));
-    if (clearGrandfatheringStatement.prepare() != SQLITE_OK)
</del><ins>+    auto clearGrandfatheringStatement = m_database.prepareStatement(makeString("UPDATE ObservedDomains SET grandfathered = 0 WHERE domainID IN (", listToClear, ")"));
+    if (!clearGrandfatheringStatement)
</ins><span class="cx">         return;
</span><span class="cx">     
</span><del>-    if (clearGrandfatheringStatement.step() != SQLITE_DONE) {
</del><ins>+    if (clearGrandfatheringStatement->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearGrandfathering failed to bind, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="lines">@@ -2617,9 +2610,8 @@
</span><span class="cx">     size_t countLeftToPrune = count - parameters().pruneEntriesDownTo;
</span><span class="cx">     ASSERT(countLeftToPrune);
</span><span class="cx"> 
</span><del>-    SQLiteStatement recordsToPrune(m_database, "SELECT domainID FROM ObservedDomains ORDER BY hadUserInteraction, isPrevalent, lastSeen LIMIT ?");
-    if (recordsToPrune.prepare() != SQLITE_OK
-        || recordsToPrune.bindInt(1, countLeftToPrune) != SQLITE_OK) {
</del><ins>+    auto recordsToPrune = m_database.prepareStatement("SELECT domainID FROM ObservedDomains ORDER BY hadUserInteraction, isPrevalent, lastSeen LIMIT ?"_s);
+    if (!recordsToPrune || recordsToPrune->bindInt(1, countLeftToPrune) != SQLITE_OK) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::pruneStatisticsIfNeeded failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="lines">@@ -2626,14 +2618,13 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Vector<unsigned> entriesToPrune;
</span><del>-    while (recordsToPrune.step() == SQLITE_ROW)
-        entriesToPrune.append(recordsToPrune.getColumnInt(0));
</del><ins>+    while (recordsToPrune->step() == SQLITE_ROW)
+        entriesToPrune.append(recordsToPrune->getColumnInt(0));
</ins><span class="cx"> 
</span><span class="cx">     auto listToPrune = buildList(WTF::IteratorRange<Vector<unsigned>::iterator>(entriesToPrune.begin(), entriesToPrune.end()));
</span><span class="cx"> 
</span><del>-    SQLiteStatement pruneCommand(m_database, makeString("DELETE from ObservedDomains WHERE domainID IN (", listToPrune, ")"));
-    if (pruneCommand.prepare() != SQLITE_OK
-        || pruneCommand.step() != SQLITE_DONE) {
</del><ins>+    auto pruneCommand = m_database.prepareStatement(makeString("DELETE from ObservedDomains WHERE domainID IN (", listToPrune, ")"));
+    if (!pruneCommand || pruneCommand->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::pruneStatisticsIfNeeded failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="lines">@@ -2717,35 +2708,33 @@
</span><span class="cx"> 
</span><span class="cx"> bool ResourceLoadStatisticsDatabaseStore::isCorrectSubStatisticsCount(const RegistrableDomain& subframeDomain, const TopFrameDomain& topFrameDomain)
</span><span class="cx"> {
</span><del>-    SQLiteStatement subFrameUnderTopFrameCount(m_database, countSubframeUnderTopFrameQuery);
-    SQLiteStatement subresourceUnderTopFrameCount(m_database, countSubresourceUnderTopFrameQuery);
-    SQLiteStatement subresourceUniqueRedirectsTo(m_database, countSubresourceUniqueRedirectsToQuery);
</del><ins>+    auto subFrameUnderTopFrameCount = m_database.prepareStatement(countSubframeUnderTopFrameQuery);
+    auto subresourceUnderTopFrameCount = m_database.prepareStatement(countSubresourceUnderTopFrameQuery);
+    auto subresourceUniqueRedirectsTo = m_database.prepareStatement(countSubresourceUniqueRedirectsToQuery);
</ins><span class="cx">     
</span><del>-    if (subFrameUnderTopFrameCount.prepare() != SQLITE_OK
-        || subresourceUnderTopFrameCount.prepare() != SQLITE_OK
-        || subresourceUniqueRedirectsTo.prepare() != SQLITE_OK) {
</del><ins>+    if (!subFrameUnderTopFrameCount || !subresourceUnderTopFrameCount || !subresourceUniqueRedirectsTo) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::countSubStatisticsTesting failed to prepare, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    if (subFrameUnderTopFrameCount.bindInt(1, domainID(subframeDomain).value()) != SQLITE_OK
-        || subFrameUnderTopFrameCount.bindInt(2, domainID(topFrameDomain).value()) != SQLITE_OK
-        || subresourceUnderTopFrameCount.bindInt(1, domainID(subframeDomain).value()) != SQLITE_OK
-        || subresourceUnderTopFrameCount.bindInt(2, domainID(topFrameDomain).value()) != SQLITE_OK
-        || subresourceUniqueRedirectsTo.bindInt(1, domainID(subframeDomain).value()) != SQLITE_OK
-        || subresourceUniqueRedirectsTo.bindInt(2, domainID(topFrameDomain).value()) != SQLITE_OK) {
</del><ins>+    if (subFrameUnderTopFrameCount->bindInt(1, domainID(subframeDomain).value()) != SQLITE_OK
+        || subFrameUnderTopFrameCount->bindInt(2, domainID(topFrameDomain).value()) != SQLITE_OK
+        || subresourceUnderTopFrameCount->bindInt(1, domainID(subframeDomain).value()) != SQLITE_OK
+        || subresourceUnderTopFrameCount->bindInt(2, domainID(topFrameDomain).value()) != SQLITE_OK
+        || subresourceUniqueRedirectsTo->bindInt(1, domainID(subframeDomain).value()) != SQLITE_OK
+        || subresourceUniqueRedirectsTo->bindInt(2, domainID(topFrameDomain).value()) != SQLITE_OK) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::countSubStatisticsTesting failed to bind, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    if (subFrameUnderTopFrameCount.step() != SQLITE_ROW
-        || subresourceUnderTopFrameCount.step() != SQLITE_ROW
-        || subresourceUniqueRedirectsTo.step() != SQLITE_ROW)
</del><ins>+    if (subFrameUnderTopFrameCount->step() != SQLITE_ROW
+        || subresourceUnderTopFrameCount->step() != SQLITE_ROW
+        || subresourceUniqueRedirectsTo->step() != SQLITE_ROW)
</ins><span class="cx">         return false;
</span><span class="cx">     
</span><del>-    return (subFrameUnderTopFrameCount.getColumnInt(0) == 1 && subresourceUnderTopFrameCount.getColumnInt(0) == 1 && subresourceUniqueRedirectsTo.getColumnInt(0) == 1);
</del><ins>+    return (subFrameUnderTopFrameCount->getColumnInt(0) == 1 && subresourceUnderTopFrameCount->getColumnInt(0) == 1 && subresourceUniqueRedirectsTo->getColumnInt(0) == 1);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void appendBoolean(StringBuilder& builder, const String& label, bool flag)
</span><span class="lines">@@ -2812,16 +2801,15 @@
</span><span class="cx">     if (query.isEmpty())
</span><span class="cx">         return;
</span><span class="cx">     
</span><del>-    SQLiteStatement data(m_database, query);
</del><ins>+    auto data = m_database.prepareStatement(query);
</ins><span class="cx">     
</span><del>-    if (data.prepare() != SQLITE_OK
-        || data.bindInt(1, domainID(RegistrableDomain::uncheckedCreateFromHost(domain)).value()) != SQLITE_OK) {
</del><ins>+    if (!data || data->bindInt(1, domainID(RegistrableDomain::uncheckedCreateFromHost(domain)).value()) != SQLITE_OK) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::appendSubStatisticList. Statement failed to prepare or bind, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    if (data.step() != SQLITE_ROW)
</del><ins>+    if (data->step() != SQLITE_ROW)
</ins><span class="cx">         return;
</span><span class="cx">     
</span><span class="cx">     builder.appendLiteral("    ");
</span><span class="lines">@@ -2828,11 +2816,11 @@
</span><span class="cx">     builder.append(tableName);
</span><span class="cx">     builder.appendLiteral(":\n");
</span><span class="cx">     
</span><del>-    auto result = getDomainStringFromDomainID(data.getColumnInt(0));
</del><ins>+    auto result = getDomainStringFromDomainID(data->getColumnInt(0));
</ins><span class="cx">     appendNextEntry(builder, result);
</span><span class="cx">     
</span><del>-    while (data.step() == SQLITE_ROW) {
-        result = getDomainStringFromDomainID(data.getColumnInt(0));
</del><ins>+    while (data->step() == SQLITE_ROW) {
+        result = getDomainStringFromDomainID(data->getColumnInt(0));
</ins><span class="cx">         appendNextEntry(builder, result);
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -2946,28 +2934,26 @@
</span><span class="cx"> 
</span><span class="cx"> void ResourceLoadStatisticsDatabaseStore::updateOperatingDatesParameters()
</span><span class="cx"> {
</span><del>-    SQLiteStatement countOperatingDatesStatement(m_database, "SELECT COUNT(*) FROM OperatingDates;"_s);
-    SQLiteStatement getMostRecentOperatingDateStatement(m_database, "SELECT * FROM OperatingDates ORDER BY year DESC, month DESC, monthDay DESC LIMIT 1;"_s);
-    SQLiteStatement getOperatingDateWindowStatement(m_database, "SELECT * FROM OperatingDates ORDER BY year DESC, month DESC, monthDay DESC LIMIT 1 OFFSET ?;"_s);
</del><ins>+    auto countOperatingDatesStatement = m_database.prepareStatement("SELECT COUNT(*) FROM OperatingDates;"_s);
+    auto getMostRecentOperatingDateStatement = m_database.prepareStatement("SELECT * FROM OperatingDates ORDER BY year DESC, month DESC, monthDay DESC LIMIT 1;"_s);
+    auto getOperatingDateWindowStatement = m_database.prepareStatement("SELECT * FROM OperatingDates ORDER BY year DESC, month DESC, monthDay DESC LIMIT 1 OFFSET ?;"_s);
</ins><span class="cx"> 
</span><del>-    if (countOperatingDatesStatement.prepare() != SQLITE_OK
-        || countOperatingDatesStatement.step() != SQLITE_ROW) {
</del><ins>+    if (!countOperatingDatesStatement || countOperatingDatesStatement->step() != SQLITE_ROW) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::updateOperatingDatesParameters countOperatingDatesStatement failed to step, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_operatingDatesSize = countOperatingDatesStatement.getColumnInt(0);
</del><ins>+    m_operatingDatesSize = countOperatingDatesStatement->getColumnInt(0);
</ins><span class="cx"> 
</span><del>-    if (getMostRecentOperatingDateStatement.prepare() != SQLITE_OK
-        || getMostRecentOperatingDateStatement.step() != SQLITE_ROW) {
</del><ins>+    if (!getMostRecentOperatingDateStatement || getMostRecentOperatingDateStatement->step() != SQLITE_ROW) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::updateOperatingDatesParameters getFirstOperatingDateStatement failed to step, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="cx">     }
</span><del>-    m_mostRecentOperatingDate = OperatingDate(getMostRecentOperatingDateStatement.getColumnInt(0), getMostRecentOperatingDateStatement.getColumnInt(1), getMostRecentOperatingDateStatement.getColumnInt(2));
</del><ins>+    m_mostRecentOperatingDate = OperatingDate(getMostRecentOperatingDateStatement->getColumnInt(0), getMostRecentOperatingDateStatement->getColumnInt(1), getMostRecentOperatingDateStatement->getColumnInt(2));
</ins><span class="cx"> 
</span><del>-    if (getOperatingDateWindowStatement.prepare() != SQLITE_OK) {
</del><ins>+    if (!getOperatingDateWindowStatement) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::updateOperatingDatesParameters getOperatingDateWindowStatement failed during the call to prepare() with error message: %" PRIVATE_LOG_STRING ".", this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return;
</span><span class="lines">@@ -2976,26 +2962,26 @@
</span><span class="cx">     if (m_operatingDatesSize <= operatingDatesWindowShort - 1)
</span><span class="cx">         m_shortWindowOperatingDate = WTF::nullopt;
</span><span class="cx">     else {
</span><del>-        if (getOperatingDateWindowStatement.bindInt(1, operatingDatesWindowShort - 1) != SQLITE_OK
-            || getOperatingDateWindowStatement.step() != SQLITE_ROW) {
</del><ins>+        if (getOperatingDateWindowStatement->bindInt(1, operatingDatesWindowShort - 1) != SQLITE_OK
+            || getOperatingDateWindowStatement->step() != SQLITE_ROW) {
</ins><span class="cx">             RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::updateOperatingDatesParameters getOperatingDateWindowStatement failed with error message: %" PRIVATE_LOG_STRING ". The error could be in the calls to bind() or step().", this, m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        m_shortWindowOperatingDate = OperatingDate(getOperatingDateWindowStatement.getColumnInt(0), getOperatingDateWindowStatement.getColumnInt(1), getOperatingDateWindowStatement.getColumnInt(2));
</del><ins>+        m_shortWindowOperatingDate = OperatingDate(getOperatingDateWindowStatement->getColumnInt(0), getOperatingDateWindowStatement->getColumnInt(1), getOperatingDateWindowStatement->getColumnInt(2));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (m_operatingDatesSize <= operatingDatesWindowLong - 1)
</span><span class="cx">         m_longWindowOperatingDate = WTF::nullopt;
</span><span class="cx">     else {
</span><del>-        getOperatingDateWindowStatement.reset();
-        if (getOperatingDateWindowStatement.bindInt(1, operatingDatesWindowLong - 1) != SQLITE_OK
-            || getOperatingDateWindowStatement.step() != SQLITE_ROW) {
</del><ins>+        getOperatingDateWindowStatement->reset();
+        if (getOperatingDateWindowStatement->bindInt(1, operatingDatesWindowLong - 1) != SQLITE_OK
+            || getOperatingDateWindowStatement->step() != SQLITE_ROW) {
</ins><span class="cx">             RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::updateOperatingDatesParameters getOperatingDateWindowStatement failed with error message: %" PRIVATE_LOG_STRING ". The error could be in the calls to bind() or step().", this, m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        m_longWindowOperatingDate = OperatingDate(getOperatingDateWindowStatement.getColumnInt(0), getOperatingDateWindowStatement.getColumnInt(1), getOperatingDateWindowStatement.getColumnInt(2));
</del><ins>+        m_longWindowOperatingDate = OperatingDate(getOperatingDateWindowStatement->getColumnInt(0), getOperatingDateWindowStatement->getColumnInt(1), getOperatingDateWindowStatement->getColumnInt(2));
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -3011,21 +2997,21 @@
</span><span class="cx"> 
</span><span class="cx">     int rowsToPrune = m_operatingDatesSize - operatingDatesWindowLong + 1;
</span><span class="cx">     if (rowsToPrune > 0) {
</span><del>-        SQLiteStatement deleteLeastRecentOperatingDateStatement(m_database, "DELETE FROM OperatingDates ORDER BY year, month, monthDay LIMIT ?;"_s);
-        if (deleteLeastRecentOperatingDateStatement.prepare() != SQLITE_OK
-            || deleteLeastRecentOperatingDateStatement.bindInt(1, rowsToPrune) != SQLITE_OK
-            || deleteLeastRecentOperatingDateStatement.step() != SQLITE_DONE) {
</del><ins>+        auto deleteLeastRecentOperatingDateStatement = m_database.prepareStatement("DELETE FROM OperatingDates ORDER BY year, month, monthDay LIMIT ?;"_s);
+        if (!deleteLeastRecentOperatingDateStatement
+            || deleteLeastRecentOperatingDateStatement->bindInt(1, rowsToPrune) != SQLITE_OK
+            || deleteLeastRecentOperatingDateStatement->step() != SQLITE_DONE) {
</ins><span class="cx">             RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::includeTodayAsOperatingDateIfNecessary deleteLeastRecentOperatingDateStatement failed to step, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    SQLiteStatement insertOperatingDateStatement(m_database, "INSERT OR IGNORE INTO OperatingDates (year, month, monthDay) SELECT ?, ?, ?;"_s);
-    if (insertOperatingDateStatement.prepare() != SQLITE_OK
-        || insertOperatingDateStatement.bindInt(1, today.year()) != SQLITE_OK
-        || insertOperatingDateStatement.bindInt(2, today.month()) != SQLITE_OK
-        || insertOperatingDateStatement.bindInt(3, today.monthDay()) != SQLITE_OK
-        || insertOperatingDateStatement.step() != SQLITE_DONE) {
</del><ins>+    auto insertOperatingDateStatement = m_database.prepareStatement("INSERT OR IGNORE INTO OperatingDates (year, month, monthDay) SELECT ?, ?, ?;"_s);
+    if (!insertOperatingDateStatement
+        || insertOperatingDateStatement->bindInt(1, today.year()) != SQLITE_OK
+        || insertOperatingDateStatement->bindInt(2, today.month()) != SQLITE_OK
+        || insertOperatingDateStatement->bindInt(3, today.monthDay()) != SQLITE_OK
+        || insertOperatingDateStatement->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::includeTodayAsOperatingDateIfNecessary insertOperatingDateStatement failed to step, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="lines">@@ -3069,16 +3055,16 @@
</span><span class="cx">         daysAgoInSeconds = WallTime::now().secondsSinceEpoch().value() - daysToSubtract;
</span><span class="cx">         auto dateToInsert = OperatingDate::fromWallTime(WallTime::fromRawSeconds(daysAgoInSeconds));
</span><span class="cx"> 
</span><del>-        SQLiteStatement insertOperatingDateStatement(m_database, "INSERT OR IGNORE INTO OperatingDates (year, month, monthDay) SELECT ?, ?, ?;"_s);
-        if (insertOperatingDateStatement.prepare() != SQLITE_OK
-            || insertOperatingDateStatement.bindInt(1, dateToInsert.year()) != SQLITE_OK
-            || insertOperatingDateStatement.bindInt(2, dateToInsert.month()) != SQLITE_OK
-            || insertOperatingDateStatement.bindInt(3, dateToInsert.monthDay()) != SQLITE_OK
-            || insertOperatingDateStatement.step() != SQLITE_DONE) {
</del><ins>+        auto insertOperatingDateStatement = m_database.prepareStatement("INSERT OR IGNORE INTO OperatingDates (year, month, monthDay) SELECT ?, ?, ?;"_s);
+        if (!insertOperatingDateStatement
+            || insertOperatingDateStatement->bindInt(1, dateToInsert.year()) != SQLITE_OK
+            || insertOperatingDateStatement->bindInt(2, dateToInsert.month()) != SQLITE_OK
+            || insertOperatingDateStatement->bindInt(3, dateToInsert.monthDay()) != SQLITE_OK
+            || insertOperatingDateStatement->step() != SQLITE_DONE) {
</ins><span class="cx">             RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::insertExpiredStatisticForTesting insertOperatingDateStatement failed to step, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">         }
</span><del>-        insertOperatingDateStatement.reset();
</del><ins>+        insertOperatingDateStatement->reset();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     updateOperatingDatesParameters();
</span><span class="lines">@@ -3201,20 +3187,20 @@
</span><span class="cx">         // We should never be inserting an attributed private click measurement value into the database without valid report times.
</span><span class="cx">         ASSERT(sourceEarliestTimeToSend != -1 && destinationEarliestTimeToSend != -1);
</span><span class="cx"> 
</span><del>-        auto statement = SQLiteStatement(m_database, insertAttributedPrivateClickMeasurementQuery);
-        if (statement.prepare() != SQLITE_OK
-            || statement.bindInt(1, *sourceData.second) != SQLITE_OK
-            || statement.bindInt(2, *attributionDestinationData.second) != SQLITE_OK
-            || statement.bindInt(3, attribution.sourceID().id) != SQLITE_OK
-            || statement.bindInt(4, attributionTriggerData) != SQLITE_OK
-            || statement.bindInt(5, priority) != SQLITE_OK
-            || statement.bindDouble(6, attribution.timeOfAdClick().secondsSinceEpoch().value()) != SQLITE_OK
-            || statement.bindDouble(7, sourceEarliestTimeToSend) != SQLITE_OK
-            || statement.bindText(8, sourceUnlinkableToken ? sourceUnlinkableToken->tokenBase64URL : emptyString()) != SQLITE_OK
-            || statement.bindText(9, sourceUnlinkableToken ? sourceUnlinkableToken->signatureBase64URL : emptyString()) != SQLITE_OK
-            || statement.bindText(10, sourceUnlinkableToken ? sourceUnlinkableToken->keyIDBase64URL : emptyString()) != SQLITE_OK
-            || statement.bindDouble(11, destinationEarliestTimeToSend) != SQLITE_OK
-            || statement.step() != SQLITE_DONE) {
</del><ins>+        auto statement = m_database.prepareStatement(insertAttributedPrivateClickMeasurementQuery);
+        if (!statement
+            || statement->bindInt(1, *sourceData.second) != SQLITE_OK
+            || statement->bindInt(2, *attributionDestinationData.second) != SQLITE_OK
+            || statement->bindInt(3, attribution.sourceID().id) != SQLITE_OK
+            || statement->bindInt(4, attributionTriggerData) != SQLITE_OK
+            || statement->bindInt(5, priority) != SQLITE_OK
+            || statement->bindDouble(6, attribution.timeOfAdClick().secondsSinceEpoch().value()) != SQLITE_OK
+            || statement->bindDouble(7, sourceEarliestTimeToSend) != SQLITE_OK
+            || statement->bindText(8, sourceUnlinkableToken ? sourceUnlinkableToken->tokenBase64URL : emptyString()) != SQLITE_OK
+            || statement->bindText(9, sourceUnlinkableToken ? sourceUnlinkableToken->signatureBase64URL : emptyString()) != SQLITE_OK
+            || statement->bindText(10, sourceUnlinkableToken ? sourceUnlinkableToken->keyIDBase64URL : emptyString()) != SQLITE_OK
+            || statement->bindDouble(11, destinationEarliestTimeToSend) != SQLITE_OK
+            || statement->step() != SQLITE_DONE) {
</ins><span class="cx">             RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement insertAttributedPrivateClickMeasurementQuery, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">             ASSERT_NOT_REACHED();
</span><span class="cx">         }
</span><span class="lines">@@ -3221,16 +3207,16 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    auto statement = SQLiteStatement(m_database, insertUnattributedPrivateClickMeasurementQuery);
-    if (statement.prepare() != SQLITE_OK
-        || statement.bindInt(1, *sourceData.second) != SQLITE_OK
-        || statement.bindInt(2, *attributionDestinationData.second) != SQLITE_OK
-        || statement.bindInt(3, attribution.sourceID().id) != SQLITE_OK
-        || statement.bindDouble(4, attribution.timeOfAdClick().secondsSinceEpoch().value()) != SQLITE_OK
-        || statement.bindText(5, sourceUnlinkableToken ? sourceUnlinkableToken->tokenBase64URL : emptyString()) != SQLITE_OK
-        || statement.bindText(6, sourceUnlinkableToken ? sourceUnlinkableToken->signatureBase64URL : emptyString()) != SQLITE_OK
-        || statement.bindText(7, sourceUnlinkableToken ? sourceUnlinkableToken->keyIDBase64URL : emptyString()) != SQLITE_OK
-        || statement.step() != SQLITE_DONE) {
</del><ins>+    auto statement = m_database.prepareStatement(insertUnattributedPrivateClickMeasurementQuery);
+    if (!statement
+        || statement->bindInt(1, *sourceData.second) != SQLITE_OK
+        || statement->bindInt(2, *attributionDestinationData.second) != SQLITE_OK
+        || statement->bindInt(3, attribution.sourceID().id) != SQLITE_OK
+        || statement->bindDouble(4, attribution.timeOfAdClick().secondsSinceEpoch().value()) != SQLITE_OK
+        || statement->bindText(5, sourceUnlinkableToken ? sourceUnlinkableToken->tokenBase64URL : emptyString()) != SQLITE_OK
+        || statement->bindText(6, sourceUnlinkableToken ? sourceUnlinkableToken->signatureBase64URL : emptyString()) != SQLITE_OK
+        || statement->bindText(7, sourceUnlinkableToken ? sourceUnlinkableToken->keyIDBase64URL : emptyString()) != SQLITE_OK
+        || statement->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement insertUnattributedPrivateClickMeasurementQuery, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="lines">@@ -3435,14 +3421,14 @@
</span><span class="cx"> 
</span><span class="cx"> String ResourceLoadStatisticsDatabaseStore::privateClickMeasurementToString()
</span><span class="cx"> {
</span><del>-    SQLiteStatement privateClickMeasurementDataExists(m_database, "SELECT (SELECT COUNT(*) FROM UnattributedPrivateClickMeasurement) as cnt1, (SELECT COUNT(*) FROM AttributedPrivateClickMeasurement) as cnt2"_s);
-    if (privateClickMeasurementDataExists.prepare() != SQLITE_OK || privateClickMeasurementDataExists.step() != SQLITE_ROW) {
</del><ins>+    auto privateClickMeasurementDataExists = m_database.prepareStatement("SELECT (SELECT COUNT(*) FROM UnattributedPrivateClickMeasurement) as cnt1, (SELECT COUNT(*) FROM AttributedPrivateClickMeasurement) as cnt2"_s);
+    if (!privateClickMeasurementDataExists || privateClickMeasurementDataExists->step() != SQLITE_ROW) {
</ins><span class="cx">         RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::privateClickMeasurementToString failed, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">         return { };
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (!privateClickMeasurementDataExists.getColumnInt(0) && !privateClickMeasurementDataExists.getColumnInt(1))
</del><ins>+    if (!privateClickMeasurementDataExists->getColumnInt(0) && !privateClickMeasurementDataExists->getColumnInt(1))
</ins><span class="cx">         return "\nNo stored Private Click Measurement data.\n"_s;
</span><span class="cx"> 
</span><span class="cx">     auto unattributedScopedStatement = this->scopedStatement(m_allUnattributedPrivateClickMeasurementAttributionsStatement, allUnattributedPrivateClickMeasurementAttributionsQuery, "privateClickMeasurementToString"_s);
</span><span class="lines">@@ -3573,11 +3559,11 @@
</span><span class="cx">     if (destinationEarliestTimeToSend || sourceEarliestTimeToSend)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    SQLiteStatement clearAttributedStatement(m_database, "DELETE FROM AttributedPrivateClickMeasurement WHERE sourceSiteDomainID = ? AND destinationSiteDomainID = ?"_s);
-    if (clearAttributedStatement.prepare() != SQLITE_OK
-        || clearAttributedStatement.bindInt(1, *sourceSiteDomainID) != SQLITE_OK
-        || clearAttributedStatement.bindInt(2, *destinationSiteDomainID) != SQLITE_OK
-        || clearAttributedStatement.step() != SQLITE_DONE) {
</del><ins>+    auto clearAttributedStatement = m_database.prepareStatement("DELETE FROM AttributedPrivateClickMeasurement WHERE sourceSiteDomainID = ? AND destinationSiteDomainID = ?"_s);
+    if (!clearAttributedStatement
+        || clearAttributedStatement->bindInt(1, *sourceSiteDomainID) != SQLITE_OK
+        || clearAttributedStatement->bindInt(2, *destinationSiteDomainID) != SQLITE_OK
+        || clearAttributedStatement->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearSentAttribution failed to step, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="lines">@@ -3587,18 +3573,17 @@
</span><span class="cx"> {
</span><span class="cx">     auto expiredTimeToSend = WallTime::now() - 1_h;
</span><span class="cx"> 
</span><del>-    auto earliestTimeToSendToSourceStatement = SQLiteStatement(m_database, "UPDATE AttributedPrivateClickMeasurement SET earliestTimeToSendToSource = ?");
-    auto earliestTimeToSendToDestinationStatement = SQLiteStatement(m_database, "UPDATE AttributedPrivateClickMeasurement SET earliestTimeToSendToDestination = null");
</del><ins>+    auto earliestTimeToSendToSourceStatement = m_database.prepareStatement("UPDATE AttributedPrivateClickMeasurement SET earliestTimeToSendToSource = ?"_s);
+    auto earliestTimeToSendToDestinationStatement = m_database.prepareStatement("UPDATE AttributedPrivateClickMeasurement SET earliestTimeToSendToDestination = null"_s);
</ins><span class="cx"> 
</span><del>-    if (earliestTimeToSendToSourceStatement.prepare() != SQLITE_OK
-        || earliestTimeToSendToSourceStatement.bindInt(1, expiredTimeToSend.secondsSinceEpoch().value()) != SQLITE_OK
-        || earliestTimeToSendToSourceStatement.step() != SQLITE_DONE) {
</del><ins>+    if (!earliestTimeToSendToSourceStatement
+        || earliestTimeToSendToSourceStatement->bindInt(1, expiredTimeToSend.secondsSinceEpoch().value()) != SQLITE_OK
+        || earliestTimeToSendToSourceStatement->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::markAttributedPrivateClickMeasurementsAsExpiredForTesting, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (earliestTimeToSendToDestinationStatement.prepare() != SQLITE_OK
-        || earliestTimeToSendToDestinationStatement.step() != SQLITE_DONE) {
</del><ins>+    if (!earliestTimeToSendToDestinationStatement || earliestTimeToSendToDestinationStatement->step() != SQLITE_DONE) {
</ins><span class="cx">         RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::markAttributedPrivateClickMeasurementsAsExpiredForTesting, error message: %" PRIVATE_LOG_STRING, this, m_database.lastErrorMsg());
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessClassifierResourceLoadStatisticsDatabaseStoreh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h      2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h 2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -175,7 +175,7 @@
</span><span class="cx">     bool missingReferenceToObservedDomains();
</span><span class="cx">     void migrateDataToNewTablesIfNecessary();
</span><span class="cx">     void destroyStatements();
</span><del>-    WebCore::SQLiteStatementAutoResetScope scopedStatement(std::unique_ptr<WebCore::SQLiteStatement>&, const String&, const String&) const;
</del><ins>+    WebCore::SQLiteStatementAutoResetScope scopedStatement(std::unique_ptr<WebCore::SQLiteStatement>&, ASCIILiteral, const String&) const;
</ins><span class="cx"> 
</span><span class="cx">     bool hasStorageAccess(const TopFrameDomain&, const SubFrameDomain&) const;
</span><span class="cx">     Vector<WebResourceLoadStatisticsStore::ThirdPartyDataForSpecificFirstParty> getThirdPartyDataForSpecificFirstPartyDomains(unsigned, const RegistrableDomain&) const;
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessWebStorageLocalStorageDatabasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.cpp   2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.cpp      2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -38,7 +38,7 @@
</span><span class="cx"> namespace WebKit {
</span><span class="cx"> using namespace WebCore;
</span><span class="cx"> 
</span><del>-static const char getItemsQueryString[] = "SELECT key, value FROM ItemTable";
</del><ins>+static const ASCIILiteral getItemsQueryString { "SELECT key, value FROM ItemTable"_s };
</ins><span class="cx"> 
</span><span class="cx"> Ref<LocalStorageDatabase> LocalStorageDatabase::create(String&& databasePath, unsigned quotaInBytes)
</span><span class="cx"> {
</span><span class="lines">@@ -99,10 +99,10 @@
</span><span class="cx">     if (!m_database.tableExists("ItemTable"))
</span><span class="cx">         return true;
</span><span class="cx"> 
</span><del>-    SQLiteStatement query(m_database, "SELECT value FROM ItemTable LIMIT 1");
</del><ins>+    auto query = m_database.prepareStatement("SELECT value FROM ItemTable LIMIT 1"_s);
</ins><span class="cx"> 
</span><span class="cx">     // This query isn't ever executed, it's just used to check the column type.
</span><del>-    if (query.isColumnDeclaredAsBlob(0))
</del><ins>+    if (query && query->isColumnDeclaredAsBlob(0))
</ins><span class="cx">         return true;
</span><span class="cx"> 
</span><span class="cx">     // Create a new table with the right type, copy all the data over to it and then replace the new table with the old table.
</span><span class="lines">@@ -302,19 +302,18 @@
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    SQLiteStatement query(m_database, "SELECT COUNT(*) FROM ItemTable");
-    if (query.prepare() != SQLITE_OK) {
</del><ins>+    auto query = m_database.prepareStatement("SELECT COUNT(*) FROM ItemTable"_s);
+    if (!query) {
</ins><span class="cx">         LOG_ERROR("Unable to count number of rows in ItemTable for local storage");
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    int result = query.step();
-    if (result != SQLITE_ROW) {
</del><ins>+    if (query->step() != SQLITE_ROW) {
</ins><span class="cx">         LOG_ERROR("No results when counting number of rows in ItemTable for local storage");
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return !query.getColumnInt(0);
</del><ins>+    return !query->getColumnInt(0);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void LocalStorageDatabase::openIfExisting()
</span><span class="lines">@@ -330,14 +329,15 @@
</span><span class="cx">         scopedStatement(m_getItemsStatement, getItemsQueryString);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-SQLiteStatementAutoResetScope LocalStorageDatabase::scopedStatement(std::unique_ptr<SQLiteStatement>& statement, const String& query) const
</del><ins>+SQLiteStatementAutoResetScope LocalStorageDatabase::scopedStatement(std::unique_ptr<SQLiteStatement>& statement, ASCIILiteral query) const
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx">     if (!statement) {
</span><del>-        statement = makeUnique<SQLiteStatement>(m_database, query);
</del><ins>+        auto statementOrError = m_database.prepareHeapStatement(query);
+        if (!statementOrError)
+            return SQLiteStatementAutoResetScope { };
+        statement = statementOrError.value().moveToUniquePtr();
</ins><span class="cx">         ASSERT(m_database.isOpen());
</span><del>-        if (statement->prepare() != SQLITE_OK)
-            return SQLiteStatementAutoResetScope { };
</del><span class="cx">     }
</span><span class="cx">     return SQLiteStatementAutoResetScope { statement.get() };
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessWebStorageLocalStorageDatabaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.h (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.h     2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.h        2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -62,7 +62,7 @@
</span><span class="cx">     bool migrateItemTableIfNeeded();
</span><span class="cx">     bool databaseIsEmpty() const;
</span><span class="cx"> 
</span><del>-    WebCore::SQLiteStatementAutoResetScope scopedStatement(std::unique_ptr<WebCore::SQLiteStatement>&, const String& query) const;
</del><ins>+    WebCore::SQLiteStatementAutoResetScope scopedStatement(std::unique_ptr<WebCore::SQLiteStatement>&, ASCIILiteral query) const;
</ins><span class="cx"> 
</span><span class="cx">     String m_databasePath;
</span><span class="cx">     mutable WebCore::SQLiteDatabase m_database;
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPIglibIconDatabasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/glib/IconDatabase.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/glib/IconDatabase.cpp  2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebKit/UIProcess/API/glib/IconDatabase.cpp     2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -66,7 +66,8 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        auto databaseVersionNumber = SQLiteStatement(m_db, "SELECT value FROM IconDatabaseInfo WHERE key = 'Version';").getColumnInt(0);
</del><ins>+        auto versionStatement = m_db.prepareStatement("SELECT value FROM IconDatabaseInfo WHERE key = 'Version';"_s);
+        auto databaseVersionNumber = versionStatement ? versionStatement->getColumnInt(0) : 0;
</ins><span class="cx">         if (databaseVersionNumber > currentDatabaseVersion) {
</span><span class="cx">             LOG(IconDatabase, "Database version number %d is greater than our current version number %d - closing the database to prevent overwriting newer versions",
</span><span class="cx">                 databaseVersionNumber, currentDatabaseVersion);
</span><span class="lines">@@ -84,7 +85,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // Reduce sqlite RAM cache size from default 2000 pages (~1.5kB per page). 3MB of cache for icon database is overkill.
</span><del>-        SQLiteStatement(m_db, "PRAGMA cache_size = 200;").executeCommand();
</del><ins>+        m_db.executeCommand("PRAGMA cache_size = 200;"_s);
</ins><span class="cx"> 
</span><span class="cx">         if (allowDatabaseWrite == AllowDatabaseWrite::Yes) {
</span><span class="cx">             m_pruneTimer = makeUnique<RunLoop::Timer<IconDatabase>>(RunLoop::current(), this, &IconDatabase::pruneTimerFired);
</span><span class="lines">@@ -175,17 +176,17 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     String importQuery = makeString("SELECT PageURL.url, IconInfo.url, IconInfo.stamp FROM PageURL INNER JOIN IconInfo ON PageURL.iconID=IconInfo.iconID WHERE IconInfo.stamp > ", floor((WallTime::now() - notUsedIconExpirationTime).secondsSinceEpoch().seconds()), ';');
</span><del>-    SQLiteStatement query(m_db, importQuery);
-    if (query.prepare() != SQLITE_OK) {
</del><ins>+    auto query = m_db.prepareStatement(importQuery);
+    if (!query) {
</ins><span class="cx">         LOG_ERROR("Unable to prepare icon url import query");
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    auto result = query.step();
</del><ins>+    auto result = query->step();
</ins><span class="cx">     LockHolder lockHolder(m_pageURLToIconURLMapLock);
</span><span class="cx">     while (result == SQLITE_ROW) {
</span><del>-        m_pageURLToIconURLMap.set(query.getColumnText(0), query.getColumnText(1));
-        result = query.step();
</del><ins>+        m_pageURLToIconURLMap.set(query->getColumnText(0), query->getColumnText(1));
+        result = query->step();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     startPruneTimer();
</span><span class="lines">@@ -214,12 +215,12 @@
</span><span class="cx">     ASSERT(m_db.isOpen());
</span><span class="cx"> 
</span><span class="cx">     if (!m_pruneIconsStatement) {
</span><del>-        m_pruneIconsStatement = makeUnique<SQLiteStatement>(m_db, "DELETE FROM IconInfo WHERE stamp <= (?);");
-        if (m_pruneIconsStatement->prepare() != SQLITE_OK) {
</del><ins>+        auto pruneIconsStatement = m_db.prepareHeapStatement("DELETE FROM IconInfo WHERE stamp <= (?);"_s);
+        if (!pruneIconsStatement) {
</ins><span class="cx">             LOG_ERROR("Preparing statement pruneIcons failed");
</span><del>-            m_pruneIconsStatement = nullptr;
</del><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+        m_pruneIconsStatement = pruneIconsStatement.value().moveToUniquePtr();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (m_pruneIconsStatement->bindInt64(1, floor((WallTime::now() - notUsedIconExpirationTime).secondsSinceEpoch().seconds())) != SQLITE_OK) {
</span><span class="lines">@@ -230,8 +231,8 @@
</span><span class="cx">     SQLiteTransaction transaction(m_db);
</span><span class="cx">     transaction.begin();
</span><span class="cx">     if (m_pruneIconsStatement->step() == SQLITE_DONE) {
</span><del>-        m_db.executeCommand("DELETE FROM IconData WHERE iconID NOT IN (SELECT iconID FROM IconInfo);");
-        m_db.executeCommand("DELETE FROM PageURL WHERE iconID NOT IN (SELECT iconID FROM IconInfo);");
</del><ins>+        m_db.executeCommand("DELETE FROM IconData WHERE iconID NOT IN (SELECT iconID FROM IconInfo);"_s);
+        m_db.executeCommand("DELETE FROM PageURL WHERE iconID NOT IN (SELECT iconID FROM IconInfo);"_s);
</ins><span class="cx">     }
</span><span class="cx">     m_pruneIconsStatement->reset();
</span><span class="cx"> 
</span><span class="lines">@@ -285,12 +286,12 @@
</span><span class="cx">     ASSERT(m_db.isOpen());
</span><span class="cx"> 
</span><span class="cx">     if (!m_iconIDForIconURLStatement) {
</span><del>-        m_iconIDForIconURLStatement = makeUnique<SQLiteStatement>(m_db, "SELECT IconInfo.iconID, IconInfo.stamp FROM IconInfo WHERE IconInfo.url = (?);");
-        if (m_iconIDForIconURLStatement->prepare() != SQLITE_OK) {
</del><ins>+        auto iconIDForIconURLStatement = m_db.prepareHeapStatement("SELECT IconInfo.iconID, IconInfo.stamp FROM IconInfo WHERE IconInfo.url = (?);"_s);
+        if (!iconIDForIconURLStatement) {
</ins><span class="cx">             LOG_ERROR("Preparing statement iconIDForIconURL failed");
</span><del>-            m_iconIDForIconURLStatement = nullptr;
</del><span class="cx">             return WTF::nullopt;
</span><span class="cx">         }
</span><ins>+        m_iconIDForIconURLStatement = iconIDForIconURLStatement.value().moveToUniquePtr();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (m_iconIDForIconURLStatement->bindText(1, iconURL) != SQLITE_OK) {
</span><span class="lines">@@ -315,12 +316,12 @@
</span><span class="cx">     ASSERT(m_allowDatabaseWrite == AllowDatabaseWrite::Yes);
</span><span class="cx"> 
</span><span class="cx">     if (!m_setIconIDForPageURLStatement) {
</span><del>-        m_setIconIDForPageURLStatement = makeUnique<SQLiteStatement>(m_db, "INSERT INTO PageURL (url, iconID) VALUES ((?), ?);");
-        if (m_setIconIDForPageURLStatement->prepare() != SQLITE_OK) {
</del><ins>+        auto setIconIDForPageURLStatement = m_db.prepareHeapStatement("INSERT INTO PageURL (url, iconID) VALUES ((?), ?);"_s);
+        if (!setIconIDForPageURLStatement) {
</ins><span class="cx">             LOG_ERROR("Preparing statement setIconIDForPageURL failed");
</span><del>-            m_setIconIDForPageURLStatement = nullptr;
</del><span class="cx">             return false;
</span><span class="cx">         }
</span><ins>+        m_setIconIDForPageURLStatement = setIconIDForPageURLStatement.value().moveToUniquePtr();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (m_setIconIDForPageURLStatement->bindText(1, pageURL) != SQLITE_OK
</span><span class="lines">@@ -342,12 +343,12 @@
</span><span class="cx">     ASSERT(m_db.isOpen());
</span><span class="cx"> 
</span><span class="cx">     if (!m_iconDataStatement) {
</span><del>-        m_iconDataStatement = makeUnique<SQLiteStatement>(m_db, "SELECT IconData.data FROM IconData WHERE IconData.iconID = (?);");
-        if (m_iconDataStatement->prepare() != SQLITE_OK) {
</del><ins>+        auto iconDataStatement = m_db.prepareHeapStatement("SELECT IconData.data FROM IconData WHERE IconData.iconID = (?);"_s);
+        if (!iconDataStatement) {
</ins><span class="cx">             LOG_ERROR("Preparing statement iconData failed");
</span><del>-            m_iconDataStatement = nullptr;
</del><span class="cx">             return { };
</span><span class="cx">         }
</span><ins>+        m_iconDataStatement = iconDataStatement.value().moveToUniquePtr();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (m_iconDataStatement->bindInt64(1, iconID) != SQLITE_OK) {
</span><span class="lines">@@ -370,20 +371,20 @@
</span><span class="cx">     ASSERT(m_allowDatabaseWrite == AllowDatabaseWrite::Yes);
</span><span class="cx"> 
</span><span class="cx">     if (!m_addIconStatement) {
</span><del>-        m_addIconStatement = makeUnique<SQLiteStatement>(m_db, "INSERT INTO IconInfo (url, stamp) VALUES (?, 0);");
-        if (m_addIconStatement->prepare() != SQLITE_OK) {
</del><ins>+        auto addIconStatement = m_db.prepareHeapStatement("INSERT INTO IconInfo (url, stamp) VALUES (?, 0);"_s);
+        if (!addIconStatement) {
</ins><span class="cx">             LOG_ERROR("Preparing statement addIcon failed");
</span><del>-            m_addIconStatement = nullptr;
</del><span class="cx">             return WTF::nullopt;
</span><span class="cx">         }
</span><ins>+        m_addIconStatement = addIconStatement.value().moveToUniquePtr();
</ins><span class="cx">     }
</span><span class="cx">     if (!m_addIconDataStatement) {
</span><del>-        m_addIconDataStatement = makeUnique<SQLiteStatement>(m_db, "INSERT INTO IconData (iconID, data) VALUES (?, ?);");
-        if (m_addIconDataStatement->prepare() != SQLITE_OK) {
</del><ins>+        auto addIconDataStatement = m_db.prepareHeapStatement("INSERT INTO IconData (iconID, data) VALUES (?, ?);"_s);
+        if (!addIconDataStatement) {
</ins><span class="cx">             LOG_ERROR("Preparing statement addIconData failed");
</span><del>-            m_addIconDataStatement = nullptr;
</del><span class="cx">             return WTF::nullopt;
</span><span class="cx">         }
</span><ins>+        m_addIconDataStatement = addIconDataStatement.value().moveToUniquePtr();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (m_addIconStatement->bindText(1, iconURL) != SQLITE_OK) {
</span><span class="lines">@@ -413,12 +414,12 @@
</span><span class="cx">     ASSERT(m_allowDatabaseWrite == AllowDatabaseWrite::Yes);
</span><span class="cx"> 
</span><span class="cx">     if (!m_updateIconTimestampStatement) {
</span><del>-        m_updateIconTimestampStatement = makeUnique<SQLiteStatement>(m_db, "UPDATE IconInfo SET stamp = ? WHERE iconID = ?;");
-        if (m_updateIconTimestampStatement->prepare() != SQLITE_OK) {
</del><ins>+        auto updateIconTimestampStatement = m_db.prepareHeapStatement("UPDATE IconInfo SET stamp = ? WHERE iconID = ?;"_s);
+        if (!updateIconTimestampStatement) {
</ins><span class="cx">             LOG_ERROR("Preparing statement updateIconTimestamp failed");
</span><del>-            m_updateIconTimestampStatement = nullptr;
</del><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+        m_updateIconTimestampStatement = updateIconTimestampStatement.value().moveToUniquePtr();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (m_updateIconTimestampStatement->bindInt64(1, timestamp) != SQLITE_OK || m_updateIconTimestampStatement->bindInt64(2, iconID) != SQLITE_OK) {
</span><span class="lines">@@ -437,28 +438,28 @@
</span><span class="cx">     ASSERT(m_allowDatabaseWrite == AllowDatabaseWrite::Yes);
</span><span class="cx"> 
</span><span class="cx">     if (!m_deletePageURLsForIconStatement) {
</span><del>-        m_deletePageURLsForIconStatement = makeUnique<SQLiteStatement>(m_db, "DELETE FROM PageURL WHERE PageURL.iconID = (?);");
-        if (m_deletePageURLsForIconStatement->prepare() != SQLITE_OK) {
</del><ins>+        auto deletePageURLsForIconStatement = m_db.prepareHeapStatement("DELETE FROM PageURL WHERE PageURL.iconID = (?);"_s);
+        if (!deletePageURLsForIconStatement) {
</ins><span class="cx">             LOG_ERROR("Preparing statement deletePageURLsForIcon failed");
</span><del>-            m_deletePageURLsForIconStatement = nullptr;
</del><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+        m_deletePageURLsForIconStatement = deletePageURLsForIconStatement.value().moveToUniquePtr();
</ins><span class="cx">     }
</span><span class="cx">     if (!m_deleteIconDataStatement) {
</span><del>-        m_deleteIconDataStatement = makeUnique<SQLiteStatement>(m_db, "DELETE FROM IconData WHERE IconData.iconID = (?);");
-        if (m_deleteIconDataStatement->prepare() != SQLITE_OK) {
</del><ins>+        auto deleteIconDataStatement = m_db.prepareHeapStatement("DELETE FROM IconData WHERE IconData.iconID = (?);"_s);
+        if (!deleteIconDataStatement) {
</ins><span class="cx">             LOG_ERROR("Preparing statement deleteIcon failed");
</span><del>-            m_deleteIconDataStatement = nullptr;
</del><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+        m_deleteIconDataStatement = deleteIconDataStatement.value().moveToUniquePtr();
</ins><span class="cx">     }
</span><span class="cx">     if (!m_deleteIconStatement) {
</span><del>-        m_deleteIconStatement = makeUnique<SQLiteStatement>(m_db, "DELETE FROM IconInfo WHERE IconInfo.iconID = (?);");
-        if (m_deleteIconStatement->prepare() != SQLITE_OK) {
</del><ins>+        auto deleteIconStatement = m_db.prepareHeapStatement("DELETE FROM IconInfo WHERE IconInfo.iconID = (?);"_s);
+        if (!deleteIconStatement) {
</ins><span class="cx">             LOG_ERROR("Preparing statement deleteIcon failed");
</span><del>-            m_deleteIconStatement = nullptr;
</del><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+        m_deleteIconStatement = deleteIconStatement.value().moveToUniquePtr();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (m_deletePageURLsForIconStatement->bindInt64(1, iconID) != SQLITE_OK
</span></span></pre></div>
<a id="trunkSourceWebKitLegacyChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKitLegacy/ChangeLog (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKitLegacy/ChangeLog      2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebKitLegacy/ChangeLog 2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -1,3 +1,25 @@
</span><ins>+2021-05-16  Chris Dumez  <cdumez@apple.com>
+
+        Modernize / Optimize SQLiteStatement creation and preparation
+        https://bugs.webkit.org/show_bug.cgi?id=225791
+
+        Reviewed by Sam Weinig.
+
+        Update code base now that the SQLiteDatabase & SQLiteStatement API has changed.
+        Also use more ASCIILiterals.
+
+        * Storage/StorageAreaSync.cpp:
+        (WebKit::StorageAreaSync::migrateItemTableIfNeeded):
+        (WebKit::StorageAreaSync::performImport):
+        (WebKit::StorageAreaSync::sync):
+        (WebKit::StorageAreaSync::deleteEmptyDatabase):
+        * Storage/StorageTracker.cpp:
+        (WebKit::StorageTracker::syncImportOriginIdentifiers):
+        (WebKit::StorageTracker::syncSetOriginDetails):
+        (WebKit::StorageTracker::syncDeleteAllOrigins):
+        (WebKit::StorageTracker::syncDeleteOrigin):
+        (WebKit::StorageTracker::databasePathForOrigin):
+
</ins><span class="cx"> 2021-05-14  Chris Dumez  <cdumez@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Rename FileSystem::getFileSize() to FileSystem::fileSize()
</span></span></pre></div>
<a id="trunkSourceWebKitLegacyStorageStorageAreaSynccpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKitLegacy/Storage/StorageAreaSync.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKitLegacy/Storage/StorageAreaSync.cpp    2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebKitLegacy/Storage/StorageAreaSync.cpp       2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -278,9 +278,9 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     {
</span><del>-        SQLiteStatement query(m_database, "SELECT value FROM ItemTable LIMIT 1");
</del><ins>+        auto query = m_database.prepareStatement("SELECT value FROM ItemTable LIMIT 1"_s);
</ins><span class="cx">         // this query isn't ever executed.
</span><del>-        if (query.isColumnDeclaredAsBlob(0))
</del><ins>+        if (query && query->isColumnDeclaredAsBlob(0))
</ins><span class="cx">             return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -326,8 +326,8 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement query(m_database, "SELECT key, value FROM ItemTable");
-    if (query.prepare() != SQLITE_OK) {
</del><ins>+    auto query = m_database.prepareStatement("SELECT key, value FROM ItemTable"_s);
+    if (!query) {
</ins><span class="cx">         LOG_ERROR("Unable to select items from ItemTable for local storage");
</span><span class="cx">         markImported();
</span><span class="cx">         return;
</span><span class="lines">@@ -335,10 +335,10 @@
</span><span class="cx"> 
</span><span class="cx">     HashMap<String, String> itemMap;
</span><span class="cx"> 
</span><del>-    int result = query.step();
</del><ins>+    int result = query->step();
</ins><span class="cx">     while (result == SQLITE_ROW) {
</span><del>-        itemMap.set(query.getColumnText(0), query.getColumnBlobAsString(1));
-        result = query.step();
</del><ins>+        itemMap.set(query->getColumnText(0), query->getColumnBlobAsString(1));
+        result = query->step();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (result != SQLITE_DONE) {
</span><span class="lines">@@ -412,13 +412,13 @@
</span><span class="cx"> 
</span><span class="cx">     // If the clear flag is set, then we clear all items out before we write any new ones in.
</span><span class="cx">     if (clearItems) {
</span><del>-        SQLiteStatement clear(m_database, "DELETE FROM ItemTable");
-        if (clear.prepare() != SQLITE_OK) {
</del><ins>+        auto clear = m_database.prepareStatement("DELETE FROM ItemTable"_s);
+        if (!clear) {
</ins><span class="cx">             LOG_ERROR("Failed to prepare clear statement - cannot write to local storage database");
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        int result = clear.step();
</del><ins>+        int result = clear->step();
</ins><span class="cx">         if (result != SQLITE_DONE) {
</span><span class="cx">             LOG_ERROR("Failed to clear all items in the local storage database - %i", result);
</span><span class="cx">             return;
</span><span class="lines">@@ -425,14 +425,14 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement insert(m_database, "INSERT INTO ItemTable VALUES (?, ?)");
-    if (insert.prepare() != SQLITE_OK) {
</del><ins>+    auto insert = m_database.prepareStatement("INSERT INTO ItemTable VALUES (?, ?)"_s);
+    if (!insert) {
</ins><span class="cx">         LOG_ERROR("Failed to prepare insert statement - cannot write to local storage database");
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SQLiteStatement remove(m_database, "DELETE FROM ItemTable WHERE key=?");
-    if (remove.prepare() != SQLITE_OK) {
</del><ins>+    auto remove = m_database.prepareStatement("DELETE FROM ItemTable WHERE key=?"_s);
+    if (!remove) {
</ins><span class="cx">         LOG_ERROR("Failed to prepare delete statement - cannot write to local storage database");
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -443,21 +443,21 @@
</span><span class="cx">     transaction.begin();
</span><span class="cx">     for (HashMap<String, String>::const_iterator it = items.begin(); it != end; ++it) {
</span><span class="cx">         // Based on the null-ness of the second argument, decide whether this is an insert or a delete.
</span><del>-        SQLiteStatement& query = it->value.isNull() ? remove : insert;
</del><ins>+        auto& query = it->value.isNull() ? remove : insert;
</ins><span class="cx"> 
</span><del>-        query.bindText(1, it->key);
</del><ins>+        query->bindText(1, it->key);
</ins><span class="cx"> 
</span><span class="cx">         // If the second argument is non-null, we're doing an insert, so bind it as the value.
</span><span class="cx">         if (!it->value.isNull())
</span><del>-            query.bindBlob(2, it->value);
</del><ins>+            query->bindBlob(2, it->value);
</ins><span class="cx"> 
</span><del>-        int result = query.step();
</del><ins>+        int result = query->step();
</ins><span class="cx">         if (result != SQLITE_DONE) {
</span><span class="cx">             LOG_ERROR("Failed to update item in the local storage database - %i", result);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        query.reset();
</del><ins>+        query->reset();
</ins><span class="cx">     }
</span><span class="cx">     transaction.commit();
</span><span class="cx"> }
</span><span class="lines">@@ -499,31 +499,33 @@
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    SQLiteStatement query(m_database, "SELECT COUNT(*) FROM ItemTable");
-    if (query.prepare() != SQLITE_OK) {
-        LOG_ERROR("Unable to count number of rows in ItemTable for local storage");
-        return;
-    }
</del><ins>+    auto count = [&] {
+        auto query = m_database.prepareStatement("SELECT COUNT(*) FROM ItemTable"_s);
+        if (!query) {
+            LOG_ERROR("Unable to count number of rows in ItemTable for local storage");
+            return -1;
+        }
</ins><span class="cx"> 
</span><del>-    int result = query.step();
-    if (result != SQLITE_ROW) {
-        LOG_ERROR("No results when counting number of rows in ItemTable for local storage");
</del><ins>+        int result = query->step();
+        if (result != SQLITE_ROW) {
+            LOG_ERROR("No results when counting number of rows in ItemTable for local storage");
+            return -1;
+        }
+
+        return query->getColumnInt(0);
+    }();
+    if (count)
</ins><span class="cx">         return;
</span><del>-    }
</del><span class="cx"> 
</span><del>-    int count = query.getColumnInt(0);
-    if (!count) {
-        query.finalize();
-        m_database.close();
-        if (StorageTracker::tracker().isActive()) {
-            callOnMainThread([databaseIdentifier = m_databaseIdentifier.isolatedCopy()] {
-                StorageTracker::tracker().deleteOriginWithIdentifier(databaseIdentifier);
-            });
-        } else {
-            String databaseFilename = m_syncManager->fullDatabaseFilename(m_databaseIdentifier);
-            if (!FileSystem::deleteFile(databaseFilename))
-                LOG_ERROR("Failed to delete database file %s\n", databaseFilename.utf8().data());
-        }
</del><ins>+    m_database.close();
+    if (StorageTracker::tracker().isActive()) {
+        callOnMainThread([databaseIdentifier = m_databaseIdentifier.isolatedCopy()] {
+            StorageTracker::tracker().deleteOriginWithIdentifier(databaseIdentifier);
+        });
+    } else {
+        String databaseFilename = m_syncManager->fullDatabaseFilename(m_databaseIdentifier);
+        if (!FileSystem::deleteFile(databaseFilename))
+            LOG_ERROR("Failed to delete database file %s\n", databaseFilename.utf8().data());
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitLegacyStorageStorageTrackercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKitLegacy/Storage/StorageTracker.cpp (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKitLegacy/Storage/StorageTracker.cpp     2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Source/WebKitLegacy/Storage/StorageTracker.cpp        2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -189,8 +189,8 @@
</span><span class="cx">         if (m_database.isOpen()) {
</span><span class="cx">             SQLiteTransactionInProgressAutoCounter transactionCounter;
</span><span class="cx"> 
</span><del>-            SQLiteStatement statement(m_database, "SELECT origin FROM Origins");
-            if (statement.prepare() != SQLITE_OK) {
</del><ins>+            auto statement = m_database.prepareStatement("SELECT origin FROM Origins"_s);
+            if (!statement) {
</ins><span class="cx">                 LOG_ERROR("Failed to prepare statement.");
</span><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="lines">@@ -199,8 +199,8 @@
</span><span class="cx">             
</span><span class="cx">             {
</span><span class="cx">                 LockHolder lockOrigins(m_originSetMutex);
</span><del>-                while ((result = statement.step()) == SQLITE_ROW)
-                    m_originSet.add(statement.getColumnText(0).isolatedCopy());
</del><ins>+                while ((result = statement->step()) == SQLITE_ROW)
+                    m_originSet.add(statement->getColumnText(0).isolatedCopy());
</ins><span class="cx">             }
</span><span class="cx">             
</span><span class="cx">             if (result != SQLITE_DONE) {
</span><span class="lines">@@ -316,16 +316,16 @@
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)");
-    if (statement.prepare() != SQLITE_OK) {
</del><ins>+    auto statement = m_database.prepareStatement("INSERT INTO Origins VALUES (?, ?)"_s);
+    if (!statement) {
</ins><span class="cx">         LOG_ERROR("Unable to establish origin '%s' in the tracker", originIdentifier.ascii().data());
</span><span class="cx">         return;
</span><span class="cx">     } 
</span><span class="cx">     
</span><del>-    statement.bindText(1, originIdentifier);
-    statement.bindText(2, databaseFile);
</del><ins>+    statement->bindText(1, originIdentifier);
+    statement->bindText(2, databaseFile);
</ins><span class="cx">     
</span><del>-    if (statement.step() != SQLITE_DONE)
</del><ins>+    if (statement->step() != SQLITE_DONE)
</ins><span class="cx">         LOG_ERROR("Unable to establish origin '%s' in the tracker", originIdentifier.ascii().data());
</span><span class="cx"> 
</span><span class="cx">     {
</span><span class="lines">@@ -404,23 +404,23 @@
</span><span class="cx">     if (!m_database.isOpen())
</span><span class="cx">         return;
</span><span class="cx">     
</span><del>-    SQLiteStatement statement(m_database, "SELECT origin, path FROM Origins");
-    if (statement.prepare() != SQLITE_OK) {
</del><ins>+    auto statement = m_database.prepareStatement("SELECT origin, path FROM Origins"_s);
+    if (!statement) {
</ins><span class="cx">         LOG_ERROR("Failed to prepare statement.");
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     int result;
</span><del>-    while ((result = statement.step()) == SQLITE_ROW) {
-        if (!canDeleteOrigin(statement.getColumnText(0)))
</del><ins>+    while ((result = statement->step()) == SQLITE_ROW) {
+        if (!canDeleteOrigin(statement->getColumnText(0)))
</ins><span class="cx">             continue;
</span><span class="cx"> 
</span><del>-        FileSystem::deleteFile(statement.getColumnText(1));
</del><ins>+        FileSystem::deleteFile(statement->getColumnText(1));
</ins><span class="cx"> 
</span><span class="cx">         {
</span><span class="cx">             LockHolder locker(m_clientMutex);
</span><span class="cx">             if (m_client)
</span><del>-                m_client->dispatchDidModifyOrigin(statement.getColumnText(0));
</del><ins>+                m_client->dispatchDidModifyOrigin(statement->getColumnText(0));
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -441,12 +441,12 @@
</span><span class="cx">         openTrackerDatabase(false);
</span><span class="cx">         if (!m_database.isOpen())
</span><span class="cx">             return;
</span><del>-        SQLiteStatement deleteStatement(m_database, "DELETE FROM Origins");
-        if (deleteStatement.prepare() != SQLITE_OK) {
</del><ins>+        auto deleteStatement = m_database.prepareStatement("DELETE FROM Origins"_s);
+        if (!deleteStatement) {
</ins><span class="cx">             LOG_ERROR("Unable to prepare deletion of all origins");
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        if (!deleteStatement.executeCommand()) {
</del><ins>+        if (!deleteStatement->executeCommand()) {
</ins><span class="cx">             LOG_ERROR("Unable to execute deletion of all origins");
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -519,13 +519,13 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    SQLiteStatement deleteStatement(m_database, "DELETE FROM Origins where origin=?");
-    if (deleteStatement.prepare() != SQLITE_OK) {
</del><ins>+    auto deleteStatement = m_database.prepareStatement("DELETE FROM Origins where origin=?"_s);
+    if (!deleteStatement) {
</ins><span class="cx">         LOG_ERROR("Unable to prepare deletion of origin '%s'", originIdentifier.ascii().data());
</span><span class="cx">         return;
</span><span class="cx">     }
</span><del>-    deleteStatement.bindText(1, originIdentifier);
-    if (!deleteStatement.executeCommand()) {
</del><ins>+    deleteStatement->bindText(1, originIdentifier);
+    if (!deleteStatement->executeCommand()) {
</ins><span class="cx">         LOG_ERROR("Unable to execute deletion of origin '%s'", originIdentifier.ascii().data());
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -614,17 +614,17 @@
</span><span class="cx"> 
</span><span class="cx">     SQLiteTransactionInProgressAutoCounter transactionCounter;
</span><span class="cx"> 
</span><del>-    SQLiteStatement pathStatement(m_database, "SELECT path FROM Origins WHERE origin=?");
-    if (pathStatement.prepare() != SQLITE_OK) {
</del><ins>+    auto pathStatement = m_database.prepareStatement("SELECT path FROM Origins WHERE origin=?"_s);
+    if (!pathStatement) {
</ins><span class="cx">         LOG_ERROR("Unable to prepare selection of path for origin '%s'", originIdentifier.ascii().data());
</span><span class="cx">         return String();
</span><span class="cx">     }
</span><del>-    pathStatement.bindText(1, originIdentifier);
-    int result = pathStatement.step();
</del><ins>+    pathStatement->bindText(1, originIdentifier);
+    int result = pathStatement->step();
</ins><span class="cx">     if (result != SQLITE_ROW)
</span><span class="cx">         return String();
</span><span class="cx"> 
</span><del>-    return pathStatement.getColumnText(0);
</del><ins>+    return pathStatement->getColumnText(0);
</ins><span class="cx"> }
</span><span class="cx">     
</span><span class="cx"> uint64_t StorageTracker::diskUsageForOrigin(SecurityOrigin* origin)
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Tools/ChangeLog       2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2021-05-16  Chris Dumez  <cdumez@apple.com>
+
+        Modernize / Optimize SQLiteStatement creation and preparation
+        https://bugs.webkit.org/show_bug.cgi?id=225791
+
+        Reviewed by Sam Weinig.
+
+        Update code base now that the SQLiteDatabase & SQLiteStatement API has changed.
+        Also use more ASCIILiterals.
+
+        * TestWebKitAPI/Tests/WebCore/cocoa/DatabaseTrackerTest.mm:
+        (TestWebKitAPI::addToDatabasesTable):
+
</ins><span class="cx"> 2021-05-15  Ryosuke Niwa  <rniwa@webkit.org>
</span><span class="cx"> 
</span><span class="cx">         Delete WebSQL code from WebKit2
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebCorecocoaDatabaseTrackerTestmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/cocoa/DatabaseTrackerTest.mm (277570 => 277571)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebCore/cocoa/DatabaseTrackerTest.mm     2021-05-16 15:57:35 UTC (rev 277570)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/cocoa/DatabaseTrackerTest.mm        2021-05-16 17:18:30 UTC (rev 277571)
</span><span class="lines">@@ -65,12 +65,12 @@
</span><span class="cx">     SQLiteDatabase database;
</span><span class="cx">     database.open(databasePath);
</span><span class="cx"> 
</span><del>-    SQLiteStatement addDatabaseStatement(database, "INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);");
-    addDatabaseStatement.prepare();
-    addDatabaseStatement.bindText(1, origin.databaseIdentifier());
-    addDatabaseStatement.bindText(2, newDatabaseName);
-    addDatabaseStatement.bindText(3, newDatabasePath);
-    addDatabaseStatement.executeCommand();
</del><ins>+    if (auto addDatabaseStatement = database.prepareStatement("INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);"_s)) {
+        addDatabaseStatement->bindText(1, origin.databaseIdentifier());
+        addDatabaseStatement->bindText(2, newDatabaseName);
+        addDatabaseStatement->bindText(3, newDatabasePath);
+        addDatabaseStatement->executeCommand();
+    }
</ins><span class="cx"> 
</span><span class="cx">     database.close();
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>