blob: 8cf32fb3f867f99c4e73e960decfe5822ff34240 [file] [log] [blame]
[email protected]44ad7d902012-03-23 00:09:051// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]e5ffd0e42009-09-11 21:30:562// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]7bae5742013-07-10 20:46:165#include "base/bind.h"
[email protected]e5ffd0e42009-09-11 21:30:566#include "base/file_util.h"
[email protected]ea1a3f62012-11-16 20:34:237#include "base/files/scoped_temp_dir.h"
[email protected]41a97c812013-02-07 02:35:388#include "base/logging.h"
[email protected]f0a54b22011-07-19 18:40:219#include "sql/connection.h"
[email protected]1348765a2012-07-24 08:25:5310#include "sql/meta_table.h"
[email protected]ea1a3f62012-11-16 20:34:2311#include "sql/statement.h"
[email protected]98cf3002013-07-12 01:38:5612#include "sql/test/error_callback_support.h"
[email protected]4350e322013-06-18 22:18:1013#include "sql/test/scoped_error_ignorer.h"
[email protected]e5ffd0e42009-09-11 21:30:5614#include "testing/gtest/include/gtest/gtest.h"
[email protected]e33cba42010-08-18 23:37:0315#include "third_party/sqlite/sqlite3.h"
[email protected]e5ffd0e42009-09-11 21:30:5616
[email protected]7bae5742013-07-10 20:46:1617namespace {
18
19// Helper to return the count of items in sqlite_master. Return -1 in
20// case of error.
21int SqliteMasterCount(sql::Connection* db) {
22 const char* kMasterCount = "SELECT COUNT(*) FROM sqlite_master";
23 sql::Statement s(db->GetUniqueStatement(kMasterCount));
24 return s.Step() ? s.ColumnInt(0) : -1;
25}
26
[email protected]98cf3002013-07-12 01:38:5627// Track the number of valid references which share the same pointer.
28// This is used to allow testing an implicitly use-after-free case by
29// explicitly having the ref count live longer than the object.
30class RefCounter {
31 public:
32 RefCounter(size_t* counter)
33 : counter_(counter) {
34 (*counter_)++;
35 }
36 RefCounter(const RefCounter& other)
37 : counter_(other.counter_) {
38 (*counter_)++;
39 }
40 ~RefCounter() {
41 (*counter_)--;
42 }
43
44 private:
45 size_t* counter_;
46
47 DISALLOW_ASSIGN(RefCounter);
48};
49
50// Empty callback for implementation of ErrorCallbackSetHelper().
51void IgnoreErrorCallback(int error, sql::Statement* stmt) {
52}
53
54void ErrorCallbackSetHelper(sql::Connection* db,
55 size_t* counter,
56 const RefCounter& r,
57 int error, sql::Statement* stmt) {
58 // The ref count should not go to zero when changing the callback.
59 EXPECT_GT(*counter, 0u);
60 db->set_error_callback(base::Bind(&IgnoreErrorCallback));
61 EXPECT_GT(*counter, 0u);
62}
63
64void ErrorCallbackResetHelper(sql::Connection* db,
65 size_t* counter,
66 const RefCounter& r,
67 int error, sql::Statement* stmt) {
68 // The ref count should not go to zero when clearing the callback.
69 EXPECT_GT(*counter, 0u);
70 db->reset_error_callback();
71 EXPECT_GT(*counter, 0u);
72}
73
[email protected]e5ffd0e42009-09-11 21:30:5674class SQLConnectionTest : public testing::Test {
75 public:
76 SQLConnectionTest() {}
77
[email protected]3dbbf7d2013-02-06 18:13:5378 virtual void SetUp() {
[email protected]3a305db2011-04-12 13:40:5379 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
[email protected]8e0c01282012-04-06 19:36:4980 ASSERT_TRUE(db_.Open(db_path()));
[email protected]e5ffd0e42009-09-11 21:30:5681 }
82
[email protected]3dbbf7d2013-02-06 18:13:5383 virtual void TearDown() {
[email protected]e5ffd0e42009-09-11 21:30:5684 db_.Close();
[email protected]e5ffd0e42009-09-11 21:30:5685 }
86
87 sql::Connection& db() { return db_; }
88
[email protected]a3ef4832013-02-02 05:12:3389 base::FilePath db_path() {
[email protected]8e0c01282012-04-06 19:36:4990 return temp_dir_.path().AppendASCII("SQLConnectionTest.db");
91 }
92
[email protected]7bae5742013-07-10 20:46:1693 // Handle errors by blowing away the database.
94 void RazeErrorCallback(int expected_error, int error, sql::Statement* stmt) {
95 EXPECT_EQ(expected_error, error);
96 db_.RazeAndClose();
97 }
98
[email protected]e5ffd0e42009-09-11 21:30:5699 private:
[email protected]ea1a3f62012-11-16 20:34:23100 base::ScopedTempDir temp_dir_;
[email protected]e5ffd0e42009-09-11 21:30:56101 sql::Connection db_;
102};
103
104TEST_F(SQLConnectionTest, Execute) {
105 // Valid statement should return true.
106 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
107 EXPECT_EQ(SQLITE_OK, db().GetErrorCode());
108
109 // Invalid statement should fail.
[email protected]eff1fa522011-12-12 23:50:59110 ASSERT_EQ(SQLITE_ERROR,
111 db().ExecuteAndReturnErrorCode("CREATE TAB foo (a, b"));
[email protected]e5ffd0e42009-09-11 21:30:56112 EXPECT_EQ(SQLITE_ERROR, db().GetErrorCode());
113}
114
[email protected]eff1fa522011-12-12 23:50:59115TEST_F(SQLConnectionTest, ExecuteWithErrorCode) {
116 ASSERT_EQ(SQLITE_OK,
117 db().ExecuteAndReturnErrorCode("CREATE TABLE foo (a, b)"));
118 ASSERT_EQ(SQLITE_ERROR,
119 db().ExecuteAndReturnErrorCode("CREATE TABLE TABLE"));
120 ASSERT_EQ(SQLITE_ERROR,
121 db().ExecuteAndReturnErrorCode(
122 "INSERT INTO foo(a, b) VALUES (1, 2, 3, 4)"));
123}
124
[email protected]e5ffd0e42009-09-11 21:30:56125TEST_F(SQLConnectionTest, CachedStatement) {
126 sql::StatementID id1("foo", 12);
127
128 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
129 ASSERT_TRUE(db().Execute("INSERT INTO foo(a, b) VALUES (12, 13)"));
130
131 // Create a new cached statement.
132 {
133 sql::Statement s(db().GetCachedStatement(id1, "SELECT a FROM foo"));
[email protected]eff1fa522011-12-12 23:50:59134 ASSERT_TRUE(s.is_valid());
[email protected]e5ffd0e42009-09-11 21:30:56135
136 ASSERT_TRUE(s.Step());
137 EXPECT_EQ(12, s.ColumnInt(0));
138 }
139
140 // The statement should be cached still.
141 EXPECT_TRUE(db().HasCachedStatement(id1));
142
143 {
144 // Get the same statement using different SQL. This should ignore our
145 // SQL and use the cached one (so it will be valid).
146 sql::Statement s(db().GetCachedStatement(id1, "something invalid("));
[email protected]eff1fa522011-12-12 23:50:59147 ASSERT_TRUE(s.is_valid());
[email protected]e5ffd0e42009-09-11 21:30:56148
149 ASSERT_TRUE(s.Step());
150 EXPECT_EQ(12, s.ColumnInt(0));
151 }
152
153 // Make sure other statements aren't marked as cached.
154 EXPECT_FALSE(db().HasCachedStatement(SQL_FROM_HERE));
155}
156
[email protected]eff1fa522011-12-12 23:50:59157TEST_F(SQLConnectionTest, IsSQLValidTest) {
158 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
159 ASSERT_TRUE(db().IsSQLValid("SELECT a FROM foo"));
160 ASSERT_FALSE(db().IsSQLValid("SELECT no_exist FROM foo"));
161}
162
[email protected]e5ffd0e42009-09-11 21:30:56163TEST_F(SQLConnectionTest, DoesStuffExist) {
164 // Test DoesTableExist.
165 EXPECT_FALSE(db().DoesTableExist("foo"));
166 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
167 EXPECT_TRUE(db().DoesTableExist("foo"));
168
169 // Should be case sensitive.
170 EXPECT_FALSE(db().DoesTableExist("FOO"));
171
172 // Test DoesColumnExist.
173 EXPECT_FALSE(db().DoesColumnExist("foo", "bar"));
174 EXPECT_TRUE(db().DoesColumnExist("foo", "a"));
175
[email protected]e7afe2452010-08-22 16:19:13176 // Testing for a column on a nonexistent table.
[email protected]e5ffd0e42009-09-11 21:30:56177 EXPECT_FALSE(db().DoesColumnExist("bar", "b"));
178}
179
180TEST_F(SQLConnectionTest, GetLastInsertRowId) {
181 ASSERT_TRUE(db().Execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"));
182
183 ASSERT_TRUE(db().Execute("INSERT INTO foo (value) VALUES (12)"));
184
185 // Last insert row ID should be valid.
186 int64 row = db().GetLastInsertRowId();
187 EXPECT_LT(0, row);
188
189 // It should be the primary key of the row we just inserted.
190 sql::Statement s(db().GetUniqueStatement("SELECT value FROM foo WHERE id=?"));
191 s.BindInt64(0, row);
192 ASSERT_TRUE(s.Step());
193 EXPECT_EQ(12, s.ColumnInt(0));
194}
[email protected]44ad7d902012-03-23 00:09:05195
196TEST_F(SQLConnectionTest, Rollback) {
197 ASSERT_TRUE(db().BeginTransaction());
198 ASSERT_TRUE(db().BeginTransaction());
199 EXPECT_EQ(2, db().transaction_nesting());
200 db().RollbackTransaction();
201 EXPECT_FALSE(db().CommitTransaction());
202 EXPECT_TRUE(db().BeginTransaction());
203}
[email protected]8e0c01282012-04-06 19:36:49204
[email protected]4350e322013-06-18 22:18:10205// Test the scoped error ignorer by attempting to insert a duplicate
206// value into an index.
207TEST_F(SQLConnectionTest, ScopedIgnoreError) {
208 const char* kCreateSql = "CREATE TABLE foo (id INTEGER UNIQUE)";
209 ASSERT_TRUE(db().Execute(kCreateSql));
210 ASSERT_TRUE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
211
212 sql::ScopedErrorIgnorer ignore_errors;
213 ignore_errors.IgnoreError(SQLITE_CONSTRAINT);
214 ASSERT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
215 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
216}
217
[email protected]98cf3002013-07-12 01:38:56218TEST_F(SQLConnectionTest, ErrorCallback) {
219 const char* kCreateSql = "CREATE TABLE foo (id INTEGER UNIQUE)";
220 ASSERT_TRUE(db().Execute(kCreateSql));
221 ASSERT_TRUE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
222
223 int error = SQLITE_OK;
224 {
225 sql::ScopedErrorCallback sec(
226 &db(), base::Bind(&sql::CaptureErrorCallback, &error));
227
228 // Inserting something other than a number into the primary key
229 // should result in the callback seeing SQLITE_MISMATCH.
230 EXPECT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
231 EXPECT_EQ(SQLITE_CONSTRAINT, error);
232 }
233
234 // Callback is no longer in force due to reset.
235 {
236 error = SQLITE_OK;
237 sql::ScopedErrorIgnorer ignore_errors;
238 ignore_errors.IgnoreError(SQLITE_CONSTRAINT);
239 ASSERT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
240 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
241 EXPECT_EQ(SQLITE_OK, error);
242 }
243
244 // base::Bind() can curry arguments to be passed by const reference
245 // to the callback function. If the callback function causes
246 // re/set_error_callback() to be called, the storage for those
247 // arguments can be deleted.
248 //
249 // RefCounter() counts how many objects are live using an external
250 // count. The same counter is passed to the callback, so that it
251 // can check directly even if the RefCounter object is no longer
252 // live.
253 {
254 size_t count = 0;
255 sql::ScopedErrorCallback sec(
256 &db(), base::Bind(&ErrorCallbackSetHelper,
257 &db(), &count, RefCounter(&count)));
258
259 EXPECT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
260 }
261
262 // Same test, but reset_error_callback() case.
263 {
264 size_t count = 0;
265 sql::ScopedErrorCallback sec(
266 &db(), base::Bind(&ErrorCallbackResetHelper,
267 &db(), &count, RefCounter(&count)));
268
269 EXPECT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
270 }
271}
272
[email protected]8e0c01282012-04-06 19:36:49273// Test that sql::Connection::Raze() results in a database without the
274// tables from the original database.
275TEST_F(SQLConnectionTest, Raze) {
276 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
277 ASSERT_TRUE(db().Execute(kCreateSql));
278 ASSERT_TRUE(db().Execute("INSERT INTO foo (value) VALUES (12)"));
279
[email protected]69c58452012-08-06 19:22:42280 int pragma_auto_vacuum = 0;
281 {
282 sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum"));
283 ASSERT_TRUE(s.Step());
284 pragma_auto_vacuum = s.ColumnInt(0);
285 ASSERT_TRUE(pragma_auto_vacuum == 0 || pragma_auto_vacuum == 1);
286 }
287
288 // If auto_vacuum is set, there's an extra page to maintain a freelist.
289 const int kExpectedPageCount = 2 + pragma_auto_vacuum;
290
[email protected]8e0c01282012-04-06 19:36:49291 {
292 sql::Statement s(db().GetUniqueStatement("PRAGMA page_count"));
293 ASSERT_TRUE(s.Step());
[email protected]69c58452012-08-06 19:22:42294 EXPECT_EQ(kExpectedPageCount, s.ColumnInt(0));
[email protected]8e0c01282012-04-06 19:36:49295 }
296
297 {
298 sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master"));
299 ASSERT_TRUE(s.Step());
300 EXPECT_EQ("table", s.ColumnString(0));
301 EXPECT_EQ("foo", s.ColumnString(1));
302 EXPECT_EQ("foo", s.ColumnString(2));
[email protected]69c58452012-08-06 19:22:42303 // Table "foo" is stored in the last page of the file.
304 EXPECT_EQ(kExpectedPageCount, s.ColumnInt(3));
[email protected]8e0c01282012-04-06 19:36:49305 EXPECT_EQ(kCreateSql, s.ColumnString(4));
306 }
307
308 ASSERT_TRUE(db().Raze());
309
310 {
311 sql::Statement s(db().GetUniqueStatement("PRAGMA page_count"));
312 ASSERT_TRUE(s.Step());
313 EXPECT_EQ(1, s.ColumnInt(0));
314 }
315
[email protected]7bae5742013-07-10 20:46:16316 ASSERT_EQ(0, SqliteMasterCount(&db()));
[email protected]69c58452012-08-06 19:22:42317
318 {
319 sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum"));
320 ASSERT_TRUE(s.Step());
[email protected]6d42f152012-11-10 00:38:24321 // The new database has the same auto_vacuum as a fresh database.
[email protected]69c58452012-08-06 19:22:42322 EXPECT_EQ(pragma_auto_vacuum, s.ColumnInt(0));
323 }
[email protected]8e0c01282012-04-06 19:36:49324}
325
326// Test that Raze() maintains page_size.
327TEST_F(SQLConnectionTest, RazePageSize) {
[email protected]e73e89222012-07-13 18:55:22328 // Fetch the default page size and double it for use in this test.
[email protected]8e0c01282012-04-06 19:36:49329 // Scoped to release statement before Close().
[email protected]e73e89222012-07-13 18:55:22330 int default_page_size = 0;
[email protected]8e0c01282012-04-06 19:36:49331 {
332 sql::Statement s(db().GetUniqueStatement("PRAGMA page_size"));
333 ASSERT_TRUE(s.Step());
[email protected]e73e89222012-07-13 18:55:22334 default_page_size = s.ColumnInt(0);
[email protected]8e0c01282012-04-06 19:36:49335 }
[email protected]e73e89222012-07-13 18:55:22336 ASSERT_GT(default_page_size, 0);
337 const int kPageSize = 2 * default_page_size;
[email protected]8e0c01282012-04-06 19:36:49338
339 // Re-open the database to allow setting the page size.
340 db().Close();
341 db().set_page_size(kPageSize);
342 ASSERT_TRUE(db().Open(db_path()));
343
344 // page_size should match the indicated value.
345 sql::Statement s(db().GetUniqueStatement("PRAGMA page_size"));
346 ASSERT_TRUE(s.Step());
347 ASSERT_EQ(kPageSize, s.ColumnInt(0));
348
349 // After raze, page_size should still match the indicated value.
350 ASSERT_TRUE(db().Raze());
[email protected]389e0a42012-04-25 21:36:41351 s.Reset(true);
[email protected]8e0c01282012-04-06 19:36:49352 ASSERT_TRUE(s.Step());
353 ASSERT_EQ(kPageSize, s.ColumnInt(0));
354}
355
356// Test that Raze() results are seen in other connections.
357TEST_F(SQLConnectionTest, RazeMultiple) {
358 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
359 ASSERT_TRUE(db().Execute(kCreateSql));
360
361 sql::Connection other_db;
362 ASSERT_TRUE(other_db.Open(db_path()));
363
364 // Check that the second connection sees the table.
[email protected]7bae5742013-07-10 20:46:16365 ASSERT_EQ(1, SqliteMasterCount(&other_db));
[email protected]8e0c01282012-04-06 19:36:49366
367 ASSERT_TRUE(db().Raze());
368
369 // The second connection sees the updated database.
[email protected]7bae5742013-07-10 20:46:16370 ASSERT_EQ(0, SqliteMasterCount(&other_db));
[email protected]8e0c01282012-04-06 19:36:49371}
372
373TEST_F(SQLConnectionTest, RazeLocked) {
374 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
375 ASSERT_TRUE(db().Execute(kCreateSql));
376
377 // Open a transaction and write some data in a second connection.
378 // This will acquire a PENDING or EXCLUSIVE transaction, which will
379 // cause the raze to fail.
380 sql::Connection other_db;
381 ASSERT_TRUE(other_db.Open(db_path()));
382 ASSERT_TRUE(other_db.BeginTransaction());
383 const char* kInsertSql = "INSERT INTO foo VALUES (1, 'data')";
384 ASSERT_TRUE(other_db.Execute(kInsertSql));
385
386 ASSERT_FALSE(db().Raze());
387
388 // Works after COMMIT.
389 ASSERT_TRUE(other_db.CommitTransaction());
390 ASSERT_TRUE(db().Raze());
391
392 // Re-create the database.
393 ASSERT_TRUE(db().Execute(kCreateSql));
394 ASSERT_TRUE(db().Execute(kInsertSql));
395
396 // An unfinished read transaction in the other connection also
397 // blocks raze.
398 const char *kQuery = "SELECT COUNT(*) FROM foo";
399 sql::Statement s(other_db.GetUniqueStatement(kQuery));
400 ASSERT_TRUE(s.Step());
401 ASSERT_FALSE(db().Raze());
402
403 // Complete the statement unlocks the database.
404 ASSERT_FALSE(s.Step());
405 ASSERT_TRUE(db().Raze());
406}
407
[email protected]7bae5742013-07-10 20:46:16408// Verify that Raze() can handle an empty file. SQLite should treat
409// this as an empty database.
410TEST_F(SQLConnectionTest, RazeEmptyDB) {
411 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
412 ASSERT_TRUE(db().Execute(kCreateSql));
413 db().Close();
414
415 {
416 file_util::ScopedFILE file(file_util::OpenFile(db_path(), "r+"));
417 ASSERT_TRUE(file.get() != NULL);
418 ASSERT_EQ(0, fseek(file.get(), 0, SEEK_SET));
419 ASSERT_TRUE(file_util::TruncateFile(file.get()));
420 }
421
422 ASSERT_TRUE(db().Open(db_path()));
423 ASSERT_TRUE(db().Raze());
424 EXPECT_EQ(0, SqliteMasterCount(&db()));
425}
426
427// Verify that Raze() can handle a file of junk.
428TEST_F(SQLConnectionTest, RazeNOTADB) {
429 db().Close();
430 sql::Connection::Delete(db_path());
[email protected]7567484142013-07-11 17:36:07431 ASSERT_FALSE(base::PathExists(db_path()));
[email protected]7bae5742013-07-10 20:46:16432
433 {
434 file_util::ScopedFILE file(file_util::OpenFile(db_path(), "w"));
435 ASSERT_TRUE(file.get() != NULL);
436
437 const char* kJunk = "This is the hour of our discontent.";
438 fputs(kJunk, file.get());
439 }
[email protected]7567484142013-07-11 17:36:07440 ASSERT_TRUE(base::PathExists(db_path()));
[email protected]7bae5742013-07-10 20:46:16441
442 // SQLite will successfully open the handle, but will fail with
443 // SQLITE_IOERR_SHORT_READ on pragma statemenets which read the
444 // header.
445 {
446 sql::ScopedErrorIgnorer ignore_errors;
447 ignore_errors.IgnoreError(SQLITE_IOERR_SHORT_READ);
448 EXPECT_TRUE(db().Open(db_path()));
449 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
450 }
451 EXPECT_TRUE(db().Raze());
452 db().Close();
453
454 // Now empty, the open should open an empty database.
455 EXPECT_TRUE(db().Open(db_path()));
456 EXPECT_EQ(0, SqliteMasterCount(&db()));
457}
458
459// Verify that Raze() can handle a database overwritten with garbage.
460TEST_F(SQLConnectionTest, RazeNOTADB2) {
461 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
462 ASSERT_TRUE(db().Execute(kCreateSql));
463 ASSERT_EQ(1, SqliteMasterCount(&db()));
464 db().Close();
465
466 {
467 file_util::ScopedFILE file(file_util::OpenFile(db_path(), "r+"));
468 ASSERT_TRUE(file.get() != NULL);
469 ASSERT_EQ(0, fseek(file.get(), 0, SEEK_SET));
470
471 const char* kJunk = "This is the hour of our discontent.";
472 fputs(kJunk, file.get());
473 }
474
475 // SQLite will successfully open the handle, but will fail with
476 // SQLITE_NOTADB on pragma statemenets which attempt to read the
477 // corrupted header.
478 {
479 sql::ScopedErrorIgnorer ignore_errors;
480 ignore_errors.IgnoreError(SQLITE_NOTADB);
481 EXPECT_TRUE(db().Open(db_path()));
482 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
483 }
484 EXPECT_TRUE(db().Raze());
485 db().Close();
486
487 // Now empty, the open should succeed with an empty database.
488 EXPECT_TRUE(db().Open(db_path()));
489 EXPECT_EQ(0, SqliteMasterCount(&db()));
490}
491
492// Test that a callback from Open() can raze the database. This is
493// essential for cases where the Open() can fail entirely, so the
[email protected]fed734a2013-07-17 04:45:13494// Raze() cannot happen later. Additionally test that when the
495// callback does this during Open(), the open is retried and succeeds.
[email protected]7bae5742013-07-10 20:46:16496//
497// Most corruptions seen in the wild seem to happen when two pages in
498// the database were not written transactionally (the transaction
499// changed both, but one wasn't successfully written for some reason).
500// A special case of that is when the header indicates that the
501// database contains more pages than are in the file. This breaks
502// things at a very basic level, verify that Raze() can handle it.
[email protected]fed734a2013-07-17 04:45:13503TEST_F(SQLConnectionTest, RazeCallbackReopen) {
[email protected]7bae5742013-07-10 20:46:16504 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
505 ASSERT_TRUE(db().Execute(kCreateSql));
506 ASSERT_EQ(1, SqliteMasterCount(&db()));
507 int page_size = 0;
508 {
509 sql::Statement s(db().GetUniqueStatement("PRAGMA page_size"));
510 ASSERT_TRUE(s.Step());
511 page_size = s.ColumnInt(0);
512 }
513 db().Close();
514
515 // Trim a single page from the end of the file.
516 {
517 file_util::ScopedFILE file(file_util::OpenFile(db_path(), "r+"));
518 ASSERT_TRUE(file.get() != NULL);
519 ASSERT_EQ(0, fseek(file.get(), -page_size, SEEK_END));
520 ASSERT_TRUE(file_util::TruncateFile(file.get()));
521 }
522
[email protected]fed734a2013-07-17 04:45:13523 // Open() will succeed, even though the PRAGMA calls within will
524 // fail with SQLITE_CORRUPT, as will this PRAGMA.
525 {
526 sql::ScopedErrorIgnorer ignore_errors;
527 ignore_errors.IgnoreError(SQLITE_CORRUPT);
528 ASSERT_TRUE(db().Open(db_path()));
529 ASSERT_FALSE(db().Execute("PRAGMA auto_vacuum"));
530 db().Close();
531 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
532 }
533
[email protected]7bae5742013-07-10 20:46:16534 db().set_error_callback(base::Bind(&SQLConnectionTest::RazeErrorCallback,
535 base::Unretained(this),
536 SQLITE_CORRUPT));
537
[email protected]fed734a2013-07-17 04:45:13538 // When the PRAGMA calls in Open() raise SQLITE_CORRUPT, the error
539 // callback will call RazeAndClose(). Open() will then fail and be
540 // retried. The second Open() on the empty database will succeed
541 // cleanly.
542 ASSERT_TRUE(db().Open(db_path()));
543 ASSERT_TRUE(db().Execute("PRAGMA auto_vacuum"));
[email protected]7bae5742013-07-10 20:46:16544 EXPECT_EQ(0, SqliteMasterCount(&db()));
545}
546
[email protected]41a97c812013-02-07 02:35:38547// Basic test of RazeAndClose() operation.
548TEST_F(SQLConnectionTest, RazeAndClose) {
549 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
550 const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)";
551
552 // Test that RazeAndClose() closes the database, and that the
553 // database is empty when re-opened.
554 ASSERT_TRUE(db().Execute(kCreateSql));
555 ASSERT_TRUE(db().Execute(kPopulateSql));
556 ASSERT_TRUE(db().RazeAndClose());
557 ASSERT_FALSE(db().is_open());
558 db().Close();
559 ASSERT_TRUE(db().Open(db_path()));
[email protected]7bae5742013-07-10 20:46:16560 ASSERT_EQ(0, SqliteMasterCount(&db()));
[email protected]41a97c812013-02-07 02:35:38561
562 // Test that RazeAndClose() can break transactions.
563 ASSERT_TRUE(db().Execute(kCreateSql));
564 ASSERT_TRUE(db().Execute(kPopulateSql));
565 ASSERT_TRUE(db().BeginTransaction());
566 ASSERT_TRUE(db().RazeAndClose());
567 ASSERT_FALSE(db().is_open());
568 ASSERT_FALSE(db().CommitTransaction());
569 db().Close();
570 ASSERT_TRUE(db().Open(db_path()));
[email protected]7bae5742013-07-10 20:46:16571 ASSERT_EQ(0, SqliteMasterCount(&db()));
[email protected]41a97c812013-02-07 02:35:38572}
573
574// Test that various operations fail without crashing after
575// RazeAndClose().
576TEST_F(SQLConnectionTest, RazeAndCloseDiagnostics) {
577 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
578 const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)";
579 const char* kSimpleSql = "SELECT 1";
580
581 ASSERT_TRUE(db().Execute(kCreateSql));
582 ASSERT_TRUE(db().Execute(kPopulateSql));
583
584 // Test baseline expectations.
585 db().Preload();
586 ASSERT_TRUE(db().DoesTableExist("foo"));
587 ASSERT_TRUE(db().IsSQLValid(kSimpleSql));
588 ASSERT_EQ(SQLITE_OK, db().ExecuteAndReturnErrorCode(kSimpleSql));
589 ASSERT_TRUE(db().Execute(kSimpleSql));
590 ASSERT_TRUE(db().is_open());
591 {
592 sql::Statement s(db().GetUniqueStatement(kSimpleSql));
593 ASSERT_TRUE(s.Step());
594 }
595 {
596 sql::Statement s(db().GetCachedStatement(SQL_FROM_HERE, kSimpleSql));
597 ASSERT_TRUE(s.Step());
598 }
599 ASSERT_TRUE(db().BeginTransaction());
600 ASSERT_TRUE(db().CommitTransaction());
601 ASSERT_TRUE(db().BeginTransaction());
602 db().RollbackTransaction();
603
604 ASSERT_TRUE(db().RazeAndClose());
605
606 // At this point, they should all fail, but not crash.
607 db().Preload();
608 ASSERT_FALSE(db().DoesTableExist("foo"));
609 ASSERT_FALSE(db().IsSQLValid(kSimpleSql));
610 ASSERT_EQ(SQLITE_ERROR, db().ExecuteAndReturnErrorCode(kSimpleSql));
611 ASSERT_FALSE(db().Execute(kSimpleSql));
612 ASSERT_FALSE(db().is_open());
613 {
614 sql::Statement s(db().GetUniqueStatement(kSimpleSql));
615 ASSERT_FALSE(s.Step());
616 }
617 {
618 sql::Statement s(db().GetCachedStatement(SQL_FROM_HERE, kSimpleSql));
619 ASSERT_FALSE(s.Step());
620 }
621 ASSERT_FALSE(db().BeginTransaction());
622 ASSERT_FALSE(db().CommitTransaction());
623 ASSERT_FALSE(db().BeginTransaction());
624 db().RollbackTransaction();
625
626 // Close normally to reset the poisoned flag.
627 db().Close();
628
629 // DEATH tests not supported on Android or iOS.
630#if !defined(OS_ANDROID) && !defined(OS_IOS)
631 // Once the real Close() has been called, various calls enforce API
632 // usage by becoming fatal in debug mode. Since DEATH tests are
633 // expensive, just test one of them.
634 if (DLOG_IS_ON(FATAL)) {
635 ASSERT_DEATH({
636 db().IsSQLValid(kSimpleSql);
637 }, "Illegal use of connection without a db");
638 }
639#endif
640}
641
642// TODO(shess): Spin up a background thread to hold other_db, to more
643// closely match real life. That would also allow testing
644// RazeWithTimeout().
645
[email protected]1348765a2012-07-24 08:25:53646#if defined(OS_ANDROID)
647TEST_F(SQLConnectionTest, SetTempDirForSQL) {
648
649 sql::MetaTable meta_table;
650 // Below call needs a temporary directory in sqlite3
651 // On Android, it can pass only when the temporary directory is set.
652 // Otherwise, sqlite3 doesn't find the correct directory to store
653 // temporary files and will report the error 'unable to open
654 // database file'.
655 ASSERT_TRUE(meta_table.Init(&db(), 4, 4));
656}
657#endif
[email protected]8d2e39e2013-06-24 05:55:08658
659TEST_F(SQLConnectionTest, Delete) {
660 EXPECT_TRUE(db().Execute("CREATE TABLE x (x)"));
661 db().Close();
662
663 // Should have both a main database file and a journal file because
664 // of journal_mode PERSIST.
665 base::FilePath journal(db_path().value() + FILE_PATH_LITERAL("-journal"));
[email protected]7567484142013-07-11 17:36:07666 ASSERT_TRUE(base::PathExists(db_path()));
667 ASSERT_TRUE(base::PathExists(journal));
[email protected]8d2e39e2013-06-24 05:55:08668
669 sql::Connection::Delete(db_path());
[email protected]7567484142013-07-11 17:36:07670 EXPECT_FALSE(base::PathExists(db_path()));
671 EXPECT_FALSE(base::PathExists(journal));
[email protected]8d2e39e2013-06-24 05:55:08672}
[email protected]7bae5742013-07-10 20:46:16673
674} // namespace