[go: nahoru, domu]

blob: cc3e2813555d43af9663e9246b8d8553ee216c9d [file] [log] [blame]
Avi Drissman69b874f2022-09-15 19:11:141// Copyright 2012 The Chromium Authors
brettw@chromium.orge5ffd0e42009-09-11 21:30:562// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Victor Costan49a903a2021-05-07 22:21:005#include "sql/database.h"
6
avi0b519202015-12-21 07:25:197#include <stddef.h>
8#include <stdint.h>
Dan McArdle4feabeb52024-01-03 15:17:139
10#include <memory>
11#include <string>
12#include <utility>
13#include <vector>
avi0b519202015-12-21 07:25:1914
Ho Cheung47524352023-08-08 03:41:1015#include "base/containers/contains.h"
Will Harris711a5ec2023-04-04 21:43:3716#include "base/files/file.h"
thestig22dfc4012014-09-05 08:29:4417#include "base/files/file_util.h"
brettw@chromium.orgea1a3f62012-11-16 20:34:2318#include "base/files/scoped_temp_dir.h"
Avi Drissman2e85357a2023-01-12 21:57:3219#include "base/functional/bind.h"
20#include "base/functional/callback_helpers.h"
shess@chromium.org41a97c812013-02-07 02:35:3821#include "base/logging.h"
Keishi Hattori0e45c022021-11-27 09:25:5222#include "base/memory/raw_ptr.h"
Victor Costand09770c2022-03-08 23:14:4623#include "base/sequence_checker.h"
Will Harris711a5ec2023-04-04 21:43:3724#include "base/strings/strcat.h"
shess7e2baba2016-10-27 23:46:0525#include "base/strings/string_number_conversions.h"
Victor Costanc02b7af2021-07-09 13:26:4526#include "base/test/bind.h"
Victor Costan613b4302018-11-20 05:32:4327#include "base/test/gtest_util.h"
Devlin Cronin147687f2018-06-05 18:03:5628#include "base/test/metrics/histogram_tester.h"
Victor Costand09770c2022-03-08 23:14:4629#include "base/thread_annotations.h"
ssid9f8022f2015-10-12 17:49:0330#include "base/trace_event/process_memory_dump.h"
Scott Graham57ee54822017-09-13 06:37:5631#include "build/build_config.h"
Victor Costancfbfa602018-08-01 23:24:4632#include "sql/database_memory_dump_provider.h"
yongsheng.zhu@intel.com13487652012-07-24 08:25:5333#include "sql/meta_table.h"
Dan McArdle4feabeb52024-01-03 15:17:1334#include "sql/recovery.h"
Shubham Aggarwalbe4f97c2020-06-19 15:58:5735#include "sql/sql_features.h"
brettw@chromium.orgea1a3f62012-11-16 20:34:2336#include "sql/statement.h"
Victor Costand1a217b2019-04-02 02:44:2137#include "sql/test/database_test_peer.h"
shess976814402016-06-21 06:56:2538#include "sql/test/scoped_error_expecter.h"
kinuko@chromium.orga8848a72013-11-18 04:18:4739#include "sql/test/test_helpers.h"
Victor Costane7944b4e2022-03-30 20:06:2240#include "sql/transaction.h"
Victor Costan4b67f542022-02-24 17:40:5541#include "testing/gmock/include/gmock/gmock.h"
brettw@chromium.orge5ffd0e42009-09-11 21:30:5642#include "testing/gtest/include/gtest/gtest.h"
phajdan.jr@chromium.orge33cba42010-08-18 23:37:0343#include "third_party/sqlite/sqlite3.h"
brettw@chromium.orge5ffd0e42009-09-11 21:30:5644
shess58b8df82015-06-03 00:19:3245namespace sql {
Victor Costan7f6abbbe2018-07-29 02:57:2746
shess@chromium.org7bae5742013-07-10 20:46:1647namespace {
48
shess7e2baba2016-10-27 23:46:0549using sql::test::ExecuteWithResult;
50
John Delaney86dbec62021-08-24 15:05:2151// Helper to return the count of items in sqlite_schema. Return -1 in
shess@chromium.org7bae5742013-07-10 20:46:1652// case of error.
John Delaney86dbec62021-08-24 15:05:2153int SqliteSchemaCount(Database* db) {
54 const char* kSchemaCount = "SELECT COUNT(*) FROM sqlite_schema";
55 Statement s(db->GetUniqueStatement(kSchemaCount));
shess@chromium.org7bae5742013-07-10 20:46:1656 return s.Step() ? s.ColumnInt(0) : -1;
57}
58
shess1cf87f22016-10-25 22:18:2959// Handle errors by blowing away the database.
Victor Costan49a903a2021-05-07 22:21:0060void RazeErrorCallback(Database* db,
shess1cf87f22016-10-25 22:18:2961 int expected_error,
62 int error,
Victor Costan49a903a2021-05-07 22:21:0063 Statement* stmt) {
shess1cf87f22016-10-25 22:18:2964 // Nothing here needs extended errors at this time.
Victor Costancfbfa602018-08-01 23:24:4665 EXPECT_EQ(expected_error, expected_error & 0xff);
66 EXPECT_EQ(expected_error, error & 0xff);
Andrew Paseltinerd309fec2023-03-28 16:59:5567 db->RazeAndPoison();
shess1cf87f22016-10-25 22:18:2968}
69
Xiaohan Wang7d09c5e2022-01-08 02:37:3670#if BUILDFLAG(IS_POSIX)
shess@chromium.org81a2a602013-07-17 19:10:3671// Set a umask and restore the old mask on destruction. Cribbed from
72// shared_memory_unittest.cc. Used by POSIX-only UserPermission test.
73class ScopedUmaskSetter {
74 public:
75 explicit ScopedUmaskSetter(mode_t target_mask) {
76 old_umask_ = umask(target_mask);
77 }
78 ~ScopedUmaskSetter() { umask(old_umask_); }
Victor Costancfbfa602018-08-01 23:24:4679
Victor Costan49a903a2021-05-07 22:21:0080 ScopedUmaskSetter(const ScopedUmaskSetter&) = delete;
81 ScopedUmaskSetter& operator=(const ScopedUmaskSetter&) = delete;
82
shess@chromium.org81a2a602013-07-17 19:10:3683 private:
84 mode_t old_umask_;
shess@chromium.org81a2a602013-07-17 19:10:3685};
Xiaohan Wang7d09c5e2022-01-08 02:37:3686#endif // BUILDFLAG(IS_POSIX)
shess@chromium.org81a2a602013-07-17 19:10:3687
Etienne Bergeron14c5d712023-11-13 15:01:1588bool IsOpenedInCorrectJournalMode(Database* db, bool is_wal) {
89 std::string expected_mode = is_wal ? "wal" : "truncate";
90 return ExecuteWithResult(db, "PRAGMA journal_mode") == expected_mode;
91}
92
shessc8cd2a162015-10-22 20:30:4693} // namespace
94
Shubham Aggarwal003708982020-10-28 17:57:5495// We use the parameter to run all tests with WAL mode on and off.
Victor Costan49a903a2021-05-07 22:21:0096class SQLDatabaseTest : public testing::Test,
Shubham Aggarwal003708982020-10-28 17:57:5497 public testing::WithParamInterface<bool> {
98 public:
Victor Costan49a903a2021-05-07 22:21:0099 enum class OverwriteType {
100 kTruncate,
101 kOverwrite,
102 };
brettw@chromium.orge5ffd0e42009-09-11 21:30:56103
Victor Costan49a903a2021-05-07 22:21:00104 ~SQLDatabaseTest() override = default;
105
106 void SetUp() override {
Victor Costan49a903a2021-05-07 22:21:00107 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
108 db_path_ = temp_dir_.GetPath().AppendASCII("database_test.sqlite");
Dan McArdle4feabeb52024-01-03 15:17:13109 CreateFreshDB();
110 }
111
112 // Resets the database handle and deletes the backing file. On return, `db_`
113 // has just been opened on a fresh temp file named by `db_path_`.
114 void CreateFreshDB() {
115 ASSERT_FALSE(db_path_.empty());
116
117 db_.reset();
118 ASSERT_TRUE(base::DeleteFile(db_path_));
119
120 db_ = std::make_unique<Database>(GetDBOptions());
Victor Costan49a903a2021-05-07 22:21:00121 ASSERT_TRUE(db_->Open(db_path_));
Dan McArdle4feabeb52024-01-03 15:17:13122 ASSERT_TRUE(base::PathExists(db_path_));
Victor Costan49a903a2021-05-07 22:21:00123 }
124
125 DatabaseOptions GetDBOptions() {
126 DatabaseOptions options;
Shubham Aggarwal003708982020-10-28 17:57:54127 options.wal_mode = IsWALEnabled();
128 // TODO(crbug.com/1120969): Remove after switching to exclusive mode on by
129 // default.
130 options.exclusive_locking = false;
Xiaohan Wang7d09c5e2022-01-08 02:37:36131#if BUILDFLAG(IS_FUCHSIA) // Exclusive mode needs to be enabled to enter WAL
132 // mode on Fuchsia
Shubham Aggarwal003708982020-10-28 17:57:54133 if (IsWALEnabled()) {
134 options.exclusive_locking = true;
135 }
Xiaohan Wang7d09c5e2022-01-08 02:37:36136#endif // BUILDFLAG(IS_FUCHSIA)
Shubham Aggarwal003708982020-10-28 17:57:54137 return options;
138 }
Victor Costan49a903a2021-05-07 22:21:00139
Shubham Aggarwal003708982020-10-28 17:57:54140 bool IsWALEnabled() { return GetParam(); }
Victor Costan49a903a2021-05-07 22:21:00141
142 bool TruncateDatabase() {
143 base::File file(db_path_,
144 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
145 return file.SetLength(0);
146 }
147
148 bool OverwriteDatabaseHeader(OverwriteType type) {
149 base::File file(db_path_,
150 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
151 if (type == OverwriteType::kTruncate) {
152 if (!file.SetLength(0))
153 return false;
154 }
155
156 static constexpr char kText[] = "Now is the winter of our discontent.";
157 constexpr int kTextBytes = sizeof(kText) - 1;
158 return file.Write(0, kText, kTextBytes) == kTextBytes;
159 }
160
161 protected:
162 base::ScopedTempDir temp_dir_;
163 base::FilePath db_path_;
164 std::unique_ptr<Database> db_;
Shubham Aggarwal003708982020-10-28 17:57:54165};
166
Victor Costan289f2c8b2021-07-22 06:33:47167TEST_P(SQLDatabaseTest, Execute_ValidStatement) {
168 ASSERT_TRUE(db_->Execute("CREATE TABLE data(contents TEXT)"));
Victor Costan49a903a2021-05-07 22:21:00169 EXPECT_EQ(SQLITE_OK, db_->GetErrorCode());
Victor Costan289f2c8b2021-07-22 06:33:47170}
brettw@chromium.orge5ffd0e42009-09-11 21:30:56171
Victor Costan289f2c8b2021-07-22 06:33:47172TEST_P(SQLDatabaseTest, Execute_InvalidStatement) {
Victor Costan205b96dc2021-07-21 20:27:46173 {
174 sql::test::ScopedErrorExpecter error_expecter;
175 error_expecter.ExpectError(SQLITE_ERROR);
Victor Costan289f2c8b2021-07-22 06:33:47176 EXPECT_FALSE(db_->Execute("CREATE TABLE data("));
Victor Costan205b96dc2021-07-21 20:27:46177 EXPECT_TRUE(error_expecter.SawExpectedErrors());
178 }
Victor Costan49a903a2021-05-07 22:21:00179 EXPECT_EQ(SQLITE_ERROR, db_->GetErrorCode());
brettw@chromium.orge5ffd0e42009-09-11 21:30:56180}
181
Victor Costan289f2c8b2021-07-22 06:33:47182TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_OneLineValid) {
183 ASSERT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data(contents TEXT)"));
184 EXPECT_EQ(SQLITE_OK, db_->GetErrorCode());
185}
186
187TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_OneLineInvalid) {
188 ASSERT_FALSE(db_->ExecuteScriptForTesting("CREATE TABLE data("));
189 EXPECT_EQ(SQLITE_ERROR, db_->GetErrorCode());
190}
191
192TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_ExtraContents) {
193 EXPECT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data1(id)"))
194 << "Minimal statement";
195 EXPECT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data2(id);"))
196 << "Extra semicolon";
197 EXPECT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data3(id) -- Comment"))
198 << "Trailing comment";
199
200 EXPECT_TRUE(db_->ExecuteScriptForTesting(
201 "CREATE TABLE data4(id);CREATE TABLE data5(id)"))
202 << "Extra statement without whitespace";
203 EXPECT_TRUE(db_->ExecuteScriptForTesting(
204 "CREATE TABLE data6(id); CREATE TABLE data7(id)"))
205 << "Extra statement separated by whitespace";
206
207 EXPECT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data8(id);-- Comment"))
208 << "Comment without whitespace";
209 EXPECT_TRUE(
210 db_->ExecuteScriptForTesting("CREATE TABLE data9(id); -- Comment"))
211 << "Comment sepatated by whitespace";
212}
213
214TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_MultipleValidLines) {
215 EXPECT_TRUE(db_->ExecuteScriptForTesting(R"(
216 CREATE TABLE data1(contents TEXT);
217 CREATE TABLE data2(contents TEXT);
218 CREATE TABLE data3(contents TEXT);
219 )"));
220 EXPECT_EQ(SQLITE_OK, db_->GetErrorCode());
221
222 // DoesColumnExist() is implemented directly on top of a SQLite call. The
223 // other schema functions use sql::Statement infrastructure to query the
224 // schema table.
225 EXPECT_TRUE(db_->DoesColumnExist("data1", "contents"));
226 EXPECT_TRUE(db_->DoesColumnExist("data2", "contents"));
227 EXPECT_TRUE(db_->DoesColumnExist("data3", "contents"));
228}
229
230TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_StopsOnCompileError) {
231 EXPECT_FALSE(db_->ExecuteScriptForTesting(R"(
232 CREATE TABLE data1(contents TEXT);
233 CREATE TABLE data1();
234 CREATE TABLE data3(contents TEXT);
235 )"));
236 EXPECT_EQ(SQLITE_ERROR, db_->GetErrorCode());
237
238 EXPECT_TRUE(db_->DoesColumnExist("data1", "contents"));
239 EXPECT_FALSE(db_->DoesColumnExist("data3", "contents"));
240}
241
242TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_StopsOnStepError) {
243 EXPECT_FALSE(db_->ExecuteScriptForTesting(R"(
244 CREATE TABLE data1(contents TEXT UNIQUE);
245 INSERT INTO data1(contents) VALUES('value1');
246 INSERT INTO data1(contents) VALUES('value1');
247 CREATE TABLE data3(contents TEXT);
248 )"));
249 EXPECT_EQ(SQLITE_CONSTRAINT_UNIQUE, db_->GetErrorCode());
250
251 EXPECT_TRUE(db_->DoesColumnExist("data1", "contents"));
252 EXPECT_FALSE(db_->DoesColumnExist("data3", "contents"));
253}
254
Shubham Aggarwal003708982020-10-28 17:57:54255TEST_P(SQLDatabaseTest, CachedStatement) {
Victor Costan49a903a2021-05-07 22:21:00256 StatementID id1 = SQL_FROM_HERE;
257 StatementID id2 = SQL_FROM_HERE;
Victor Costan613b4302018-11-20 05:32:43258 static const char kId1Sql[] = "SELECT a FROM foo";
Victor Costan87cf8c72018-07-19 19:36:04259 static const char kId2Sql[] = "SELECT b FROM foo";
brettw@chromium.orge5ffd0e42009-09-11 21:30:56260
Victor Costan49a903a2021-05-07 22:21:00261 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
262 ASSERT_TRUE(db_->Execute("INSERT INTO foo(a, b) VALUES (12, 13)"));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56263
Victor Costan87cf8c72018-07-19 19:36:04264 sqlite3_stmt* raw_id1_statement;
265 sqlite3_stmt* raw_id2_statement;
brettw@chromium.orge5ffd0e42009-09-11 21:30:56266 {
Victor Costan49a903a2021-05-07 22:21:00267 scoped_refptr<Database::StatementRef> ref_from_id1 =
268 db_->GetCachedStatement(id1, kId1Sql);
Victor Costan87cf8c72018-07-19 19:36:04269 raw_id1_statement = ref_from_id1->stmt();
brettw@chromium.orge5ffd0e42009-09-11 21:30:56270
Victor Costan49a903a2021-05-07 22:21:00271 Statement from_id1(std::move(ref_from_id1));
Victor Costan87cf8c72018-07-19 19:36:04272 ASSERT_TRUE(from_id1.is_valid());
273 ASSERT_TRUE(from_id1.Step());
274 EXPECT_EQ(12, from_id1.ColumnInt(0));
275
Victor Costan49a903a2021-05-07 22:21:00276 scoped_refptr<Database::StatementRef> ref_from_id2 =
277 db_->GetCachedStatement(id2, kId2Sql);
Victor Costan87cf8c72018-07-19 19:36:04278 raw_id2_statement = ref_from_id2->stmt();
279 EXPECT_NE(raw_id1_statement, raw_id2_statement);
280
Victor Costan49a903a2021-05-07 22:21:00281 Statement from_id2(std::move(ref_from_id2));
Victor Costan87cf8c72018-07-19 19:36:04282 ASSERT_TRUE(from_id2.is_valid());
283 ASSERT_TRUE(from_id2.Step());
284 EXPECT_EQ(13, from_id2.ColumnInt(0));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56285 }
286
brettw@chromium.orge5ffd0e42009-09-11 21:30:56287 {
Victor Costan49a903a2021-05-07 22:21:00288 scoped_refptr<Database::StatementRef> ref_from_id1 =
289 db_->GetCachedStatement(id1, kId1Sql);
Victor Costan87cf8c72018-07-19 19:36:04290 EXPECT_EQ(raw_id1_statement, ref_from_id1->stmt())
291 << "statement was not cached";
brettw@chromium.orge5ffd0e42009-09-11 21:30:56292
Victor Costan49a903a2021-05-07 22:21:00293 Statement from_id1(std::move(ref_from_id1));
Victor Costan87cf8c72018-07-19 19:36:04294 ASSERT_TRUE(from_id1.is_valid());
295 ASSERT_TRUE(from_id1.Step()) << "cached statement was not reset";
296 EXPECT_EQ(12, from_id1.ColumnInt(0));
297
Victor Costan49a903a2021-05-07 22:21:00298 scoped_refptr<Database::StatementRef> ref_from_id2 =
299 db_->GetCachedStatement(id2, kId2Sql);
Victor Costan87cf8c72018-07-19 19:36:04300 EXPECT_EQ(raw_id2_statement, ref_from_id2->stmt())
301 << "statement was not cached";
302
Victor Costan49a903a2021-05-07 22:21:00303 Statement from_id2(std::move(ref_from_id2));
Victor Costan87cf8c72018-07-19 19:36:04304 ASSERT_TRUE(from_id2.is_valid());
305 ASSERT_TRUE(from_id2.Step()) << "cached statement was not reset";
306 EXPECT_EQ(13, from_id2.ColumnInt(0));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56307 }
Victor Costan613b4302018-11-20 05:32:43308
Victor Costan49a903a2021-05-07 22:21:00309 EXPECT_DCHECK_DEATH(db_->GetCachedStatement(id1, kId2Sql))
Victor Costan613b4302018-11-20 05:32:43310 << "Using a different SQL with the same statement ID should DCHECK";
Victor Costan49a903a2021-05-07 22:21:00311 EXPECT_DCHECK_DEATH(db_->GetCachedStatement(id2, kId1Sql))
Victor Costan613b4302018-11-20 05:32:43312 << "Using a different SQL with the same statement ID should DCHECK";
brettw@chromium.orge5ffd0e42009-09-11 21:30:56313}
314
Shubham Aggarwal003708982020-10-28 17:57:54315TEST_P(SQLDatabaseTest, IsSQLValidTest) {
Victor Costan49a903a2021-05-07 22:21:00316 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
317 ASSERT_TRUE(db_->IsSQLValid("SELECT a FROM foo"));
318 ASSERT_FALSE(db_->IsSQLValid("SELECT no_exist FROM foo"));
shess@chromium.orgeff1fa522011-12-12 23:50:59319}
320
Shubham Aggarwal003708982020-10-28 17:57:54321TEST_P(SQLDatabaseTest, DoesTableExist) {
Victor Costan49a903a2021-05-07 22:21:00322 EXPECT_FALSE(db_->DoesTableExist("foo"));
323 EXPECT_FALSE(db_->DoesTableExist("foo_index"));
shessa62504d2016-11-07 19:26:12324
Victor Costan49a903a2021-05-07 22:21:00325 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
326 ASSERT_TRUE(db_->Execute("CREATE INDEX foo_index ON foo (a)"));
327 EXPECT_TRUE(db_->DoesTableExist("foo"));
328 EXPECT_FALSE(db_->DoesTableExist("foo_index"));
Victor Costanf85512e52019-04-10 20:51:36329
330 // DoesTableExist() is case-sensitive.
Victor Costan49a903a2021-05-07 22:21:00331 EXPECT_FALSE(db_->DoesTableExist("Foo"));
332 EXPECT_FALSE(db_->DoesTableExist("FOO"));
Victor Costan70bedf22018-07-18 21:21:14333}
334
Shubham Aggarwal003708982020-10-28 17:57:54335TEST_P(SQLDatabaseTest, DoesIndexExist) {
Victor Costan49a903a2021-05-07 22:21:00336 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
337 EXPECT_FALSE(db_->DoesIndexExist("foo"));
338 EXPECT_FALSE(db_->DoesIndexExist("foo_ubdex"));
Victor Costan70bedf22018-07-18 21:21:14339
Victor Costan49a903a2021-05-07 22:21:00340 ASSERT_TRUE(db_->Execute("CREATE INDEX foo_index ON foo (a)"));
341 EXPECT_TRUE(db_->DoesIndexExist("foo_index"));
342 EXPECT_FALSE(db_->DoesIndexExist("foo"));
Victor Costanf85512e52019-04-10 20:51:36343
344 // DoesIndexExist() is case-sensitive.
Victor Costan49a903a2021-05-07 22:21:00345 EXPECT_FALSE(db_->DoesIndexExist("Foo_index"));
346 EXPECT_FALSE(db_->DoesIndexExist("Foo_Index"));
347 EXPECT_FALSE(db_->DoesIndexExist("FOO_INDEX"));
Victor Costan70bedf22018-07-18 21:21:14348}
349
Shubham Aggarwal003708982020-10-28 17:57:54350TEST_P(SQLDatabaseTest, DoesViewExist) {
Victor Costan49a903a2021-05-07 22:21:00351 EXPECT_FALSE(db_->DoesViewExist("voo"));
352 ASSERT_TRUE(db_->Execute("CREATE VIEW voo (a) AS SELECT 1"));
353 EXPECT_FALSE(db_->DoesIndexExist("voo"));
354 EXPECT_FALSE(db_->DoesTableExist("voo"));
355 EXPECT_TRUE(db_->DoesViewExist("voo"));
Victor Costanf85512e52019-04-10 20:51:36356
357 // DoesTableExist() is case-sensitive.
Victor Costan49a903a2021-05-07 22:21:00358 EXPECT_FALSE(db_->DoesViewExist("Voo"));
359 EXPECT_FALSE(db_->DoesViewExist("VOO"));
Victor Costan70bedf22018-07-18 21:21:14360}
brettw@chromium.orge5ffd0e42009-09-11 21:30:56361
Shubham Aggarwal003708982020-10-28 17:57:54362TEST_P(SQLDatabaseTest, DoesColumnExist) {
Victor Costan49a903a2021-05-07 22:21:00363 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
Victor Costan70bedf22018-07-18 21:21:14364
Victor Costan49a903a2021-05-07 22:21:00365 EXPECT_FALSE(db_->DoesColumnExist("foo", "bar"));
366 EXPECT_TRUE(db_->DoesColumnExist("foo", "a"));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56367
Victor Costan49a903a2021-05-07 22:21:00368 ASSERT_FALSE(db_->DoesTableExist("bar"));
369 EXPECT_FALSE(db_->DoesColumnExist("bar", "b"));
shess92a2ab12015-04-09 01:59:47370
Victor Costanf85512e52019-04-10 20:51:36371 // SQLite resolves table/column names without case sensitivity.
Victor Costan49a903a2021-05-07 22:21:00372 EXPECT_TRUE(db_->DoesColumnExist("FOO", "A"));
373 EXPECT_TRUE(db_->DoesColumnExist("FOO", "a"));
374 EXPECT_TRUE(db_->DoesColumnExist("foo", "A"));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56375}
376
Shubham Aggarwal003708982020-10-28 17:57:54377TEST_P(SQLDatabaseTest, GetLastInsertRowId) {
Victor Costan49a903a2021-05-07 22:21:00378 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56379
Victor Costan49a903a2021-05-07 22:21:00380 ASSERT_TRUE(db_->Execute("INSERT INTO foo (value) VALUES (12)"));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56381
382 // Last insert row ID should be valid.
Victor Costan49a903a2021-05-07 22:21:00383 int64_t row = db_->GetLastInsertRowId();
brettw@chromium.orge5ffd0e42009-09-11 21:30:56384 EXPECT_LT(0, row);
385
386 // It should be the primary key of the row we just inserted.
Victor Costan49a903a2021-05-07 22:21:00387 Statement s(db_->GetUniqueStatement("SELECT value FROM foo WHERE id=?"));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56388 s.BindInt64(0, row);
389 ASSERT_TRUE(s.Step());
390 EXPECT_EQ(12, s.ColumnInt(0));
391}
michaelbai@chromium.org44ad7d902012-03-23 00:09:05392
shess976814402016-06-21 06:56:25393// Test the scoped error expecter by attempting to insert a duplicate
shess@chromium.org4350e322013-06-18 22:18:10394// value into an index.
Shubham Aggarwal003708982020-10-28 17:57:54395TEST_P(SQLDatabaseTest, ScopedErrorExpecter) {
shess@chromium.org4350e322013-06-18 22:18:10396 const char* kCreateSql = "CREATE TABLE foo (id INTEGER UNIQUE)";
Victor Costan49a903a2021-05-07 22:21:00397 ASSERT_TRUE(db_->Execute(kCreateSql));
398 ASSERT_TRUE(db_->Execute("INSERT INTO foo (id) VALUES (12)"));
shess@chromium.org4350e322013-06-18 22:18:10399
shess92a2ab12015-04-09 01:59:47400 {
shess976814402016-06-21 06:56:25401 sql::test::ScopedErrorExpecter expecter;
402 expecter.ExpectError(SQLITE_CONSTRAINT);
Victor Costan49a903a2021-05-07 22:21:00403 ASSERT_FALSE(db_->Execute("INSERT INTO foo (id) VALUES (12)"));
shess976814402016-06-21 06:56:25404 ASSERT_TRUE(expecter.SawExpectedErrors());
shess92a2ab12015-04-09 01:59:47405 }
406}
407
Victor Costan106e5002021-07-17 00:04:49408TEST_P(SQLDatabaseTest, SchemaIntrospectionUsesErrorExpecter) {
shess92a2ab12015-04-09 01:59:47409 const char* kCreateSql = "CREATE TABLE foo (id INTEGER UNIQUE)";
Victor Costan49a903a2021-05-07 22:21:00410 ASSERT_TRUE(db_->Execute(kCreateSql));
411 ASSERT_FALSE(db_->DoesTableExist("bar"));
412 ASSERT_TRUE(db_->DoesTableExist("foo"));
413 ASSERT_TRUE(db_->DoesColumnExist("foo", "id"));
414 db_->Close();
shess92a2ab12015-04-09 01:59:47415
416 // Corrupt the database so that nothing works, including PRAGMAs.
Victor Costan49a903a2021-05-07 22:21:00417 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
shess92a2ab12015-04-09 01:59:47418
419 {
shess976814402016-06-21 06:56:25420 sql::test::ScopedErrorExpecter expecter;
421 expecter.ExpectError(SQLITE_CORRUPT);
Dan McArdle4feabeb52024-01-03 15:17:13422 ASSERT_FALSE(db_->Open(db_path_));
Victor Costan49a903a2021-05-07 22:21:00423 ASSERT_FALSE(db_->DoesTableExist("bar"));
424 ASSERT_FALSE(db_->DoesTableExist("foo"));
425 ASSERT_FALSE(db_->DoesColumnExist("foo", "id"));
shess976814402016-06-21 06:56:25426 ASSERT_TRUE(expecter.SawExpectedErrors());
shess92a2ab12015-04-09 01:59:47427 }
shess@chromium.org4350e322013-06-18 22:18:10428}
429
Victor Costand09770c2022-03-08 23:14:46430TEST_P(SQLDatabaseTest, SetErrorCallback) {
431 static constexpr char kCreateSql[] =
432 "CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)";
Victor Costan49a903a2021-05-07 22:21:00433 ASSERT_TRUE(db_->Execute(kCreateSql));
Victor Costand09770c2022-03-08 23:14:46434 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
shess@chromium.org98cf3002013-07-12 01:38:56435
Victor Costand09770c2022-03-08 23:14:46436 bool error_callback_called = false;
shess@chromium.org98cf3002013-07-12 01:38:56437 int error = SQLITE_OK;
Victor Costand09770c2022-03-08 23:14:46438 db_->set_error_callback(base::BindLambdaForTesting(
439 [&](int sqlite_error, sql::Statement* statement) {
440 error_callback_called = true;
441 error = sqlite_error;
442 }));
443 EXPECT_FALSE(db_->Execute("INSERT INTO rows(id) VALUES(12)"))
444 << "Inserting a duplicate primary key should have failed";
445 EXPECT_TRUE(error_callback_called)
446 << "Execute() should report errors to the database error callback";
447 EXPECT_EQ(SQLITE_CONSTRAINT_PRIMARYKEY, error)
448 << "Execute() should report errors to the database error callback";
449}
Dominique Fauteux-Chapleau28963652022-03-08 19:27:30450
Victor Costand09770c2022-03-08 23:14:46451TEST_P(SQLDatabaseTest, SetErrorCallbackDchecksOnExistingCallback) {
452 db_->set_error_callback(base::DoNothing());
453 EXPECT_DCHECK_DEATH(db_->set_error_callback(base::DoNothing()))
454 << "set_error_callback() should DCHECK if error callback already exists";
455}
Dominique Fauteux-Chapleau28963652022-03-08 19:27:30456
Victor Costand09770c2022-03-08 23:14:46457TEST_P(SQLDatabaseTest, ResetErrorCallback) {
458 static constexpr char kCreateSql[] =
459 "CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)";
460 ASSERT_TRUE(db_->Execute(kCreateSql));
461 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
462
463 bool error_callback_called = false;
464 int error = SQLITE_OK;
465 db_->set_error_callback(
466 base::BindLambdaForTesting([&](int sqlite_error, Statement* statement) {
467 error_callback_called = true;
468 error = sqlite_error;
469 }));
470 db_->reset_error_callback();
471
Dominique Fauteux-Chapleau28963652022-03-08 19:27:30472 {
shess976814402016-06-21 06:56:25473 sql::test::ScopedErrorExpecter expecter;
474 expecter.ExpectError(SQLITE_CONSTRAINT);
Victor Costand09770c2022-03-08 23:14:46475 EXPECT_FALSE(db_->Execute("INSERT INTO rows(id) VALUES(12)"))
476 << "Inserting a duplicate primary key should have failed";
477 EXPECT_TRUE(expecter.SawExpectedErrors())
478 << "Inserting a duplicate primary key should have failed";
479 }
480 EXPECT_FALSE(error_callback_called)
481 << "Execute() should not report errors after reset_error_callback()";
482 EXPECT_EQ(SQLITE_OK, error)
483 << "Execute() should not report errors after reset_error_callback()";
484}
485
Dan McArdle643e8742024-01-31 18:52:43486// Regression test for https://crbug.com/1522873
487TEST_P(SQLDatabaseTest, ErrorCallbackThatClosesDb) {
488 for (const bool reopen_db : {false, true}) {
489 SCOPED_TRACE(::testing::Message() << "reopen_db: " << reopen_db);
490 // Ensure that `db_` is fresh in this iteration.
491 CreateFreshDB();
492 static constexpr char kCreateSql[] =
493 "CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)";
494 ASSERT_TRUE(db_->Execute(kCreateSql));
495 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
496
497 bool error_callback_called = false;
498 int error = SQLITE_OK;
499 db_->set_error_callback(
500 base::BindLambdaForTesting([&](int sqlite_error, Statement* statement) {
501 error_callback_called = true;
502 error = sqlite_error;
503 db_->Close();
504 if (reopen_db) {
505 ASSERT_TRUE(db_->Open(db_path_));
506 }
507 }));
508
509 {
510 sql::test::ScopedErrorExpecter expecter;
511 expecter.ExpectError(SQLITE_CONSTRAINT);
512 EXPECT_FALSE(db_->Execute("INSERT INTO rows(id) VALUES(12)"))
513 << "Inserting a duplicate primary key should have failed";
514 EXPECT_TRUE(expecter.SawExpectedErrors())
515 << "Inserting a duplicate primary key should have failed";
516 }
517 EXPECT_TRUE(error_callback_called);
518 EXPECT_EQ(SQLITE_CONSTRAINT_PRIMARYKEY, error);
519 EXPECT_EQ(db_->is_open(), reopen_db);
520 }
521}
522
523// Regression test for https://crbug.com/1522873
524TEST_P(SQLDatabaseTest, ErrorCallbackThatFreesDatabase) {
525 static constexpr char kCreateSql[] =
526 "CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)";
527 ASSERT_TRUE(db_->Execute(kCreateSql));
528 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
529
530 bool error_callback_called = false;
531 int error = SQLITE_OK;
532 db_->set_error_callback(
533 base::BindLambdaForTesting([&](int sqlite_error, Statement* statement) {
534 error_callback_called = true;
535 error = sqlite_error;
536 db_.reset();
537 }));
538
539 {
540 sql::test::ScopedErrorExpecter expecter;
541 expecter.ExpectError(SQLITE_CONSTRAINT);
542 EXPECT_FALSE(db_->Execute("INSERT INTO rows(id) VALUES(12)"))
543 << "Inserting a duplicate primary key should have failed";
544 EXPECT_TRUE(expecter.SawExpectedErrors())
545 << "Inserting a duplicate primary key should have failed";
546 }
547 EXPECT_TRUE(error_callback_called);
548 EXPECT_EQ(SQLITE_CONSTRAINT_PRIMARYKEY, error);
549}
550
Victor Costand09770c2022-03-08 23:14:46551// Sets a flag to true/false to track being alive.
552class LifeTracker {
553 public:
554 explicit LifeTracker(bool* flag_ptr) : flag_ptr_(flag_ptr) {
555 DCHECK(flag_ptr != nullptr);
556 DCHECK(!*flag_ptr)
557 << "LifeTracker's flag should be set to false prior to construction";
558 *flag_ptr_ = true;
shess@chromium.org98cf3002013-07-12 01:38:56559 }
560
Victor Costand09770c2022-03-08 23:14:46561 LifeTracker(LifeTracker&& rhs) {
562 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
563 DCHECK_CALLED_ON_VALID_SEQUENCE(rhs.sequence_checker_);
564 flag_ptr_ = rhs.flag_ptr_;
565 rhs.flag_ptr_ = nullptr;
shess@chromium.org98cf3002013-07-12 01:38:56566 }
567
Victor Costand09770c2022-03-08 23:14:46568 // base::RepeatingCallback only requires move-construction support.
569 LifeTracker& operator=(const LifeTracker& rhs) = delete;
shess@chromium.org98cf3002013-07-12 01:38:56570
Victor Costand09770c2022-03-08 23:14:46571 ~LifeTracker() {
572 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
573 if (flag_ptr_)
574 *flag_ptr_ = false;
shess@chromium.org98cf3002013-07-12 01:38:56575 }
Victor Costand09770c2022-03-08 23:14:46576
577 private:
578 SEQUENCE_CHECKER(sequence_checker_);
579 raw_ptr<bool> flag_ptr_ GUARDED_BY_CONTEXT(sequence_checker_);
580};
581
582// base::BindRepeating() can curry arguments to be passed by const reference to
583// the callback function. If the error callback function calls
584// reset_error_callback() and the Database doesn't hang onto the callback while
585// running it, the storage for those arguments may be deleted while the callback
586// function is executing. This test ensures that the database is hanging onto
587// the callback while running it.
588TEST_P(SQLDatabaseTest, ErrorCallbackStorageProtectedWhileRun) {
589 bool is_alive = false;
590 db_->set_error_callback(base::BindRepeating(
591 [](Database* db, bool* life_tracker_is_alive,
592 const LifeTracker& life_tracker, int sqlite_error,
593 Statement* statement) {
594 EXPECT_TRUE(*life_tracker_is_alive)
595 << "The error callback storage should be alive when it is Run()";
596 db->reset_error_callback();
597 EXPECT_TRUE(*life_tracker_is_alive)
598 << "The error storage should remain alive during Run() after "
599 << "reset_error_callback()";
600 },
601 base::Unretained(db_.get()), base::Unretained(&is_alive),
602 LifeTracker(&is_alive)));
603
604 EXPECT_TRUE(is_alive)
605 << "The error callback storage should be alive after creation";
606 EXPECT_FALSE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
607 EXPECT_FALSE(is_alive)
608 << "The error callback storage should be released after Run() completes";
shess@chromium.org98cf3002013-07-12 01:38:56609}
610
Victor Costanc02b7af2021-07-09 13:26:45611TEST_P(SQLDatabaseTest, Execute_CompilationError) {
612 bool error_callback_called = false;
613 db_->set_error_callback(base::BindLambdaForTesting([&](int error,
614 sql::Statement*
615 statement) {
616 EXPECT_EQ(SQLITE_ERROR, error);
617 EXPECT_EQ(nullptr, statement);
618 EXPECT_FALSE(error_callback_called)
619 << "SQL compilation errors should call the error callback exactly once";
620 error_callback_called = true;
621 }));
622
623 {
624 sql::test::ScopedErrorExpecter expecter;
625 expecter.ExpectError(SQLITE_ERROR);
626 EXPECT_FALSE(db_->Execute("SELECT missing_column FROM missing_table"));
627 EXPECT_TRUE(expecter.SawExpectedErrors());
628 }
629
630 EXPECT_TRUE(error_callback_called)
631 << "SQL compilation errors should call the error callback";
632}
633
634TEST_P(SQLDatabaseTest, GetUniqueStatement_CompilationError) {
635 bool error_callback_called = false;
636 db_->set_error_callback(base::BindLambdaForTesting([&](int error,
637 sql::Statement*
638 statement) {
639 EXPECT_EQ(SQLITE_ERROR, error);
640 EXPECT_EQ(nullptr, statement);
641 EXPECT_FALSE(error_callback_called)
642 << "SQL compilation errors should call the error callback exactly once";
643 error_callback_called = true;
644 }));
645
646 {
647 sql::test::ScopedErrorExpecter expecter;
648 expecter.ExpectError(SQLITE_ERROR);
649 sql::Statement statement(
650 db_->GetUniqueStatement("SELECT missing_column FROM missing_table"));
651 EXPECT_FALSE(statement.is_valid());
652 EXPECT_TRUE(expecter.SawExpectedErrors());
653 }
654
655 EXPECT_TRUE(error_callback_called)
656 << "SQL compilation errors should call the error callback";
657}
658
659TEST_P(SQLDatabaseTest, GetCachedStatement_CompilationError) {
660 bool error_callback_called = false;
661 db_->set_error_callback(base::BindLambdaForTesting([&](int error,
662 sql::Statement*
663 statement) {
664 EXPECT_EQ(SQLITE_ERROR, error);
665 EXPECT_EQ(nullptr, statement);
666 EXPECT_FALSE(error_callback_called)
667 << "SQL compilation errors should call the error callback exactly once";
668 error_callback_called = true;
669 }));
670
671 {
672 sql::test::ScopedErrorExpecter expecter;
673 expecter.ExpectError(SQLITE_ERROR);
674 sql::Statement statement(db_->GetCachedStatement(
675 SQL_FROM_HERE, "SELECT missing_column FROM missing_table"));
676 EXPECT_FALSE(statement.is_valid());
677 EXPECT_TRUE(expecter.SawExpectedErrors());
678 }
679
680 EXPECT_TRUE(error_callback_called)
681 << "SQL compilation errors should call the error callback";
682}
683
Victor Costan55309322021-07-19 17:58:42684TEST_P(SQLDatabaseTest, GetUniqueStatement_ExtraContents) {
685 sql::Statement minimal(db_->GetUniqueStatement("SELECT 1"));
686 sql::Statement extra_semicolon(db_->GetUniqueStatement("SELECT 1;"));
687
688 // It would be nice to flag trailing comments too, as they cost binary size.
689 // However, there's no easy way of doing that.
690 sql::Statement trailing_comment(
691 db_->GetUniqueStatement("SELECT 1 -- Comment"));
692
693 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("SELECT 1;SELECT 2"))
694 << "Extra statement without whitespace";
695 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("SELECT 1; SELECT 2"))
696 << "Extra statement separated by whitespace";
697 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("SELECT 1;-- Comment"))
698 << "Comment without whitespace";
699 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("SELECT 1; -- Comment"))
700 << "Comment separated by whitespace";
701}
702
703TEST_P(SQLDatabaseTest, GetCachedStatement_ExtraContents) {
704 sql::Statement minimal(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
705 sql::Statement extra_semicolon(
706 db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1;"));
707
708 // It would be nice to flag trailing comments too, as they cost binary size.
709 // However, there's no easy way of doing that.
710 sql::Statement trailing_comment(
711 db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1 -- Comment"));
712
713 EXPECT_DCHECK_DEATH(
714 db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1;SELECT 2"))
715 << "Extra statement without whitespace";
716 EXPECT_DCHECK_DEATH(
717 db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1; SELECT 2"))
718 << "Extra statement separated by whitespace";
719 EXPECT_DCHECK_DEATH(
720 db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1;-- Comment"))
721 << "Comment without whitespace";
722 EXPECT_DCHECK_DEATH(
723 db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1; -- Comment"))
724 << "Comment separated by whitespace";
725}
726
727TEST_P(SQLDatabaseTest, IsSQLValid_ExtraContents) {
728 EXPECT_TRUE(db_->IsSQLValid("SELECT 1"));
729 EXPECT_TRUE(db_->IsSQLValid("SELECT 1;"))
730 << "Trailing semicolons are currently tolerated";
731
732 // It would be nice to flag trailing comments too, as they cost binary size.
733 // However, there's no easy way of doing that.
734 EXPECT_TRUE(db_->IsSQLValid("SELECT 1 -- Comment"))
735 << "Trailing comments are currently tolerated";
736
737 EXPECT_DCHECK_DEATH(db_->IsSQLValid("SELECT 1;SELECT 2"))
738 << "Extra statement without whitespace";
739 EXPECT_DCHECK_DEATH(db_->IsSQLValid("SELECT 1; SELECT 2"))
740 << "Extra statement separated by whitespace";
741 EXPECT_DCHECK_DEATH(db_->IsSQLValid("SELECT 1;-- Comment"))
742 << "Comment without whitespace";
743 EXPECT_DCHECK_DEATH(db_->IsSQLValid("SELECT 1; -- Comment"))
744 << "Comment separated by whitespace";
745}
746
Victor Costan18f9e7a2021-07-22 06:34:17747TEST_P(SQLDatabaseTest, GetUniqueStatement_NoContents) {
748 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("")) << "Empty string";
749 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement(" ")) << "Space";
750 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("\n")) << "Newline";
751 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("-- Comment")) << "Comment";
752}
753
754TEST_P(SQLDatabaseTest, GetCachedStatement_NoContents) {
755 EXPECT_DCHECK_DEATH(db_->GetCachedStatement(SQL_FROM_HERE, ""))
756 << "Empty string";
757 EXPECT_DCHECK_DEATH(db_->GetCachedStatement(SQL_FROM_HERE, " ")) << "Space";
758 EXPECT_DCHECK_DEATH(db_->GetCachedStatement(SQL_FROM_HERE, "\n"))
759 << "Newline";
760 EXPECT_DCHECK_DEATH(db_->GetCachedStatement(SQL_FROM_HERE, "-- Comment"))
761 << "Comment";
762}
763
ssid583f55e2022-04-21 19:59:00764TEST_P(SQLDatabaseTest, GetReadonlyStatement) {
765 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
766 ASSERT_TRUE(db_->Execute(kCreateSql));
767 ASSERT_TRUE(db_->Execute("INSERT INTO foo (value) VALUES (12)"));
768
769 // PRAGMA statements do not change the database file.
770 {
771 Statement s(db_->GetReadonlyStatement("PRAGMA analysis_limit"));
772 ASSERT_TRUE(s.Step());
773 }
774 {
775 Statement s(db_->GetReadonlyStatement("PRAGMA analysis_limit=100"));
776 ASSERT_TRUE(s.is_valid());
777 }
778
779 // Create and insert statements should fail, while the same queries as unique
780 // statement succeeds.
781 {
782 Statement s(db_->GetReadonlyStatement(
783 "CREATE TABLE IF NOT EXISTS foo (id INTEGER PRIMARY KEY, value)"));
784 ASSERT_FALSE(s.is_valid());
785 Statement s1(db_->GetUniqueStatement(
786 "CREATE TABLE IF NOT EXISTS foo (id INTEGER PRIMARY KEY, value)"));
787 ASSERT_TRUE(s1.is_valid());
788 }
789 {
790 Statement s(
791 db_->GetReadonlyStatement("INSERT INTO foo (value) VALUES (12)"));
792 ASSERT_FALSE(s.is_valid());
793 Statement s1(
794 db_->GetUniqueStatement("INSERT INTO foo (value) VALUES (12)"));
795 ASSERT_TRUE(s1.is_valid());
796 }
797 {
798 Statement s(
799 db_->GetReadonlyStatement("CREATE VIRTUAL TABLE bar USING module"));
800 ASSERT_FALSE(s.is_valid());
801 Statement s1(
802 db_->GetUniqueStatement("CREATE VIRTUAL TABLE bar USING module"));
803 ASSERT_TRUE(s1.is_valid());
804 }
805
806 // Select statement is successful.
807 {
808 Statement s(db_->GetReadonlyStatement("SELECT * FROM foo"));
809 ASSERT_TRUE(s.Step());
810 EXPECT_EQ(s.ColumnInt(1), 12);
811 }
812}
813
Victor Costan18f9e7a2021-07-22 06:34:17814TEST_P(SQLDatabaseTest, IsSQLValid_NoContents) {
815 EXPECT_DCHECK_DEATH(db_->IsSQLValid("")) << "Empty string";
816 EXPECT_DCHECK_DEATH(db_->IsSQLValid(" ")) << "Space";
817 EXPECT_DCHECK_DEATH(db_->IsSQLValid("\n")) << "Newline";
818 EXPECT_DCHECK_DEATH(db_->IsSQLValid("-- Comment")) << "Comment";
819}
820
Victor Costan49a903a2021-05-07 22:21:00821// Test that Database::Raze() results in a database without the
shess@chromium.org8e0c01282012-04-06 19:36:49822// tables from the original database.
Shubham Aggarwal003708982020-10-28 17:57:54823TEST_P(SQLDatabaseTest, Raze) {
shess@chromium.org8e0c01282012-04-06 19:36:49824 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
Victor Costan49a903a2021-05-07 22:21:00825 ASSERT_TRUE(db_->Execute(kCreateSql));
826 ASSERT_TRUE(db_->Execute("INSERT INTO foo (value) VALUES (12)"));
shess@chromium.org8e0c01282012-04-06 19:36:49827
yfriedman@chromium.org69c58452012-08-06 19:22:42828 int pragma_auto_vacuum = 0;
829 {
Victor Costan49a903a2021-05-07 22:21:00830 Statement s(db_->GetUniqueStatement("PRAGMA auto_vacuum"));
yfriedman@chromium.org69c58452012-08-06 19:22:42831 ASSERT_TRUE(s.Step());
832 pragma_auto_vacuum = s.ColumnInt(0);
833 ASSERT_TRUE(pragma_auto_vacuum == 0 || pragma_auto_vacuum == 1);
834 }
835
836 // If auto_vacuum is set, there's an extra page to maintain a freelist.
837 const int kExpectedPageCount = 2 + pragma_auto_vacuum;
838
shess@chromium.org8e0c01282012-04-06 19:36:49839 {
Victor Costan49a903a2021-05-07 22:21:00840 Statement s(db_->GetUniqueStatement("PRAGMA page_count"));
shess@chromium.org8e0c01282012-04-06 19:36:49841 ASSERT_TRUE(s.Step());
yfriedman@chromium.org69c58452012-08-06 19:22:42842 EXPECT_EQ(kExpectedPageCount, s.ColumnInt(0));
shess@chromium.org8e0c01282012-04-06 19:36:49843 }
844
845 {
John Delaney86dbec62021-08-24 15:05:21846 Statement s(db_->GetUniqueStatement("SELECT * FROM sqlite_schema"));
shess@chromium.org8e0c01282012-04-06 19:36:49847 ASSERT_TRUE(s.Step());
848 EXPECT_EQ("table", s.ColumnString(0));
849 EXPECT_EQ("foo", s.ColumnString(1));
850 EXPECT_EQ("foo", s.ColumnString(2));
yfriedman@chromium.org69c58452012-08-06 19:22:42851 // Table "foo" is stored in the last page of the file.
852 EXPECT_EQ(kExpectedPageCount, s.ColumnInt(3));
shess@chromium.org8e0c01282012-04-06 19:36:49853 EXPECT_EQ(kCreateSql, s.ColumnString(4));
854 }
855
Victor Costan49a903a2021-05-07 22:21:00856 ASSERT_TRUE(db_->Raze());
shess@chromium.org8e0c01282012-04-06 19:36:49857
858 {
Victor Costan49a903a2021-05-07 22:21:00859 Statement s(db_->GetUniqueStatement("PRAGMA page_count"));
shess@chromium.org8e0c01282012-04-06 19:36:49860 ASSERT_TRUE(s.Step());
861 EXPECT_EQ(1, s.ColumnInt(0));
862 }
863
John Delaney86dbec62021-08-24 15:05:21864 ASSERT_EQ(0, SqliteSchemaCount(db_.get()));
yfriedman@chromium.org69c58452012-08-06 19:22:42865
866 {
Victor Costan49a903a2021-05-07 22:21:00867 Statement s(db_->GetUniqueStatement("PRAGMA auto_vacuum"));
yfriedman@chromium.org69c58452012-08-06 19:22:42868 ASSERT_TRUE(s.Step());
shess@chromium.org6d42f152012-11-10 00:38:24869 // The new database has the same auto_vacuum as a fresh database.
yfriedman@chromium.org69c58452012-08-06 19:22:42870 EXPECT_EQ(pragma_auto_vacuum, s.ColumnInt(0));
871 }
shess@chromium.org8e0c01282012-04-06 19:36:49872}
873
Victor Costancdef3842022-03-28 18:51:08874TEST_P(SQLDatabaseTest, RazeDuringSelect) {
875 ASSERT_TRUE(
876 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
877 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(1)"));
878 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(2)"));
879
880 {
881 // SELECT implicitly creates a transaction while it's executing. This
882 // implicit transaction will not be caught by Raze()'s checks.
883 Statement select(db_->GetUniqueStatement("SELECT id FROM rows"));
884 ASSERT_TRUE(select.Step());
885 EXPECT_FALSE(db_->Raze()) << "Raze() should fail while SELECT is executing";
886 }
887
888 {
889 Statement count(db_->GetUniqueStatement("SELECT COUNT(*) FROM rows"));
890 ASSERT_TRUE(count.Step());
891 EXPECT_EQ(2, count.ColumnInt(0)) << "Raze() deleted some data";
892 }
893}
894
Victor Costancfbfa602018-08-01 23:24:46895// Helper for SQLDatabaseTest.RazePageSize. Creates a fresh db based on
shess7e2baba2016-10-27 23:46:05896// db_prefix, with the given initial page size, and verifies it against the
897// expected size. Then changes to the final page size and razes, verifying that
898// the fresh database ends up with the expected final page size.
899void TestPageSize(const base::FilePath& db_prefix,
900 int initial_page_size,
901 const std::string& expected_initial_page_size,
902 int final_page_size,
903 const std::string& expected_final_page_size) {
Victor Costan1d868352018-06-26 19:06:48904 static const char kCreateSql[] = "CREATE TABLE x (t TEXT)";
905 static const char kInsertSql1[] = "INSERT INTO x VALUES ('This is a test')";
906 static const char kInsertSql2[] = "INSERT INTO x VALUES ('That was a test')";
shess7e2baba2016-10-27 23:46:05907
908 const base::FilePath db_path = db_prefix.InsertBeforeExtensionASCII(
Raul Tambre6c708e32019-02-08 22:35:14909 base::NumberToString(initial_page_size));
Victor Costan49a903a2021-05-07 22:21:00910 Database::Delete(db_path);
911 Database db({.page_size = initial_page_size});
shess7e2baba2016-10-27 23:46:05912 ASSERT_TRUE(db.Open(db_path));
913 ASSERT_TRUE(db.Execute(kCreateSql));
914 ASSERT_TRUE(db.Execute(kInsertSql1));
915 ASSERT_TRUE(db.Execute(kInsertSql2));
916 ASSERT_EQ(expected_initial_page_size,
917 ExecuteWithResult(&db, "PRAGMA page_size"));
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28918 db.Close();
shess7e2baba2016-10-27 23:46:05919
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28920 // Re-open the database while setting a new |options.page_size| in the object.
Victor Costan49a903a2021-05-07 22:21:00921 Database razed_db({.page_size = final_page_size});
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28922 ASSERT_TRUE(razed_db.Open(db_path));
shess7e2baba2016-10-27 23:46:05923 // Raze will use the page size set in the connection object, which may not
924 // match the file's page size.
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28925 ASSERT_TRUE(razed_db.Raze());
shess7e2baba2016-10-27 23:46:05926
927 // SQLite 3.10.2 (at least) has a quirk with the sqlite3_backup() API (used by
928 // Raze()) which causes the destination database to remember the previous
929 // page_size, even if the overwriting database changed the page_size. Access
930 // the actual database to cause the cached value to be updated.
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28931 EXPECT_EQ("0",
John Delaney86dbec62021-08-24 15:05:21932 ExecuteWithResult(&razed_db, "SELECT COUNT(*) FROM sqlite_schema"));
shess7e2baba2016-10-27 23:46:05933
934 EXPECT_EQ(expected_final_page_size,
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28935 ExecuteWithResult(&razed_db, "PRAGMA page_size"));
936 EXPECT_EQ("1", ExecuteWithResult(&razed_db, "PRAGMA page_count"));
shess7e2baba2016-10-27 23:46:05937}
938
Victor Costan49a903a2021-05-07 22:21:00939// Verify that Recovery maintains the page size, and the virtual table
shess7e2baba2016-10-27 23:46:05940// works with page sizes other than SQLite's default. Also verify the case
941// where the default page size has changed.
Shubham Aggarwal003708982020-10-28 17:57:54942TEST_P(SQLDatabaseTest, RazePageSize) {
shess7e2baba2016-10-27 23:46:05943 const std::string default_page_size =
Victor Costan49a903a2021-05-07 22:21:00944 ExecuteWithResult(db_.get(), "PRAGMA page_size");
shess@chromium.org8e0c01282012-04-06 19:36:49945
Victor Costan7f6abbbe2018-07-29 02:57:27946 // Sync uses 32k pages.
shess7e2baba2016-10-27 23:46:05947 EXPECT_NO_FATAL_FAILURE(
Victor Costan49a903a2021-05-07 22:21:00948 TestPageSize(db_path_, 32768, "32768", 32768, "32768"));
shess@chromium.org8e0c01282012-04-06 19:36:49949
shess7e2baba2016-10-27 23:46:05950 // Many clients use 4k pages. This is the SQLite default after 3.12.0.
Victor Costan49a903a2021-05-07 22:21:00951 EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 4096, "4096", 4096, "4096"));
shess7e2baba2016-10-27 23:46:05952
953 // 1k is the default page size before 3.12.0.
Victor Costan49a903a2021-05-07 22:21:00954 EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 1024, "1024", 1024, "1024"));
shess7e2baba2016-10-27 23:46:05955
Victor Costan49a903a2021-05-07 22:21:00956 EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 2048, "2048", 4096, "4096"));
shess7e2baba2016-10-27 23:46:05957
Victor Costan7f6abbbe2018-07-29 02:57:27958 // Databases with no page size specified should result in the default
shess7e2baba2016-10-27 23:46:05959 // page size. 2k has never been the default page size.
960 ASSERT_NE("2048", default_page_size);
Victor Costan49a903a2021-05-07 22:21:00961 EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 2048, "2048",
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28962 DatabaseOptions::kDefaultPageSize,
963 default_page_size));
shess@chromium.org8e0c01282012-04-06 19:36:49964}
965
966// Test that Raze() results are seen in other connections.
Shubham Aggarwal003708982020-10-28 17:57:54967TEST_P(SQLDatabaseTest, RazeMultiple) {
shess@chromium.org8e0c01282012-04-06 19:36:49968 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
Victor Costan49a903a2021-05-07 22:21:00969 ASSERT_TRUE(db_->Execute(kCreateSql));
shess@chromium.org8e0c01282012-04-06 19:36:49970
Victor Costan49a903a2021-05-07 22:21:00971 Database other_db(GetDBOptions());
972 ASSERT_TRUE(other_db.Open(db_path_));
shess@chromium.org8e0c01282012-04-06 19:36:49973
974 // Check that the second connection sees the table.
John Delaney86dbec62021-08-24 15:05:21975 ASSERT_EQ(1, SqliteSchemaCount(&other_db));
shess@chromium.org8e0c01282012-04-06 19:36:49976
Victor Costan49a903a2021-05-07 22:21:00977 ASSERT_TRUE(db_->Raze());
shess@chromium.org8e0c01282012-04-06 19:36:49978
979 // The second connection sees the updated database.
John Delaney86dbec62021-08-24 15:05:21980 ASSERT_EQ(0, SqliteSchemaCount(&other_db));
shess@chromium.org8e0c01282012-04-06 19:36:49981}
982
Victor Costane7944b4e2022-03-30 20:06:22983TEST_P(SQLDatabaseTest, Raze_OtherConnectionHasWriteLock) {
984 ASSERT_TRUE(db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY)"));
shess@chromium.org8e0c01282012-04-06 19:36:49985
Victor Costan49a903a2021-05-07 22:21:00986 Database other_db(GetDBOptions());
987 ASSERT_TRUE(other_db.Open(db_path_));
shess@chromium.org8e0c01282012-04-06 19:36:49988
Victor Costane7944b4e2022-03-30 20:06:22989 Transaction other_db_transaction(&other_db);
990 ASSERT_TRUE(other_db_transaction.Begin());
991 ASSERT_TRUE(other_db.Execute("INSERT INTO rows(id) VALUES(1)"));
shess@chromium.org8e0c01282012-04-06 19:36:49992
Victor Costane7944b4e2022-03-30 20:06:22993 EXPECT_FALSE(db_->Raze())
994 << "Raze() should fail while another connection has a write lock";
shess@chromium.org8e0c01282012-04-06 19:36:49995
Victor Costane7944b4e2022-03-30 20:06:22996 ASSERT_TRUE(other_db_transaction.Commit());
997 EXPECT_TRUE(db_->Raze())
998 << "Raze() should succeed after the other connection releases the lock";
shess@chromium.org8e0c01282012-04-06 19:36:49999}
1000
Victor Costane7944b4e2022-03-30 20:06:221001TEST_P(SQLDatabaseTest, Raze_OtherConnectionHasReadLock) {
1002 ASSERT_TRUE(db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY)"));
1003 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(1)"));
1004
1005 if (IsWALEnabled()) {
1006 // In WAL mode, read transactions in other connections do not block a write
1007 // transaction.
1008 return;
1009 }
1010
1011 Database other_db(GetDBOptions());
1012 ASSERT_TRUE(other_db.Open(db_path_));
1013
1014 Statement select(other_db.GetUniqueStatement("SELECT id FROM rows"));
1015 ASSERT_TRUE(select.Step());
1016 EXPECT_FALSE(db_->Raze())
1017 << "Raze() should fail while another connection has a read lock";
1018
1019 ASSERT_FALSE(select.Step())
1020 << "The SELECT statement should not produce more than one row";
1021 EXPECT_TRUE(db_->Raze())
1022 << "Raze() should succeed after the other connection releases the lock";
1023}
1024
1025TEST_P(SQLDatabaseTest, Raze_EmptyDatabaseFile) {
1026 ASSERT_TRUE(
1027 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
Victor Costan49a903a2021-05-07 22:21:001028 db_->Close();
shess@chromium.org7bae5742013-07-10 20:46:161029
Victor Costan49a903a2021-05-07 22:21:001030 ASSERT_TRUE(TruncateDatabase());
Victor Costane7944b4e2022-03-30 20:06:221031 ASSERT_TRUE(db_->Open(db_path_))
1032 << "Failed to reopen database after truncating";
shess@chromium.org7bae5742013-07-10 20:46:161033
Victor Costane7944b4e2022-03-30 20:06:221034 EXPECT_TRUE(db_->Raze()) << "Raze() failed on an empty file";
1035 EXPECT_TRUE(
1036 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
1037 << "Raze() did not produce a healthy empty database";
shess@chromium.org7bae5742013-07-10 20:46:161038}
1039
1040// Verify that Raze() can handle a file of junk.
Shubham Aggarwal7b60fe6e2020-10-15 06:00:281041// Need exclusive mode off here as there are some subtleties (by design) around
1042// how the cache is used with it on which causes the test to fail.
Shubham Aggarwal003708982020-10-28 17:57:541043TEST_P(SQLDatabaseTest, RazeNOTADB) {
Victor Costan49a903a2021-05-07 22:21:001044 db_->Close();
1045 Database::Delete(db_path_);
1046 ASSERT_FALSE(base::PathExists(db_path_));
shess@chromium.org7bae5742013-07-10 20:46:161047
Victor Costan49a903a2021-05-07 22:21:001048 ASSERT_TRUE(OverwriteDatabaseHeader(OverwriteType::kTruncate));
1049 ASSERT_TRUE(base::PathExists(db_path_));
shess@chromium.org7bae5742013-07-10 20:46:161050
Scott Hessdcf120482015-02-10 21:33:291051 // SQLite will successfully open the handle, but fail when running PRAGMA
1052 // statements that access the database.
shess@chromium.org7bae5742013-07-10 20:46:161053 {
shess976814402016-06-21 06:56:251054 sql::test::ScopedErrorExpecter expecter;
Victor Costan42988a92018-02-06 02:22:141055 expecter.ExpectError(SQLITE_NOTADB);
Scott Hessdcf120482015-02-10 21:33:291056
Dan McArdle4feabeb52024-01-03 15:17:131057 EXPECT_FALSE(db_->Open(db_path_));
shess976814402016-06-21 06:56:251058 ASSERT_TRUE(expecter.SawExpectedErrors());
shess@chromium.org7bae5742013-07-10 20:46:161059 }
Victor Costan49a903a2021-05-07 22:21:001060 EXPECT_TRUE(db_->Raze());
1061 db_->Close();
shess@chromium.org7bae5742013-07-10 20:46:161062
1063 // Now empty, the open should open an empty database.
Victor Costan49a903a2021-05-07 22:21:001064 EXPECT_TRUE(db_->Open(db_path_));
John Delaney86dbec62021-08-24 15:05:211065 EXPECT_EQ(0, SqliteSchemaCount(db_.get()));
shess@chromium.org7bae5742013-07-10 20:46:161066}
1067
1068// Verify that Raze() can handle a database overwritten with garbage.
Shubham Aggarwal003708982020-10-28 17:57:541069TEST_P(SQLDatabaseTest, RazeNOTADB2) {
shess@chromium.org7bae5742013-07-10 20:46:161070 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
Victor Costan49a903a2021-05-07 22:21:001071 ASSERT_TRUE(db_->Execute(kCreateSql));
John Delaney86dbec62021-08-24 15:05:211072 ASSERT_EQ(1, SqliteSchemaCount(db_.get()));
Victor Costan49a903a2021-05-07 22:21:001073 db_->Close();
shess@chromium.org7bae5742013-07-10 20:46:161074
Victor Costan49a903a2021-05-07 22:21:001075 ASSERT_TRUE(OverwriteDatabaseHeader(OverwriteType::kOverwrite));
shess@chromium.org7bae5742013-07-10 20:46:161076
1077 // SQLite will successfully open the handle, but will fail with
1078 // SQLITE_NOTADB on pragma statemenets which attempt to read the
1079 // corrupted header.
1080 {
shess976814402016-06-21 06:56:251081 sql::test::ScopedErrorExpecter expecter;
1082 expecter.ExpectError(SQLITE_NOTADB);
Dan McArdle4feabeb52024-01-03 15:17:131083 EXPECT_FALSE(db_->Open(db_path_));
shess976814402016-06-21 06:56:251084 ASSERT_TRUE(expecter.SawExpectedErrors());
shess@chromium.org7bae5742013-07-10 20:46:161085 }
Victor Costan49a903a2021-05-07 22:21:001086 EXPECT_TRUE(db_->Raze());
1087 db_->Close();
shess@chromium.org7bae5742013-07-10 20:46:161088
1089 // Now empty, the open should succeed with an empty database.
Victor Costan49a903a2021-05-07 22:21:001090 EXPECT_TRUE(db_->Open(db_path_));
John Delaney86dbec62021-08-24 15:05:211091 EXPECT_EQ(0, SqliteSchemaCount(db_.get()));
shess@chromium.org7bae5742013-07-10 20:46:161092}
1093
1094// Test that a callback from Open() can raze the database. This is
1095// essential for cases where the Open() can fail entirely, so the
shess@chromium.orgfed734a2013-07-17 04:45:131096// Raze() cannot happen later. Additionally test that when the
1097// callback does this during Open(), the open is retried and succeeds.
Shubham Aggarwal003708982020-10-28 17:57:541098TEST_P(SQLDatabaseTest, RazeCallbackReopen) {
shess@chromium.org7bae5742013-07-10 20:46:161099 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
Victor Costan49a903a2021-05-07 22:21:001100 ASSERT_TRUE(db_->Execute(kCreateSql));
John Delaney86dbec62021-08-24 15:05:211101 ASSERT_EQ(1, SqliteSchemaCount(db_.get()));
Victor Costan49a903a2021-05-07 22:21:001102 db_->Close();
shess@chromium.org7bae5742013-07-10 20:46:161103
kinuko@chromium.orga8848a72013-11-18 04:18:471104 // Corrupt the database so that nothing works, including PRAGMAs.
Victor Costan49a903a2021-05-07 22:21:001105 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
shess@chromium.org7bae5742013-07-10 20:46:161106
shess@chromium.orgfed734a2013-07-17 04:45:131107 // Open() will succeed, even though the PRAGMA calls within will
1108 // fail with SQLITE_CORRUPT, as will this PRAGMA.
1109 {
shess976814402016-06-21 06:56:251110 sql::test::ScopedErrorExpecter expecter;
1111 expecter.ExpectError(SQLITE_CORRUPT);
Dan McArdle4feabeb52024-01-03 15:17:131112 ASSERT_FALSE(db_->Open(db_path_));
Victor Costan49a903a2021-05-07 22:21:001113 ASSERT_FALSE(db_->Execute("PRAGMA auto_vacuum"));
1114 db_->Close();
shess976814402016-06-21 06:56:251115 ASSERT_TRUE(expecter.SawExpectedErrors());
shess@chromium.orgfed734a2013-07-17 04:45:131116 }
1117
Victor Costan49a903a2021-05-07 22:21:001118 db_->set_error_callback(
1119 base::BindRepeating(&RazeErrorCallback, db_.get(), SQLITE_CORRUPT));
shess@chromium.org7bae5742013-07-10 20:46:161120
shess@chromium.orgfed734a2013-07-17 04:45:131121 // When the PRAGMA calls in Open() raise SQLITE_CORRUPT, the error
Andrew Paseltinerd309fec2023-03-28 16:59:551122 // callback will call RazeAndPoison(). Open() will then fail and be
shess@chromium.orgfed734a2013-07-17 04:45:131123 // retried. The second Open() on the empty database will succeed
1124 // cleanly.
Victor Costan49a903a2021-05-07 22:21:001125 ASSERT_TRUE(db_->Open(db_path_));
1126 ASSERT_TRUE(db_->Execute("PRAGMA auto_vacuum"));
John Delaney86dbec62021-08-24 15:05:211127 EXPECT_EQ(0, SqliteSchemaCount(db_.get()));
shess@chromium.org7bae5742013-07-10 20:46:161128}
1129
Andrew Paseltinerd309fec2023-03-28 16:59:551130TEST_P(SQLDatabaseTest, RazeAndPoison_DeletesData) {
Victor Costane7944b4e2022-03-30 20:06:221131 ASSERT_TRUE(
1132 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1133 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
Andrew Paseltinerd309fec2023-03-28 16:59:551134 ASSERT_TRUE(db_->RazeAndPoison());
shess@chromium.org41a97c812013-02-07 02:35:381135
Andrew Paseltinerd309fec2023-03-28 16:59:551136 // We need to call Close() in order to re-Open().
Victor Costan49a903a2021-05-07 22:21:001137 db_->Close();
Victor Costane7944b4e2022-03-30 20:06:221138 ASSERT_TRUE(db_->Open(db_path_))
Andrew Paseltinerd309fec2023-03-28 16:59:551139 << "RazeAndPoison() did not produce a healthy database";
Victor Costane7944b4e2022-03-30 20:06:221140 EXPECT_TRUE(
1141 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
Andrew Paseltinerd309fec2023-03-28 16:59:551142 << "RazeAndPoison() did not produce a healthy empty database";
shess@chromium.org41a97c812013-02-07 02:35:381143}
1144
Andrew Paseltinerd309fec2023-03-28 16:59:551145TEST_P(SQLDatabaseTest, RazeAndPoison_IsOpen) {
Victor Costane7944b4e2022-03-30 20:06:221146 ASSERT_TRUE(
1147 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1148 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
Andrew Paseltinerd309fec2023-03-28 16:59:551149 ASSERT_TRUE(db_->RazeAndPoison());
shess@chromium.org41a97c812013-02-07 02:35:381150
Victor Costane7944b4e2022-03-30 20:06:221151 EXPECT_FALSE(db_->is_open())
Andrew Paseltinerd309fec2023-03-28 16:59:551152 << "RazeAndPoison() did not mark the database as closed";
shess@chromium.org41a97c812013-02-07 02:35:381153}
1154
Andrew Paseltinerd309fec2023-03-28 16:59:551155TEST_P(SQLDatabaseTest, RazeAndPoison_Reopen_NoChanges) {
1156 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:221157 EXPECT_FALSE(
1158 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
Andrew Paseltinerd309fec2023-03-28 16:59:551159 << "Execute() should return false after RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:221160
Andrew Paseltinerd309fec2023-03-28 16:59:551161 // We need to call Close() in order to re-Open().
Victor Costane7944b4e2022-03-30 20:06:221162 db_->Close();
1163 ASSERT_TRUE(db_->Open(db_path_))
Andrew Paseltinerd309fec2023-03-28 16:59:551164 << "RazeAndPoison() did not produce a healthy database";
Victor Costane7944b4e2022-03-30 20:06:221165 EXPECT_TRUE(
1166 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
Andrew Paseltinerd309fec2023-03-28 16:59:551167 << "Execute() returned false but went through after RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:221168}
1169
Andrew Paseltinerd309fec2023-03-28 16:59:551170TEST_P(SQLDatabaseTest, RazeAndPoison_OpenTransaction) {
Victor Costane7944b4e2022-03-30 20:06:221171 ASSERT_TRUE(
1172 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1173 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
1174
1175 Transaction transaction(db_.get());
1176 ASSERT_TRUE(transaction.Begin());
Andrew Paseltinerd309fec2023-03-28 16:59:551177 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:221178
1179 EXPECT_FALSE(db_->is_open())
Andrew Paseltinerd309fec2023-03-28 16:59:551180 << "RazeAndPoison() did not mark the database as closed";
Victor Costane7944b4e2022-03-30 20:06:221181 EXPECT_FALSE(transaction.Commit())
Andrew Paseltinerd309fec2023-03-28 16:59:551182 << "RazeAndPoison() did not cancel the transaction";
Victor Costane7944b4e2022-03-30 20:06:221183
Andrew Paseltinerd309fec2023-03-28 16:59:551184 // We need to call Close() in order to re-Open().
Victor Costane7944b4e2022-03-30 20:06:221185 db_->Close();
1186
1187 ASSERT_TRUE(db_->Open(db_path_));
1188 EXPECT_TRUE(
1189 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
Andrew Paseltinerd309fec2023-03-28 16:59:551190 << "RazeAndPoison() did not produce a healthy empty database";
Victor Costane7944b4e2022-03-30 20:06:221191}
1192
Andrew Paseltinerd309fec2023-03-28 16:59:551193TEST_P(SQLDatabaseTest, RazeAndPoison_Preload_NoCrash) {
Victor Costane7944b4e2022-03-30 20:06:221194 db_->Preload();
Andrew Paseltinerd309fec2023-03-28 16:59:551195 db_->RazeAndPoison();
Victor Costane7944b4e2022-03-30 20:06:221196 db_->Preload();
1197}
1198
Andrew Paseltinerd309fec2023-03-28 16:59:551199TEST_P(SQLDatabaseTest, RazeAndPoison_DoesTableExist) {
Victor Costane7944b4e2022-03-30 20:06:221200 ASSERT_TRUE(
1201 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1202 ASSERT_TRUE(db_->DoesTableExist("rows")) << "Incorrect test setup";
1203
Andrew Paseltinerd309fec2023-03-28 16:59:551204 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:221205 EXPECT_FALSE(db_->DoesTableExist("rows"))
Andrew Paseltinerd309fec2023-03-28 16:59:551206 << "DoesTableExist() should return false after RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:221207}
1208
Andrew Paseltinerd309fec2023-03-28 16:59:551209TEST_P(SQLDatabaseTest, RazeAndPoison_IsSQLValid) {
Victor Costane7944b4e2022-03-30 20:06:221210 ASSERT_TRUE(db_->IsSQLValid("SELECT 1")) << "Incorrect test setup";
1211
Andrew Paseltinerd309fec2023-03-28 16:59:551212 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:221213 EXPECT_FALSE(db_->IsSQLValid("SELECT 1"))
Andrew Paseltinerd309fec2023-03-28 16:59:551214 << "IsSQLValid() should return false after RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:221215}
1216
Andrew Paseltinerd309fec2023-03-28 16:59:551217TEST_P(SQLDatabaseTest, RazeAndPoison_Execute) {
Victor Costane7944b4e2022-03-30 20:06:221218 ASSERT_TRUE(db_->Execute("SELECT 1")) << "Incorrect test setup";
1219
Andrew Paseltinerd309fec2023-03-28 16:59:551220 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:221221 EXPECT_FALSE(db_->Execute("SELECT 1"))
Andrew Paseltinerd309fec2023-03-28 16:59:551222 << "Execute() should return false after RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:221223}
1224
Andrew Paseltinerd309fec2023-03-28 16:59:551225TEST_P(SQLDatabaseTest, RazeAndPoison_GetUniqueStatement) {
Victor Costane7944b4e2022-03-30 20:06:221226 {
1227 Statement select(db_->GetUniqueStatement("SELECT 1"));
1228 ASSERT_TRUE(select.Step()) << "Incorrect test setup";
1229 }
1230
Andrew Paseltinerd309fec2023-03-28 16:59:551231 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:221232 {
1233 Statement select(db_->GetUniqueStatement("SELECT 1"));
1234 EXPECT_FALSE(select.Step())
1235 << "GetUniqueStatement() should return an invalid Statement after "
Andrew Paseltinerd309fec2023-03-28 16:59:551236 << "RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:221237 }
1238}
1239
Andrew Paseltinerd309fec2023-03-28 16:59:551240TEST_P(SQLDatabaseTest, RazeAndPoison_GetCachedStatement) {
Victor Costane7944b4e2022-03-30 20:06:221241 {
1242 Statement select(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
1243 ASSERT_TRUE(select.Step()) << "Incorrect test setup";
1244 }
1245
Andrew Paseltinerd309fec2023-03-28 16:59:551246 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:221247 {
1248 Statement select(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
1249 EXPECT_FALSE(select.Step())
1250 << "GetCachedStatement() should return an invalid Statement after "
Andrew Paseltinerd309fec2023-03-28 16:59:551251 << "RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:221252 }
1253}
1254
Andrew Paseltinerd309fec2023-03-28 16:59:551255TEST_P(SQLDatabaseTest, RazeAndPoison_InvalidatesUniqueStatement) {
Victor Costane7944b4e2022-03-30 20:06:221256 Statement select(db_->GetUniqueStatement("SELECT 1"));
1257 ASSERT_TRUE(select.is_valid()) << "Incorrect test setup";
1258 ASSERT_TRUE(select.Step()) << "Incorrect test setup";
1259 select.Reset(/*clear_bound_vars=*/true);
1260
Andrew Paseltinerd309fec2023-03-28 16:59:551261 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:221262 EXPECT_FALSE(select.is_valid())
Andrew Paseltinerd309fec2023-03-28 16:59:551263 << "RazeAndPoison() should invalidate live Statements";
Victor Costane7944b4e2022-03-30 20:06:221264 EXPECT_FALSE(select.Step())
Andrew Paseltinerd309fec2023-03-28 16:59:551265 << "RazeAndPoison() should invalidate live Statements";
Victor Costane7944b4e2022-03-30 20:06:221266}
1267
Andrew Paseltinerd309fec2023-03-28 16:59:551268TEST_P(SQLDatabaseTest, RazeAndPoison_InvalidatesCachedStatement) {
Victor Costane7944b4e2022-03-30 20:06:221269 Statement select(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
1270 ASSERT_TRUE(select.is_valid()) << "Incorrect test setup";
1271 ASSERT_TRUE(select.Step()) << "Incorrect test setup";
1272 select.Reset(/*clear_bound_vars=*/true);
1273
Andrew Paseltinerd309fec2023-03-28 16:59:551274 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:221275 EXPECT_FALSE(select.is_valid())
Andrew Paseltinerd309fec2023-03-28 16:59:551276 << "RazeAndPoison() should invalidate live Statements";
Victor Costane7944b4e2022-03-30 20:06:221277 EXPECT_FALSE(select.Step())
Andrew Paseltinerd309fec2023-03-28 16:59:551278 << "RazeAndPoison() should invalidate live Statements";
Victor Costane7944b4e2022-03-30 20:06:221279}
1280
Andrew Paseltinerd309fec2023-03-28 16:59:551281TEST_P(SQLDatabaseTest, RazeAndPoison_TransactionBegin) {
Victor Costane7944b4e2022-03-30 20:06:221282 {
1283 Transaction transaction(db_.get());
1284 ASSERT_TRUE(transaction.Begin()) << "Incorrect test setup";
1285 ASSERT_TRUE(transaction.Commit()) << "Incorrect test setup";
1286 }
1287
Andrew Paseltinerd309fec2023-03-28 16:59:551288 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:221289 {
1290 Transaction transaction(db_.get());
1291 EXPECT_FALSE(transaction.Begin())
Andrew Paseltinerd309fec2023-03-28 16:59:551292 << "Transaction::Begin() should return false after RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:221293 EXPECT_FALSE(transaction.IsActiveForTesting())
Andrew Paseltinerd309fec2023-03-28 16:59:551294 << "RazeAndPoison() should block transactions from starting";
Victor Costane7944b4e2022-03-30 20:06:221295 }
1296}
1297
1298TEST_P(SQLDatabaseTest, Close_IsSQLValid) {
1299 ASSERT_TRUE(db_->IsSQLValid("SELECT 1")) << "Incorrect test setup";
1300
1301 db_->Close();
1302
1303 EXPECT_DCHECK_DEATH_WITH({ std::ignore = db_->IsSQLValid("SELECT 1"); },
1304 "Illegal use of Database without a db");
1305}
shess@chromium.org41a97c812013-02-07 02:35:381306
shess92a6fb22017-04-23 04:33:301307// On Windows, truncate silently fails against a memory-mapped file. One goal
1308// of Raze() is to truncate the file to remove blocks which generate I/O errors.
1309// Test that Raze() turns off memory mapping so that the file is truncated.
1310// [This would not cover the case of multiple connections where one of the other
1311// connections is memory-mapped. That is infrequent in Chromium.]
Shubham Aggarwal003708982020-10-28 17:57:541312TEST_P(SQLDatabaseTest, RazeTruncate) {
shess92a6fb22017-04-23 04:33:301313 // The empty database has 0 or 1 pages. Raze() should leave it with exactly 1
1314 // page. Not checking directly because auto_vacuum on Android adds a freelist
1315 // page.
Victor Costan49a903a2021-05-07 22:21:001316 ASSERT_TRUE(db_->Raze());
shess92a6fb22017-04-23 04:33:301317 int64_t expected_size;
Victor Costan49a903a2021-05-07 22:21:001318 ASSERT_TRUE(base::GetFileSize(db_path_, &expected_size));
shess92a6fb22017-04-23 04:33:301319 ASSERT_GT(expected_size, 0);
1320
1321 // Cause the database to take a few pages.
1322 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
Victor Costan49a903a2021-05-07 22:21:001323 ASSERT_TRUE(db_->Execute(kCreateSql));
shess92a6fb22017-04-23 04:33:301324 for (size_t i = 0; i < 24; ++i) {
1325 ASSERT_TRUE(
Victor Costan49a903a2021-05-07 22:21:001326 db_->Execute("INSERT INTO foo (value) VALUES (randomblob(1024))"));
shess92a6fb22017-04-23 04:33:301327 }
Shubham Aggarwalbe4f97c2020-06-19 15:58:571328
1329 // In WAL mode, writes don't reach the database file until a checkpoint
1330 // happens.
Victor Costan49a903a2021-05-07 22:21:001331 ASSERT_TRUE(db_->CheckpointDatabase());
Shubham Aggarwalbe4f97c2020-06-19 15:58:571332
shess92a6fb22017-04-23 04:33:301333 int64_t db_size;
Victor Costan49a903a2021-05-07 22:21:001334 ASSERT_TRUE(base::GetFileSize(db_path_, &db_size));
shess92a6fb22017-04-23 04:33:301335 ASSERT_GT(db_size, expected_size);
1336
1337 // Make a query covering most of the database file to make sure that the
1338 // blocks are actually mapped into memory. Empirically, the truncate problem
1339 // doesn't seem to happen if no blocks are mapped.
1340 EXPECT_EQ("24576",
Victor Costan49a903a2021-05-07 22:21:001341 ExecuteWithResult(db_.get(), "SELECT SUM(LENGTH(value)) FROM foo"));
shess92a6fb22017-04-23 04:33:301342
Victor Costan49a903a2021-05-07 22:21:001343 ASSERT_TRUE(db_->Raze());
1344 ASSERT_TRUE(base::GetFileSize(db_path_, &db_size));
shess92a6fb22017-04-23 04:33:301345 ASSERT_EQ(expected_size, db_size);
1346}
1347
Xiaohan Wang7d09c5e2022-01-08 02:37:361348#if BUILDFLAG(IS_ANDROID)
Shubham Aggarwal003708982020-10-28 17:57:541349TEST_P(SQLDatabaseTest, SetTempDirForSQL) {
Victor Costan49a903a2021-05-07 22:21:001350 MetaTable meta_table;
yongsheng.zhu@intel.com13487652012-07-24 08:25:531351 // Below call needs a temporary directory in sqlite3
1352 // On Android, it can pass only when the temporary directory is set.
1353 // Otherwise, sqlite3 doesn't find the correct directory to store
1354 // temporary files and will report the error 'unable to open
1355 // database file'.
Victor Costan49a903a2021-05-07 22:21:001356 ASSERT_TRUE(meta_table.Init(db_.get(), 4, 4));
yongsheng.zhu@intel.com13487652012-07-24 08:25:531357}
Xiaohan Wang7d09c5e2022-01-08 02:37:361358#endif // BUILDFLAG(IS_ANDROID)
shess@chromium.org8d2e39e2013-06-24 05:55:081359
Shubham Aggarwal003708982020-10-28 17:57:541360TEST_P(SQLDatabaseTest, Delete) {
Victor Costan49a903a2021-05-07 22:21:001361 EXPECT_TRUE(db_->Execute("CREATE TABLE x (x)"));
1362 db_->Close();
shess@chromium.org8d2e39e2013-06-24 05:55:081363
Victor Costan49a903a2021-05-07 22:21:001364 base::FilePath journal_path = Database::JournalPath(db_path_);
1365 base::FilePath wal_path = Database::WriteAheadLogPath(db_path_);
Shubham Aggarwalbe4f97c2020-06-19 15:58:571366
1367 // Should have both a main database file and a journal file if
1368 // journal_mode is TRUNCATE. There is no WAL file as it is deleted on Close.
Victor Costan49a903a2021-05-07 22:21:001369 ASSERT_TRUE(base::PathExists(db_path_));
Shubham Aggarwalbe4f97c2020-06-19 15:58:571370 if (!IsWALEnabled()) { // TRUNCATE mode
Victor Costan49a903a2021-05-07 22:21:001371 ASSERT_TRUE(base::PathExists(journal_path));
Shubham Aggarwalbe4f97c2020-06-19 15:58:571372 }
shess@chromium.org8d2e39e2013-06-24 05:55:081373
Victor Costan49a903a2021-05-07 22:21:001374 Database::Delete(db_path_);
1375 EXPECT_FALSE(base::PathExists(db_path_));
1376 EXPECT_FALSE(base::PathExists(journal_path));
1377 EXPECT_FALSE(base::PathExists(wal_path));
shess@chromium.org8d2e39e2013-06-24 05:55:081378}
shess@chromium.org7bae5742013-07-10 20:46:161379
Xiaohan Wang7d09c5e2022-01-08 02:37:361380#if BUILDFLAG(IS_POSIX) // This test operates on POSIX file permissions.
Shubham Aggarwal003708982020-10-28 17:57:541381TEST_P(SQLDatabaseTest, PosixFilePermissions) {
Victor Costan49a903a2021-05-07 22:21:001382 db_->Close();
1383 Database::Delete(db_path_);
1384 ASSERT_FALSE(base::PathExists(db_path_));
Victor Costance678e72018-07-24 10:25:001385
1386 // If the bots all had a restrictive umask setting such that databases are
1387 // always created with only the owner able to read them, then the code could
1388 // break without breaking the tests. Temporarily provide a more permissive
1389 // umask.
shess@chromium.org81a2a602013-07-17 19:10:361390 ScopedUmaskSetter permissive_umask(S_IWGRP | S_IWOTH);
Victor Costance678e72018-07-24 10:25:001391
Victor Costan49a903a2021-05-07 22:21:001392 ASSERT_TRUE(db_->Open(db_path_));
shess@chromium.org81a2a602013-07-17 19:10:361393
Victor Costance678e72018-07-24 10:25:001394 // Cause the journal file to be created. If the default journal_mode is
1395 // changed back to DELETE, this test will need to be updated.
Victor Costan49a903a2021-05-07 22:21:001396 EXPECT_TRUE(db_->Execute("CREATE TABLE x (x)"));
shess@chromium.org81a2a602013-07-17 19:10:361397
shess@chromium.org81a2a602013-07-17 19:10:361398 int mode;
Victor Costan49a903a2021-05-07 22:21:001399 ASSERT_TRUE(base::PathExists(db_path_));
1400 EXPECT_TRUE(base::GetPosixFilePermissions(db_path_, &mode));
Victor Costance678e72018-07-24 10:25:001401 ASSERT_EQ(mode, 0600);
shess@chromium.org81a2a602013-07-17 19:10:361402
Shubham Aggarwalbe4f97c2020-06-19 15:58:571403 if (IsWALEnabled()) { // WAL mode
1404 // The WAL file is created lazily on first change.
Victor Costan49a903a2021-05-07 22:21:001405 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
shess@chromium.org81a2a602013-07-17 19:10:361406
Victor Costan49a903a2021-05-07 22:21:001407 base::FilePath wal_path = Database::WriteAheadLogPath(db_path_);
1408 ASSERT_TRUE(base::PathExists(wal_path));
Victor Costance678e72018-07-24 10:25:001409 EXPECT_TRUE(base::GetPosixFilePermissions(wal_path, &mode));
1410 ASSERT_EQ(mode, 0600);
1411
Shubham Aggarwal7b60fe6e2020-10-15 06:00:281412 // The shm file doesn't exist in exclusive locking mode.
Victor Costan49a903a2021-05-07 22:21:001413 if (ExecuteWithResult(db_.get(), "PRAGMA locking_mode") == "normal") {
1414 base::FilePath shm_path = Database::SharedMemoryFilePath(db_path_);
1415 ASSERT_TRUE(base::PathExists(shm_path));
Shubham Aggarwal7b60fe6e2020-10-15 06:00:281416 EXPECT_TRUE(base::GetPosixFilePermissions(shm_path, &mode));
1417 ASSERT_EQ(mode, 0600);
1418 }
Shubham Aggarwalbe4f97c2020-06-19 15:58:571419 } else { // Truncate mode
Victor Costan49a903a2021-05-07 22:21:001420 base::FilePath journal_path = Database::JournalPath(db_path_);
Shubham Aggarwalbe4f97c2020-06-19 15:58:571421 DLOG(ERROR) << "journal_path: " << journal_path;
Victor Costan49a903a2021-05-07 22:21:001422 ASSERT_TRUE(base::PathExists(journal_path));
Shubham Aggarwalbe4f97c2020-06-19 15:58:571423 EXPECT_TRUE(base::GetPosixFilePermissions(journal_path, &mode));
1424 ASSERT_EQ(mode, 0600);
Victor Costance678e72018-07-24 10:25:001425 }
shess@chromium.org81a2a602013-07-17 19:10:361426}
Xiaohan Wang7d09c5e2022-01-08 02:37:361427#endif // BUILDFLAG(IS_POSIX)
shess@chromium.org81a2a602013-07-17 19:10:361428
Victor Costane7944b4e2022-03-30 20:06:221429TEST_P(SQLDatabaseTest, Poison_IsOpen) {
1430 db_->Poison();
1431 EXPECT_FALSE(db_->is_open())
1432 << "Poison() did not mark the database as closed";
1433}
shess@chromium.org8d409412013-07-19 18:25:301434
Victor Costane7944b4e2022-03-30 20:06:221435TEST_P(SQLDatabaseTest, Poison_Close_Reopen_NoChanges) {
1436 db_->Poison();
1437 EXPECT_FALSE(
1438 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
1439 << "Execute() should return false after Poison()";
shess@chromium.org8d409412013-07-19 18:25:301440
Victor Costane7944b4e2022-03-30 20:06:221441 db_->Close();
1442 ASSERT_TRUE(db_->Open(db_path_)) << "Poison() damaged the database";
1443 EXPECT_TRUE(
1444 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
1445 << "Execute() returned false but went through after Poison()";
1446}
1447
1448TEST_P(SQLDatabaseTest, Poison_Preload_NoCrash) {
1449 db_->Preload();
1450 db_->Poison();
1451 db_->Preload();
1452}
1453
1454TEST_P(SQLDatabaseTest, Poison_DoesTableExist) {
1455 ASSERT_TRUE(
1456 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1457 ASSERT_TRUE(db_->DoesTableExist("rows")) << "Incorrect test setup";
shess@chromium.org8d409412013-07-19 18:25:301458
Victor Costan49a903a2021-05-07 22:21:001459 db_->Poison();
Victor Costane7944b4e2022-03-30 20:06:221460 EXPECT_FALSE(db_->DoesTableExist("rows"))
1461 << "DoesTableExist() should return false after Poison()";
1462}
shess@chromium.org8d409412013-07-19 18:25:301463
Victor Costane7944b4e2022-03-30 20:06:221464TEST_P(SQLDatabaseTest, Poison_IsSQLValid) {
1465 ASSERT_TRUE(db_->IsSQLValid("SELECT 1")) << "Incorrect test setup";
1466
1467 db_->Poison();
1468 EXPECT_FALSE(db_->IsSQLValid("SELECT 1"))
1469 << "IsSQLValid() should return false after Poison()";
1470}
1471
1472TEST_P(SQLDatabaseTest, Poison_Execute) {
1473 ASSERT_TRUE(db_->Execute("SELECT 1")) << "Incorrect test setup";
1474
1475 db_->Poison();
1476 EXPECT_FALSE(db_->Execute("SELECT 1"))
1477 << "Execute() should return false after Poison()";
1478}
1479
1480TEST_P(SQLDatabaseTest, Poison_GetUniqueStatement) {
shess@chromium.org8d409412013-07-19 18:25:301481 {
Victor Costane7944b4e2022-03-30 20:06:221482 Statement select(db_->GetUniqueStatement("SELECT 1"));
1483 ASSERT_TRUE(select.Step()) << "Incorrect test setup";
shess@chromium.org8d409412013-07-19 18:25:301484 }
1485
Victor Costane7944b4e2022-03-30 20:06:221486 db_->Poison();
1487 {
1488 Statement select(db_->GetUniqueStatement("SELECT 1"));
1489 EXPECT_FALSE(select.Step())
1490 << "GetUniqueStatement() should return an invalid Statement after "
1491 << "Poison()";
1492 }
1493}
shess644fc8a2016-02-26 18:15:581494
Victor Costane7944b4e2022-03-30 20:06:221495TEST_P(SQLDatabaseTest, Poison_GetCachedStatement) {
1496 {
1497 Statement select(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
1498 ASSERT_TRUE(select.Step()) << "Incorrect test setup";
1499 }
1500
1501 db_->Poison();
1502 {
1503 Statement select(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
1504 EXPECT_FALSE(select.Step())
1505 << "GetCachedStatement() should return an invalid Statement after "
1506 << "Poison()";
1507 }
1508}
1509
1510TEST_P(SQLDatabaseTest, Poison_InvalidatesUniqueStatement) {
1511 Statement select(db_->GetUniqueStatement("SELECT 1"));
1512 ASSERT_TRUE(select.is_valid()) << "Incorrect test setup";
1513 ASSERT_TRUE(select.Step()) << "Incorrect test setup";
1514 select.Reset(/*clear_bound_vars=*/true);
1515
1516 db_->Poison();
1517 EXPECT_FALSE(select.is_valid())
1518 << "Poison() should invalidate live Statements";
1519 EXPECT_FALSE(select.Step()) << "Poison() should invalidate live Statements";
1520}
1521
1522TEST_P(SQLDatabaseTest, Poison_InvalidatesCachedStatement) {
1523 Statement select(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
1524 ASSERT_TRUE(select.is_valid()) << "Incorrect test setup";
1525 ASSERT_TRUE(select.Step()) << "Incorrect test setup";
1526 select.Reset(/*clear_bound_vars=*/true);
1527
1528 db_->Poison();
1529 EXPECT_FALSE(select.is_valid())
1530 << "Poison() should invalidate live Statements";
1531 EXPECT_FALSE(select.Step()) << "Poison() should invalidate live Statements";
1532}
1533
1534TEST_P(SQLDatabaseTest, Poison_TransactionBegin) {
1535 {
1536 Transaction transaction(db_.get());
1537 ASSERT_TRUE(transaction.Begin()) << "Incorrect test setup";
1538 ASSERT_TRUE(transaction.Commit()) << "Incorrect test setup";
1539 }
1540
1541 db_->Poison();
1542 {
1543 Transaction transaction(db_.get());
1544 EXPECT_FALSE(transaction.Begin())
1545 << "Transaction::Begin() should return false after Poison()";
1546 EXPECT_FALSE(transaction.IsActiveForTesting())
1547 << "Poison() should block transactions from starting";
1548 }
1549}
1550
1551TEST_P(SQLDatabaseTest, Poison_OpenTransaction) {
1552 Transaction transaction(db_.get());
1553 ASSERT_TRUE(transaction.Begin());
1554
1555 db_->Poison();
1556 EXPECT_FALSE(transaction.Commit())
1557 << "Poison() did not cancel the transaction";
shess@chromium.org8d409412013-07-19 18:25:301558}
1559
Shubham Aggarwal003708982020-10-28 17:57:541560TEST_P(SQLDatabaseTest, AttachDatabase) {
Victor Costane7944b4e2022-03-30 20:06:221561 ASSERT_TRUE(
1562 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
shess@chromium.org8d409412013-07-19 18:25:301563
1564 // Create a database to attach to.
1565 base::FilePath attach_path =
Victor Costane7944b4e2022-03-30 20:06:221566 db_path_.DirName().AppendASCII("attach_database_test.db");
1567 static constexpr char kAttachmentPoint[] = "other";
shess@chromium.org8d409412013-07-19 18:25:301568 {
Victor Costan49a903a2021-05-07 22:21:001569 Database other_db;
shess@chromium.org8d409412013-07-19 18:25:301570 ASSERT_TRUE(other_db.Open(attach_path));
Victor Costane7944b4e2022-03-30 20:06:221571 ASSERT_TRUE(
1572 other_db.Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1573 ASSERT_TRUE(other_db.Execute("INSERT INTO rows VALUES(42)"));
shess@chromium.org8d409412013-07-19 18:25:301574 }
1575
1576 // Cannot see the attached database, yet.
Victor Costane7944b4e2022-03-30 20:06:221577 EXPECT_FALSE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
shess@chromium.org8d409412013-07-19 18:25:301578
Victor Costan49a903a2021-05-07 22:21:001579 EXPECT_TRUE(DatabaseTestPeer::AttachDatabase(db_.get(), attach_path,
1580 kAttachmentPoint));
Victor Costane7944b4e2022-03-30 20:06:221581 EXPECT_TRUE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
shess@chromium.org8d409412013-07-19 18:25:301582
Victor Costan8a87f7e52017-11-10 01:29:301583 // Queries can touch both databases after the ATTACH.
Victor Costane7944b4e2022-03-30 20:06:221584 EXPECT_TRUE(db_->Execute("INSERT INTO rows SELECT id FROM other.rows"));
shess@chromium.org8d409412013-07-19 18:25:301585 {
Victor Costane7944b4e2022-03-30 20:06:221586 Statement select(db_->GetUniqueStatement("SELECT COUNT(*) FROM rows"));
1587 ASSERT_TRUE(select.Step());
1588 EXPECT_EQ(1, select.ColumnInt(0));
shess@chromium.org8d409412013-07-19 18:25:301589 }
1590
Victor Costan49a903a2021-05-07 22:21:001591 EXPECT_TRUE(DatabaseTestPeer::DetachDatabase(db_.get(), kAttachmentPoint));
Victor Costane7944b4e2022-03-30 20:06:221592 EXPECT_FALSE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
Victor Costan8a87f7e52017-11-10 01:29:301593}
1594
Shubham Aggarwal003708982020-10-28 17:57:541595TEST_P(SQLDatabaseTest, AttachDatabaseWithOpenTransaction) {
Victor Costane7944b4e2022-03-30 20:06:221596 ASSERT_TRUE(
1597 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
Victor Costan8a87f7e52017-11-10 01:29:301598
1599 // Create a database to attach to.
1600 base::FilePath attach_path =
Victor Costane7944b4e2022-03-30 20:06:221601 db_path_.DirName().AppendASCII("attach_database_test.db");
1602 static constexpr char kAttachmentPoint[] = "other";
Victor Costan8a87f7e52017-11-10 01:29:301603 {
Victor Costan49a903a2021-05-07 22:21:001604 Database other_db;
Victor Costan8a87f7e52017-11-10 01:29:301605 ASSERT_TRUE(other_db.Open(attach_path));
Victor Costane7944b4e2022-03-30 20:06:221606 ASSERT_TRUE(
1607 other_db.Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1608 ASSERT_TRUE(other_db.Execute("INSERT INTO rows VALUES(42)"));
Victor Costan8a87f7e52017-11-10 01:29:301609 }
1610
1611 // Cannot see the attached database, yet.
Victor Costane7944b4e2022-03-30 20:06:221612 EXPECT_FALSE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
Victor Costan8a87f7e52017-11-10 01:29:301613
Victor Costan8a87f7e52017-11-10 01:29:301614 // Attach succeeds in a transaction.
Victor Costane7944b4e2022-03-30 20:06:221615 Transaction transaction(db_.get());
1616 EXPECT_TRUE(transaction.Begin());
Victor Costan49a903a2021-05-07 22:21:001617 EXPECT_TRUE(DatabaseTestPeer::AttachDatabase(db_.get(), attach_path,
1618 kAttachmentPoint));
Victor Costane7944b4e2022-03-30 20:06:221619 EXPECT_TRUE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
Victor Costan8a87f7e52017-11-10 01:29:301620
1621 // Queries can touch both databases after the ATTACH.
Victor Costane7944b4e2022-03-30 20:06:221622 EXPECT_TRUE(db_->Execute("INSERT INTO rows SELECT id FROM other.rows"));
Victor Costan8a87f7e52017-11-10 01:29:301623 {
Victor Costane7944b4e2022-03-30 20:06:221624 Statement select(db_->GetUniqueStatement("SELECT COUNT(*) FROM rows"));
1625 ASSERT_TRUE(select.Step());
1626 EXPECT_EQ(1, select.ColumnInt(0));
Victor Costan8a87f7e52017-11-10 01:29:301627 }
1628
1629 // Detaching the same database fails, database is locked in the transaction.
1630 {
1631 sql::test::ScopedErrorExpecter expecter;
1632 expecter.ExpectError(SQLITE_ERROR);
Victor Costan49a903a2021-05-07 22:21:001633 EXPECT_FALSE(DatabaseTestPeer::DetachDatabase(db_.get(), kAttachmentPoint));
shess976814402016-06-21 06:56:251634 ASSERT_TRUE(expecter.SawExpectedErrors());
shess@chromium.org8d409412013-07-19 18:25:301635 }
Victor Costane7944b4e2022-03-30 20:06:221636 EXPECT_TRUE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
shess@chromium.org8d409412013-07-19 18:25:301637
Victor Costan8a87f7e52017-11-10 01:29:301638 // Detach succeeds when the transaction is closed.
Victor Costane7944b4e2022-03-30 20:06:221639 transaction.Rollback();
Victor Costan49a903a2021-05-07 22:21:001640 EXPECT_TRUE(DatabaseTestPeer::DetachDatabase(db_.get(), kAttachmentPoint));
Victor Costane7944b4e2022-03-30 20:06:221641 EXPECT_FALSE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
shess@chromium.org8d409412013-07-19 18:25:301642}
1643
Victor Costan4b67f542022-02-24 17:40:551644TEST_P(SQLDatabaseTest, FullIntegrityCheck) {
1645 static constexpr char kTableSql[] =
1646 "CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL, value TEXT NOT NULL)";
1647 ASSERT_TRUE(db_->Execute(kTableSql));
Victor Costan8c3a9922022-02-26 03:50:521648 ASSERT_TRUE(db_->Execute("CREATE INDEX rows_by_value ON rows(value)"));
1649
Victor Costan4b67f542022-02-24 17:40:551650 {
1651 std::vector<std::string> messages;
1652 EXPECT_TRUE(db_->FullIntegrityCheck(&messages))
1653 << "FullIntegrityCheck() failed before database was corrupted";
1654 EXPECT_THAT(messages, testing::ElementsAre("ok"))
1655 << "FullIntegrityCheck() should report ok before database is corrupted";
1656 }
michaeln@chromium.org579446c2013-12-16 18:36:521657
Victor Costan8c3a9922022-02-26 03:50:521658 db_->Close();
1659 ASSERT_TRUE(sql::test::CorruptIndexRootPage(db_path_, "rows_by_value"));
1660 ASSERT_TRUE(db_->Open(db_path_));
1661
Victor Costan4b67f542022-02-24 17:40:551662 {
1663 std::vector<std::string> messages;
1664 EXPECT_TRUE(db_->FullIntegrityCheck(&messages))
1665 << "FullIntegrityCheck() failed on corrupted database";
1666 EXPECT_THAT(messages, testing::Not(testing::ElementsAre("ok")))
1667 << "FullIntegrityCheck() should not report ok for a corrupted database";
michaeln@chromium.org579446c2013-12-16 18:36:521668 }
michaeln@chromium.org579446c2013-12-16 18:36:521669}
1670
Shubham Aggarwal003708982020-10-28 17:57:541671TEST_P(SQLDatabaseTest, OnMemoryDump) {
ssid9f8022f2015-10-12 17:49:031672 base::trace_event::MemoryDumpArgs args = {
Ho Cheungadbf3fb2023-09-08 02:01:111673 base::trace_event::MemoryDumpLevelOfDetail::kDetailed};
erikchenf62ea042018-05-25 21:30:571674 base::trace_event::ProcessMemoryDump pmd(args);
Victor Costan49a903a2021-05-07 22:21:001675 ASSERT_TRUE(db_->memory_dump_provider_->OnMemoryDump(args, &pmd));
ssid9f8022f2015-10-12 17:49:031676 EXPECT_GE(pmd.allocator_dumps().size(), 1u);
1677}
1678
shessc8cd2a162015-10-22 20:30:461679// Test that the functions to collect diagnostic data run to completion, without
1680// worrying too much about what they generate (since that will change).
Shubham Aggarwal003708982020-10-28 17:57:541681TEST_P(SQLDatabaseTest, CollectDiagnosticInfo) {
Victor Costan49a903a2021-05-07 22:21:001682 const std::string corruption_info = db_->CollectCorruptionInfo();
Ho Cheung47524352023-08-08 03:41:101683 EXPECT_TRUE(base::Contains(corruption_info, "SQLITE_CORRUPT"));
1684 EXPECT_TRUE(base::Contains(corruption_info, "integrity_check"));
shessc8cd2a162015-10-22 20:30:461685
1686 // A statement to see in the results.
1687 const char* kSimpleSql = "SELECT 'mountain'";
Victor Costan49a903a2021-05-07 22:21:001688 Statement s(db_->GetCachedStatement(SQL_FROM_HERE, kSimpleSql));
shessc8cd2a162015-10-22 20:30:461689
1690 // Error includes the statement.
Tommy C. Li7803636c2022-07-27 21:47:221691 {
1692 DatabaseDiagnostics diagnostics;
1693 const std::string readonly_info =
1694 db_->CollectErrorInfo(SQLITE_READONLY, &s, &diagnostics);
Ho Cheung47524352023-08-08 03:41:101695 EXPECT_TRUE(base::Contains(readonly_info, kSimpleSql));
Tommy C. Li7803636c2022-07-27 21:47:221696 EXPECT_EQ(diagnostics.sql_statement, kSimpleSql);
1697 }
shessc8cd2a162015-10-22 20:30:461698
Tommy C. Li7803636c2022-07-27 21:47:221699 // Some other error doesn't include the statement.
1700 {
1701 DatabaseDiagnostics diagnostics;
1702 const std::string full_info =
1703 db_->CollectErrorInfo(SQLITE_FULL, nullptr, &diagnostics);
Ho Cheung47524352023-08-08 03:41:101704 EXPECT_FALSE(base::Contains(full_info, kSimpleSql));
Tommy C. Li7803636c2022-07-27 21:47:221705 EXPECT_TRUE(diagnostics.sql_statement.empty());
1706 }
shessc8cd2a162015-10-22 20:30:461707
1708 // A table to see in the SQLITE_ERROR results.
Victor Costan49a903a2021-05-07 22:21:001709 EXPECT_TRUE(db_->Execute("CREATE TABLE volcano (x)"));
shessc8cd2a162015-10-22 20:30:461710
1711 // Version info to see in the SQLITE_ERROR results.
Victor Costan49a903a2021-05-07 22:21:001712 MetaTable meta_table;
1713 ASSERT_TRUE(meta_table.Init(db_.get(), 4, 4));
shessc8cd2a162015-10-22 20:30:461714
Tommy C. Li7803636c2022-07-27 21:47:221715 {
1716 DatabaseDiagnostics diagnostics;
1717 const std::string error_info =
1718 db_->CollectErrorInfo(SQLITE_ERROR, &s, &diagnostics);
Ho Cheung47524352023-08-08 03:41:101719 EXPECT_TRUE(base::Contains(error_info, kSimpleSql));
1720 EXPECT_TRUE(base::Contains(error_info, "volcano"));
1721 EXPECT_TRUE(base::Contains(error_info, "version: 4"));
Tommy C. Li7803636c2022-07-27 21:47:221722 EXPECT_EQ(diagnostics.sql_statement, kSimpleSql);
1723 EXPECT_EQ(diagnostics.version, 4);
1724
1725 ASSERT_EQ(diagnostics.schema_sql_rows.size(), 2U);
1726 EXPECT_EQ(diagnostics.schema_sql_rows[0], "CREATE TABLE volcano (x)");
1727 EXPECT_EQ(diagnostics.schema_sql_rows[1],
1728 "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, "
1729 "value LONGVARCHAR)");
1730
1731 ASSERT_EQ(diagnostics.schema_other_row_names.size(), 1U);
1732 EXPECT_EQ(diagnostics.schema_other_row_names[0], "sqlite_autoindex_meta_1");
1733 }
Tommy C. Li400c0f12022-09-13 22:39:281734
1735 // Test that an error message is included in the diagnostics.
1736 {
1737 sql::test::ScopedErrorExpecter error_expecter;
1738 error_expecter.ExpectError(SQLITE_ERROR);
1739 EXPECT_FALSE(
1740 db_->Execute("INSERT INTO volcano VALUES ('bound_value1', 42, 1234)"));
1741 EXPECT_TRUE(error_expecter.SawExpectedErrors());
1742
1743 DatabaseDiagnostics diagnostics;
1744 const std::string error_info =
1745 db_->CollectErrorInfo(SQLITE_ERROR, &s, &diagnostics);
1746 // Expect that the error message contains the table name and a column error.
Ho Cheung47524352023-08-08 03:41:101747 EXPECT_TRUE(base::Contains(diagnostics.error_message, "table"));
1748 EXPECT_TRUE(base::Contains(diagnostics.error_message, "volcano"));
1749 EXPECT_TRUE(base::Contains(diagnostics.error_message, "column"));
Tommy C. Li400c0f12022-09-13 22:39:281750
1751 // Expect that bound values are not present.
Ho Cheung47524352023-08-08 03:41:101752 EXPECT_FALSE(base::Contains(diagnostics.error_message, "bound_value1"));
1753 EXPECT_FALSE(base::Contains(diagnostics.error_message, "42"));
1754 EXPECT_FALSE(base::Contains(diagnostics.error_message, "1234"));
Tommy C. Li400c0f12022-09-13 22:39:281755 }
shessc8cd2a162015-10-22 20:30:461756}
1757
shess9bf2c672015-12-18 01:18:081758// Test that a fresh database has mmap enabled by default, if mmap'ed I/O is
1759// enabled by SQLite.
Shubham Aggarwal003708982020-10-28 17:57:541760TEST_P(SQLDatabaseTest, MmapInitiallyEnabled) {
shess9bf2c672015-12-18 01:18:081761 {
Victor Costan49a903a2021-05-07 22:21:001762 Statement s(db_->GetUniqueStatement("PRAGMA mmap_size"));
Victor Costan42988a92018-02-06 02:22:141763 ASSERT_TRUE(s.Step())
1764 << "All supported SQLite versions should have mmap support";
shess9bf2c672015-12-18 01:18:081765
1766 // If mmap I/O is not on, attempt to turn it on. If that succeeds, then
1767 // Open() should have turned it on. If mmap support is disabled, 0 is
1768 // returned. If the VFS does not understand SQLITE_FCNTL_MMAP_SIZE (for
1769 // instance MojoVFS), -1 is returned.
1770 if (s.ColumnInt(0) <= 0) {
Victor Costan49a903a2021-05-07 22:21:001771 ASSERT_TRUE(db_->Execute("PRAGMA mmap_size = 1048576"));
shess9bf2c672015-12-18 01:18:081772 s.Reset(true);
1773 ASSERT_TRUE(s.Step());
1774 EXPECT_LE(s.ColumnInt(0), 0);
1775 }
1776 }
1777
1778 // Test that explicit disable prevents mmap'ed I/O.
Victor Costan49a903a2021-05-07 22:21:001779 db_->Close();
1780 Database::Delete(db_path_);
1781 db_->set_mmap_disabled();
1782 ASSERT_TRUE(db_->Open(db_path_));
1783 EXPECT_EQ("0", ExecuteWithResult(db_.get(), "PRAGMA mmap_size"));
shessa62504d2016-11-07 19:26:121784}
1785
1786// Test whether a fresh database gets mmap enabled when using alternate status
1787// storage.
Shubham Aggarwal003708982020-10-28 17:57:541788TEST_P(SQLDatabaseTest, MmapInitiallyEnabledAltStatus) {
shessa62504d2016-11-07 19:26:121789 // Re-open fresh database with alt-status flag set.
Victor Costan49a903a2021-05-07 22:21:001790 db_->Close();
1791 Database::Delete(db_path_);
Victor Costan8ec18ee42021-07-13 19:45:321792
1793 DatabaseOptions options = GetDBOptions();
1794 options.mmap_alt_status_discouraged = true;
Victor Costanfe078f92021-07-19 20:02:591795 options.enable_views_discouraged = true;
Victor Costan8ec18ee42021-07-13 19:45:321796 db_ = std::make_unique<Database>(options);
Victor Costan49a903a2021-05-07 22:21:001797 ASSERT_TRUE(db_->Open(db_path_));
shessa62504d2016-11-07 19:26:121798
shess9bf2c672015-12-18 01:18:081799 {
Victor Costan49a903a2021-05-07 22:21:001800 Statement s(db_->GetUniqueStatement("PRAGMA mmap_size"));
Victor Costan42988a92018-02-06 02:22:141801 ASSERT_TRUE(s.Step())
1802 << "All supported SQLite versions should have mmap support";
shessa62504d2016-11-07 19:26:121803
1804 // If mmap I/O is not on, attempt to turn it on. If that succeeds, then
1805 // Open() should have turned it on. If mmap support is disabled, 0 is
1806 // returned. If the VFS does not understand SQLITE_FCNTL_MMAP_SIZE (for
1807 // instance MojoVFS), -1 is returned.
1808 if (s.ColumnInt(0) <= 0) {
Victor Costan49a903a2021-05-07 22:21:001809 ASSERT_TRUE(db_->Execute("PRAGMA mmap_size = 1048576"));
shessa62504d2016-11-07 19:26:121810 s.Reset(true);
1811 ASSERT_TRUE(s.Step());
1812 EXPECT_LE(s.ColumnInt(0), 0);
1813 }
shess9bf2c672015-12-18 01:18:081814 }
shessa62504d2016-11-07 19:26:121815
1816 // Test that explicit disable overrides set_mmap_alt_status().
Victor Costan49a903a2021-05-07 22:21:001817 db_->Close();
1818 Database::Delete(db_path_);
1819 db_->set_mmap_disabled();
1820 ASSERT_TRUE(db_->Open(db_path_));
1821 EXPECT_EQ("0", ExecuteWithResult(db_.get(), "PRAGMA mmap_size"));
shess9bf2c672015-12-18 01:18:081822}
1823
Victor Costandc72e8d2022-03-14 18:14:511824TEST_P(SQLDatabaseTest, ComputeMmapSizeForOpen) {
shess9bf2c672015-12-18 01:18:081825 const size_t kMmapAlot = 25 * 1024 * 1024;
shess9e77283d2016-06-13 23:53:201826 int64_t mmap_status = MetaTable::kMmapFailure;
shess9bf2c672015-12-18 01:18:081827
1828 // If there is no meta table (as for a fresh database), assume that everything
shess9e77283d2016-06-13 23:53:201829 // should be mapped, and the status of the meta table is not affected.
Victor Costan49a903a2021-05-07 22:21:001830 ASSERT_TRUE(!db_->DoesTableExist("meta"));
Victor Costandc72e8d2022-03-14 18:14:511831 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Victor Costan49a903a2021-05-07 22:21:001832 ASSERT_TRUE(!db_->DoesTableExist("meta"));
shess9bf2c672015-12-18 01:18:081833
1834 // When the meta table is first created, it sets up to map everything.
Andrew Paseltineref652c92023-02-08 21:26:321835 ASSERT_TRUE(MetaTable().Init(db_.get(), 1, 1));
Victor Costan49a903a2021-05-07 22:21:001836 ASSERT_TRUE(db_->DoesTableExist("meta"));
Victor Costandc72e8d2022-03-14 18:14:511837 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Victor Costan49a903a2021-05-07 22:21:001838 ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(), &mmap_status));
shess9bf2c672015-12-18 01:18:081839 ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status);
1840
shessa7b07acd2017-03-19 23:59:381841 // Preload with partial progress of one page. Should map everything.
Victor Costan49a903a2021-05-07 22:21:001842 ASSERT_TRUE(db_->Execute("REPLACE INTO meta VALUES ('mmap_status', 1)"));
Victor Costandc72e8d2022-03-14 18:14:511843 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Victor Costan49a903a2021-05-07 22:21:001844 ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(), &mmap_status));
shessa7b07acd2017-03-19 23:59:381845 ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status);
1846
shess9bf2c672015-12-18 01:18:081847 // Failure status maps nothing.
Victor Costan49a903a2021-05-07 22:21:001848 ASSERT_TRUE(db_->Execute("REPLACE INTO meta VALUES ('mmap_status', -2)"));
Victor Costandc72e8d2022-03-14 18:14:511849 ASSERT_EQ(0UL, db_->ComputeMmapSizeForOpen());
shess9bf2c672015-12-18 01:18:081850
1851 // Re-initializing the meta table does not re-create the key if the table
1852 // already exists.
Victor Costan49a903a2021-05-07 22:21:001853 ASSERT_TRUE(db_->Execute("DELETE FROM meta WHERE key = 'mmap_status'"));
Andrew Paseltineref652c92023-02-08 21:26:321854 ASSERT_TRUE(MetaTable().Init(db_.get(), 1, 1));
shess9bf2c672015-12-18 01:18:081855 ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status);
Victor Costan49a903a2021-05-07 22:21:001856 ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(), &mmap_status));
shess9bf2c672015-12-18 01:18:081857 ASSERT_EQ(0, mmap_status);
1858
1859 // With no key, map everything and create the key.
1860 // TODO(shess): This really should be "maps everything after validating it",
1861 // but that is more complicated to structure.
Victor Costandc72e8d2022-03-14 18:14:511862 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Victor Costan49a903a2021-05-07 22:21:001863 ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(), &mmap_status));
shess9bf2c672015-12-18 01:18:081864 ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status);
1865}
shess9bf2c672015-12-18 01:18:081866
Victor Costandc72e8d2022-03-14 18:14:511867TEST_P(SQLDatabaseTest, ComputeMmapSizeForOpenAltStatus) {
shessa62504d2016-11-07 19:26:121868 const size_t kMmapAlot = 25 * 1024 * 1024;
1869
Victor Costancfbfa602018-08-01 23:24:461870 // At this point, Database still expects a future [meta] table.
Victor Costan49a903a2021-05-07 22:21:001871 ASSERT_FALSE(db_->DoesTableExist("meta"));
1872 ASSERT_FALSE(db_->DoesViewExist("MmapStatus"));
Victor Costandc72e8d2022-03-14 18:14:511873 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Victor Costan49a903a2021-05-07 22:21:001874 ASSERT_FALSE(db_->DoesTableExist("meta"));
1875 ASSERT_FALSE(db_->DoesViewExist("MmapStatus"));
shessa62504d2016-11-07 19:26:121876
1877 // Using alt status, everything should be mapped, with state in the view.
Victor Costan8ec18ee42021-07-13 19:45:321878 DatabaseOptions options = GetDBOptions();
1879 options.mmap_alt_status_discouraged = true;
Victor Costanfe078f92021-07-19 20:02:591880 options.enable_views_discouraged = true;
Victor Costan8ec18ee42021-07-13 19:45:321881 db_ = std::make_unique<Database>(options);
1882 ASSERT_TRUE(db_->Open(db_path_));
1883
Victor Costandc72e8d2022-03-14 18:14:511884 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Victor Costan49a903a2021-05-07 22:21:001885 ASSERT_FALSE(db_->DoesTableExist("meta"));
1886 ASSERT_TRUE(db_->DoesViewExist("MmapStatus"));
Raul Tambre6c708e32019-02-08 22:35:141887 EXPECT_EQ(base::NumberToString(MetaTable::kMmapSuccess),
Victor Costan49a903a2021-05-07 22:21:001888 ExecuteWithResult(db_.get(), "SELECT * FROM MmapStatus"));
shessa62504d2016-11-07 19:26:121889
shessa7b07acd2017-03-19 23:59:381890 // Also maps everything when kMmapSuccess is already in the view.
Victor Costandc72e8d2022-03-14 18:14:511891 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
shessa62504d2016-11-07 19:26:121892
shessa7b07acd2017-03-19 23:59:381893 // Preload with partial progress of one page. Should map everything.
Victor Costan49a903a2021-05-07 22:21:001894 ASSERT_TRUE(db_->Execute("DROP VIEW MmapStatus"));
1895 ASSERT_TRUE(db_->Execute("CREATE VIEW MmapStatus (value) AS SELECT 1"));
Victor Costandc72e8d2022-03-14 18:14:511896 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Raul Tambre6c708e32019-02-08 22:35:141897 EXPECT_EQ(base::NumberToString(MetaTable::kMmapSuccess),
Victor Costan49a903a2021-05-07 22:21:001898 ExecuteWithResult(db_.get(), "SELECT * FROM MmapStatus"));
shessa7b07acd2017-03-19 23:59:381899
shessa62504d2016-11-07 19:26:121900 // Failure status leads to nothing being mapped.
Victor Costan49a903a2021-05-07 22:21:001901 ASSERT_TRUE(db_->Execute("DROP VIEW MmapStatus"));
1902 ASSERT_TRUE(db_->Execute("CREATE VIEW MmapStatus (value) AS SELECT -2"));
Victor Costandc72e8d2022-03-14 18:14:511903 ASSERT_EQ(0UL, db_->ComputeMmapSizeForOpen());
Raul Tambre6c708e32019-02-08 22:35:141904 EXPECT_EQ(base::NumberToString(MetaTable::kMmapFailure),
Victor Costan49a903a2021-05-07 22:21:001905 ExecuteWithResult(db_.get(), "SELECT * FROM MmapStatus"));
shessa62504d2016-11-07 19:26:121906}
1907
Shubham Aggarwal003708982020-10-28 17:57:541908TEST_P(SQLDatabaseTest, GetMemoryUsage) {
Victor Costand6e73252020-10-14 21:11:251909 // Databases with mmap enabled may not follow the assumptions below.
Victor Costan49a903a2021-05-07 22:21:001910 db_->Close();
1911 db_->set_mmap_disabled();
1912 ASSERT_TRUE(db_->Open(db_path_));
Victor Costand6e73252020-10-14 21:11:251913
Victor Costan49a903a2021-05-07 22:21:001914 int initial_memory = db_->GetMemoryUsage();
Victor Costand6e73252020-10-14 21:11:251915 EXPECT_GT(initial_memory, 0)
1916 << "SQLite should always use some memory for a database";
1917
Victor Costan49a903a2021-05-07 22:21:001918 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
1919 ASSERT_TRUE(db_->Execute("INSERT INTO foo(a, b) VALUES (12, 13)"));
Victor Costand6e73252020-10-14 21:11:251920
Victor Costan49a903a2021-05-07 22:21:001921 int post_query_memory = db_->GetMemoryUsage();
Victor Costand6e73252020-10-14 21:11:251922 EXPECT_GT(post_query_memory, initial_memory)
1923 << "Page cache usage should go up after executing queries";
1924
Victor Costan49a903a2021-05-07 22:21:001925 db_->TrimMemory();
1926 int post_trim_memory = db_->GetMemoryUsage();
Victor Costand6e73252020-10-14 21:11:251927 EXPECT_GT(post_query_memory, post_trim_memory)
1928 << "Page cache usage should go down after calling TrimMemory()";
1929}
1930
Victor Costan4e442d02021-07-20 17:43:131931TEST_P(SQLDatabaseTest, DoubleQuotedStringLiteralsDisabledByDefault) {
1932 ASSERT_TRUE(db_->Execute("CREATE TABLE data(item TEXT NOT NULL);"));
1933
1934 struct TestCase {
1935 const char* sql;
1936 bool is_valid;
1937 };
1938 std::vector<TestCase> test_cases = {
1939 // DML tests.
1940 {"SELECT item FROM data WHERE item >= 'string literal'", true},
1941 {"SELECT item FROM data WHERE item >= \"string literal\"", false},
1942 {"INSERT INTO data(item) VALUES('string literal')", true},
1943 {"INSERT INTO data(item) VALUES(\"string literal\")", false},
1944 {"UPDATE data SET item = 'string literal'", true},
1945 {"UPDATE data SET item = \"string literal\"", false},
1946 {"DELETE FROM data WHERE item >= 'string literal'", true},
1947 {"DELETE FROM data WHERE item >= \"string literal\"", false},
1948
1949 // DDL tests.
1950 {"CREATE INDEX data_item ON data(item) WHERE item >= 'string literal'",
1951 true},
1952 {"CREATE INDEX data_item ON data(item) WHERE item >= \"string literal\"",
1953 false},
1954 {"CREATE TABLE data2(item TEXT DEFAULT 'string literal')", true},
1955
1956 // This should be an invalid DDL statement, due to the double-quoted
1957 // string literal. However, SQLite currently parses it.
1958 {"CREATE TABLE data2(item TEXT DEFAULT \"string literal\")", true},
1959 };
1960
1961 for (const TestCase& test_case : test_cases) {
1962 SCOPED_TRACE(test_case.sql);
1963
1964 EXPECT_EQ(test_case.is_valid, db_->IsSQLValid(test_case.sql));
1965 }
1966}
1967
Victor Costan54d71382022-03-21 21:47:181968TEST_P(SQLDatabaseTest, ForeignKeyEnforcementDisabledByDefault) {
Victor Costan54d71382022-03-21 21:47:181969 ASSERT_TRUE(db_->Execute("CREATE TABLE targets(id INTEGER PRIMARY KEY)"));
1970 // sqlite3_db_config() currently only disables foreign key enforcement. Schema
1971 // operations on foreign keys are still allowed.
1972 ASSERT_TRUE(
1973 db_->Execute("CREATE TABLE refs("
1974 "id INTEGER PRIMARY KEY,"
1975 "target_id INTEGER REFERENCES targets(id))"));
1976
1977 ASSERT_TRUE(db_->Execute("INSERT INTO targets(id) VALUES(42)"));
1978 ASSERT_TRUE(db_->Execute("INSERT INTO refs(id, target_id) VALUES(42, 42)"));
1979
1980 EXPECT_TRUE(db_->Execute("DELETE FROM targets WHERE id=42"))
1981 << "Foreign key enforcement is not disabled";
1982}
1983
Victor Costan7c234822021-07-13 03:03:021984TEST_P(SQLDatabaseTest, TriggersDisabledByDefault) {
1985 ASSERT_TRUE(db_->Execute("CREATE TABLE data(id INTEGER)"));
1986
1987 // sqlite3_db_config() currently only disables running triggers. Schema
1988 // operations on triggers are still allowed.
1989 EXPECT_TRUE(
1990 db_->Execute("CREATE TRIGGER trigger AFTER INSERT ON data "
1991 "BEGIN DELETE FROM data; END"));
1992
1993 ASSERT_TRUE(db_->Execute("INSERT INTO data(id) VALUES(42)"));
1994
1995 Statement select(db_->GetUniqueStatement("SELECT id FROM data"));
1996 EXPECT_TRUE(select.Step())
1997 << "If the trigger did not run, the table should not be empty.";
1998 EXPECT_EQ(42, select.ColumnInt64(0));
1999
2000 // sqlite3_db_config() currently only disables running triggers. Schema
2001 // operations on triggers are still allowed.
2002 EXPECT_TRUE(db_->Execute("DROP TRIGGER IF EXISTS trigger"));
2003}
2004
Etienne Bergeron14c5d712023-11-13 15:01:152005// This test ensures that a database can be open/create with a journal mode and
2006// can be re-open later with a different journal mode.
2007TEST_P(SQLDatabaseTest, ReOpenWithDifferentJournalMode) {
2008 const bool is_wal = IsWALEnabled();
2009 const base::FilePath journal_path = Database::JournalPath(db_path_);
2010 const base::FilePath wal_path = Database::WriteAheadLogPath(db_path_);
2011
2012 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"));
2013 ASSERT_TRUE(db_->Execute("INSERT INTO foo (value) VALUES (12)"));
2014
2015 // Last insert row ID should be valid.
2016 int64_t row = db_->GetLastInsertRowId();
2017 EXPECT_LT(0, row);
2018
2019 // It should be the primary key of the row we just inserted.
2020 {
2021 Statement s(db_->GetUniqueStatement("SELECT value FROM foo WHERE id=?"));
2022 s.BindInt64(0, row);
2023 ASSERT_TRUE(s.Step());
2024 EXPECT_EQ(12, s.ColumnInt(0));
2025 }
2026
2027 // Ensure appropriate journal mode and the journal file exists.
2028 EXPECT_TRUE(IsOpenedInCorrectJournalMode(db_.get(), is_wal));
2029 EXPECT_EQ(base::PathExists(wal_path), is_wal);
2030
2031 db_->Close();
2032 if (is_wal) {
2033 // The WAL journal file is removed on database close. Database that enable
2034 // WAL mode can use a different journal mode on a subsequent database open.
2035 EXPECT_FALSE(base::PathExists(wal_path));
2036 } else {
2037 // The Rollback journal should have a zero size when pending operations
2038 // are completed.
2039 int64_t journal_size = 0;
2040 base::GetFileSize(journal_path, &journal_size);
2041 EXPECT_EQ(journal_size, 0);
2042 }
2043
2044 // Re-open the database with a different mode (Rollback vs WAL).
2045 DatabaseOptions options = GetDBOptions();
2046 options.wal_mode = !is_wal;
2047#if BUILDFLAG(IS_FUCHSIA)
2048 // Exclusive mode needs to be enabled to enter WAL mode on Fuchsia.
2049 if (options.wal_mode) {
2050 options.exclusive_locking = true;
2051 }
2052#endif // BUILDFLAG(IS_FUCHSIA)
2053
2054 db_ = std::make_unique<Database>(options);
2055 ASSERT_TRUE(db_->Open(db_path_));
2056
2057 // The value for the last inserted row should be valid.
2058 {
2059 Statement s(db_->GetUniqueStatement("SELECT value FROM foo WHERE id=?"));
2060 s.BindInt64(0, row);
2061 ASSERT_TRUE(s.Step());
2062 EXPECT_EQ(12, s.ColumnInt(0));
2063 }
2064
2065 // Ensure appropriate journal file exists.
2066 EXPECT_TRUE(IsOpenedInCorrectJournalMode(db_.get(), options.wal_mode));
2067 EXPECT_EQ(base::PathExists(wal_path), options.wal_mode);
2068}
2069
Will Harris711a5ec2023-04-04 21:43:372070#if BUILDFLAG(IS_WIN)
2071
2072class SQLDatabaseTestExclusiveFileLockMode
2073 : public testing::Test,
2074 public testing::WithParamInterface<::testing::tuple<bool, bool>> {
2075 public:
2076 ~SQLDatabaseTestExclusiveFileLockMode() override = default;
2077
2078 void SetUp() override {
2079 db_ = std::make_unique<Database>(GetDBOptions());
2080 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
2081 db_path_ = temp_dir_.GetPath().AppendASCII("maybelocked.sqlite");
2082 ASSERT_TRUE(db_->Open(db_path_));
2083 }
2084
2085 DatabaseOptions GetDBOptions() {
2086 DatabaseOptions options;
2087 options.wal_mode = IsWALEnabled();
2088 options.exclusive_locking = true;
2089 options.exclusive_database_file_lock = IsExclusivelockEnabled();
2090 return options;
2091 }
2092
2093 bool IsWALEnabled() { return std::get<0>(GetParam()); }
2094 bool IsExclusivelockEnabled() { return std::get<1>(GetParam()); }
2095
2096 protected:
2097 base::ScopedTempDir temp_dir_;
2098 base::FilePath db_path_;
2099 std::unique_ptr<Database> db_;
2100};
2101
2102TEST_P(SQLDatabaseTestExclusiveFileLockMode, BasicStatement) {
2103 ASSERT_TRUE(db_->Execute("CREATE TABLE data(contents TEXT)"));
2104 EXPECT_EQ(SQLITE_OK, db_->GetErrorCode());
2105
2106 ASSERT_TRUE(base::PathExists(db_path_));
2107 base::File open_db(db_path_, base::File::Flags::FLAG_OPEN_ALWAYS |
2108 base::File::Flags::FLAG_READ);
2109
2110 // If exclusive lock is enabled, then the test should not be able to re-open
2111 // the database file, on Windows only.
2112 EXPECT_EQ(IsExclusivelockEnabled(), !open_db.IsValid());
2113}
2114
2115INSTANTIATE_TEST_SUITE_P(
2116 All,
2117 SQLDatabaseTestExclusiveFileLockMode,
2118 ::testing::Combine(::testing::Bool(), ::testing::Bool()),
2119 [](const auto& info) {
2120 return base::StrCat(
2121 {std::get<0>(info.param) ? "WALEnabled" : "WALDisabled",
2122 std::get<1>(info.param) ? "ExclusiveLock" : "NoExclusiveLock"});
2123 });
2124
2125#else
2126
2127TEST(SQLInvalidDatabaseFlagsDeathTest, ExclusiveDatabaseLock) {
2128 base::ScopedTempDir temp_dir;
2129 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
2130 auto db_path = temp_dir.GetPath().AppendASCII("database_test_locked.sqlite");
2131
2132 Database db({.exclusive_database_file_lock = true});
2133
2134 EXPECT_CHECK_DEATH_WITH(
2135 { std::ignore = db.Open(db_path); },
2136 "exclusive_database_file_lock is only supported on Windows");
2137}
2138
2139#endif // BUILDFLAG(IS_WIN)
2140
Victor Costan49a903a2021-05-07 22:21:002141class SQLDatabaseTestExclusiveMode : public testing::Test,
2142 public testing::WithParamInterface<bool> {
Shubham Aggarwal7b60fe6e2020-10-15 06:00:282143 public:
Victor Costan49a903a2021-05-07 22:21:002144 ~SQLDatabaseTestExclusiveMode() override = default;
2145
2146 void SetUp() override {
2147 db_ = std::make_unique<Database>(GetDBOptions());
2148 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
2149 db_path_ = temp_dir_.GetPath().AppendASCII("recovery_test.sqlite");
2150 ASSERT_TRUE(db_->Open(db_path_));
2151 }
Shubham Aggarwal003708982020-10-28 17:57:542152
2153 DatabaseOptions GetDBOptions() {
Victor Costan49a903a2021-05-07 22:21:002154 DatabaseOptions options;
2155 options.wal_mode = IsWALEnabled();
Shubham Aggarwal003708982020-10-28 17:57:542156 options.exclusive_locking = true;
2157 return options;
2158 }
Victor Costan49a903a2021-05-07 22:21:002159
2160 bool IsWALEnabled() { return GetParam(); }
2161
2162 protected:
2163 base::ScopedTempDir temp_dir_;
2164 base::FilePath db_path_;
2165 std::unique_ptr<Database> db_;
Shubham Aggarwal7b60fe6e2020-10-15 06:00:282166};
Victor Costanb2230792020-10-09 08:35:142167
Shubham Aggarwal003708982020-10-28 17:57:542168TEST_P(SQLDatabaseTestExclusiveMode, LockingModeExclusive) {
Victor Costan49a903a2021-05-07 22:21:002169 EXPECT_EQ(ExecuteWithResult(db_.get(), "PRAGMA locking_mode"), "exclusive");
Victor Costanb2230792020-10-09 08:35:142170}
2171
Shubham Aggarwal003708982020-10-28 17:57:542172TEST_P(SQLDatabaseTest, LockingModeNormal) {
Victor Costan49a903a2021-05-07 22:21:002173 EXPECT_EQ(ExecuteWithResult(db_.get(), "PRAGMA locking_mode"), "normal");
Victor Costanb2230792020-10-09 08:35:142174}
2175
Shubham Aggarwal003708982020-10-28 17:57:542176TEST_P(SQLDatabaseTest, OpenedInCorrectMode) {
Etienne Bergeron14c5d712023-11-13 15:01:152177 EXPECT_TRUE(IsOpenedInCorrectJournalMode(db_.get(), IsWALEnabled()));
Shubham Aggarwalbe4f97c2020-06-19 15:58:572178}
2179
Shubham Aggarwal003708982020-10-28 17:57:542180TEST_P(SQLDatabaseTest, CheckpointDatabase) {
Shubham Aggarwal7b60fe6e2020-10-15 06:00:282181 if (!IsWALEnabled())
2182 return;
Shubham Aggarwalbe4f97c2020-06-19 15:58:572183
Victor Costan49a903a2021-05-07 22:21:002184 base::FilePath wal_path = Database::WriteAheadLogPath(db_path_);
Shubham Aggarwalbe4f97c2020-06-19 15:58:572185
2186 int64_t wal_size = 0;
2187 // WAL file initially empty.
Victor Costan49a903a2021-05-07 22:21:002188 EXPECT_TRUE(base::PathExists(wal_path));
Shubham Aggarwalbe4f97c2020-06-19 15:58:572189 base::GetFileSize(wal_path, &wal_size);
2190 EXPECT_EQ(wal_size, 0);
2191
2192 ASSERT_TRUE(
Victor Costan49a903a2021-05-07 22:21:002193 db_->Execute("CREATE TABLE foo (id INTEGER UNIQUE, value INTEGER)"));
2194 ASSERT_TRUE(db_->Execute("INSERT INTO foo VALUES (1, 1)"));
2195 ASSERT_TRUE(db_->Execute("INSERT INTO foo VALUES (2, 2)"));
Shubham Aggarwalbe4f97c2020-06-19 15:58:572196
2197 // Writes reach WAL file but not db file.
2198 base::GetFileSize(wal_path, &wal_size);
2199 EXPECT_GT(wal_size, 0);
2200
2201 int64_t db_size = 0;
Victor Costan49a903a2021-05-07 22:21:002202 base::GetFileSize(db_path_, &db_size);
2203 EXPECT_EQ(db_size, db_->page_size());
Shubham Aggarwalbe4f97c2020-06-19 15:58:572204
2205 // Checkpoint database to immediately propagate writes to DB file.
Victor Costan49a903a2021-05-07 22:21:002206 EXPECT_TRUE(db_->CheckpointDatabase());
Shubham Aggarwalbe4f97c2020-06-19 15:58:572207
Victor Costan49a903a2021-05-07 22:21:002208 base::GetFileSize(db_path_, &db_size);
2209 EXPECT_GT(db_size, db_->page_size());
2210 EXPECT_EQ(ExecuteWithResult(db_.get(), "SELECT value FROM foo where id=1"),
2211 "1");
2212 EXPECT_EQ(ExecuteWithResult(db_.get(), "SELECT value FROM foo where id=2"),
2213 "2");
Shubham Aggarwalbe4f97c2020-06-19 15:58:572214}
2215
Victor Costan3c802712022-02-24 17:33:062216TEST_P(SQLDatabaseTest, OpenFailsAfterCorruptSizeInHeader) {
2217 // The database file ends up empty if we don't create at least one table.
2218 ASSERT_TRUE(
2219 db_->Execute("CREATE TABLE rows(i INTEGER PRIMARY KEY NOT NULL)"));
Victor Costan49a903a2021-05-07 22:21:002220 db_->Close();
Shubham Aggarwal1c06850ffa2020-07-07 13:42:572221
Victor Costan49a903a2021-05-07 22:21:002222 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
Shubham Aggarwal1c06850ffa2020-07-07 13:42:572223 {
2224 sql::test::ScopedErrorExpecter expecter;
2225 expecter.ExpectError(SQLITE_CORRUPT);
Dan McArdle4feabeb52024-01-03 15:17:132226 ASSERT_FALSE(db_->Open(db_path_));
Shubham Aggarwal1c06850ffa2020-07-07 13:42:572227 EXPECT_TRUE(expecter.SawExpectedErrors());
2228 }
2229}
2230
Dan McArdle4feabeb52024-01-03 15:17:132231TEST_P(SQLDatabaseTest, OpenWithRecoveryHandlesCorruption) {
2232 for (const bool corrupt_after_recovery : {false, true}) {
2233 SCOPED_TRACE(::testing::Message()
2234 << "corrupt_after_recovery: " << corrupt_after_recovery);
2235 // Ensure that `db_` is fresh in this iteration.
2236 CreateFreshDB();
2237 // The database file ends up empty if we don't create at least one table.
2238 ASSERT_TRUE(
2239 db_->Execute("CREATE TABLE rows(i INTEGER PRIMARY KEY NOT NULL)"));
2240 db_->Close();
2241
2242 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
2243
2244 size_t error_count = 0;
2245 auto callback = base::BindLambdaForTesting([&](int error, Statement* stmt) {
2246 error_count++;
2247 ASSERT_TRUE(BuiltInRecovery::RecoverIfPossible(
2248 db_.get(), error, sql::BuiltInRecovery::Strategy::kRecoverOrRaze));
2249 if (corrupt_after_recovery) {
2250 // Corrupt the file again after temporarily recovering it.
2251 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
2252 }
2253 });
2254 db_->set_error_callback(std::move(callback));
2255
2256 {
2257 sql::test::ScopedErrorExpecter expecter;
2258 expecter.ExpectError(SQLITE_CORRUPT);
2259
2260 // When `corrupt_after_recovery` is true, `Database::Open()` will return
2261 // false because both attempts at opening the database will fail. When the
2262 // database is *not* corrupted after recovery, recovery will succeed and
2263 // thus `Database::Open()`'s second attempt at opening the database will
2264 // succeed.
2265 ASSERT_EQ(db_->Open(db_path_), !corrupt_after_recovery);
2266 EXPECT_TRUE(expecter.SawExpectedErrors());
2267 }
2268 EXPECT_EQ(error_count, 1u);
2269 EXPECT_FALSE(db_->has_error_callback());
2270 }
2271}
2272
Victor Costan3c802712022-02-24 17:33:062273TEST_P(SQLDatabaseTest, ExecuteFailsAfterCorruptSizeInHeader) {
2274 ASSERT_TRUE(
2275 db_->Execute("CREATE TABLE rows(i INTEGER PRIMARY KEY NOT NULL)"));
2276 constexpr static char kSelectSql[] = "SELECT * from rows";
2277 EXPECT_TRUE(db_->Execute(kSelectSql))
2278 << "The test Execute() statement fails before the header is corrupted";
2279 db_->Close();
2280
2281 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
2282 {
2283 sql::test::ScopedErrorExpecter expecter;
2284 expecter.ExpectError(SQLITE_CORRUPT);
Dan McArdle4feabeb52024-01-03 15:17:132285 ASSERT_FALSE(db_->Open(db_path_));
Victor Costan3c802712022-02-24 17:33:062286 EXPECT_TRUE(expecter.SawExpectedErrors())
2287 << "Database::Open() did not encounter SQLITE_CORRUPT";
2288 }
2289 {
2290 sql::test::ScopedErrorExpecter expecter;
2291 expecter.ExpectError(SQLITE_CORRUPT);
2292 EXPECT_FALSE(db_->Execute(kSelectSql));
2293 EXPECT_TRUE(expecter.SawExpectedErrors())
2294 << "Database::Execute() did not encounter SQLITE_CORRUPT";
2295 }
2296}
2297
2298TEST_P(SQLDatabaseTest, SchemaFailsAfterCorruptSizeInHeader) {
2299 ASSERT_TRUE(
2300 db_->Execute("CREATE TABLE rows(i INTEGER PRIMARY KEY NOT NULL)"));
2301 ASSERT_TRUE(db_->DoesTableExist("rows"))
2302 << "The test schema check fails before the header is corrupted";
2303 db_->Close();
2304
2305 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
2306 {
2307 sql::test::ScopedErrorExpecter expecter;
2308 expecter.ExpectError(SQLITE_CORRUPT);
Dan McArdle4feabeb52024-01-03 15:17:132309 ASSERT_FALSE(db_->Open(db_path_));
Victor Costan3c802712022-02-24 17:33:062310 EXPECT_TRUE(expecter.SawExpectedErrors())
2311 << "Database::Open() did not encounter SQLITE_CORRUPT";
2312 }
2313 {
2314 sql::test::ScopedErrorExpecter expecter;
2315 expecter.ExpectError(SQLITE_CORRUPT);
2316 EXPECT_FALSE(db_->DoesTableExist("rows"));
2317 EXPECT_TRUE(expecter.SawExpectedErrors())
2318 << "Database::DoesTableExist() did not encounter SQLITE_CORRUPT";
2319 }
2320}
2321
a20.singhb0ca1122022-05-26 03:32:452322TEST(SQLEmptyPathDatabaseTest, EmptyPathTest) {
2323 Database db;
2324 EXPECT_TRUE(db.OpenInMemory());
2325 EXPECT_TRUE(db.is_open());
2326 EXPECT_TRUE(db.DbPath().empty());
2327}
2328
Victor Costan15d905de2021-01-07 22:18:582329// WAL mode is currently not supported on Fuchsia.
Xiaohan Wang7d09c5e2022-01-08 02:37:362330#if !BUILDFLAG(IS_FUCHSIA)
Victor Costan15d905de2021-01-07 22:18:582331INSTANTIATE_TEST_SUITE_P(JournalMode, SQLDatabaseTest, testing::Bool());
2332INSTANTIATE_TEST_SUITE_P(JournalMode,
2333 SQLDatabaseTestExclusiveMode,
2334 testing::Bool());
2335#else
2336INSTANTIATE_TEST_SUITE_P(JournalMode, SQLDatabaseTest, testing::Values(false));
2337INSTANTIATE_TEST_SUITE_P(JournalMode,
2338 SQLDatabaseTestExclusiveMode,
2339 testing::Values(false));
2340#endif
shessc8cd2a162015-10-22 20:30:462341} // namespace sql