Movatterモバイル変換


[0]ホーム

URL:


Google Git
Sign in
chromium /chromium /src /refs/heads/main /. /sql /database_unittest.cc
blob: 9f1d898e6e40d7ed4891982df85914fb71a94871 [file] [log] [blame]
Avi Drissman69b874f2022-09-15 19:11:14[diff] [blame]1// Copyright 2012 The Chromium Authors
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Arthur Sonzogni68107b02024-08-20 15:38:30[diff] [blame]5#ifdef UNSAFE_BUFFERS_BUILD
6// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
7#pragma allow_unsafe_buffers
8#endif
9
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]10#include"sql/database.h"
11
avi0b519202015-12-21 07:25:19[diff] [blame]12#include<stddef.h>
13#include<stdint.h>
Takuto Ikuta2eb61342024-05-10 09:05:35[diff] [blame]14#include<sys/stat.h>
15#include<sys/types.h>
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]16
Peter Kasting3f01b692025-01-27 19:50:47[diff] [blame]17#include<algorithm>
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]18#include<memory>
Helmut Januschkaec716742024-10-11 06:45:00[diff] [blame]19#include<optional>
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]20#include<string>
Takuto Ikuta2eb61342024-05-10 09:05:35[diff] [blame]21#include<tuple>
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]22#include<utility>
23#include<vector>
avi0b519202015-12-21 07:25:19[diff] [blame]24
Takuto Ikuta2eb61342024-05-10 09:05:35[diff] [blame]25#include"base/check.h"
Ho Cheung47524352023-08-08 03:41:10[diff] [blame]26#include"base/containers/contains.h"
Olivier Li Shing Tat-Dupuise8a59fb12024-12-03 19:38:42[diff] [blame]27#include"base/containers/span.h"
Will Harris711a5ec2023-04-04 21:43:37[diff] [blame]28#include"base/files/file.h"
thestig22dfc4012014-09-05 08:29:44[diff] [blame]29#include"base/files/file_util.h"
brettw@chromium.orgea1a3f62012-11-16 20:34:23[diff] [blame]30#include"base/files/scoped_temp_dir.h"
Dan McArdleb52665c2024-05-23 20:24:31[diff] [blame]31#include"base/functional/bind.h"
32#include"base/functional/callback_helpers.h"
Takuto Ikuta2eb61342024-05-10 09:05:35[diff] [blame]33#include"base/location.h"
shess@chromium.org41a97c812013-02-07 02:35:38[diff] [blame]34#include"base/logging.h"
Dan McArdleb52665c2024-05-23 20:24:31[diff] [blame]35#include"base/memory/raw_ptr.h"
Takuto Ikuta2eb61342024-05-10 09:05:35[diff] [blame]36#include"base/memory/scoped_refptr.h"
37#include"base/run_loop.h"
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]38#include"base/sequence_checker.h"
Olivier Li Shing Tat-Dupuis7b7a35b2024-12-05 06:58:02[diff] [blame]39#include"base/strings/cstring_view.h"
shess7e2baba2016-10-27 23:46:05[diff] [blame]40#include"base/strings/string_number_conversions.h"
Daniel Cheng17390fd2025-06-07 06:38:26[diff] [blame]41#include"base/strings/string_view_util.h"
Dan McArdleba44e47b2024-02-29 17:12:18[diff] [blame]42#include"base/task/sequenced_task_runner.h"
Dan McArdleb52665c2024-05-23 20:24:31[diff] [blame]43#include"base/task/task_traits.h"
Dan McArdleba44e47b2024-02-29 17:12:18[diff] [blame]44#include"base/task/thread_pool.h"
Victor Costanc02b7af2021-07-09 13:26:45[diff] [blame]45#include"base/test/bind.h"
Victor Costan613b4302018-11-20 05:32:43[diff] [blame]46#include"base/test/gtest_util.h"
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]47#include"base/test/metrics/histogram_tester.h"
Dan McArdleba44e47b2024-02-29 17:12:18[diff] [blame]48#include"base/test/task_environment.h"
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]49#include"base/thread_annotations.h"
Takuto Ikuta2eb61342024-05-10 09:05:35[diff] [blame]50#include"base/trace_event/memory_dump_request_args.h"
ssid9f8022f2015-10-12 17:49:03[diff] [blame]51#include"base/trace_event/process_memory_dump.h"
Scott Graham57ee54822017-09-13 06:37:56[diff] [blame]52#include"build/build_config.h"
Victor Costancfbfa602018-08-01 23:24:46[diff] [blame]53#include"sql/database_memory_dump_provider.h"
yongsheng.zhu@intel.com1348765a2012-07-24 08:25:53[diff] [blame]54#include"sql/meta_table.h"
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]55#include"sql/recovery.h"
brettw@chromium.orgea1a3f62012-11-16 20:34:23[diff] [blame]56#include"sql/statement.h"
Takuto Ikuta2eb61342024-05-10 09:05:35[diff] [blame]57#include"sql/statement_id.h"
shess976814402016-06-21 06:56:25[diff] [blame]58#include"sql/test/scoped_error_expecter.h"
kinuko@chromium.orga8848a72013-11-18 04:18:47[diff] [blame]59#include"sql/test/test_helpers.h"
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]60#include"sql/transaction.h"
Victor Costan4b67f542022-02-24 17:40:55[diff] [blame]61#include"testing/gmock/include/gmock/gmock.h"
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]62#include"testing/gtest/include/gtest/gtest.h"
Olivier Li Shing Tat-Dupuise8a59fb12024-12-03 19:38:42[diff] [blame]63#include"third_party/abseil-cpp/absl/cleanup/cleanup.h"
phajdan.jr@chromium.orge33cba42010-08-18 23:37:03[diff] [blame]64#include"third_party/sqlite/sqlite3.h"
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]65
Takuto Ikuta2eb61342024-05-10 09:05:35[diff] [blame]66#if BUILDFLAG(IS_WIN)
67#include"base/strings/strcat.h"
68#endif
69
shess58b8df82015-06-03 00:19:32[diff] [blame]70namespace sql{
Victor Costan7f6abbbe2018-07-29 02:57:27[diff] [blame]71
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]72namespace{
73
shess7e2baba2016-10-27 23:46:05[diff] [blame]74using sql::test::ExecuteWithResult;
75
John Delaney86dbec62021-08-24 15:05:21[diff] [blame]76// Helper to return the count of items in sqlite_schema. Return -1 in
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]77// case of error.
John Delaney86dbec62021-08-24 15:05:21[diff] [blame]78intSqliteSchemaCount(Database* db){
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]79staticconstexprchar kSchemaCount[]="SELECT COUNT(*) FROM sqlite_schema";
John Delaney86dbec62021-08-24 15:05:21[diff] [blame]80Statement s(db->GetUniqueStatement(kSchemaCount));
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]81return s.Step()? s.ColumnInt(0):-1;
82}
83
shess1cf87f22016-10-25 22:18:29[diff] [blame]84// Handle errors by blowing away the database.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]85voidRazeErrorCallback(Database* db,
shess1cf87f22016-10-25 22:18:29[diff] [blame]86int expected_error,
87int error,
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]88Statement* stmt){
shess1cf87f22016-10-25 22:18:29[diff] [blame]89// Nothing here needs extended errors at this time.
Victor Costancfbfa602018-08-01 23:24:46[diff] [blame]90 EXPECT_EQ(expected_error, expected_error&0xff);
91 EXPECT_EQ(expected_error, error&0xff);
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]92 db->RazeAndPoison();
shess1cf87f22016-10-25 22:18:29[diff] [blame]93}
94
Xiaohan Wang7d09c5e2022-01-08 02:37:36[diff] [blame]95#if BUILDFLAG(IS_POSIX)
shess@chromium.org81a2a602013-07-17 19:10:36[diff] [blame]96// Set a umask and restore the old mask on destruction. Cribbed from
97// shared_memory_unittest.cc. Used by POSIX-only UserPermission test.
98classScopedUmaskSetter{
99public:
100explicitScopedUmaskSetter(mode_t target_mask){
101 old_umask_= umask(target_mask);
102}
103~ScopedUmaskSetter(){ umask(old_umask_);}
Victor Costancfbfa602018-08-01 23:24:46[diff] [blame]104
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]105ScopedUmaskSetter(constScopedUmaskSetter&)=delete;
106ScopedUmaskSetter&operator=(constScopedUmaskSetter&)=delete;
107
shess@chromium.org81a2a602013-07-17 19:10:36[diff] [blame]108private:
109mode_t old_umask_;
shess@chromium.org81a2a602013-07-17 19:10:36[diff] [blame]110};
Xiaohan Wang7d09c5e2022-01-08 02:37:36[diff] [blame]111#endif// BUILDFLAG(IS_POSIX)
shess@chromium.org81a2a602013-07-17 19:10:36[diff] [blame]112
Etienne Bergeron14c5d712023-11-13 15:01:15[diff] [blame]113boolIsOpenedInCorrectJournalMode(Database* db,bool is_wal){
114 std::string expected_mode= is_wal?"wal":"truncate";
115returnExecuteWithResult(db,"PRAGMA journal_mode")== expected_mode;
116}
117
shessc8cd2a162015-10-22 20:30:46[diff] [blame]118}// namespace
119
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]120// We use the parameter to run all tests with WAL mode on and off.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]121classSQLDatabaseTest:public testing::Test,
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]122public testing::WithParamInterface<bool>{
123public:
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]124enumclassOverwriteType{
125 kTruncate,
126 kOverwrite,
127};
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]128
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]129~SQLDatabaseTest() override=default;
130
131voidSetUp() override{
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]132 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
133 db_path_= temp_dir_.GetPath().AppendASCII("database_test.sqlite");
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]134CreateFreshDB();
135}
136
137// Resets the database handle and deletes the backing file. On return, `db_`
138// has just been opened on a fresh temp file named by `db_path_`.
139voidCreateFreshDB(){
140 ASSERT_FALSE(db_path_.empty());
141
142 db_.reset();
143 ASSERT_TRUE(base::DeleteFile(db_path_));
144
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]145 db_= std::make_unique<Database>(GetDBOptions(), test::kTestTag);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]146 ASSERT_TRUE(db_->Open(db_path_));
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]147 ASSERT_TRUE(base::PathExists(db_path_));
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]148}
149
150DatabaseOptionsGetDBOptions(){
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]151returnDatabaseOptions()
152.set_wal_mode(IsWALEnabled())
Alison Gale71bd8f152024-04-26 22:38:20[diff] [blame]153// TODO(crbug.com/40146017): Remove after switching to exclusive mode on by
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]154// default.
Xiaohan Wang7d09c5e2022-01-08 02:37:36[diff] [blame]155#if BUILDFLAG(IS_FUCHSIA) // Exclusive mode needs to be enabled to enter WAL
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]156.set_exclusive_locking(IsWALEnabled())
157#else
158.set_exclusive_locking(false)
Xiaohan Wang7d09c5e2022-01-08 02:37:36[diff] [blame]159#endif// BUILDFLAG(IS_FUCHSIA)
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]160;
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]161}
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]162
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]163boolIsWALEnabled(){returnGetParam();}
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]164
165boolTruncateDatabase(){
166 base::File file(db_path_,
167 base::File::FLAG_CREATE_ALWAYS| base::File::FLAG_WRITE);
168return file.SetLength(0);
169}
170
171boolOverwriteDatabaseHeader(OverwriteType type){
172 base::File file(db_path_,
173 base::File::FLAG_CREATE_ALWAYS| base::File::FLAG_WRITE);
174if(type==OverwriteType::kTruncate){
175if(!file.SetLength(0))
176returnfalse;
177}
178
179staticconstexprchar kText[]="Now is the winter of our discontent.";
180constexprint kTextBytes=sizeof(kText)-1;
181return file.Write(0, kText, kTextBytes)== kTextBytes;
182}
183
184protected:
185 base::ScopedTempDir temp_dir_;
186 base::FilePath db_path_;
187 std::unique_ptr<Database> db_;
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]188};
189
Victor Costan289f2c8b2021-07-22 06:33:47[diff] [blame]190TEST_P(SQLDatabaseTest,Execute_ValidStatement){
191 ASSERT_TRUE(db_->Execute("CREATE TABLE data(contents TEXT)"));
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]192 EXPECT_EQ(SQLITE_OK, db_->GetErrorCode());
Victor Costan289f2c8b2021-07-22 06:33:47[diff] [blame]193}
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]194
Victor Costan289f2c8b2021-07-22 06:33:47[diff] [blame]195TEST_P(SQLDatabaseTest,Execute_InvalidStatement){
Victor Costan205b96dc2021-07-21 20:27:46[diff] [blame]196{
197 sql::test::ScopedErrorExpecter error_expecter;
198 error_expecter.ExpectError(SQLITE_ERROR);
Victor Costan289f2c8b2021-07-22 06:33:47[diff] [blame]199 EXPECT_FALSE(db_->Execute("CREATE TABLE data("));
Victor Costan205b96dc2021-07-21 20:27:46[diff] [blame]200 EXPECT_TRUE(error_expecter.SawExpectedErrors());
201}
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]202 EXPECT_EQ(SQLITE_ERROR, db_->GetErrorCode());
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]203}
204
Victor Costan289f2c8b2021-07-22 06:33:47[diff] [blame]205TEST_P(SQLDatabaseTest,ExecuteScriptForTesting_OneLineValid){
206 ASSERT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data(contents TEXT)"));
207 EXPECT_EQ(SQLITE_OK, db_->GetErrorCode());
208}
209
210TEST_P(SQLDatabaseTest,ExecuteScriptForTesting_OneLineInvalid){
211 ASSERT_FALSE(db_->ExecuteScriptForTesting("CREATE TABLE data("));
212 EXPECT_EQ(SQLITE_ERROR, db_->GetErrorCode());
213}
214
215TEST_P(SQLDatabaseTest,ExecuteScriptForTesting_ExtraContents){
216 EXPECT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data1(id)"))
217<<"Minimal statement";
218 EXPECT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data2(id);"))
219<<"Extra semicolon";
220 EXPECT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data3(id) -- Comment"))
221<<"Trailing comment";
222
223 EXPECT_TRUE(db_->ExecuteScriptForTesting(
224"CREATE TABLE data4(id);CREATE TABLE data5(id)"))
225<<"Extra statement without whitespace";
226 EXPECT_TRUE(db_->ExecuteScriptForTesting(
227"CREATE TABLE data6(id); CREATE TABLE data7(id)"))
228<<"Extra statement separated by whitespace";
229
230 EXPECT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data8(id);-- Comment"))
231<<"Comment without whitespace";
232 EXPECT_TRUE(
233 db_->ExecuteScriptForTesting("CREATE TABLE data9(id); -- Comment"))
234<<"Comment sepatated by whitespace";
235}
236
237TEST_P(SQLDatabaseTest,ExecuteScriptForTesting_MultipleValidLines){
238 EXPECT_TRUE(db_->ExecuteScriptForTesting(R"(
239 CREATE TABLE data1(contents TEXT);
240 CREATE TABLE data2(contents TEXT);
241 CREATE TABLE data3(contents TEXT);
242)"));
243 EXPECT_EQ(SQLITE_OK, db_->GetErrorCode());
244
245// DoesColumnExist() is implemented directly on top of a SQLite call. The
246// other schema functions use sql::Statement infrastructure to query the
247// schema table.
248 EXPECT_TRUE(db_->DoesColumnExist("data1","contents"));
249 EXPECT_TRUE(db_->DoesColumnExist("data2","contents"));
250 EXPECT_TRUE(db_->DoesColumnExist("data3","contents"));
251}
252
253TEST_P(SQLDatabaseTest,ExecuteScriptForTesting_StopsOnCompileError){
254 EXPECT_FALSE(db_->ExecuteScriptForTesting(R"(
255 CREATE TABLE data1(contents TEXT);
256 CREATE TABLE data1();
257 CREATE TABLE data3(contents TEXT);
258)"));
259 EXPECT_EQ(SQLITE_ERROR, db_->GetErrorCode());
260
261 EXPECT_TRUE(db_->DoesColumnExist("data1","contents"));
262 EXPECT_FALSE(db_->DoesColumnExist("data3","contents"));
263}
264
265TEST_P(SQLDatabaseTest,ExecuteScriptForTesting_StopsOnStepError){
266 EXPECT_FALSE(db_->ExecuteScriptForTesting(R"(
267 CREATE TABLE data1(contents TEXT UNIQUE);
268 INSERT INTO data1(contents) VALUES('value1');
269 INSERT INTO data1(contents) VALUES('value1');
270 CREATE TABLE data3(contents TEXT);
271)"));
272 EXPECT_EQ(SQLITE_CONSTRAINT_UNIQUE, db_->GetErrorCode());
273
274 EXPECT_TRUE(db_->DoesColumnExist("data1","contents"));
275 EXPECT_FALSE(db_->DoesColumnExist("data3","contents"));
276}
277
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]278TEST_P(SQLDatabaseTest,CachedStatement){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]279StatementID id1= SQL_FROM_HERE;
280StatementID id2= SQL_FROM_HERE;
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]281staticconstexprchar kId1Sql[]="SELECT a FROM foo";
282staticconstexprchar kId2Sql[]="SELECT b FROM foo";
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]283
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]284 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
285 ASSERT_TRUE(db_->Execute("INSERT INTO foo(a, b) VALUES (12, 13)"));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]286
Victor Costan87cf8c72018-07-19 19:36:04[diff] [blame]287 sqlite3_stmt* raw_id1_statement;
288 sqlite3_stmt* raw_id2_statement;
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]289{
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]290 scoped_refptr<Database::StatementRef> ref_from_id1=
291 db_->GetCachedStatement(id1, kId1Sql);
Victor Costan87cf8c72018-07-19 19:36:04[diff] [blame]292 raw_id1_statement= ref_from_id1->stmt();
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]293
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]294Statement from_id1(std::move(ref_from_id1));
Victor Costan87cf8c72018-07-19 19:36:04[diff] [blame]295 ASSERT_TRUE(from_id1.is_valid());
296 ASSERT_TRUE(from_id1.Step());
297 EXPECT_EQ(12, from_id1.ColumnInt(0));
298
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]299 scoped_refptr<Database::StatementRef> ref_from_id2=
300 db_->GetCachedStatement(id2, kId2Sql);
Victor Costan87cf8c72018-07-19 19:36:04[diff] [blame]301 raw_id2_statement= ref_from_id2->stmt();
302 EXPECT_NE(raw_id1_statement, raw_id2_statement);
303
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]304Statement from_id2(std::move(ref_from_id2));
Victor Costan87cf8c72018-07-19 19:36:04[diff] [blame]305 ASSERT_TRUE(from_id2.is_valid());
306 ASSERT_TRUE(from_id2.Step());
307 EXPECT_EQ(13, from_id2.ColumnInt(0));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]308}
309
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]310{
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]311 scoped_refptr<Database::StatementRef> ref_from_id1=
312 db_->GetCachedStatement(id1, kId1Sql);
Victor Costan87cf8c72018-07-19 19:36:04[diff] [blame]313 EXPECT_EQ(raw_id1_statement, ref_from_id1->stmt())
314<<"statement was not cached";
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]315
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]316Statement from_id1(std::move(ref_from_id1));
Victor Costan87cf8c72018-07-19 19:36:04[diff] [blame]317 ASSERT_TRUE(from_id1.is_valid());
318 ASSERT_TRUE(from_id1.Step())<<"cached statement was not reset";
319 EXPECT_EQ(12, from_id1.ColumnInt(0));
320
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]321 scoped_refptr<Database::StatementRef> ref_from_id2=
322 db_->GetCachedStatement(id2, kId2Sql);
Victor Costan87cf8c72018-07-19 19:36:04[diff] [blame]323 EXPECT_EQ(raw_id2_statement, ref_from_id2->stmt())
324<<"statement was not cached";
325
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]326Statement from_id2(std::move(ref_from_id2));
Victor Costan87cf8c72018-07-19 19:36:04[diff] [blame]327 ASSERT_TRUE(from_id2.is_valid());
328 ASSERT_TRUE(from_id2.Step())<<"cached statement was not reset";
329 EXPECT_EQ(13, from_id2.ColumnInt(0));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]330}
Victor Costan613b4302018-11-20 05:32:43[diff] [blame]331
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]332 EXPECT_DCHECK_DEATH(db_->GetCachedStatement(id1, kId2Sql))
Victor Costan613b4302018-11-20 05:32:43[diff] [blame]333<<"Using a different SQL with the same statement ID should DCHECK";
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]334 EXPECT_DCHECK_DEATH(db_->GetCachedStatement(id2, kId1Sql))
Victor Costan613b4302018-11-20 05:32:43[diff] [blame]335<<"Using a different SQL with the same statement ID should DCHECK";
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]336}
337
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]338TEST_P(SQLDatabaseTest,IsSQLValidTest){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]339 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
340 ASSERT_TRUE(db_->IsSQLValid("SELECT a FROM foo"));
341 ASSERT_FALSE(db_->IsSQLValid("SELECT no_exist FROM foo"));
shess@chromium.orgeff1fa522011-12-12 23:50:59[diff] [blame]342}
343
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]344TEST_P(SQLDatabaseTest,DoesTableExist){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]345 EXPECT_FALSE(db_->DoesTableExist("foo"));
346 EXPECT_FALSE(db_->DoesTableExist("foo_index"));
shessa62504d2016-11-07 19:26:12[diff] [blame]347
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]348 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
349 ASSERT_TRUE(db_->Execute("CREATE INDEX foo_index ON foo (a)"));
350 EXPECT_TRUE(db_->DoesTableExist("foo"));
351 EXPECT_FALSE(db_->DoesTableExist("foo_index"));
Victor Costanf85512e52019-04-10 20:51:36[diff] [blame]352
353// DoesTableExist() is case-sensitive.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]354 EXPECT_FALSE(db_->DoesTableExist("Foo"));
355 EXPECT_FALSE(db_->DoesTableExist("FOO"));
Victor Costan70bedf22018-07-18 21:21:14[diff] [blame]356}
357
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]358TEST_P(SQLDatabaseTest,DoesIndexExist){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]359 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
360 EXPECT_FALSE(db_->DoesIndexExist("foo"));
361 EXPECT_FALSE(db_->DoesIndexExist("foo_ubdex"));
Victor Costan70bedf22018-07-18 21:21:14[diff] [blame]362
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]363 ASSERT_TRUE(db_->Execute("CREATE INDEX foo_index ON foo (a)"));
364 EXPECT_TRUE(db_->DoesIndexExist("foo_index"));
365 EXPECT_FALSE(db_->DoesIndexExist("foo"));
Victor Costanf85512e52019-04-10 20:51:36[diff] [blame]366
367// DoesIndexExist() is case-sensitive.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]368 EXPECT_FALSE(db_->DoesIndexExist("Foo_index"));
369 EXPECT_FALSE(db_->DoesIndexExist("Foo_Index"));
370 EXPECT_FALSE(db_->DoesIndexExist("FOO_INDEX"));
Victor Costan70bedf22018-07-18 21:21:14[diff] [blame]371}
372
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]373TEST_P(SQLDatabaseTest,DoesViewExist){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]374 EXPECT_FALSE(db_->DoesViewExist("voo"));
375 ASSERT_TRUE(db_->Execute("CREATE VIEW voo (a) AS SELECT 1"));
376 EXPECT_FALSE(db_->DoesIndexExist("voo"));
377 EXPECT_FALSE(db_->DoesTableExist("voo"));
378 EXPECT_TRUE(db_->DoesViewExist("voo"));
Victor Costanf85512e52019-04-10 20:51:36[diff] [blame]379
380// DoesTableExist() is case-sensitive.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]381 EXPECT_FALSE(db_->DoesViewExist("Voo"));
382 EXPECT_FALSE(db_->DoesViewExist("VOO"));
Victor Costan70bedf22018-07-18 21:21:14[diff] [blame]383}
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]384
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]385TEST_P(SQLDatabaseTest,DoesColumnExist){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]386 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
Victor Costan70bedf22018-07-18 21:21:14[diff] [blame]387
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]388 EXPECT_FALSE(db_->DoesColumnExist("foo","bar"));
389 EXPECT_TRUE(db_->DoesColumnExist("foo","a"));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]390
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]391 ASSERT_FALSE(db_->DoesTableExist("bar"));
392 EXPECT_FALSE(db_->DoesColumnExist("bar","b"));
shess92a2ab12015-04-09 01:59:47[diff] [blame]393
Victor Costanf85512e52019-04-10 20:51:36[diff] [blame]394// SQLite resolves table/column names without case sensitivity.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]395 EXPECT_TRUE(db_->DoesColumnExist("FOO","A"));
396 EXPECT_TRUE(db_->DoesColumnExist("FOO","a"));
397 EXPECT_TRUE(db_->DoesColumnExist("foo","A"));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]398}
399
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]400TEST_P(SQLDatabaseTest,GetLastInsertRowId){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]401 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]402
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]403 ASSERT_TRUE(db_->Execute("INSERT INTO foo (value) VALUES (12)"));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]404
405// Last insert row ID should be valid.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]406int64_t row= db_->GetLastInsertRowId();
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]407 EXPECT_LT(0, row);
408
409// It should be the primary key of the row we just inserted.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]410Statement s(db_->GetUniqueStatement("SELECT value FROM foo WHERE id=?"));
brettw@chromium.orge5ffd0e42009-09-11 21:30:56[diff] [blame]411 s.BindInt64(0, row);
412 ASSERT_TRUE(s.Step());
413 EXPECT_EQ(12, s.ColumnInt(0));
414}
michaelbai@chromium.org44ad7d902012-03-23 00:09:05[diff] [blame]415
shess976814402016-06-21 06:56:25[diff] [blame]416// Test the scoped error expecter by attempting to insert a duplicate
shess@chromium.org4350e322013-06-18 22:18:10[diff] [blame]417// value into an index.
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]418TEST_P(SQLDatabaseTest,ScopedErrorExpecter){
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]419staticconstexprchar kCreateSql[]="CREATE TABLE foo (id INTEGER UNIQUE)";
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]420 ASSERT_TRUE(db_->Execute(kCreateSql));
421 ASSERT_TRUE(db_->Execute("INSERT INTO foo (id) VALUES (12)"));
shess@chromium.org4350e322013-06-18 22:18:10[diff] [blame]422
shess92a2ab12015-04-09 01:59:47[diff] [blame]423{
shess976814402016-06-21 06:56:25[diff] [blame]424 sql::test::ScopedErrorExpecter expecter;
425 expecter.ExpectError(SQLITE_CONSTRAINT);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]426 ASSERT_FALSE(db_->Execute("INSERT INTO foo (id) VALUES (12)"));
shess976814402016-06-21 06:56:25[diff] [blame]427 ASSERT_TRUE(expecter.SawExpectedErrors());
shess92a2ab12015-04-09 01:59:47[diff] [blame]428}
429}
430
Victor Costan106e50072021-07-17 00:04:49[diff] [blame]431TEST_P(SQLDatabaseTest,SchemaIntrospectionUsesErrorExpecter){
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]432staticconstexprchar kCreateSql[]="CREATE TABLE foo (id INTEGER UNIQUE)";
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]433 ASSERT_TRUE(db_->Execute(kCreateSql));
434 ASSERT_FALSE(db_->DoesTableExist("bar"));
435 ASSERT_TRUE(db_->DoesTableExist("foo"));
436 ASSERT_TRUE(db_->DoesColumnExist("foo","id"));
437 db_->Close();
shess92a2ab12015-04-09 01:59:47[diff] [blame]438
439// Corrupt the database so that nothing works, including PRAGMAs.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]440 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
shess92a2ab12015-04-09 01:59:47[diff] [blame]441
442{
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]443 base::HistogramTester tester;
shess976814402016-06-21 06:56:25[diff] [blame]444 sql::test::ScopedErrorExpecter expecter;
445 expecter.ExpectError(SQLITE_CORRUPT);
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]446 ASSERT_FALSE(db_->Open(db_path_));
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]447 ASSERT_FALSE(db_->DoesTableExist("bar"));
448 ASSERT_FALSE(db_->DoesTableExist("foo"));
449 ASSERT_FALSE(db_->DoesColumnExist("foo","id"));
shess976814402016-06-21 06:56:25[diff] [blame]450 ASSERT_TRUE(expecter.SawExpectedErrors());
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]451 tester.ExpectUniqueSample("Sql.Database.Open.FirstAttempt.Error.Test",
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]452SqliteResultCode::kCorrupt,1);
shess92a2ab12015-04-09 01:59:47[diff] [blame]453}
shess@chromium.org4350e322013-06-18 22:18:10[diff] [blame]454}
455
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]456TEST_P(SQLDatabaseTest,SetErrorCallback){
457staticconstexprchar kCreateSql[]=
458"CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)";
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]459 ASSERT_TRUE(db_->Execute(kCreateSql));
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]460 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
shess@chromium.org98cf3002013-07-12 01:38:56[diff] [blame]461
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]462bool error_callback_called=false;
shess@chromium.org98cf3002013-07-12 01:38:56[diff] [blame]463int error= SQLITE_OK;
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]464 db_->set_error_callback(base::BindLambdaForTesting(
465[&](int sqlite_error, sql::Statement* statement){
466 error_callback_called=true;
467 error= sqlite_error;
468}));
469 EXPECT_FALSE(db_->Execute("INSERT INTO rows(id) VALUES(12)"))
470<<"Inserting a duplicate primary key should have failed";
471 EXPECT_TRUE(error_callback_called)
472<<"Execute() should report errors to the database error callback";
473 EXPECT_EQ(SQLITE_CONSTRAINT_PRIMARYKEY, error)
474<<"Execute() should report errors to the database error callback";
475}
Dominique Fauteux-Chapleau289636512022-03-08 19:27:30[diff] [blame]476
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]477TEST_P(SQLDatabaseTest,SetErrorCallbackDchecksOnExistingCallback){
478 db_->set_error_callback(base::DoNothing());
479 EXPECT_DCHECK_DEATH(db_->set_error_callback(base::DoNothing()))
480<<"set_error_callback() should DCHECK if error callback already exists";
481}
Dominique Fauteux-Chapleau289636512022-03-08 19:27:30[diff] [blame]482
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]483TEST_P(SQLDatabaseTest,ResetErrorCallback){
484staticconstexprchar kCreateSql[]=
485"CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)";
486 ASSERT_TRUE(db_->Execute(kCreateSql));
487 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
488
489bool error_callback_called=false;
490int error= SQLITE_OK;
491 db_->set_error_callback(
492 base::BindLambdaForTesting([&](int sqlite_error,Statement* statement){
493 error_callback_called=true;
494 error= sqlite_error;
495}));
496 db_->reset_error_callback();
497
Dominique Fauteux-Chapleau289636512022-03-08 19:27:30[diff] [blame]498{
shess976814402016-06-21 06:56:25[diff] [blame]499 sql::test::ScopedErrorExpecter expecter;
500 expecter.ExpectError(SQLITE_CONSTRAINT);
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]501 EXPECT_FALSE(db_->Execute("INSERT INTO rows(id) VALUES(12)"))
502<<"Inserting a duplicate primary key should have failed";
503 EXPECT_TRUE(expecter.SawExpectedErrors())
504<<"Inserting a duplicate primary key should have failed";
505}
506 EXPECT_FALSE(error_callback_called)
507<<"Execute() should not report errors after reset_error_callback()";
508 EXPECT_EQ(SQLITE_OK, error)
509<<"Execute() should not report errors after reset_error_callback()";
510}
511
Dan McArdle643e8742024-01-31 18:52:43[diff] [blame]512// Regression test for https://crbug.com/1522873
513TEST_P(SQLDatabaseTest,ErrorCallbackThatClosesDb){
514for(constbool reopen_db:{false,true}){
515 SCOPED_TRACE(::testing::Message()<<"reopen_db: "<< reopen_db);
516// Ensure that `db_` is fresh in this iteration.
517CreateFreshDB();
518staticconstexprchar kCreateSql[]=
519"CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)";
520 ASSERT_TRUE(db_->Execute(kCreateSql));
521 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
522
523bool error_callback_called=false;
524int error= SQLITE_OK;
525 db_->set_error_callback(
526 base::BindLambdaForTesting([&](int sqlite_error,Statement* statement){
527 error_callback_called=true;
528 error= sqlite_error;
529 db_->Close();
530if(reopen_db){
531 ASSERT_TRUE(db_->Open(db_path_));
532}
533}));
534
535{
536 sql::test::ScopedErrorExpecter expecter;
537 expecter.ExpectError(SQLITE_CONSTRAINT);
538 EXPECT_FALSE(db_->Execute("INSERT INTO rows(id) VALUES(12)"))
539<<"Inserting a duplicate primary key should have failed";
540 EXPECT_TRUE(expecter.SawExpectedErrors())
541<<"Inserting a duplicate primary key should have failed";
542}
543 EXPECT_TRUE(error_callback_called);
544 EXPECT_EQ(SQLITE_CONSTRAINT_PRIMARYKEY, error);
545 EXPECT_EQ(db_->is_open(), reopen_db);
546}
547}
548
Dan McArdleba44e47b2024-02-29 17:12:18[diff] [blame]549TEST_P(SQLDatabaseTest,DetachFromSequence){
550 base::test::TaskEnvironment task_environment;
551
552// Get a task runner so we can post tasks to different sequence.
553 scoped_refptr<base::SequencedTaskRunner> task_runner=
554 base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
555 ASSERT_FALSE(task_runner->RunsTasksInCurrentSequence());
556
557// The database's sequence checker is already implicitly attached to the
558// current sequence because the test fixture opened it.
559 ASSERT_TRUE(db_->is_open());
560
561// Detach before moving the Database instance to another sequence. Note that
562// it will be destroyed on the other sequence.
563 db_->DetachFromSequence();
564 base::RunLoop run_loop;
565 task_runner->PostTaskAndReply(
566 FROM_HERE,
567 base::BindOnce(
568[](std::unique_ptr<Database> db){
569staticconstexprchar kCreateSql[]=
570"CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)";
571 ASSERT_TRUE(db->Execute(kCreateSql));
572},
573 std::move(db_)),
574 run_loop.QuitClosure());
575 run_loop.Run();
576}
577
Dan McArdle643e8742024-01-31 18:52:43[diff] [blame]578// Regression test for https://crbug.com/1522873
579TEST_P(SQLDatabaseTest,ErrorCallbackThatFreesDatabase){
580staticconstexprchar kCreateSql[]=
581"CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)";
582 ASSERT_TRUE(db_->Execute(kCreateSql));
583 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
584
585bool error_callback_called=false;
586int error= SQLITE_OK;
587 db_->set_error_callback(
588 base::BindLambdaForTesting([&](int sqlite_error,Statement* statement){
589 error_callback_called=true;
590 error= sqlite_error;
591 db_.reset();
592}));
593
594{
595 sql::test::ScopedErrorExpecter expecter;
596 expecter.ExpectError(SQLITE_CONSTRAINT);
597 EXPECT_FALSE(db_->Execute("INSERT INTO rows(id) VALUES(12)"))
598<<"Inserting a duplicate primary key should have failed";
599 EXPECT_TRUE(expecter.SawExpectedErrors())
600<<"Inserting a duplicate primary key should have failed";
601}
602 EXPECT_TRUE(error_callback_called);
603 EXPECT_EQ(SQLITE_CONSTRAINT_PRIMARYKEY, error);
604}
605
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]606// Sets a flag to true/false to track being alive.
607classLifeTracker{
608public:
609explicitLifeTracker(bool* flag_ptr): flag_ptr_(flag_ptr){
610 DCHECK(flag_ptr!=nullptr);
611 DCHECK(!*flag_ptr)
612<<"LifeTracker's flag should be set to false prior to construction";
613*flag_ptr_=true;
shess@chromium.org98cf3002013-07-12 01:38:56[diff] [blame]614}
615
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]616LifeTracker(LifeTracker&& rhs){
617 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
618 DCHECK_CALLED_ON_VALID_SEQUENCE(rhs.sequence_checker_);
619 flag_ptr_= rhs.flag_ptr_;
620 rhs.flag_ptr_=nullptr;
shess@chromium.org98cf3002013-07-12 01:38:56[diff] [blame]621}
622
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]623// base::RepeatingCallback only requires move-construction support.
624LifeTracker&operator=(constLifeTracker& rhs)=delete;
shess@chromium.org98cf3002013-07-12 01:38:56[diff] [blame]625
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]626~LifeTracker(){
627 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
628if(flag_ptr_)
629*flag_ptr_=false;
shess@chromium.org98cf3002013-07-12 01:38:56[diff] [blame]630}
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]631
632private:
633 SEQUENCE_CHECKER(sequence_checker_);
634 raw_ptr<bool> flag_ptr_ GUARDED_BY_CONTEXT(sequence_checker_);
635};
636
Olivier Li Shing Tat-Dupuise8a59fb12024-12-03 19:38:42[diff] [blame]637intTestVfsOpen(sqlite3_vfs* vfs,
638constchar* full_path,
639 sqlite3_file* result_file,
640int requested_flags,
641int* granted_flags){
642uint64_t* call_count=reinterpret_cast<uint64_t*>(vfs->pAppData);
643++*call_count;
644return SQLITE_ERROR;
645}
646intTestVfsFullPathname(sqlite3_vfs* vfs,
647constchar* file_path,
648int result_size,
649char* result){
650uint64_t* call_count=reinterpret_cast<uint64_t*>(vfs->pAppData);
651++*call_count;
652
653if(result_size<0){
654return SQLITE_CANTOPEN;
655}
656
657constsize_t expected_result_size= result_size;
658 base::cstring_view file_path_view(file_path);
659if(expected_result_size< file_path_view.size()+sizeof(*file_path)){
660return SQLITE_CANTOPEN;
661}
662
663// `copy()` returns an output iterator just past the last char copied. Write
664// the string terminator to that location.
Peter Kasting45eb7982025-01-16 18:10:43[diff] [blame]665*std::ranges::copy(file_path_view,
666 base::span(result, expected_result_size).begin())
667.out=0;
Olivier Li Shing Tat-Dupuise8a59fb12024-12-03 19:38:42[diff] [blame]668return SQLITE_OK;
669}
670
671TEST_P(SQLDatabaseTest,UseVfs){
672uint64_t call_count=0;
673
674constexprconstchar kVFSName[]="test_vfs";
675staticconstexprint kSqliteVfsApiVersion=3;
676staticconstexprint kSqliteMaxPathSize=512;
677
678 sqlite3_vfs vfs{
679 kSqliteVfsApiVersion,
680sizeof(sqlite3_vfs),
681 kSqliteMaxPathSize,
682/*pNext=*/nullptr,
683 kVFSName,
684// Provide pointer to `call_count` so it can be modified from within calls
685// to the VFS and used in test assertions.
686/*pAppData=*/&call_count,
687TestVfsOpen,
688/*xDelete*/nullptr,
689/*xAccess*/nullptr,
690TestVfsFullPathname,
691/*xDlOpen=*/nullptr,
692/*xDlError=*/nullptr,
693/*xDlSym=*/nullptr,
694/*xDlClose=*/nullptr,
695/*xRandomness*/nullptr,
696/*xSleep*/nullptr,
697/*xCurrentTime=*/nullptr,
698/*xGetLastError*/nullptr,
699/*xCurrentTimeInt64*/nullptr,
700/*xSetSystemCall=*/nullptr,
701/*xGetSystemCall=*/nullptr,
702/*xNextSystemCall=*/nullptr,
703};
704
705 sqlite3_vfs_register(&vfs,/*makeDflt=*/false);
706 absl::Cleanup vfs_unregisterer=[&vfs](){ sqlite3_vfs_unregister(&vfs);};
707
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]708DatabaseOptions options=GetDBOptions().set_vfs_name_discouraged(kVFSName);
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]709Database other_db(options, test::kTestTag);
Olivier Li Shing Tat-Dupuise8a59fb12024-12-03 19:38:42[diff] [blame]710
711// Since the vfs's Open function is not implemented `Open()` will fail.
712 ASSERT_FALSE(other_db.Open(db_path_));
713
714// Vfs implementation called twice, once for open and once for path name.
715 ASSERT_EQ(call_count,2ull);
716}
717
Victor Costand09770c2022-03-08 23:14:46[diff] [blame]718// base::BindRepeating() can curry arguments to be passed by const reference to
719// the callback function. If the error callback function calls
720// reset_error_callback() and the Database doesn't hang onto the callback while
721// running it, the storage for those arguments may be deleted while the callback
722// function is executing. This test ensures that the database is hanging onto
723// the callback while running it.
724TEST_P(SQLDatabaseTest,ErrorCallbackStorageProtectedWhileRun){
725bool is_alive=false;
726 db_->set_error_callback(base::BindRepeating(
727[](Database* db,bool* life_tracker_is_alive,
728constLifeTracker& life_tracker,int sqlite_error,
729Statement* statement){
730 EXPECT_TRUE(*life_tracker_is_alive)
731<<"The error callback storage should be alive when it is Run()";
732 db->reset_error_callback();
733 EXPECT_TRUE(*life_tracker_is_alive)
734<<"The error storage should remain alive during Run() after "
735<<"reset_error_callback()";
736},
737 base::Unretained(db_.get()), base::Unretained(&is_alive),
738LifeTracker(&is_alive)));
739
740 EXPECT_TRUE(is_alive)
741<<"The error callback storage should be alive after creation";
742 EXPECT_FALSE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
743 EXPECT_FALSE(is_alive)
744<<"The error callback storage should be released after Run() completes";
shess@chromium.org98cf3002013-07-12 01:38:56[diff] [blame]745}
746
Victor Costanc02b7af2021-07-09 13:26:45[diff] [blame]747TEST_P(SQLDatabaseTest,Execute_CompilationError){
748bool error_callback_called=false;
749 db_->set_error_callback(base::BindLambdaForTesting([&](int error,
750 sql::Statement*
751 statement){
752 EXPECT_EQ(SQLITE_ERROR, error);
753 EXPECT_EQ(nullptr, statement);
754 EXPECT_FALSE(error_callback_called)
755<<"SQL compilation errors should call the error callback exactly once";
756 error_callback_called=true;
757}));
758
759{
760 sql::test::ScopedErrorExpecter expecter;
761 expecter.ExpectError(SQLITE_ERROR);
762 EXPECT_FALSE(db_->Execute("SELECT missing_column FROM missing_table"));
763 EXPECT_TRUE(expecter.SawExpectedErrors());
764}
765
766 EXPECT_TRUE(error_callback_called)
767<<"SQL compilation errors should call the error callback";
768}
769
770TEST_P(SQLDatabaseTest,GetUniqueStatement_CompilationError){
771bool error_callback_called=false;
772 db_->set_error_callback(base::BindLambdaForTesting([&](int error,
773 sql::Statement*
774 statement){
775 EXPECT_EQ(SQLITE_ERROR, error);
776 EXPECT_EQ(nullptr, statement);
777 EXPECT_FALSE(error_callback_called)
778<<"SQL compilation errors should call the error callback exactly once";
779 error_callback_called=true;
780}));
781
782{
783 sql::test::ScopedErrorExpecter expecter;
784 expecter.ExpectError(SQLITE_ERROR);
785 sql::Statement statement(
786 db_->GetUniqueStatement("SELECT missing_column FROM missing_table"));
787 EXPECT_FALSE(statement.is_valid());
788 EXPECT_TRUE(expecter.SawExpectedErrors());
789}
790
791 EXPECT_TRUE(error_callback_called)
792<<"SQL compilation errors should call the error callback";
793}
794
795TEST_P(SQLDatabaseTest,GetCachedStatement_CompilationError){
796bool error_callback_called=false;
797 db_->set_error_callback(base::BindLambdaForTesting([&](int error,
798 sql::Statement*
799 statement){
800 EXPECT_EQ(SQLITE_ERROR, error);
801 EXPECT_EQ(nullptr, statement);
802 EXPECT_FALSE(error_callback_called)
803<<"SQL compilation errors should call the error callback exactly once";
804 error_callback_called=true;
805}));
806
807{
808 sql::test::ScopedErrorExpecter expecter;
809 expecter.ExpectError(SQLITE_ERROR);
810 sql::Statement statement(db_->GetCachedStatement(
811 SQL_FROM_HERE,"SELECT missing_column FROM missing_table"));
812 EXPECT_FALSE(statement.is_valid());
813 EXPECT_TRUE(expecter.SawExpectedErrors());
814}
815
816 EXPECT_TRUE(error_callback_called)
817<<"SQL compilation errors should call the error callback";
818}
819
Victor Costan55309322021-07-19 17:58:42[diff] [blame]820TEST_P(SQLDatabaseTest,GetUniqueStatement_ExtraContents){
821 sql::Statement minimal(db_->GetUniqueStatement("SELECT 1"));
822 sql::Statement extra_semicolon(db_->GetUniqueStatement("SELECT 1;"));
823
824// It would be nice to flag trailing comments too, as they cost binary size.
825// However, there's no easy way of doing that.
826 sql::Statement trailing_comment(
827 db_->GetUniqueStatement("SELECT 1 -- Comment"));
828
829 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("SELECT 1;SELECT 2"))
830<<"Extra statement without whitespace";
831 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("SELECT 1; SELECT 2"))
832<<"Extra statement separated by whitespace";
833 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("SELECT 1;-- Comment"))
834<<"Comment without whitespace";
835 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("SELECT 1; -- Comment"))
836<<"Comment separated by whitespace";
837}
838
839TEST_P(SQLDatabaseTest,GetCachedStatement_ExtraContents){
840 sql::Statement minimal(db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1"));
841 sql::Statement extra_semicolon(
842 db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1;"));
843
844// It would be nice to flag trailing comments too, as they cost binary size.
845// However, there's no easy way of doing that.
846 sql::Statement trailing_comment(
847 db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1 -- Comment"));
848
849 EXPECT_DCHECK_DEATH(
850 db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1;SELECT 2"))
851<<"Extra statement without whitespace";
852 EXPECT_DCHECK_DEATH(
853 db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1; SELECT 2"))
854<<"Extra statement separated by whitespace";
855 EXPECT_DCHECK_DEATH(
856 db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1;-- Comment"))
857<<"Comment without whitespace";
858 EXPECT_DCHECK_DEATH(
859 db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1; -- Comment"))
860<<"Comment separated by whitespace";
861}
862
863TEST_P(SQLDatabaseTest,IsSQLValid_ExtraContents){
864 EXPECT_TRUE(db_->IsSQLValid("SELECT 1"));
865 EXPECT_TRUE(db_->IsSQLValid("SELECT 1;"))
866<<"Trailing semicolons are currently tolerated";
867
868// It would be nice to flag trailing comments too, as they cost binary size.
869// However, there's no easy way of doing that.
870 EXPECT_TRUE(db_->IsSQLValid("SELECT 1 -- Comment"))
871<<"Trailing comments are currently tolerated";
872
873 EXPECT_DCHECK_DEATH(db_->IsSQLValid("SELECT 1;SELECT 2"))
874<<"Extra statement without whitespace";
875 EXPECT_DCHECK_DEATH(db_->IsSQLValid("SELECT 1; SELECT 2"))
876<<"Extra statement separated by whitespace";
877 EXPECT_DCHECK_DEATH(db_->IsSQLValid("SELECT 1;-- Comment"))
878<<"Comment without whitespace";
879 EXPECT_DCHECK_DEATH(db_->IsSQLValid("SELECT 1; -- Comment"))
880<<"Comment separated by whitespace";
881}
882
Victor Costan18f9e7a2021-07-22 06:34:17[diff] [blame]883TEST_P(SQLDatabaseTest,GetUniqueStatement_NoContents){
884 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement(""))<<"Empty string";
885 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement(" "))<<"Space";
886 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("\n"))<<"Newline";
887 EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("-- Comment"))<<"Comment";
888}
889
890TEST_P(SQLDatabaseTest,GetCachedStatement_NoContents){
891 EXPECT_DCHECK_DEATH(db_->GetCachedStatement(SQL_FROM_HERE,""))
892<<"Empty string";
893 EXPECT_DCHECK_DEATH(db_->GetCachedStatement(SQL_FROM_HERE," "))<<"Space";
894 EXPECT_DCHECK_DEATH(db_->GetCachedStatement(SQL_FROM_HERE,"\n"))
895<<"Newline";
896 EXPECT_DCHECK_DEATH(db_->GetCachedStatement(SQL_FROM_HERE,"-- Comment"))
897<<"Comment";
898}
899
ssid583f55e2022-04-21 19:59:00[diff] [blame]900TEST_P(SQLDatabaseTest,GetReadonlyStatement){
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]901staticconstexprchar kCreateSql[]=
902"CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
ssid583f55e2022-04-21 19:59:00[diff] [blame]903 ASSERT_TRUE(db_->Execute(kCreateSql));
904 ASSERT_TRUE(db_->Execute("INSERT INTO foo (value) VALUES (12)"));
905
906// PRAGMA statements do not change the database file.
907{
908Statement s(db_->GetReadonlyStatement("PRAGMA analysis_limit"));
909 ASSERT_TRUE(s.Step());
910}
911{
912Statement s(db_->GetReadonlyStatement("PRAGMA analysis_limit=100"));
913 ASSERT_TRUE(s.is_valid());
914}
915
916// Create and insert statements should fail, while the same queries as unique
917// statement succeeds.
918{
919Statement s(db_->GetReadonlyStatement(
920"CREATE TABLE IF NOT EXISTS foo (id INTEGER PRIMARY KEY, value)"));
921 ASSERT_FALSE(s.is_valid());
922Statement s1(db_->GetUniqueStatement(
923"CREATE TABLE IF NOT EXISTS foo (id INTEGER PRIMARY KEY, value)"));
924 ASSERT_TRUE(s1.is_valid());
925}
926{
927Statement s(
928 db_->GetReadonlyStatement("INSERT INTO foo (value) VALUES (12)"));
929 ASSERT_FALSE(s.is_valid());
930Statement s1(
931 db_->GetUniqueStatement("INSERT INTO foo (value) VALUES (12)"));
932 ASSERT_TRUE(s1.is_valid());
933}
934{
935Statement s(
936 db_->GetReadonlyStatement("CREATE VIRTUAL TABLE bar USING module"));
937 ASSERT_FALSE(s.is_valid());
938Statement s1(
939 db_->GetUniqueStatement("CREATE VIRTUAL TABLE bar USING module"));
940 ASSERT_TRUE(s1.is_valid());
941}
942
943// Select statement is successful.
944{
945Statement s(db_->GetReadonlyStatement("SELECT * FROM foo"));
946 ASSERT_TRUE(s.Step());
947 EXPECT_EQ(s.ColumnInt(1),12);
948}
949}
950
Victor Costan18f9e7a2021-07-22 06:34:17[diff] [blame]951TEST_P(SQLDatabaseTest,IsSQLValid_NoContents){
952 EXPECT_DCHECK_DEATH(db_->IsSQLValid(""))<<"Empty string";
953 EXPECT_DCHECK_DEATH(db_->IsSQLValid(" "))<<"Space";
954 EXPECT_DCHECK_DEATH(db_->IsSQLValid("\n"))<<"Newline";
955 EXPECT_DCHECK_DEATH(db_->IsSQLValid("-- Comment"))<<"Comment";
956}
957
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]958// Test that Database::Raze() results in a database without the
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]959// tables from the original database.
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]960TEST_P(SQLDatabaseTest,Raze){
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]961staticconstexprchar kCreateSql[]=
962"CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]963 ASSERT_TRUE(db_->Execute(kCreateSql));
964 ASSERT_TRUE(db_->Execute("INSERT INTO foo (value) VALUES (12)"));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]965
yfriedman@chromium.org69c58452012-08-06 19:22:42[diff] [blame]966int pragma_auto_vacuum=0;
967{
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]968Statement s(db_->GetUniqueStatement("PRAGMA auto_vacuum"));
yfriedman@chromium.org69c58452012-08-06 19:22:42[diff] [blame]969 ASSERT_TRUE(s.Step());
970 pragma_auto_vacuum= s.ColumnInt(0);
971 ASSERT_TRUE(pragma_auto_vacuum==0|| pragma_auto_vacuum==1);
972}
973
974// If auto_vacuum is set, there's an extra page to maintain a freelist.
975constint kExpectedPageCount=2+ pragma_auto_vacuum;
976
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]977{
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]978Statement s(db_->GetUniqueStatement("PRAGMA page_count"));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]979 ASSERT_TRUE(s.Step());
yfriedman@chromium.org69c58452012-08-06 19:22:42[diff] [blame]980 EXPECT_EQ(kExpectedPageCount, s.ColumnInt(0));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]981}
982
983{
John Delaney86dbec62021-08-24 15:05:21[diff] [blame]984Statement s(db_->GetUniqueStatement("SELECT * FROM sqlite_schema"));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]985 ASSERT_TRUE(s.Step());
986 EXPECT_EQ("table", s.ColumnString(0));
987 EXPECT_EQ("foo", s.ColumnString(1));
988 EXPECT_EQ("foo", s.ColumnString(2));
yfriedman@chromium.org69c58452012-08-06 19:22:42[diff] [blame]989// Table "foo" is stored in the last page of the file.
990 EXPECT_EQ(kExpectedPageCount, s.ColumnInt(3));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]991 EXPECT_EQ(kCreateSql, s.ColumnString(4));
992}
993
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]994 ASSERT_TRUE(db_->Raze());
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]995
996{
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]997Statement s(db_->GetUniqueStatement("PRAGMA page_count"));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]998 ASSERT_TRUE(s.Step());
999 EXPECT_EQ(1, s.ColumnInt(0));
1000}
1001
John Delaney86dbec62021-08-24 15:05:21[diff] [blame]1002 ASSERT_EQ(0,SqliteSchemaCount(db_.get()));
yfriedman@chromium.org69c58452012-08-06 19:22:42[diff] [blame]1003
1004{
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1005Statement s(db_->GetUniqueStatement("PRAGMA auto_vacuum"));
yfriedman@chromium.org69c58452012-08-06 19:22:42[diff] [blame]1006 ASSERT_TRUE(s.Step());
shess@chromium.org6d42f152012-11-10 00:38:24[diff] [blame]1007// The new database has the same auto_vacuum as a fresh database.
yfriedman@chromium.org69c58452012-08-06 19:22:42[diff] [blame]1008 EXPECT_EQ(pragma_auto_vacuum, s.ColumnInt(0));
1009}
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1010}
1011
Etienne Bergeronc34759492025-06-16 15:45:17[diff] [blame]1012TEST_P(SQLDatabaseTest,RazeFailedOnPoisoned){
1013// Poison the database.
1014 db_->Poison();
1015
1016 base::HistogramTester tester;
1017 EXPECT_FALSE(db_->Raze());
1018 tester.ExpectTotalCount("Sql.Database.Raze.FailureReason.Test",1);
1019}
1020
Victor Costancdef3842022-03-28 18:51:08[diff] [blame]1021TEST_P(SQLDatabaseTest,RazeDuringSelect){
1022 ASSERT_TRUE(
1023 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1024 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(1)"));
1025 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(2)"));
1026
1027{
1028// SELECT implicitly creates a transaction while it's executing. This
1029// implicit transaction will not be caught by Raze()'s checks.
1030Statement select(db_->GetUniqueStatement("SELECT id FROM rows"));
1031 ASSERT_TRUE(select.Step());
1032 EXPECT_FALSE(db_->Raze())<<"Raze() should fail while SELECT is executing";
1033}
1034
1035{
1036Statement count(db_->GetUniqueStatement("SELECT COUNT(*) FROM rows"));
1037 ASSERT_TRUE(count.Step());
1038 EXPECT_EQ(2, count.ColumnInt(0))<<"Raze() deleted some data";
1039}
1040}
1041
Victor Costancfbfa602018-08-01 23:24:46[diff] [blame]1042// Helper for SQLDatabaseTest.RazePageSize. Creates a fresh db based on
shess7e2baba2016-10-27 23:46:05[diff] [blame]1043// db_prefix, with the given initial page size, and verifies it against the
1044// expected size. Then changes to the final page size and razes, verifying that
1045// the fresh database ends up with the expected final page size.
1046voidTestPageSize(const base::FilePath& db_prefix,
1047int initial_page_size,
1048const std::string& expected_initial_page_size,
1049int final_page_size,
1050const std::string& expected_final_page_size){
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]1051staticconstexprchar kCreateSql[]="CREATE TABLE x (t TEXT)";
1052staticconstexprchar kInsertSql1[]=
1053"INSERT INTO x VALUES ('This is a test')";
1054staticconstexprchar kInsertSql2[]=
1055"INSERT INTO x VALUES ('That was a test')";
shess7e2baba2016-10-27 23:46:05[diff] [blame]1056
1057const base::FilePath db_path= db_prefix.InsertBeforeExtensionASCII(
Raul Tambre6c708e32019-02-08 22:35:14[diff] [blame]1058 base::NumberToString(initial_page_size));
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1059Database::Delete(db_path);
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]1060Database db(DatabaseOptions().set_page_size(initial_page_size),
1061 test::kTestTag);
shess7e2baba2016-10-27 23:46:05[diff] [blame]1062 ASSERT_TRUE(db.Open(db_path));
1063 ASSERT_TRUE(db.Execute(kCreateSql));
1064 ASSERT_TRUE(db.Execute(kInsertSql1));
1065 ASSERT_TRUE(db.Execute(kInsertSql2));
1066 ASSERT_EQ(expected_initial_page_size,
1067ExecuteWithResult(&db,"PRAGMA page_size"));
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]1068 db.Close();
shess7e2baba2016-10-27 23:46:05[diff] [blame]1069
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]1070// Re-open the database while setting a new |options.page_size| in the object.
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]1071Database razed_db(DatabaseOptions().set_page_size(final_page_size),
1072 test::kTestTag);
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]1073 ASSERT_TRUE(razed_db.Open(db_path));
shess7e2baba2016-10-27 23:46:05[diff] [blame]1074// Raze will use the page size set in the connection object, which may not
1075// match the file's page size.
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]1076 ASSERT_TRUE(razed_db.Raze());
shess7e2baba2016-10-27 23:46:05[diff] [blame]1077
1078// SQLite 3.10.2 (at least) has a quirk with the sqlite3_backup() API (used by
1079// Raze()) which causes the destination database to remember the previous
1080// page_size, even if the overwriting database changed the page_size. Access
1081// the actual database to cause the cached value to be updated.
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]1082 EXPECT_EQ("0",
John Delaney86dbec62021-08-24 15:05:21[diff] [blame]1083ExecuteWithResult(&razed_db,"SELECT COUNT(*) FROM sqlite_schema"));
shess7e2baba2016-10-27 23:46:05[diff] [blame]1084
1085 EXPECT_EQ(expected_final_page_size,
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]1086ExecuteWithResult(&razed_db,"PRAGMA page_size"));
1087 EXPECT_EQ("1",ExecuteWithResult(&razed_db,"PRAGMA page_count"));
shess7e2baba2016-10-27 23:46:05[diff] [blame]1088}
1089
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1090// Verify that Recovery maintains the page size, and the virtual table
shess7e2baba2016-10-27 23:46:05[diff] [blame]1091// works with page sizes other than SQLite's default. Also verify the case
1092// where the default page size has changed.
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1093TEST_P(SQLDatabaseTest,RazePageSize){
shess7e2baba2016-10-27 23:46:05[diff] [blame]1094const std::string default_page_size=
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1095ExecuteWithResult(db_.get(),"PRAGMA page_size");
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1096
Victor Costan7f6abbbe2018-07-29 02:57:27[diff] [blame]1097// Sync uses 32k pages.
shess7e2baba2016-10-27 23:46:05[diff] [blame]1098 EXPECT_NO_FATAL_FAILURE(
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1099TestPageSize(db_path_,32768,"32768",32768,"32768"));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1100
shess7e2baba2016-10-27 23:46:05[diff] [blame]1101// Many clients use 4k pages. This is the SQLite default after 3.12.0.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1102 EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_,4096,"4096",4096,"4096"));
shess7e2baba2016-10-27 23:46:05[diff] [blame]1103
1104// 1k is the default page size before 3.12.0.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1105 EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_,1024,"1024",1024,"1024"));
shess7e2baba2016-10-27 23:46:05[diff] [blame]1106
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1107 EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_,2048,"2048",4096,"4096"));
shess7e2baba2016-10-27 23:46:05[diff] [blame]1108
Victor Costan7f6abbbe2018-07-29 02:57:27[diff] [blame]1109// Databases with no page size specified should result in the default
shess7e2baba2016-10-27 23:46:05[diff] [blame]1110// page size. 2k has never been the default page size.
1111 ASSERT_NE("2048", default_page_size);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1112 EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_,2048,"2048",
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]1113DatabaseOptions::kDefaultPageSize,
1114 default_page_size));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1115}
1116
1117// Test that Raze() results are seen in other connections.
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1118TEST_P(SQLDatabaseTest,RazeMultiple){
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]1119staticconstexprchar kCreateSql[]=
1120"CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1121 ASSERT_TRUE(db_->Execute(kCreateSql));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1122
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]1123Database other_db(GetDBOptions(), test::kTestTag);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1124 ASSERT_TRUE(other_db.Open(db_path_));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1125
1126// Check that the second connection sees the table.
John Delaney86dbec62021-08-24 15:05:21[diff] [blame]1127 ASSERT_EQ(1,SqliteSchemaCount(&other_db));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1128
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1129 ASSERT_TRUE(db_->Raze());
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1130
1131// The second connection sees the updated database.
John Delaney86dbec62021-08-24 15:05:21[diff] [blame]1132 ASSERT_EQ(0,SqliteSchemaCount(&other_db));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1133}
1134
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1135TEST_P(SQLDatabaseTest,Raze_OtherConnectionHasWriteLock){
1136 ASSERT_TRUE(db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY)"));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1137
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]1138Database other_db(GetDBOptions(), test::kTestTag);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1139 ASSERT_TRUE(other_db.Open(db_path_));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1140
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1141Transaction other_db_transaction(&other_db);
1142 ASSERT_TRUE(other_db_transaction.Begin());
1143 ASSERT_TRUE(other_db.Execute("INSERT INTO rows(id) VALUES(1)"));
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1144
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1145 EXPECT_FALSE(db_->Raze())
1146<<"Raze() should fail while another connection has a write lock";
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1147
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1148 ASSERT_TRUE(other_db_transaction.Commit());
1149 EXPECT_TRUE(db_->Raze())
1150<<"Raze() should succeed after the other connection releases the lock";
shess@chromium.org8e0c01282012-04-06 19:36:49[diff] [blame]1151}
1152
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1153TEST_P(SQLDatabaseTest,Raze_OtherConnectionHasReadLock){
1154 ASSERT_TRUE(db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY)"));
1155 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(1)"));
1156
1157if(IsWALEnabled()){
1158// In WAL mode, read transactions in other connections do not block a write
1159// transaction.
1160return;
1161}
1162
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]1163Database other_db(GetDBOptions(), test::kTestTag);
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1164 ASSERT_TRUE(other_db.Open(db_path_));
1165
1166Statement select(other_db.GetUniqueStatement("SELECT id FROM rows"));
1167 ASSERT_TRUE(select.Step());
1168 EXPECT_FALSE(db_->Raze())
1169<<"Raze() should fail while another connection has a read lock";
1170
1171 ASSERT_FALSE(select.Step())
1172<<"The SELECT statement should not produce more than one row";
1173 EXPECT_TRUE(db_->Raze())
1174<<"Raze() should succeed after the other connection releases the lock";
1175}
1176
1177TEST_P(SQLDatabaseTest,Raze_EmptyDatabaseFile){
1178 ASSERT_TRUE(
1179 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1180 db_->Close();
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1181
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1182 ASSERT_TRUE(TruncateDatabase());
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1183 ASSERT_TRUE(db_->Open(db_path_))
1184<<"Failed to reopen database after truncating";
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1185
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1186 EXPECT_TRUE(db_->Raze())<<"Raze() failed on an empty file";
1187 EXPECT_TRUE(
1188 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
1189<<"Raze() did not produce a healthy empty database";
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1190}
1191
1192// Verify that Raze() can handle a file of junk.
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]1193// Need exclusive mode off here as there are some subtleties (by design) around
1194// how the cache is used with it on which causes the test to fail.
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1195TEST_P(SQLDatabaseTest,RazeNOTADB){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1196 db_->Close();
1197Database::Delete(db_path_);
1198 ASSERT_FALSE(base::PathExists(db_path_));
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1199
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1200 ASSERT_TRUE(OverwriteDatabaseHeader(OverwriteType::kTruncate));
1201 ASSERT_TRUE(base::PathExists(db_path_));
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1202
Scott Hessdcf120482015-02-10 21:33:29[diff] [blame]1203// SQLite will successfully open the handle, but fail when running PRAGMA
1204// statements that access the database.
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1205{
shess976814402016-06-21 06:56:25[diff] [blame]1206 sql::test::ScopedErrorExpecter expecter;
Victor Costan42988a92018-02-06 02:22:14[diff] [blame]1207 expecter.ExpectError(SQLITE_NOTADB);
Scott Hessdcf120482015-02-10 21:33:29[diff] [blame]1208
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]1209 EXPECT_FALSE(db_->Open(db_path_));
shess976814402016-06-21 06:56:25[diff] [blame]1210 ASSERT_TRUE(expecter.SawExpectedErrors());
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1211}
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1212 EXPECT_TRUE(db_->Raze());
1213 db_->Close();
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1214
1215// Now empty, the open should open an empty database.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1216 EXPECT_TRUE(db_->Open(db_path_));
John Delaney86dbec62021-08-24 15:05:21[diff] [blame]1217 EXPECT_EQ(0,SqliteSchemaCount(db_.get()));
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1218}
1219
1220// Verify that Raze() can handle a database overwritten with garbage.
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1221TEST_P(SQLDatabaseTest,RazeNOTADB2){
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]1222staticconstexprchar kCreateSql[]=
1223"CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1224 ASSERT_TRUE(db_->Execute(kCreateSql));
John Delaney86dbec62021-08-24 15:05:21[diff] [blame]1225 ASSERT_EQ(1,SqliteSchemaCount(db_.get()));
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1226 db_->Close();
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1227
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1228 ASSERT_TRUE(OverwriteDatabaseHeader(OverwriteType::kOverwrite));
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1229
1230// SQLite will successfully open the handle, but will fail with
1231// SQLITE_NOTADB on pragma statemenets which attempt to read the
1232// corrupted header.
1233{
shess976814402016-06-21 06:56:25[diff] [blame]1234 sql::test::ScopedErrorExpecter expecter;
1235 expecter.ExpectError(SQLITE_NOTADB);
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]1236 EXPECT_FALSE(db_->Open(db_path_));
shess976814402016-06-21 06:56:25[diff] [blame]1237 ASSERT_TRUE(expecter.SawExpectedErrors());
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1238}
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1239 EXPECT_TRUE(db_->Raze());
1240 db_->Close();
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1241
1242// Now empty, the open should succeed with an empty database.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1243 EXPECT_TRUE(db_->Open(db_path_));
John Delaney86dbec62021-08-24 15:05:21[diff] [blame]1244 EXPECT_EQ(0,SqliteSchemaCount(db_.get()));
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1245}
1246
1247// Test that a callback from Open() can raze the database. This is
1248// essential for cases where the Open() can fail entirely, so the
shess@chromium.orgfed734a2013-07-17 04:45:13[diff] [blame]1249// Raze() cannot happen later. Additionally test that when the
1250// callback does this during Open(), the open is retried and succeeds.
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1251TEST_P(SQLDatabaseTest,RazeCallbackReopen){
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]1252staticconstexprchar kCreateSql[]=
1253"CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1254 ASSERT_TRUE(db_->Execute(kCreateSql));
John Delaney86dbec62021-08-24 15:05:21[diff] [blame]1255 ASSERT_EQ(1,SqliteSchemaCount(db_.get()));
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1256 db_->Close();
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1257
kinuko@chromium.orga8848a72013-11-18 04:18:47[diff] [blame]1258// Corrupt the database so that nothing works, including PRAGMAs.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1259 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1260
shess@chromium.orgfed734a2013-07-17 04:45:13[diff] [blame]1261// Open() will succeed, even though the PRAGMA calls within will
1262// fail with SQLITE_CORRUPT, as will this PRAGMA.
1263{
shess976814402016-06-21 06:56:25[diff] [blame]1264 sql::test::ScopedErrorExpecter expecter;
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]1265 base::HistogramTester tester;
shess976814402016-06-21 06:56:25[diff] [blame]1266 expecter.ExpectError(SQLITE_CORRUPT);
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]1267 ASSERT_FALSE(db_->Open(db_path_));
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]1268 tester.ExpectUniqueSample("Sql.Database.Open.FirstAttempt.Error.Test",
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]1269SqliteResultCode::kCorrupt,1);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1270 ASSERT_FALSE(db_->Execute("PRAGMA auto_vacuum"));
1271 db_->Close();
shess976814402016-06-21 06:56:25[diff] [blame]1272 ASSERT_TRUE(expecter.SawExpectedErrors());
shess@chromium.orgfed734a2013-07-17 04:45:13[diff] [blame]1273}
1274
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1275 db_->set_error_callback(
1276 base::BindRepeating(&RazeErrorCallback, db_.get(), SQLITE_CORRUPT));
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1277
shess@chromium.orgfed734a2013-07-17 04:45:13[diff] [blame]1278// When the PRAGMA calls in Open() raise SQLITE_CORRUPT, the error
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1279// callback will call RazeAndPoison(). Open() will then fail and be
shess@chromium.orgfed734a2013-07-17 04:45:13[diff] [blame]1280// retried. The second Open() on the empty database will succeed
1281// cleanly.
Etienne Bergeronc34759492025-06-16 15:45:17[diff] [blame]1282{
1283 base::HistogramTester tester;
1284 ASSERT_TRUE(db_->Open(db_path_));
1285 tester.ExpectTotalCount("Sql.Database.RazeTime.Test",1);
1286 ASSERT_TRUE(db_->Execute("PRAGMA auto_vacuum"));
1287 EXPECT_EQ(0,SqliteSchemaCount(db_.get()));
1288}
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1289}
1290
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1291TEST_P(SQLDatabaseTest,RazeAndPoison_DeletesData){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1292 ASSERT_TRUE(
1293 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1294 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1295 ASSERT_TRUE(db_->RazeAndPoison());
shess@chromium.org41a97c812013-02-07 02:35:38[diff] [blame]1296
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1297// We need to call Close() in order to re-Open().
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1298 db_->Close();
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1299 ASSERT_TRUE(db_->Open(db_path_))
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1300<<"RazeAndPoison() did not produce a healthy database";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1301 EXPECT_TRUE(
1302 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1303<<"RazeAndPoison() did not produce a healthy empty database";
shess@chromium.org41a97c812013-02-07 02:35:38[diff] [blame]1304}
1305
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1306TEST_P(SQLDatabaseTest,RazeAndPoison_IsOpen){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1307 ASSERT_TRUE(
1308 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1309 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1310 ASSERT_TRUE(db_->RazeAndPoison());
shess@chromium.org41a97c812013-02-07 02:35:38[diff] [blame]1311
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1312 EXPECT_FALSE(db_->is_open())
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1313<<"RazeAndPoison() did not mark the database as closed";
shess@chromium.org41a97c812013-02-07 02:35:38[diff] [blame]1314}
1315
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1316TEST_P(SQLDatabaseTest,RazeAndPoison_Reopen_NoChanges){
1317 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1318 EXPECT_FALSE(
1319 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1320<<"Execute() should return false after RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1321
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1322// We need to call Close() in order to re-Open().
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1323 db_->Close();
1324 ASSERT_TRUE(db_->Open(db_path_))
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1325<<"RazeAndPoison() did not produce a healthy database";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1326 EXPECT_TRUE(
1327 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1328<<"Execute() returned false but went through after RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1329}
1330
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1331TEST_P(SQLDatabaseTest,RazeAndPoison_OpenTransaction){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1332 ASSERT_TRUE(
1333 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1334 ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
1335
1336Transaction transaction(db_.get());
1337 ASSERT_TRUE(transaction.Begin());
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1338 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1339
1340 EXPECT_FALSE(db_->is_open())
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1341<<"RazeAndPoison() did not mark the database as closed";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1342 EXPECT_FALSE(transaction.Commit())
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1343<<"RazeAndPoison() did not cancel the transaction";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1344
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1345// We need to call Close() in order to re-Open().
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1346 db_->Close();
1347
1348 ASSERT_TRUE(db_->Open(db_path_));
1349 EXPECT_TRUE(
1350 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1351<<"RazeAndPoison() did not produce a healthy empty database";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1352}
1353
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1354TEST_P(SQLDatabaseTest,RazeAndPoison_DoesTableExist){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1355 ASSERT_TRUE(
1356 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1357 ASSERT_TRUE(db_->DoesTableExist("rows"))<<"Incorrect test setup";
1358
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1359 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1360 EXPECT_FALSE(db_->DoesTableExist("rows"))
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1361<<"DoesTableExist() should return false after RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1362}
1363
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1364TEST_P(SQLDatabaseTest,RazeAndPoison_IsSQLValid){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1365 ASSERT_TRUE(db_->IsSQLValid("SELECT 1"))<<"Incorrect test setup";
1366
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1367 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1368 EXPECT_FALSE(db_->IsSQLValid("SELECT 1"))
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1369<<"IsSQLValid() should return false after RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1370}
1371
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1372TEST_P(SQLDatabaseTest,RazeAndPoison_Execute){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1373 ASSERT_TRUE(db_->Execute("SELECT 1"))<<"Incorrect test setup";
1374
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1375 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1376 EXPECT_FALSE(db_->Execute("SELECT 1"))
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1377<<"Execute() should return false after RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1378}
1379
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1380TEST_P(SQLDatabaseTest,RazeAndPoison_GetUniqueStatement){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1381{
1382Statement select(db_->GetUniqueStatement("SELECT 1"));
1383 ASSERT_TRUE(select.Step())<<"Incorrect test setup";
1384}
1385
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1386 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1387{
1388Statement select(db_->GetUniqueStatement("SELECT 1"));
1389 EXPECT_FALSE(select.Step())
1390<<"GetUniqueStatement() should return an invalid Statement after "
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1391<<"RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1392}
1393}
1394
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1395TEST_P(SQLDatabaseTest,RazeAndPoison_GetCachedStatement){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1396{
1397Statement select(db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1"));
1398 ASSERT_TRUE(select.Step())<<"Incorrect test setup";
1399}
1400
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1401 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1402{
1403Statement select(db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1"));
1404 EXPECT_FALSE(select.Step())
1405<<"GetCachedStatement() should return an invalid Statement after "
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1406<<"RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1407}
1408}
1409
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1410TEST_P(SQLDatabaseTest,RazeAndPoison_InvalidatesUniqueStatement){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1411Statement select(db_->GetUniqueStatement("SELECT 1"));
1412 ASSERT_TRUE(select.is_valid())<<"Incorrect test setup";
1413 ASSERT_TRUE(select.Step())<<"Incorrect test setup";
1414 select.Reset(/*clear_bound_vars=*/true);
1415
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1416 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1417 EXPECT_FALSE(select.is_valid())
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1418<<"RazeAndPoison() should invalidate live Statements";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1419 EXPECT_FALSE(select.Step())
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1420<<"RazeAndPoison() should invalidate live Statements";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1421}
1422
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1423TEST_P(SQLDatabaseTest,RazeAndPoison_InvalidatesCachedStatement){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1424Statement select(db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1"));
1425 ASSERT_TRUE(select.is_valid())<<"Incorrect test setup";
1426 ASSERT_TRUE(select.Step())<<"Incorrect test setup";
1427 select.Reset(/*clear_bound_vars=*/true);
1428
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1429 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1430 EXPECT_FALSE(select.is_valid())
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1431<<"RazeAndPoison() should invalidate live Statements";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1432 EXPECT_FALSE(select.Step())
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1433<<"RazeAndPoison() should invalidate live Statements";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1434}
1435
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1436TEST_P(SQLDatabaseTest,RazeAndPoison_TransactionBegin){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1437{
1438Transaction transaction(db_.get());
1439 ASSERT_TRUE(transaction.Begin())<<"Incorrect test setup";
1440 ASSERT_TRUE(transaction.Commit())<<"Incorrect test setup";
1441}
1442
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1443 ASSERT_TRUE(db_->RazeAndPoison());
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1444{
1445Transaction transaction(db_.get());
1446 EXPECT_FALSE(transaction.Begin())
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1447<<"Transaction::Begin() should return false after RazeAndPoison()";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1448 EXPECT_FALSE(transaction.IsActiveForTesting())
Andrew Paseltinerd309fec2023-03-28 16:59:55[diff] [blame]1449<<"RazeAndPoison() should block transactions from starting";
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1450}
1451}
1452
Etienne Bergeron1ee05fe2025-05-23 14:37:36[diff] [blame]1453TEST_P(SQLDatabaseTest,RazeAndPoison_ComputeMmapSizeForOpen){
1454 ASSERT_TRUE(db_->RazeAndPoison());
1455 EXPECT_EQ(db_->ComputeMmapSizeForOpen(),0u);
1456}
1457
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1458TEST_P(SQLDatabaseTest,Close_IsSQLValid){
1459 ASSERT_TRUE(db_->IsSQLValid("SELECT 1"))<<"Incorrect test setup";
1460
1461 db_->Close();
1462
1463 EXPECT_DCHECK_DEATH_WITH({ std::ignore= db_->IsSQLValid("SELECT 1");},
1464"Illegal use of Database without a db");
1465}
shess@chromium.org41a97c812013-02-07 02:35:38[diff] [blame]1466
shess92a6fb22017-04-23 04:33:30[diff] [blame]1467// On Windows, truncate silently fails against a memory-mapped file. One goal
1468// of Raze() is to truncate the file to remove blocks which generate I/O errors.
1469// Test that Raze() turns off memory mapping so that the file is truncated.
1470// [This would not cover the case of multiple connections where one of the other
1471// connections is memory-mapped. That is infrequent in Chromium.]
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1472TEST_P(SQLDatabaseTest,RazeTruncate){
shess92a6fb22017-04-23 04:33:30[diff] [blame]1473// The empty database has 0 or 1 pages. Raze() should leave it with exactly 1
1474// page. Not checking directly because auto_vacuum on Android adds a freelist
1475// page.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1476 ASSERT_TRUE(db_->Raze());
Helmut Januschkaec716742024-10-11 06:45:00[diff] [blame]1477 std::optional<int64_t> expected_size=GetFileSize(db_path_);
1478 ASSERT_TRUE(expected_size.has_value());
1479 EXPECT_GT(*expected_size,0);
shess92a6fb22017-04-23 04:33:30[diff] [blame]1480
1481// Cause the database to take a few pages.
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]1482staticconstexprchar kCreateSql[]=
1483"CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1484 ASSERT_TRUE(db_->Execute(kCreateSql));
shess92a6fb22017-04-23 04:33:30[diff] [blame]1485for(size_t i=0; i<24;++i){
1486 ASSERT_TRUE(
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1487 db_->Execute("INSERT INTO foo (value) VALUES (randomblob(1024))"));
shess92a6fb22017-04-23 04:33:30[diff] [blame]1488}
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]1489
1490// In WAL mode, writes don't reach the database file until a checkpoint
1491// happens.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1492 ASSERT_TRUE(db_->CheckpointDatabase());
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]1493
Helmut Januschkaec716742024-10-11 06:45:00[diff] [blame]1494 std::optional<int64_t> db_size=GetFileSize(db_path_);
1495 ASSERT_TRUE(db_size.has_value());
1496 EXPECT_GT(*db_size,*expected_size);
shess92a6fb22017-04-23 04:33:30[diff] [blame]1497
1498// Make a query covering most of the database file to make sure that the
1499// blocks are actually mapped into memory. Empirically, the truncate problem
1500// doesn't seem to happen if no blocks are mapped.
1501 EXPECT_EQ("24576",
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1502ExecuteWithResult(db_.get(),"SELECT SUM(LENGTH(value)) FROM foo"));
shess92a6fb22017-04-23 04:33:30[diff] [blame]1503
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1504 ASSERT_TRUE(db_->Raze());
Helmut Januschkaec716742024-10-11 06:45:00[diff] [blame]1505 db_size=GetFileSize(db_path_);
1506 ASSERT_TRUE(db_size.has_value());
1507 EXPECT_EQ(*expected_size,*db_size);
shess92a6fb22017-04-23 04:33:30[diff] [blame]1508}
1509
Xiaohan Wang7d09c5e2022-01-08 02:37:36[diff] [blame]1510#if BUILDFLAG(IS_ANDROID)
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1511TEST_P(SQLDatabaseTest,SetTempDirForSQL){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1512MetaTable meta_table;
yongsheng.zhu@intel.com1348765a2012-07-24 08:25:53[diff] [blame]1513// Below call needs a temporary directory in sqlite3
1514// On Android, it can pass only when the temporary directory is set.
1515// Otherwise, sqlite3 doesn't find the correct directory to store
1516// temporary files and will report the error 'unable to open
1517// database file'.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1518 ASSERT_TRUE(meta_table.Init(db_.get(),4,4));
yongsheng.zhu@intel.com1348765a2012-07-24 08:25:53[diff] [blame]1519}
Xiaohan Wang7d09c5e2022-01-08 02:37:36[diff] [blame]1520#endif// BUILDFLAG(IS_ANDROID)
shess@chromium.org8d2e39e2013-06-24 05:55:08[diff] [blame]1521
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1522TEST_P(SQLDatabaseTest,Delete){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1523 EXPECT_TRUE(db_->Execute("CREATE TABLE x (x)"));
1524 db_->Close();
shess@chromium.org8d2e39e2013-06-24 05:55:08[diff] [blame]1525
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1526 base::FilePath journal_path=Database::JournalPath(db_path_);
1527 base::FilePath wal_path=Database::WriteAheadLogPath(db_path_);
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]1528
1529// Should have both a main database file and a journal file if
1530// journal_mode is TRUNCATE. There is no WAL file as it is deleted on Close.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1531 ASSERT_TRUE(base::PathExists(db_path_));
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]1532if(!IsWALEnabled()){// TRUNCATE mode
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1533 ASSERT_TRUE(base::PathExists(journal_path));
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]1534}
shess@chromium.org8d2e39e2013-06-24 05:55:08[diff] [blame]1535
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1536Database::Delete(db_path_);
1537 EXPECT_FALSE(base::PathExists(db_path_));
1538 EXPECT_FALSE(base::PathExists(journal_path));
1539 EXPECT_FALSE(base::PathExists(wal_path));
shess@chromium.org8d2e39e2013-06-24 05:55:08[diff] [blame]1540}
shess@chromium.org7bae5742013-07-10 20:46:16[diff] [blame]1541
Xiaohan Wang7d09c5e2022-01-08 02:37:36[diff] [blame]1542#if BUILDFLAG(IS_POSIX) // This test operates on POSIX file permissions.
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1543TEST_P(SQLDatabaseTest,PosixFilePermissions){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1544 db_->Close();
1545Database::Delete(db_path_);
1546 ASSERT_FALSE(base::PathExists(db_path_));
Victor Costance678e72018-07-24 10:25:00[diff] [blame]1547
1548// If the bots all had a restrictive umask setting such that databases are
1549// always created with only the owner able to read them, then the code could
1550// break without breaking the tests. Temporarily provide a more permissive
1551// umask.
shess@chromium.org81a2a602013-07-17 19:10:36[diff] [blame]1552ScopedUmaskSetter permissive_umask(S_IWGRP| S_IWOTH);
Victor Costance678e72018-07-24 10:25:00[diff] [blame]1553
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1554 ASSERT_TRUE(db_->Open(db_path_));
shess@chromium.org81a2a602013-07-17 19:10:36[diff] [blame]1555
Victor Costance678e72018-07-24 10:25:00[diff] [blame]1556// Cause the journal file to be created. If the default journal_mode is
1557// changed back to DELETE, this test will need to be updated.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1558 EXPECT_TRUE(db_->Execute("CREATE TABLE x (x)"));
shess@chromium.org81a2a602013-07-17 19:10:36[diff] [blame]1559
shess@chromium.org81a2a602013-07-17 19:10:36[diff] [blame]1560int mode;
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1561 ASSERT_TRUE(base::PathExists(db_path_));
1562 EXPECT_TRUE(base::GetPosixFilePermissions(db_path_,&mode));
Victor Costance678e72018-07-24 10:25:00[diff] [blame]1563 ASSERT_EQ(mode,0600);
shess@chromium.org81a2a602013-07-17 19:10:36[diff] [blame]1564
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]1565if(IsWALEnabled()){// WAL mode
1566// The WAL file is created lazily on first change.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1567 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
shess@chromium.org81a2a602013-07-17 19:10:36[diff] [blame]1568
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1569 base::FilePath wal_path=Database::WriteAheadLogPath(db_path_);
1570 ASSERT_TRUE(base::PathExists(wal_path));
Victor Costance678e72018-07-24 10:25:00[diff] [blame]1571 EXPECT_TRUE(base::GetPosixFilePermissions(wal_path,&mode));
1572 ASSERT_EQ(mode,0600);
1573
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]1574// The shm file doesn't exist in exclusive locking mode.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1575if(ExecuteWithResult(db_.get(),"PRAGMA locking_mode")=="normal"){
1576 base::FilePath shm_path=Database::SharedMemoryFilePath(db_path_);
1577 ASSERT_TRUE(base::PathExists(shm_path));
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]1578 EXPECT_TRUE(base::GetPosixFilePermissions(shm_path,&mode));
1579 ASSERT_EQ(mode,0600);
1580}
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]1581}else{// Truncate mode
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1582 base::FilePath journal_path=Database::JournalPath(db_path_);
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]1583 DLOG(ERROR)<<"journal_path: "<< journal_path;
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1584 ASSERT_TRUE(base::PathExists(journal_path));
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]1585 EXPECT_TRUE(base::GetPosixFilePermissions(journal_path,&mode));
1586 ASSERT_EQ(mode,0600);
Victor Costance678e72018-07-24 10:25:00[diff] [blame]1587}
shess@chromium.org81a2a602013-07-17 19:10:36[diff] [blame]1588}
Xiaohan Wang7d09c5e2022-01-08 02:37:36[diff] [blame]1589#endif// BUILDFLAG(IS_POSIX)
shess@chromium.org81a2a602013-07-17 19:10:36[diff] [blame]1590
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1591TEST_P(SQLDatabaseTest,Poison_IsOpen){
1592 db_->Poison();
1593 EXPECT_FALSE(db_->is_open())
1594<<"Poison() did not mark the database as closed";
1595}
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1596
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1597TEST_P(SQLDatabaseTest,Poison_Close_Reopen_NoChanges){
1598 db_->Poison();
1599 EXPECT_FALSE(
1600 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
1601<<"Execute() should return false after Poison()";
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1602
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1603 db_->Close();
1604 ASSERT_TRUE(db_->Open(db_path_))<<"Poison() damaged the database";
1605 EXPECT_TRUE(
1606 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
1607<<"Execute() returned false but went through after Poison()";
1608}
1609
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1610TEST_P(SQLDatabaseTest,Poison_DoesTableExist){
1611 ASSERT_TRUE(
1612 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1613 ASSERT_TRUE(db_->DoesTableExist("rows"))<<"Incorrect test setup";
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1614
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1615 db_->Poison();
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1616 EXPECT_FALSE(db_->DoesTableExist("rows"))
1617<<"DoesTableExist() should return false after Poison()";
1618}
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1619
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1620TEST_P(SQLDatabaseTest,Poison_IsSQLValid){
1621 ASSERT_TRUE(db_->IsSQLValid("SELECT 1"))<<"Incorrect test setup";
1622
1623 db_->Poison();
1624 EXPECT_FALSE(db_->IsSQLValid("SELECT 1"))
1625<<"IsSQLValid() should return false after Poison()";
1626}
1627
1628TEST_P(SQLDatabaseTest,Poison_Execute){
1629 ASSERT_TRUE(db_->Execute("SELECT 1"))<<"Incorrect test setup";
1630
1631 db_->Poison();
1632 EXPECT_FALSE(db_->Execute("SELECT 1"))
1633<<"Execute() should return false after Poison()";
1634}
1635
1636TEST_P(SQLDatabaseTest,Poison_GetUniqueStatement){
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1637{
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1638Statement select(db_->GetUniqueStatement("SELECT 1"));
1639 ASSERT_TRUE(select.Step())<<"Incorrect test setup";
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1640}
1641
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1642 db_->Poison();
1643{
1644Statement select(db_->GetUniqueStatement("SELECT 1"));
1645 EXPECT_FALSE(select.Step())
1646<<"GetUniqueStatement() should return an invalid Statement after "
1647<<"Poison()";
1648}
1649}
shess644fc8a2016-02-26 18:15:58[diff] [blame]1650
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1651TEST_P(SQLDatabaseTest,Poison_GetCachedStatement){
1652{
1653Statement select(db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1"));
1654 ASSERT_TRUE(select.Step())<<"Incorrect test setup";
1655}
1656
1657 db_->Poison();
1658{
1659Statement select(db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1"));
1660 EXPECT_FALSE(select.Step())
1661<<"GetCachedStatement() should return an invalid Statement after "
1662<<"Poison()";
1663}
1664}
1665
1666TEST_P(SQLDatabaseTest,Poison_InvalidatesUniqueStatement){
1667Statement select(db_->GetUniqueStatement("SELECT 1"));
1668 ASSERT_TRUE(select.is_valid())<<"Incorrect test setup";
1669 ASSERT_TRUE(select.Step())<<"Incorrect test setup";
1670 select.Reset(/*clear_bound_vars=*/true);
1671
1672 db_->Poison();
1673 EXPECT_FALSE(select.is_valid())
1674<<"Poison() should invalidate live Statements";
1675 EXPECT_FALSE(select.Step())<<"Poison() should invalidate live Statements";
1676}
1677
1678TEST_P(SQLDatabaseTest,Poison_InvalidatesCachedStatement){
1679Statement select(db_->GetCachedStatement(SQL_FROM_HERE,"SELECT 1"));
1680 ASSERT_TRUE(select.is_valid())<<"Incorrect test setup";
1681 ASSERT_TRUE(select.Step())<<"Incorrect test setup";
1682 select.Reset(/*clear_bound_vars=*/true);
1683
1684 db_->Poison();
1685 EXPECT_FALSE(select.is_valid())
1686<<"Poison() should invalidate live Statements";
1687 EXPECT_FALSE(select.Step())<<"Poison() should invalidate live Statements";
1688}
1689
1690TEST_P(SQLDatabaseTest,Poison_TransactionBegin){
1691{
1692Transaction transaction(db_.get());
1693 ASSERT_TRUE(transaction.Begin())<<"Incorrect test setup";
1694 ASSERT_TRUE(transaction.Commit())<<"Incorrect test setup";
1695}
1696
1697 db_->Poison();
1698{
1699Transaction transaction(db_.get());
1700 EXPECT_FALSE(transaction.Begin())
1701<<"Transaction::Begin() should return false after Poison()";
1702 EXPECT_FALSE(transaction.IsActiveForTesting())
1703<<"Poison() should block transactions from starting";
1704}
1705}
1706
1707TEST_P(SQLDatabaseTest,Poison_OpenTransaction){
1708Transaction transaction(db_.get());
1709 ASSERT_TRUE(transaction.Begin());
1710
1711 db_->Poison();
1712 EXPECT_FALSE(transaction.Commit())
1713<<"Poison() did not cancel the transaction";
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1714}
1715
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1716TEST_P(SQLDatabaseTest,AttachDatabase){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1717 ASSERT_TRUE(
1718 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1719
1720// Create a database to attach to.
1721 base::FilePath attach_path=
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1722 db_path_.DirName().AppendASCII("attach_database_test.db");
1723staticconstexprchar kAttachmentPoint[]="other";
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1724{
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]1725Database other_db(test::kTestTag);
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1726 ASSERT_TRUE(other_db.Open(attach_path));
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1727 ASSERT_TRUE(
1728 other_db.Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1729 ASSERT_TRUE(other_db.Execute("INSERT INTO rows VALUES(42)"));
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1730}
1731
1732// Cannot see the attached database, yet.
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1733 EXPECT_FALSE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1734
Evan Stade1d80896e2024-02-28 18:40:26[diff] [blame]1735 EXPECT_TRUE(db_->AttachDatabase(attach_path, kAttachmentPoint));
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1736 EXPECT_TRUE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1737
Victor Costan8a87f7e52017-11-10 01:29:30[diff] [blame]1738// Queries can touch both databases after the ATTACH.
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1739 EXPECT_TRUE(db_->Execute("INSERT INTO rows SELECT id FROM other.rows"));
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1740{
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1741Statement select(db_->GetUniqueStatement("SELECT COUNT(*) FROM rows"));
1742 ASSERT_TRUE(select.Step());
1743 EXPECT_EQ(1, select.ColumnInt(0));
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1744}
1745
Evan Stade1d80896e2024-02-28 18:40:26[diff] [blame]1746 EXPECT_TRUE(db_->DetachDatabase(kAttachmentPoint));
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1747 EXPECT_FALSE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
Victor Costan8a87f7e52017-11-10 01:29:30[diff] [blame]1748}
1749
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1750TEST_P(SQLDatabaseTest,AttachDatabaseWithOpenTransaction){
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1751 ASSERT_TRUE(
1752 db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
Victor Costan8a87f7e52017-11-10 01:29:30[diff] [blame]1753
1754// Create a database to attach to.
1755 base::FilePath attach_path=
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1756 db_path_.DirName().AppendASCII("attach_database_test.db");
1757staticconstexprchar kAttachmentPoint[]="other";
Victor Costan8a87f7e52017-11-10 01:29:30[diff] [blame]1758{
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]1759Database other_db(test::kTestTag);
Victor Costan8a87f7e52017-11-10 01:29:30[diff] [blame]1760 ASSERT_TRUE(other_db.Open(attach_path));
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1761 ASSERT_TRUE(
1762 other_db.Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
1763 ASSERT_TRUE(other_db.Execute("INSERT INTO rows VALUES(42)"));
Victor Costan8a87f7e52017-11-10 01:29:30[diff] [blame]1764}
1765
1766// Cannot see the attached database, yet.
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1767 EXPECT_FALSE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
Victor Costan8a87f7e52017-11-10 01:29:30[diff] [blame]1768
Victor Costan8a87f7e52017-11-10 01:29:30[diff] [blame]1769// Attach succeeds in a transaction.
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1770Transaction transaction(db_.get());
1771 EXPECT_TRUE(transaction.Begin());
Evan Stade1d80896e2024-02-28 18:40:26[diff] [blame]1772 EXPECT_TRUE(db_->AttachDatabase(attach_path, kAttachmentPoint));
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1773 EXPECT_TRUE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
Victor Costan8a87f7e52017-11-10 01:29:30[diff] [blame]1774
1775// Queries can touch both databases after the ATTACH.
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1776 EXPECT_TRUE(db_->Execute("INSERT INTO rows SELECT id FROM other.rows"));
Victor Costan8a87f7e52017-11-10 01:29:30[diff] [blame]1777{
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1778Statement select(db_->GetUniqueStatement("SELECT COUNT(*) FROM rows"));
1779 ASSERT_TRUE(select.Step());
1780 EXPECT_EQ(1, select.ColumnInt(0));
Victor Costan8a87f7e52017-11-10 01:29:30[diff] [blame]1781}
1782
1783// Detaching the same database fails, database is locked in the transaction.
1784{
1785 sql::test::ScopedErrorExpecter expecter;
1786 expecter.ExpectError(SQLITE_ERROR);
Evan Stade1d80896e2024-02-28 18:40:26[diff] [blame]1787 EXPECT_FALSE(db_->DetachDatabase(kAttachmentPoint));
shess976814402016-06-21 06:56:25[diff] [blame]1788 ASSERT_TRUE(expecter.SawExpectedErrors());
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1789}
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1790 EXPECT_TRUE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1791
Victor Costan8a87f7e52017-11-10 01:29:30[diff] [blame]1792// Detach succeeds when the transaction is closed.
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1793 transaction.Rollback();
Evan Stade1d80896e2024-02-28 18:40:26[diff] [blame]1794 EXPECT_TRUE(db_->DetachDatabase(kAttachmentPoint));
Victor Costane7944b4e2022-03-30 20:06:22[diff] [blame]1795 EXPECT_FALSE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
shess@chromium.org8d409412013-07-19 18:25:30[diff] [blame]1796}
1797
Victor Costan4b67f542022-02-24 17:40:55[diff] [blame]1798TEST_P(SQLDatabaseTest,FullIntegrityCheck){
1799staticconstexprchar kTableSql[]=
1800"CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL, value TEXT NOT NULL)";
1801 ASSERT_TRUE(db_->Execute(kTableSql));
Victor Costan8c3a9922022-02-26 03:50:52[diff] [blame]1802 ASSERT_TRUE(db_->Execute("CREATE INDEX rows_by_value ON rows(value)"));
1803
Victor Costan4b67f542022-02-24 17:40:55[diff] [blame]1804{
1805 std::vector<std::string> messages;
1806 EXPECT_TRUE(db_->FullIntegrityCheck(&messages))
1807<<"FullIntegrityCheck() failed before database was corrupted";
1808 EXPECT_THAT(messages, testing::ElementsAre("ok"))
1809<<"FullIntegrityCheck() should report ok before database is corrupted";
1810}
michaeln@chromium.org579446c2013-12-16 18:36:52[diff] [blame]1811
Victor Costan8c3a9922022-02-26 03:50:52[diff] [blame]1812 db_->Close();
1813 ASSERT_TRUE(sql::test::CorruptIndexRootPage(db_path_,"rows_by_value"));
1814 ASSERT_TRUE(db_->Open(db_path_));
1815
Victor Costan4b67f542022-02-24 17:40:55[diff] [blame]1816{
1817 std::vector<std::string> messages;
1818 EXPECT_TRUE(db_->FullIntegrityCheck(&messages))
1819<<"FullIntegrityCheck() failed on corrupted database";
1820 EXPECT_THAT(messages, testing::Not(testing::ElementsAre("ok")))
1821<<"FullIntegrityCheck() should not report ok for a corrupted database";
michaeln@chromium.org579446c2013-12-16 18:36:52[diff] [blame]1822}
michaeln@chromium.org579446c2013-12-16 18:36:52[diff] [blame]1823}
1824
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1825TEST_P(SQLDatabaseTest,OnMemoryDump){
ssid9f8022f2015-10-12 17:49:03[diff] [blame]1826 base::trace_event::MemoryDumpArgs args={
Ho Cheungadbf3fb2023-09-08 02:01:11[diff] [blame]1827 base::trace_event::MemoryDumpLevelOfDetail::kDetailed};
erikchenf62ea042018-05-25 21:30:57[diff] [blame]1828 base::trace_event::ProcessMemoryDump pmd(args);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1829 ASSERT_TRUE(db_->memory_dump_provider_->OnMemoryDump(args,&pmd));
ssid9f8022f2015-10-12 17:49:03[diff] [blame]1830 EXPECT_GE(pmd.allocator_dumps().size(),1u);
1831}
1832
shessc8cd2a162015-10-22 20:30:46[diff] [blame]1833// Test that the functions to collect diagnostic data run to completion, without
1834// worrying too much about what they generate (since that will change).
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1835TEST_P(SQLDatabaseTest,CollectDiagnosticInfo){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1836const std::string corruption_info= db_->CollectCorruptionInfo();
Ho Cheung47524352023-08-08 03:41:10[diff] [blame]1837 EXPECT_TRUE(base::Contains(corruption_info,"SQLITE_CORRUPT"));
1838 EXPECT_TRUE(base::Contains(corruption_info,"integrity_check"));
shessc8cd2a162015-10-22 20:30:46[diff] [blame]1839
1840// A statement to see in the results.
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]1841staticconstexprchar kSimpleSql[]="SELECT 'mountain'";
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1842Statement s(db_->GetCachedStatement(SQL_FROM_HERE, kSimpleSql));
shessc8cd2a162015-10-22 20:30:46[diff] [blame]1843
1844// Error includes the statement.
Tommy C. Li7803636c2022-07-27 21:47:22[diff] [blame]1845{
1846DatabaseDiagnostics diagnostics;
1847const std::string readonly_info=
1848 db_->CollectErrorInfo(SQLITE_READONLY,&s,&diagnostics);
Ho Cheung47524352023-08-08 03:41:10[diff] [blame]1849 EXPECT_TRUE(base::Contains(readonly_info, kSimpleSql));
Tommy C. Li7803636c2022-07-27 21:47:22[diff] [blame]1850 EXPECT_EQ(diagnostics.sql_statement, kSimpleSql);
1851}
shessc8cd2a162015-10-22 20:30:46[diff] [blame]1852
Tommy C. Li7803636c2022-07-27 21:47:22[diff] [blame]1853// Some other error doesn't include the statement.
1854{
1855DatabaseDiagnostics diagnostics;
1856const std::string full_info=
1857 db_->CollectErrorInfo(SQLITE_FULL,nullptr,&diagnostics);
Ho Cheung47524352023-08-08 03:41:10[diff] [blame]1858 EXPECT_FALSE(base::Contains(full_info, kSimpleSql));
Tommy C. Li7803636c2022-07-27 21:47:22[diff] [blame]1859 EXPECT_TRUE(diagnostics.sql_statement.empty());
1860}
shessc8cd2a162015-10-22 20:30:46[diff] [blame]1861
1862// A table to see in the SQLITE_ERROR results.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1863 EXPECT_TRUE(db_->Execute("CREATE TABLE volcano (x)"));
shessc8cd2a162015-10-22 20:30:46[diff] [blame]1864
1865// Version info to see in the SQLITE_ERROR results.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1866MetaTable meta_table;
1867 ASSERT_TRUE(meta_table.Init(db_.get(),4,4));
shessc8cd2a162015-10-22 20:30:46[diff] [blame]1868
Tommy C. Li7803636c2022-07-27 21:47:22[diff] [blame]1869{
1870DatabaseDiagnostics diagnostics;
1871const std::string error_info=
1872 db_->CollectErrorInfo(SQLITE_ERROR,&s,&diagnostics);
Ho Cheung47524352023-08-08 03:41:10[diff] [blame]1873 EXPECT_TRUE(base::Contains(error_info, kSimpleSql));
1874 EXPECT_TRUE(base::Contains(error_info,"volcano"));
1875 EXPECT_TRUE(base::Contains(error_info,"version: 4"));
Tommy C. Li7803636c2022-07-27 21:47:22[diff] [blame]1876 EXPECT_EQ(diagnostics.sql_statement, kSimpleSql);
1877 EXPECT_EQ(diagnostics.version,4);
1878
1879 ASSERT_EQ(diagnostics.schema_sql_rows.size(),2U);
1880 EXPECT_EQ(diagnostics.schema_sql_rows[0],"CREATE TABLE volcano (x)");
1881 EXPECT_EQ(diagnostics.schema_sql_rows[1],
1882"CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, "
1883"value LONGVARCHAR)");
1884
1885 ASSERT_EQ(diagnostics.schema_other_row_names.size(),1U);
1886 EXPECT_EQ(diagnostics.schema_other_row_names[0],"sqlite_autoindex_meta_1");
1887}
Tommy C. Li400c0f12022-09-13 22:39:28[diff] [blame]1888
1889// Test that an error message is included in the diagnostics.
1890{
1891 sql::test::ScopedErrorExpecter error_expecter;
1892 error_expecter.ExpectError(SQLITE_ERROR);
1893 EXPECT_FALSE(
1894 db_->Execute("INSERT INTO volcano VALUES ('bound_value1', 42, 1234)"));
1895 EXPECT_TRUE(error_expecter.SawExpectedErrors());
1896
1897DatabaseDiagnostics diagnostics;
1898const std::string error_info=
1899 db_->CollectErrorInfo(SQLITE_ERROR,&s,&diagnostics);
1900// Expect that the error message contains the table name and a column error.
Ho Cheung47524352023-08-08 03:41:10[diff] [blame]1901 EXPECT_TRUE(base::Contains(diagnostics.error_message,"table"));
1902 EXPECT_TRUE(base::Contains(diagnostics.error_message,"volcano"));
1903 EXPECT_TRUE(base::Contains(diagnostics.error_message,"column"));
Tommy C. Li400c0f12022-09-13 22:39:28[diff] [blame]1904
1905// Expect that bound values are not present.
Ho Cheung47524352023-08-08 03:41:10[diff] [blame]1906 EXPECT_FALSE(base::Contains(diagnostics.error_message,"bound_value1"));
1907 EXPECT_FALSE(base::Contains(diagnostics.error_message,"42"));
1908 EXPECT_FALSE(base::Contains(diagnostics.error_message,"1234"));
Tommy C. Li400c0f12022-09-13 22:39:28[diff] [blame]1909}
shessc8cd2a162015-10-22 20:30:46[diff] [blame]1910}
1911
shess9bf2c672015-12-18 01:18:08[diff] [blame]1912// Test that a fresh database has mmap enabled by default, if mmap'ed I/O is
1913// enabled by SQLite.
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1914TEST_P(SQLDatabaseTest,MmapInitiallyEnabled){
shess9bf2c672015-12-18 01:18:08[diff] [blame]1915{
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1916Statement s(db_->GetUniqueStatement("PRAGMA mmap_size"));
Victor Costan42988a92018-02-06 02:22:14[diff] [blame]1917 ASSERT_TRUE(s.Step())
1918<<"All supported SQLite versions should have mmap support";
shess9bf2c672015-12-18 01:18:08[diff] [blame]1919
1920// If mmap I/O is not on, attempt to turn it on. If that succeeds, then
1921// Open() should have turned it on. If mmap support is disabled, 0 is
1922// returned. If the VFS does not understand SQLITE_FCNTL_MMAP_SIZE (for
1923// instance MojoVFS), -1 is returned.
1924if(s.ColumnInt(0)<=0){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1925 ASSERT_TRUE(db_->Execute("PRAGMA mmap_size = 1048576"));
shess9bf2c672015-12-18 01:18:08[diff] [blame]1926 s.Reset(true);
1927 ASSERT_TRUE(s.Step());
1928 EXPECT_LE(s.ColumnInt(0),0);
1929}
1930}
1931
1932// Test that explicit disable prevents mmap'ed I/O.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1933 db_->Close();
1934Database::Delete(db_path_);
1935 db_->set_mmap_disabled();
1936 ASSERT_TRUE(db_->Open(db_path_));
1937 EXPECT_EQ("0",ExecuteWithResult(db_.get(),"PRAGMA mmap_size"));
shessa62504d2016-11-07 19:26:12[diff] [blame]1938}
1939
1940// Test whether a fresh database gets mmap enabled when using alternate status
1941// storage.
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]1942TEST_P(SQLDatabaseTest,MmapInitiallyEnabledAltStatus){
shessa62504d2016-11-07 19:26:12[diff] [blame]1943// Re-open fresh database with alt-status flag set.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1944 db_->Close();
1945Database::Delete(db_path_);
Victor Costan8ec18ee42021-07-13 19:45:32[diff] [blame]1946
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]1947DatabaseOptions options=GetDBOptions()
1948.set_mmap_alt_status_discouraged(true)
1949.set_enable_views_discouraged(true);
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]1950 db_= std::make_unique<Database>(options, test::kTestTag);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1951 ASSERT_TRUE(db_->Open(db_path_));
shessa62504d2016-11-07 19:26:12[diff] [blame]1952
shess9bf2c672015-12-18 01:18:08[diff] [blame]1953{
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1954Statement s(db_->GetUniqueStatement("PRAGMA mmap_size"));
Victor Costan42988a92018-02-06 02:22:14[diff] [blame]1955 ASSERT_TRUE(s.Step())
1956<<"All supported SQLite versions should have mmap support";
shessa62504d2016-11-07 19:26:12[diff] [blame]1957
1958// If mmap I/O is not on, attempt to turn it on. If that succeeds, then
1959// Open() should have turned it on. If mmap support is disabled, 0 is
1960// returned. If the VFS does not understand SQLITE_FCNTL_MMAP_SIZE (for
1961// instance MojoVFS), -1 is returned.
1962if(s.ColumnInt(0)<=0){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1963 ASSERT_TRUE(db_->Execute("PRAGMA mmap_size = 1048576"));
shessa62504d2016-11-07 19:26:12[diff] [blame]1964 s.Reset(true);
1965 ASSERT_TRUE(s.Step());
1966 EXPECT_LE(s.ColumnInt(0),0);
1967}
shess9bf2c672015-12-18 01:18:08[diff] [blame]1968}
shessa62504d2016-11-07 19:26:12[diff] [blame]1969
1970// Test that explicit disable overrides set_mmap_alt_status().
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1971 db_->Close();
1972Database::Delete(db_path_);
1973 db_->set_mmap_disabled();
1974 ASSERT_TRUE(db_->Open(db_path_));
1975 EXPECT_EQ("0",ExecuteWithResult(db_.get(),"PRAGMA mmap_size"));
shess9bf2c672015-12-18 01:18:08[diff] [blame]1976}
1977
Victor Costandc72e8d2022-03-14 18:14:51[diff] [blame]1978TEST_P(SQLDatabaseTest,ComputeMmapSizeForOpen){
shess9bf2c672015-12-18 01:18:08[diff] [blame]1979constsize_t kMmapAlot=25*1024*1024;
shess9e77283d2016-06-13 23:53:20[diff] [blame]1980int64_t mmap_status=MetaTable::kMmapFailure;
shess9bf2c672015-12-18 01:18:08[diff] [blame]1981
1982// If there is no meta table (as for a fresh database), assume that everything
shess9e77283d2016-06-13 23:53:20[diff] [blame]1983// should be mapped, and the status of the meta table is not affected.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1984 ASSERT_TRUE(!db_->DoesTableExist("meta"));
Victor Costandc72e8d2022-03-14 18:14:51[diff] [blame]1985 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1986 ASSERT_TRUE(!db_->DoesTableExist("meta"));
shess9bf2c672015-12-18 01:18:08[diff] [blame]1987
1988// When the meta table is first created, it sets up to map everything.
Andrew Paseltineref652c912023-02-08 21:26:32[diff] [blame]1989 ASSERT_TRUE(MetaTable().Init(db_.get(),1,1));
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1990 ASSERT_TRUE(db_->DoesTableExist("meta"));
Victor Costandc72e8d2022-03-14 18:14:51[diff] [blame]1991 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1992 ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(),&mmap_status));
shess9bf2c672015-12-18 01:18:08[diff] [blame]1993 ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status);
1994
shessa7b07acd2017-03-19 23:59:38[diff] [blame]1995// Preload with partial progress of one page. Should map everything.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1996 ASSERT_TRUE(db_->Execute("REPLACE INTO meta VALUES ('mmap_status', 1)"));
Victor Costandc72e8d2022-03-14 18:14:51[diff] [blame]1997 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]1998 ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(),&mmap_status));
shessa7b07acd2017-03-19 23:59:38[diff] [blame]1999 ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status);
2000
shess9bf2c672015-12-18 01:18:08[diff] [blame]2001// Failure status maps nothing.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2002 ASSERT_TRUE(db_->Execute("REPLACE INTO meta VALUES ('mmap_status', -2)"));
Victor Costandc72e8d2022-03-14 18:14:51[diff] [blame]2003 ASSERT_EQ(0UL, db_->ComputeMmapSizeForOpen());
shess9bf2c672015-12-18 01:18:08[diff] [blame]2004
2005// Re-initializing the meta table does not re-create the key if the table
2006// already exists.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2007 ASSERT_TRUE(db_->Execute("DELETE FROM meta WHERE key = 'mmap_status'"));
Andrew Paseltineref652c912023-02-08 21:26:32[diff] [blame]2008 ASSERT_TRUE(MetaTable().Init(db_.get(),1,1));
shess9bf2c672015-12-18 01:18:08[diff] [blame]2009 ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2010 ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(),&mmap_status));
shess9bf2c672015-12-18 01:18:08[diff] [blame]2011 ASSERT_EQ(0, mmap_status);
2012
2013// With no key, map everything and create the key.
2014// TODO(shess): This really should be "maps everything after validating it",
2015// but that is more complicated to structure.
Victor Costandc72e8d2022-03-14 18:14:51[diff] [blame]2016 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2017 ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(),&mmap_status));
shess9bf2c672015-12-18 01:18:08[diff] [blame]2018 ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status);
2019}
shess9bf2c672015-12-18 01:18:08[diff] [blame]2020
Victor Costandc72e8d2022-03-14 18:14:51[diff] [blame]2021TEST_P(SQLDatabaseTest,ComputeMmapSizeForOpenAltStatus){
shessa62504d2016-11-07 19:26:12[diff] [blame]2022constsize_t kMmapAlot=25*1024*1024;
2023
Victor Costancfbfa602018-08-01 23:24:46[diff] [blame]2024// At this point, Database still expects a future [meta] table.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2025 ASSERT_FALSE(db_->DoesTableExist("meta"));
2026 ASSERT_FALSE(db_->DoesViewExist("MmapStatus"));
Victor Costandc72e8d2022-03-14 18:14:51[diff] [blame]2027 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2028 ASSERT_FALSE(db_->DoesTableExist("meta"));
2029 ASSERT_FALSE(db_->DoesViewExist("MmapStatus"));
shessa62504d2016-11-07 19:26:12[diff] [blame]2030
2031// Using alt status, everything should be mapped, with state in the view.
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]2032DatabaseOptions options=GetDBOptions()
2033.set_mmap_alt_status_discouraged(true)
2034.set_enable_views_discouraged(true);
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]2035 db_= std::make_unique<Database>(options, test::kTestTag);
Victor Costan8ec18ee42021-07-13 19:45:32[diff] [blame]2036 ASSERT_TRUE(db_->Open(db_path_));
2037
Victor Costandc72e8d2022-03-14 18:14:51[diff] [blame]2038 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2039 ASSERT_FALSE(db_->DoesTableExist("meta"));
2040 ASSERT_TRUE(db_->DoesViewExist("MmapStatus"));
Raul Tambre6c708e32019-02-08 22:35:14[diff] [blame]2041 EXPECT_EQ(base::NumberToString(MetaTable::kMmapSuccess),
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2042ExecuteWithResult(db_.get(),"SELECT * FROM MmapStatus"));
shessa62504d2016-11-07 19:26:12[diff] [blame]2043
shessa7b07acd2017-03-19 23:59:38[diff] [blame]2044// Also maps everything when kMmapSuccess is already in the view.
Victor Costandc72e8d2022-03-14 18:14:51[diff] [blame]2045 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
shessa62504d2016-11-07 19:26:12[diff] [blame]2046
shessa7b07acd2017-03-19 23:59:38[diff] [blame]2047// Preload with partial progress of one page. Should map everything.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2048 ASSERT_TRUE(db_->Execute("DROP VIEW MmapStatus"));
2049 ASSERT_TRUE(db_->Execute("CREATE VIEW MmapStatus (value) AS SELECT 1"));
Victor Costandc72e8d2022-03-14 18:14:51[diff] [blame]2050 ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
Raul Tambre6c708e32019-02-08 22:35:14[diff] [blame]2051 EXPECT_EQ(base::NumberToString(MetaTable::kMmapSuccess),
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2052ExecuteWithResult(db_.get(),"SELECT * FROM MmapStatus"));
shessa7b07acd2017-03-19 23:59:38[diff] [blame]2053
shessa62504d2016-11-07 19:26:12[diff] [blame]2054// Failure status leads to nothing being mapped.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2055 ASSERT_TRUE(db_->Execute("DROP VIEW MmapStatus"));
2056 ASSERT_TRUE(db_->Execute("CREATE VIEW MmapStatus (value) AS SELECT -2"));
Victor Costandc72e8d2022-03-14 18:14:51[diff] [blame]2057 ASSERT_EQ(0UL, db_->ComputeMmapSizeForOpen());
Raul Tambre6c708e32019-02-08 22:35:14[diff] [blame]2058 EXPECT_EQ(base::NumberToString(MetaTable::kMmapFailure),
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2059ExecuteWithResult(db_.get(),"SELECT * FROM MmapStatus"));
shessa62504d2016-11-07 19:26:12[diff] [blame]2060}
2061
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]2062TEST_P(SQLDatabaseTest,GetMemoryUsage){
Victor Costand6e73252020-10-14 21:11:25[diff] [blame]2063// Databases with mmap enabled may not follow the assumptions below.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2064 db_->Close();
2065 db_->set_mmap_disabled();
2066 ASSERT_TRUE(db_->Open(db_path_));
Victor Costand6e73252020-10-14 21:11:25[diff] [blame]2067
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2068int initial_memory= db_->GetMemoryUsage();
Victor Costand6e73252020-10-14 21:11:25[diff] [blame]2069 EXPECT_GT(initial_memory,0)
2070<<"SQLite should always use some memory for a database";
2071
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2072 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
2073 ASSERT_TRUE(db_->Execute("INSERT INTO foo(a, b) VALUES (12, 13)"));
Victor Costand6e73252020-10-14 21:11:25[diff] [blame]2074
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2075int post_query_memory= db_->GetMemoryUsage();
Victor Costand6e73252020-10-14 21:11:25[diff] [blame]2076 EXPECT_GT(post_query_memory, initial_memory)
2077<<"Page cache usage should go up after executing queries";
2078
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2079 db_->TrimMemory();
2080int post_trim_memory= db_->GetMemoryUsage();
Victor Costand6e73252020-10-14 21:11:25[diff] [blame]2081 EXPECT_GT(post_query_memory, post_trim_memory)
2082<<"Page cache usage should go down after calling TrimMemory()";
2083}
2084
Victor Costan4e442d02021-07-20 17:43:13[diff] [blame]2085TEST_P(SQLDatabaseTest,DoubleQuotedStringLiteralsDisabledByDefault){
2086 ASSERT_TRUE(db_->Execute("CREATE TABLE data(item TEXT NOT NULL);"));
2087
2088structTestCase{
Evan Stadee63b8342024-06-07 15:55:23[diff] [blame]2089const std::string sql;
Victor Costan4e442d02021-07-20 17:43:13[diff] [blame]2090bool is_valid;
2091};
2092 std::vector<TestCase> test_cases={
2093// DML tests.
2094{"SELECT item FROM data WHERE item >= 'string literal'",true},
2095{"SELECT item FROM data WHERE item >= \"string literal\"",false},
2096{"INSERT INTO data(item) VALUES('string literal')",true},
2097{"INSERT INTO data(item) VALUES(\"string literal\")",false},
2098{"UPDATE data SET item = 'string literal'",true},
2099{"UPDATE data SET item = \"string literal\"",false},
2100{"DELETE FROM data WHERE item >= 'string literal'",true},
2101{"DELETE FROM data WHERE item >= \"string literal\"",false},
2102
2103// DDL tests.
2104{"CREATE INDEX data_item ON data(item) WHERE item >= 'string literal'",
2105true},
2106{"CREATE INDEX data_item ON data(item) WHERE item >= \"string literal\"",
2107false},
2108{"CREATE TABLE data2(item TEXT DEFAULT 'string literal')",true},
2109
2110// This should be an invalid DDL statement, due to the double-quoted
2111// string literal. However, SQLite currently parses it.
2112{"CREATE TABLE data2(item TEXT DEFAULT \"string literal\")",true},
2113};
2114
2115for(constTestCase& test_case: test_cases){
2116 SCOPED_TRACE(test_case.sql);
2117
2118 EXPECT_EQ(test_case.is_valid, db_->IsSQLValid(test_case.sql));
2119}
2120}
2121
Victor Costan54d71382022-03-21 21:47:18[diff] [blame]2122TEST_P(SQLDatabaseTest,ForeignKeyEnforcementDisabledByDefault){
Victor Costan54d71382022-03-21 21:47:18[diff] [blame]2123 ASSERT_TRUE(db_->Execute("CREATE TABLE targets(id INTEGER PRIMARY KEY)"));
2124// sqlite3_db_config() currently only disables foreign key enforcement. Schema
2125// operations on foreign keys are still allowed.
2126 ASSERT_TRUE(
2127 db_->Execute("CREATE TABLE refs("
2128"id INTEGER PRIMARY KEY,"
2129"target_id INTEGER REFERENCES targets(id))"));
2130
2131 ASSERT_TRUE(db_->Execute("INSERT INTO targets(id) VALUES(42)"));
2132 ASSERT_TRUE(db_->Execute("INSERT INTO refs(id, target_id) VALUES(42, 42)"));
2133
2134 EXPECT_TRUE(db_->Execute("DELETE FROM targets WHERE id=42"))
2135<<"Foreign key enforcement is not disabled";
2136}
2137
Victor Costan7c234822021-07-13 03:03:02[diff] [blame]2138TEST_P(SQLDatabaseTest,TriggersDisabledByDefault){
2139 ASSERT_TRUE(db_->Execute("CREATE TABLE data(id INTEGER)"));
2140
2141// sqlite3_db_config() currently only disables running triggers. Schema
2142// operations on triggers are still allowed.
2143 EXPECT_TRUE(
2144 db_->Execute("CREATE TRIGGER trigger AFTER INSERT ON data "
2145"BEGIN DELETE FROM data; END"));
2146
2147 ASSERT_TRUE(db_->Execute("INSERT INTO data(id) VALUES(42)"));
2148
2149Statement select(db_->GetUniqueStatement("SELECT id FROM data"));
2150 EXPECT_TRUE(select.Step())
2151<<"If the trigger did not run, the table should not be empty.";
2152 EXPECT_EQ(42, select.ColumnInt64(0));
2153
2154// sqlite3_db_config() currently only disables running triggers. Schema
2155// operations on triggers are still allowed.
2156 EXPECT_TRUE(db_->Execute("DROP TRIGGER IF EXISTS trigger"));
2157}
2158
Etienne Bergeron14c5d712023-11-13 15:01:15[diff] [blame]2159// This test ensures that a database can be open/create with a journal mode and
2160// can be re-open later with a different journal mode.
2161TEST_P(SQLDatabaseTest,ReOpenWithDifferentJournalMode){
2162constbool is_wal=IsWALEnabled();
2163const base::FilePath journal_path=Database::JournalPath(db_path_);
2164const base::FilePath wal_path=Database::WriteAheadLogPath(db_path_);
2165
2166 ASSERT_TRUE(db_->Execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"));
2167 ASSERT_TRUE(db_->Execute("INSERT INTO foo (value) VALUES (12)"));
2168
2169// Last insert row ID should be valid.
2170int64_t row= db_->GetLastInsertRowId();
2171 EXPECT_LT(0, row);
2172
2173// It should be the primary key of the row we just inserted.
2174{
2175Statement s(db_->GetUniqueStatement("SELECT value FROM foo WHERE id=?"));
2176 s.BindInt64(0, row);
2177 ASSERT_TRUE(s.Step());
2178 EXPECT_EQ(12, s.ColumnInt(0));
2179}
2180
2181// Ensure appropriate journal mode and the journal file exists.
2182 EXPECT_TRUE(IsOpenedInCorrectJournalMode(db_.get(), is_wal));
2183 EXPECT_EQ(base::PathExists(wal_path), is_wal);
2184
2185 db_->Close();
2186if(is_wal){
2187// The WAL journal file is removed on database close. Database that enable
2188// WAL mode can use a different journal mode on a subsequent database open.
2189 EXPECT_FALSE(base::PathExists(wal_path));
2190}else{
2191// The Rollback journal should have a zero size when pending operations
2192// are completed.
Helmut Januschkaec716742024-10-11 06:45:00[diff] [blame]2193 std::optional<int64_t> journal_size=GetFileSize(journal_path);
2194 EXPECT_THAT(journal_size, testing::Optional(0));
Etienne Bergeron14c5d712023-11-13 15:01:15[diff] [blame]2195}
2196
2197// Re-open the database with a different mode (Rollback vs WAL).
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]2198DatabaseOptions options=
2199GetDBOptions()
2200.set_wal_mode(!is_wal)
Etienne Bergeron14c5d712023-11-13 15:01:15[diff] [blame]2201#if BUILDFLAG(IS_FUCHSIA)
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]2202// Exclusive mode needs to be enabled to enter WAL mode on Fuchsia.
2203.set_exclusive_locking(!is_wal)
Etienne Bergeron14c5d712023-11-13 15:01:15[diff] [blame]2204#endif// BUILDFLAG(IS_FUCHSIA)
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]2205;
Etienne Bergeron14c5d712023-11-13 15:01:15[diff] [blame]2206
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]2207 db_= std::make_unique<Database>(options, test::kTestTag);
Etienne Bergeron14c5d712023-11-13 15:01:15[diff] [blame]2208 ASSERT_TRUE(db_->Open(db_path_));
2209
2210// The value for the last inserted row should be valid.
2211{
2212Statement s(db_->GetUniqueStatement("SELECT value FROM foo WHERE id=?"));
2213 s.BindInt64(0, row);
2214 ASSERT_TRUE(s.Step());
2215 EXPECT_EQ(12, s.ColumnInt(0));
2216}
2217
2218// Ensure appropriate journal file exists.
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]2219 EXPECT_TRUE(IsOpenedInCorrectJournalMode(db_.get(), options.wal_mode_));
2220 EXPECT_EQ(base::PathExists(wal_path), options.wal_mode_);
Etienne Bergeron14c5d712023-11-13 15:01:15[diff] [blame]2221}
2222
Will Harris711a5ec2023-04-04 21:43:37[diff] [blame]2223#if BUILDFLAG(IS_WIN)
2224
2225classSQLDatabaseTestExclusiveFileLockMode
2226:public testing::Test,
2227public testing::WithParamInterface<::testing::tuple<bool,bool>>{
2228public:
2229~SQLDatabaseTestExclusiveFileLockMode() override=default;
2230
2231voidSetUp() override{
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]2232 db_= std::make_unique<Database>(GetDBOptions(), test::kTestTag);
Will Harris711a5ec2023-04-04 21:43:37[diff] [blame]2233 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
2234 db_path_= temp_dir_.GetPath().AppendASCII("maybelocked.sqlite");
2235 ASSERT_TRUE(db_->Open(db_path_));
2236}
2237
2238DatabaseOptionsGetDBOptions(){
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]2239returnDatabaseOptions()
2240.set_wal_mode(IsWALEnabled())
2241.set_exclusive_locking(true)
2242.set_exclusive_database_file_lock(IsExclusivelockEnabled());
Will Harris711a5ec2023-04-04 21:43:37[diff] [blame]2243}
2244
2245boolIsWALEnabled(){return std::get<0>(GetParam());}
2246boolIsExclusivelockEnabled(){return std::get<1>(GetParam());}
2247
2248protected:
2249 base::ScopedTempDir temp_dir_;
2250 base::FilePath db_path_;
2251 std::unique_ptr<Database> db_;
2252};
2253
2254TEST_P(SQLDatabaseTestExclusiveFileLockMode,BasicStatement){
2255 ASSERT_TRUE(db_->Execute("CREATE TABLE data(contents TEXT)"));
2256 EXPECT_EQ(SQLITE_OK, db_->GetErrorCode());
2257
2258 ASSERT_TRUE(base::PathExists(db_path_));
2259 base::File open_db(db_path_, base::File::Flags::FLAG_OPEN_ALWAYS|
2260 base::File::Flags::FLAG_READ);
2261
2262// If exclusive lock is enabled, then the test should not be able to re-open
2263// the database file, on Windows only.
2264 EXPECT_EQ(IsExclusivelockEnabled(),!open_db.IsValid());
2265}
2266
2267INSTANTIATE_TEST_SUITE_P(
2268All,
2269SQLDatabaseTestExclusiveFileLockMode,
2270::testing::Combine(::testing::Bool(),::testing::Bool()),
2271[](constauto& info){
2272return base::StrCat(
2273{std::get<0>(info.param)?"WALEnabled":"WALDisabled",
2274 std::get<1>(info.param)?"ExclusiveLock":"NoExclusiveLock"});
2275});
2276
2277#else
2278
2279TEST(SQLInvalidDatabaseFlagsDeathTest,ExclusiveDatabaseLock){
2280 base::ScopedTempDir temp_dir;
2281 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
2282auto db_path= temp_dir.GetPath().AppendASCII("database_test_locked.sqlite");
2283
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]2284Database db(DatabaseOptions().set_exclusive_database_file_lock(true),
2285 test::kTestTag);
Will Harris711a5ec2023-04-04 21:43:37[diff] [blame]2286
2287 EXPECT_CHECK_DEATH_WITH(
2288{ std::ignore= db.Open(db_path);},
2289"exclusive_database_file_lock is only supported on Windows");
2290}
2291
2292#endif// BUILDFLAG(IS_WIN)
2293
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2294classSQLDatabaseTestExclusiveMode:public testing::Test,
2295public testing::WithParamInterface<bool>{
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]2296public:
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2297~SQLDatabaseTestExclusiveMode() override=default;
2298
2299voidSetUp() override{
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]2300 db_= std::make_unique<Database>(GetDBOptions(), test::kTestTag);
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2301 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
2302 db_path_= temp_dir_.GetPath().AppendASCII("recovery_test.sqlite");
2303 ASSERT_TRUE(db_->Open(db_path_));
2304}
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]2305
2306DatabaseOptionsGetDBOptions(){
Anthony Vallée-Dubois9adf0bb2025-02-03 17:01:41[diff] [blame]2307returnDatabaseOptions()
2308.set_wal_mode(IsWALEnabled())
2309.set_exclusive_locking(true);
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]2310}
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2311
2312boolIsWALEnabled(){returnGetParam();}
2313
2314protected:
2315 base::ScopedTempDir temp_dir_;
2316 base::FilePath db_path_;
2317 std::unique_ptr<Database> db_;
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]2318};
Victor Costanb2230792020-10-09 08:35:14[diff] [blame]2319
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]2320TEST_P(SQLDatabaseTestExclusiveMode,LockingModeExclusive){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2321 EXPECT_EQ(ExecuteWithResult(db_.get(),"PRAGMA locking_mode"),"exclusive");
Victor Costanb2230792020-10-09 08:35:14[diff] [blame]2322}
2323
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]2324TEST_P(SQLDatabaseTest,LockingModeNormal){
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2325 EXPECT_EQ(ExecuteWithResult(db_.get(),"PRAGMA locking_mode"),"normal");
Victor Costanb2230792020-10-09 08:35:14[diff] [blame]2326}
2327
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]2328TEST_P(SQLDatabaseTest,OpenedInCorrectMode){
Etienne Bergeron14c5d712023-11-13 15:01:15[diff] [blame]2329 EXPECT_TRUE(IsOpenedInCorrectJournalMode(db_.get(),IsWALEnabled()));
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]2330}
2331
Shubham Aggarwal003708982020-10-28 17:57:54[diff] [blame]2332TEST_P(SQLDatabaseTest,CheckpointDatabase){
Shubham Aggarwal7b60fe6e2020-10-15 06:00:28[diff] [blame]2333if(!IsWALEnabled())
2334return;
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]2335
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2336 base::FilePath wal_path=Database::WriteAheadLogPath(db_path_);
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]2337
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]2338// WAL file initially empty.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2339 EXPECT_TRUE(base::PathExists(wal_path));
Helmut Januschkaec716742024-10-11 06:45:00[diff] [blame]2340 std::optional<int64_t> wal_size=GetFileSize(wal_path);
2341 EXPECT_THAT(wal_size, testing::Optional(0));
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]2342
2343 ASSERT_TRUE(
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2344 db_->Execute("CREATE TABLE foo (id INTEGER UNIQUE, value INTEGER)"));
2345 ASSERT_TRUE(db_->Execute("INSERT INTO foo VALUES (1, 1)"));
2346 ASSERT_TRUE(db_->Execute("INSERT INTO foo VALUES (2, 2)"));
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]2347
2348// Writes reach WAL file but not db file.
Helmut Januschkaec716742024-10-11 06:45:00[diff] [blame]2349 wal_size=GetFileSize(wal_path);
2350 ASSERT_TRUE(wal_size.has_value());
2351 EXPECT_GT(wal_size.value(),0);
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]2352
Helmut Januschkaec716742024-10-11 06:45:00[diff] [blame]2353 std::optional<int64_t> db_size=GetFileSize(db_path_);
2354 ASSERT_TRUE(db_size.has_value());
2355 EXPECT_EQ(db_size.value(), db_->page_size());
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]2356
2357// Checkpoint database to immediately propagate writes to DB file.
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2358 EXPECT_TRUE(db_->CheckpointDatabase());
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]2359
Helmut Januschkaec716742024-10-11 06:45:00[diff] [blame]2360 db_size=GetFileSize(db_path_);
2361 EXPECT_TRUE(db_size.has_value());
2362 EXPECT_GT(db_size.value(), db_->page_size());
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2363 EXPECT_EQ(ExecuteWithResult(db_.get(),"SELECT value FROM foo where id=1"),
2364"1");
2365 EXPECT_EQ(ExecuteWithResult(db_.get(),"SELECT value FROM foo where id=2"),
2366"2");
Shubham Aggarwalbe4f97ce2020-06-19 15:58:57[diff] [blame]2367}
2368
Etienne Bergeronc1f808072025-01-16 05:09:53[diff] [blame]2369#if BUILDFLAG(IS_WIN)
2370
2371TEST_P(SQLDatabaseTest,OpenFails_WindowsExclusiveReadMode){
2372 db_->Close();
2373
2374 base::File file(db_path_, base::File::FLAG_OPEN| base::File::FLAG_READ|
2375// Do not allow others to read from the file.
2376 base::File::FLAG_WIN_EXCLUSIVE_READ);
2377 ASSERT_TRUE(file.IsValid());
2378
Etienne Bergeronbee2b672025-01-30 22:11:42[diff] [blame]2379 base::HistogramTester tester;
Etienne Bergeronc1f808072025-01-16 05:09:53[diff] [blame]2380 sql::test::ScopedErrorExpecter expecter;
2381 expecter.ExpectError(SQLITE_CANTOPEN);
2382 ASSERT_FALSE(db_->Open(db_path_));
2383 ASSERT_TRUE(expecter.SawExpectedErrors());
Etienne Bergeronbee2b672025-01-30 22:11:42[diff] [blame]2384 tester.ExpectTotalCount("Sql.Database.Open.FailureReason.Test",1);
Etienne Bergeronc1f808072025-01-16 05:09:53[diff] [blame]2385 db_->Close();
2386
2387 file.Close();
2388
2389 ASSERT_TRUE(db_->Open(db_path_));
2390}
2391
2392TEST_P(SQLDatabaseTest,OpenFails_WindowsExclusiveWriteMode){
2393 db_->Close();
2394
2395 base::File file(db_path_, base::File::FLAG_OPEN| base::File::FLAG_READ|
2396// Do not allow others to write to the file.
2397 base::File::FLAG_WIN_EXCLUSIVE_WRITE);
2398 ASSERT_TRUE(file.IsValid());
2399
Etienne Bergeronbee2b672025-01-30 22:11:42[diff] [blame]2400 base::HistogramTester tester;
Etienne Bergeronc1f808072025-01-16 05:09:53[diff] [blame]2401 sql::test::ScopedErrorExpecter expecter;
2402 expecter.ExpectError(SQLITE_READONLY);
2403 ASSERT_FALSE(db_->Open(db_path_));
2404 ASSERT_TRUE(expecter.SawExpectedErrors());
Etienne Bergeronbee2b672025-01-30 22:11:42[diff] [blame]2405 tester.ExpectTotalCount("Sql.Database.Open.FailureReason.Test",1);
Etienne Bergeronc1f808072025-01-16 05:09:53[diff] [blame]2406 db_->Close();
2407
2408 file.Close();
2409
2410 ASSERT_TRUE(db_->Open(db_path_));
2411}
2412
2413TEST_P(SQLDatabaseTest,OpenFails_ExclusiveLock){
2414 db_->Close();
2415
2416 base::File file(db_path_, base::File::FLAG_OPEN| base::File::FLAG_READ);
2417 ASSERT_TRUE(file.IsValid());
2418 ASSERT_EQ(base::File::FILE_OK, file.Lock(base::File::LockMode::kExclusive));
2419
2420{
Etienne Bergeronbee2b672025-01-30 22:11:42[diff] [blame]2421 base::HistogramTester tester;
Etienne Bergeronc1f808072025-01-16 05:09:53[diff] [blame]2422 sql::test::ScopedErrorExpecter expecter;
2423 expecter.ExpectError(SQLITE_IOERR_READ);
2424 ASSERT_FALSE(db_->Open(db_path_));
2425 ASSERT_TRUE(expecter.SawExpectedErrors());
Etienne Bergeronbee2b672025-01-30 22:11:42[diff] [blame]2426 tester.ExpectTotalCount("Sql.Database.Open.FailureReason.Test",1);
Etienne Bergeronc1f808072025-01-16 05:09:53[diff] [blame]2427 db_->Close();
2428}
2429
2430 ASSERT_EQ(base::File::FILE_OK, file.Unlock());
2431
2432 ASSERT_TRUE(db_->Open(db_path_));
2433}
2434
Etienne Bergeronc1f808072025-01-16 05:09:53[diff] [blame]2435#endif// BUILDFLAG(IS_WIN)
2436
Etienne Bergeron98f446ed2025-01-24 16:16:22[diff] [blame]2437TEST_P(SQLDatabaseTest,OpenHistograms){
2438staticconstexprchar kCreateSql[]="CREATE TABLE foo (id INTEGER UNIQUE)";
2439 ASSERT_TRUE(db_->Execute(kCreateSql));
2440 db_->Close();
2441
2442 base::HistogramTester tester;
2443 ASSERT_TRUE(db_->Open(db_path_));
2444 tester.ExpectTotalCount("Sql.Database.Success.SqliteOpenTime.Test",1);
2445 tester.ExpectTotalCount("Sql.Database.Success.OpenInternalTime.Test",1);
Etienne Bergeron98f446ed2025-01-24 16:16:22[diff] [blame]2446}
2447
Victor Costan3c802712022-02-24 17:33:06[diff] [blame]2448TEST_P(SQLDatabaseTest,OpenFailsAfterCorruptSizeInHeader){
2449// The database file ends up empty if we don't create at least one table.
2450 ASSERT_TRUE(
2451 db_->Execute("CREATE TABLE rows(i INTEGER PRIMARY KEY NOT NULL)"));
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2452 db_->Close();
Shubham Aggarwal1c06850ffa2020-07-07 13:42:57[diff] [blame]2453
Victor Costan49a903a2021-05-07 22:21:00[diff] [blame]2454 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
Shubham Aggarwal1c06850ffa2020-07-07 13:42:57[diff] [blame]2455{
2456 sql::test::ScopedErrorExpecter expecter;
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]2457 base::HistogramTester tester;
Shubham Aggarwal1c06850ffa2020-07-07 13:42:57[diff] [blame]2458 expecter.ExpectError(SQLITE_CORRUPT);
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]2459 ASSERT_FALSE(db_->Open(db_path_));
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]2460 tester.ExpectUniqueSample("Sql.Database.Open.FirstAttempt.Error.Test",
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]2461SqliteResultCode::kCorrupt,1);
Shubham Aggarwal1c06850ffa2020-07-07 13:42:57[diff] [blame]2462 EXPECT_TRUE(expecter.SawExpectedErrors());
2463}
2464}
2465
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]2466TEST_P(SQLDatabaseTest,OpenWithRecoveryHandlesCorruption){
2467for(constbool corrupt_after_recovery:{false,true}){
2468 SCOPED_TRACE(::testing::Message()
2469<<"corrupt_after_recovery: "<< corrupt_after_recovery);
2470// Ensure that `db_` is fresh in this iteration.
2471CreateFreshDB();
2472// The database file ends up empty if we don't create at least one table.
2473 ASSERT_TRUE(
2474 db_->Execute("CREATE TABLE rows(i INTEGER PRIMARY KEY NOT NULL)"));
2475 db_->Close();
2476
2477 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
2478
2479size_t error_count=0;
2480auto callback= base::BindLambdaForTesting([&](int error,Statement* stmt){
2481 error_count++;
Evan Stade4c7d6b32024-03-12 16:50:27[diff] [blame]2482 ASSERT_TRUE(Recovery::RecoverIfPossible(
2483 db_.get(), error, sql::Recovery::Strategy::kRecoverOrRaze));
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]2484if(corrupt_after_recovery){
2485// Corrupt the file again after temporarily recovering it.
2486 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
2487}
2488});
2489 db_->set_error_callback(std::move(callback));
2490
2491{
2492 sql::test::ScopedErrorExpecter expecter;
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]2493 base::HistogramTester tester;
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]2494 expecter.ExpectError(SQLITE_CORRUPT);
2495
2496// When `corrupt_after_recovery` is true, `Database::Open()` will return
2497// false because both attempts at opening the database will fail. When the
2498// database is *not* corrupted after recovery, recovery will succeed and
2499// thus `Database::Open()`'s second attempt at opening the database will
2500// succeed.
2501 ASSERT_EQ(db_->Open(db_path_),!corrupt_after_recovery);
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]2502 tester.ExpectUniqueSample("Sql.Database.Open.FirstAttempt.Error.Test",
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]2503SqliteResultCode::kCorrupt,1);
2504if(corrupt_after_recovery){
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]2505 tester.ExpectUniqueSample("Sql.Database.Open.SecondAttempt.Error.Test",
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]2506SqliteResultCode::kCorrupt,1);
2507}
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]2508 EXPECT_TRUE(expecter.SawExpectedErrors());
2509}
2510 EXPECT_EQ(error_count,1u);
2511 EXPECT_FALSE(db_->has_error_callback());
2512}
2513}
2514
Etienne Bergeron9635e20f2025-02-11 17:52:38[diff] [blame]2515TEST_P(SQLDatabaseTest,OpenWithPreload){
2516 db_->Close();
2517
2518DatabaseOptions options=GetDBOptions().set_preload(true);
2519 db_= std::make_unique<Database>(options, test::kTestTag);
2520 ASSERT_TRUE(db_->Open(db_path_));
2521}
2522
Victor Costan3c802712022-02-24 17:33:06[diff] [blame]2523TEST_P(SQLDatabaseTest,ExecuteFailsAfterCorruptSizeInHeader){
2524 ASSERT_TRUE(
2525 db_->Execute("CREATE TABLE rows(i INTEGER PRIMARY KEY NOT NULL)"));
2526constexprstaticchar kSelectSql[]="SELECT * from rows";
2527 EXPECT_TRUE(db_->Execute(kSelectSql))
2528<<"The test Execute() statement fails before the header is corrupted";
2529 db_->Close();
2530
2531 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
2532{
2533 sql::test::ScopedErrorExpecter expecter;
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]2534 base::HistogramTester tester;
Victor Costan3c802712022-02-24 17:33:06[diff] [blame]2535 expecter.ExpectError(SQLITE_CORRUPT);
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]2536 ASSERT_FALSE(db_->Open(db_path_));
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]2537 tester.ExpectUniqueSample("Sql.Database.Open.FirstAttempt.Error.Test",
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]2538SqliteResultCode::kCorrupt,1);
Victor Costan3c802712022-02-24 17:33:06[diff] [blame]2539 EXPECT_TRUE(expecter.SawExpectedErrors())
2540<<"Database::Open() did not encounter SQLITE_CORRUPT";
2541}
2542{
2543 sql::test::ScopedErrorExpecter expecter;
2544 expecter.ExpectError(SQLITE_CORRUPT);
2545 EXPECT_FALSE(db_->Execute(kSelectSql));
2546 EXPECT_TRUE(expecter.SawExpectedErrors())
2547<<"Database::Execute() did not encounter SQLITE_CORRUPT";
2548}
2549}
2550
2551TEST_P(SQLDatabaseTest,SchemaFailsAfterCorruptSizeInHeader){
2552 ASSERT_TRUE(
2553 db_->Execute("CREATE TABLE rows(i INTEGER PRIMARY KEY NOT NULL)"));
2554 ASSERT_TRUE(db_->DoesTableExist("rows"))
2555<<"The test schema check fails before the header is corrupted";
2556 db_->Close();
2557
2558 ASSERT_TRUE(sql::test::CorruptSizeInHeader(db_path_));
2559{
2560 sql::test::ScopedErrorExpecter expecter;
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]2561 base::HistogramTester tester;
Victor Costan3c802712022-02-24 17:33:06[diff] [blame]2562 expecter.ExpectError(SQLITE_CORRUPT);
Dan McArdle4feabeb52024-01-03 15:17:13[diff] [blame]2563 ASSERT_FALSE(db_->Open(db_path_));
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]2564 tester.ExpectUniqueSample("Sql.Database.Open.FirstAttempt.Error.Test",
Anthony Vallée-Duboisde37202582024-12-04 18:52:30[diff] [blame]2565SqliteResultCode::kCorrupt,1);
Victor Costan3c802712022-02-24 17:33:06[diff] [blame]2566 EXPECT_TRUE(expecter.SawExpectedErrors())
2567<<"Database::Open() did not encounter SQLITE_CORRUPT";
2568}
2569{
2570 sql::test::ScopedErrorExpecter expecter;
2571 expecter.ExpectError(SQLITE_CORRUPT);
2572 EXPECT_FALSE(db_->DoesTableExist("rows"));
2573 EXPECT_TRUE(expecter.SawExpectedErrors())
2574<<"Database::DoesTableExist() did not encounter SQLITE_CORRUPT";
2575}
2576}
2577
Etienne Bergeronc34759492025-06-16 15:45:17[diff] [blame]2578TEST_P(SQLDatabaseTest,StatementErrorHistogram){
2579staticconstexprchar kCreateSql[]="CREATE TABLE foo (id INTEGER UNIQUE)";
2580 ASSERT_TRUE(db_->Execute(kCreateSql));
2581
2582 sql::test::ScopedErrorExpecter expecter;
2583 expecter.ExpectError(SQLITE_ERROR);
2584
2585 base::HistogramTester tester;
2586 EXPECT_FALSE(db_->Execute("SELECT invalid_column from foo"));
2587 tester.ExpectUniqueSample("Sql.Database.Statement.Error.Test",
2588SqliteResultCode::kError,1);
2589 EXPECT_TRUE(expecter.SawExpectedErrors());
2590}
2591
a20.singhb0ca1122022-05-26 03:32:45[diff] [blame]2592TEST(SQLEmptyPathDatabaseTest,EmptyPathTest){
Anthony Vallée-Duboise3c94912024-12-12 16:47:47[diff] [blame]2593Database db(test::kTestTag);
a20.singhb0ca1122022-05-26 03:32:45[diff] [blame]2594 EXPECT_TRUE(db.OpenInMemory());
2595 EXPECT_TRUE(db.is_open());
2596 EXPECT_TRUE(db.DbPath().empty());
2597}
2598
Victor Costan15d905de2021-01-07 22:18:58[diff] [blame]2599// WAL mode is currently not supported on Fuchsia.
Xiaohan Wang7d09c5e2022-01-08 02:37:36[diff] [blame]2600#if !BUILDFLAG(IS_FUCHSIA)
Victor Costan15d905de2021-01-07 22:18:58[diff] [blame]2601INSTANTIATE_TEST_SUITE_P(JournalMode,SQLDatabaseTest, testing::Bool());
2602INSTANTIATE_TEST_SUITE_P(JournalMode,
2603SQLDatabaseTestExclusiveMode,
2604 testing::Bool());
2605#else
2606INSTANTIATE_TEST_SUITE_P(JournalMode,SQLDatabaseTest, testing::Values(false));
2607INSTANTIATE_TEST_SUITE_P(JournalMode,
2608SQLDatabaseTestExclusiveMode,
2609 testing::Values(false));
2610#endif
Olivier Li0408c8c12025-04-30 14:29:35[diff] [blame]2611
2612classReadOnlySQLDatabaseTest
2613:public testing::Test,
2614public testing::WithParamInterface<std::tuple<bool,bool,bool>>{
2615protected:
2616voidSetUp() override{
2617 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
2618constchar* db_name="database_test.db";
2619 db_path_= temp_dir_.GetPath().AppendASCII(db_name);
2620
2621 std::tie(wal_mode_, exclusive_mode_, readonly_mode_)=GetParam();
2622}
2623
2624// Opens a database with options that depend on test params. If
2625// `force_readwrite` is true, the database is opened in read/write mode
2626// irrespective of the "read-only" test param. The database is created
2627// if it doesn't already exist iff it is opened in read/write mode.
2628voidOpenDatabase(bool force_read_write){
2629 ASSERT_FALSE(db_path_.empty());
2630 db_.reset();
2631 db_= std::make_unique<Database>(GetDBOptions(force_read_write),
2632 test::kTestTag);
2633 ASSERT_TRUE(db_->Open(db_path_));
2634}
2635
2636voidCreateTable(){
2637 ASSERT_TRUE(db_->Execute(
2638"CREATE TABLE IF NOT EXISTS entries(key TEXT PRIMARY KEY UNIQUE NOT "
2639"NULL, content BLOB NOT NULL)"));
2640}
2641
2642voidInsert(){
2643 sql::Statement stm(
2644 db_->GetCachedStatement(SQL_FROM_HERE,
2645"REPLACE INTO entries (key, content "
2646") VALUES (?, ?)"));
2647 stm.BindString(0, value);
2648 stm.BindString(1, base::as_string_view(value));
2649 ASSERT_TRUE(stm.is_valid());
2650 EXPECT_TRUE(stm.Run());
2651}
2652
2653voidSelect(){
2654 sql::Statement stm= sql::Statement(db_->GetCachedStatement(
2655 SQL_FROM_HERE,"SELECT content FROM entries WHERE key = ?"));
2656 stm.BindString(0, value);
2657 ASSERT_TRUE(stm.is_valid());
2658 EXPECT_TRUE(stm.Step());
2659}
2660
2661DatabaseOptionsGetDBOptions(bool force_readwrite_only){
2662returnDatabaseOptions()
2663.set_read_only(force_readwrite_only?false: readonly_mode_)
2664.set_wal_mode(wal_mode_)
2665.set_exclusive_locking(exclusive_mode_);
2666}
2667
2668protected:
2669const std::string value{"VALUE"};
2670 base::ScopedTempDir temp_dir_;
2671 base::FilePath db_path_;
2672 std::unique_ptr<Database> db_;
2673
2674bool wal_mode_;
2675bool exclusive_mode_;
2676bool readonly_mode_;
2677};
2678
2679TEST_P(ReadOnlySQLDatabaseTest,MmapSize){
2680// Ensures the DB exists.
2681 ASSERT_NO_FATAL_FAILURE(OpenDatabase(true));
2682// Re-open and test the mmap on the existing DB.
2683 ASSERT_NO_FATAL_FAILURE(OpenDatabase(false));
2684 sql::Statement pragma_mmap_size(db_->GetUniqueStatement("PRAGMA mmap_size"));
2685 pragma_mmap_size.Step();
2686 EXPECT_NE(pragma_mmap_size.ColumnInt64(0),0);
2687}
2688
2689TEST_P(ReadOnlySQLDatabaseTest,Histograms){
2690 base::HistogramTester tester;
2691 ASSERT_NO_FATAL_FAILURE(OpenDatabase(true));
2692
2693 tester.ExpectTotalCount("Sql.Database.Success.OpenInternalTime.Test",1);
2694 tester.ExpectTotalCount("Sql.Database.Success.SqliteOpenTime.Test",1);
Olivier Li0408c8c12025-04-30 14:29:35[diff] [blame]2695
2696 ASSERT_NO_FATAL_FAILURE(OpenDatabase(false));
2697
2698 tester.ExpectTotalCount("Sql.Database.Success.OpenInternalTime.Test",2);
2699 tester.ExpectTotalCount("Sql.Database.Success.SqliteOpenTime.Test",2);
Olivier Li0408c8c12025-04-30 14:29:35[diff] [blame]2700}
2701
2702TEST_P(ReadOnlySQLDatabaseTest,CreateAndSelect){
2703// Not yet supported by Sqlite. Cannot be tested.
2704// TODO(crbug.com/413595430): Remove this if the combination of flags ever
2705// works.
2706if(wal_mode_&& exclusive_mode_&& readonly_mode_){
2707return;
2708}
2709
2710 ASSERT_NO_FATAL_FAILURE(OpenDatabase(true));
2711 ASSERT_NO_FATAL_FAILURE(CreateTable());
2712 ASSERT_NO_FATAL_FAILURE(Insert());
2713 ASSERT_NO_FATAL_FAILURE(Select());
2714
2715 ASSERT_NO_FATAL_FAILURE(OpenDatabase(false));
2716 ASSERT_NO_FATAL_FAILURE(Select());
2717}
2718
2719INSTANTIATE_TEST_SUITE_P(LockingMode,
2720ReadOnlySQLDatabaseTest,
2721 testing::Combine(testing::Bool(),
2722 testing::Bool(),
2723 testing::Bool()));
2724
shessc8cd2a162015-10-22 20:30:46[diff] [blame]2725}// namespace sql

[8]ページ先頭

©2009-2025 Movatter.jp