sql: Restrict recovery-only API in Connection with passkeys.
This CL uses the passkey idiom recommended in https://abseil.io/tips/134
to restrict APIs in sql::Connection to sql::Recovery. Test APIs are
exposed via a peer class, following recommendations in the same tip.
This CL also exposes sql::Connection::page_size(). Asides from being
used in sql::Recovery, this can be useful in unit tests. It is worth
noting that set_page_size() is a widely-used part of the sql::Connection
API, so page_size() does not introduce a new concept.
Last, in order to make page_size() intuitive, this CL removes the
possibility of having sql::Connection::page_size_ be zero. Instead,
SQLite is configured with an explicit SQLITE_DEFAULT_PAGE_SIZE (matching
the current default), and page_size_ is initialized with
sql::Connection::kDefaultPageSize, which is guaranteed to match the
SQLite configuration.
Bug: none
Change-Id: I555a0bcf02f12ee006bbfc1a91080d7c0b8845d4
Reviewed-on: https://chromium-review.googlesource.com/1146768
Commit-Queue: Victor Costan <[email protected]>
Reviewed-by: Chris Mumford <[email protected]>
Cr-Commit-Position: refs/heads/master@{#578945}
diff --git a/sql/connection.cc b/sql/connection.cc
index b50f9f2..4813b8d0 100644
--- a/sql/connection.cc
+++ b/sql/connection.cc
@@ -255,9 +255,15 @@
was_valid_ = was_valid_ && forced;
}
+static_assert(
+ Connection::kDefaultPageSize == SQLITE_DEFAULT_PAGE_SIZE,
+ "Connection::kDefaultPageSize must match the value configured into SQLite");
+
+constexpr int Connection::kDefaultPageSize;
+
Connection::Connection()
: db_(nullptr),
- page_size_(0),
+ page_size_(kDefaultPageSize),
cache_size_(0),
exclusive_locking_(false),
transaction_nesting_(0),
@@ -433,9 +439,12 @@
return;
}
+ // The constructor and set_page_size() ensure that page_size_ is never zero.
+ const int page_size = page_size_;
+ DCHECK(page_size);
+
// Use local settings if provided, otherwise use documented defaults. The
// actual results could be fetching via PRAGMA calls.
- const int page_size = page_size_ ? page_size_ : 1024;
sqlite3_int64 preload_size = page_size * (cache_size_ ? cache_size_ : 2000);
if (preload_size < 1)
return;
@@ -1004,17 +1013,9 @@
return false;
}
- if (page_size_) {
- // Enforce SQLite restrictions on |page_size_|.
- DCHECK(!(page_size_ & (page_size_ - 1)))
- << " page_size_ " << page_size_ << " is not a power of two.";
- const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h
- DCHECK_LE(page_size_, kSqliteMaxPageSize);
- const std::string sql =
- base::StringPrintf("PRAGMA page_size=%d", page_size_);
- if (!null_db.Execute(sql.c_str()))
- return false;
- }
+ const std::string sql = base::StringPrintf("PRAGMA page_size=%d", page_size_);
+ if (!null_db.Execute(sql.c_str()))
+ return false;
#if defined(OS_ANDROID)
// Android compiles with SQLITE_DEFAULT_AUTOVACUUM. Unfortunately,
@@ -1267,7 +1268,8 @@
}
bool Connection::AttachDatabase(const base::FilePath& other_db_path,
- const char* attachment_point) {
+ const char* attachment_point,
+ InternalApiToken) {
DCHECK(ValidAttachmentPoint(attachment_point));
Statement s(GetUniqueStatement("ATTACH DATABASE ? AS ?"));
@@ -1282,7 +1284,8 @@
return s.Run();
}
-bool Connection::DetachDatabase(const char* attachment_point) {
+bool Connection::DetachDatabase(const char* attachment_point,
+ InternalApiToken) {
DCHECK(ValidAttachmentPoint(attachment_point));
Statement s(GetUniqueStatement("DETACH DATABASE ?"));
@@ -1698,16 +1701,8 @@
const base::TimeDelta kBusyTimeout =
base::TimeDelta::FromSeconds(kBusyTimeoutSeconds);
- if (page_size_ != 0) {
- // Enforce SQLite restrictions on |page_size_|.
- DCHECK(!(page_size_ & (page_size_ - 1)))
- << " page_size_ " << page_size_ << " is not a power of two.";
- const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h
- DCHECK_LE(page_size_, kSqliteMaxPageSize);
- const std::string sql =
- base::StringPrintf("PRAGMA page_size=%d", page_size_);
- ignore_result(ExecuteWithTimeout(sql.c_str(), kBusyTimeout));
- }
+ const std::string sql = base::StringPrintf("PRAGMA page_size=%d", page_size_);
+ ignore_result(ExecuteWithTimeout(sql.c_str(), kBusyTimeout));
if (cache_size_ != 0) {
const std::string sql =