blob: b43e83cb48eceae63429d403b7fbf23c22bdeada [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]e5ffd0e42009-09-11 21:30:565#include "base/file_util.h"
[email protected]ea1a3f62012-11-16 20:34:236#include "base/files/scoped_temp_dir.h"
[email protected]41a97c812013-02-07 02:35:387#include "base/logging.h"
[email protected]f0a54b22011-07-19 18:40:218#include "sql/connection.h"
[email protected]1348765a2012-07-24 08:25:539#include "sql/meta_table.h"
[email protected]ea1a3f62012-11-16 20:34:2310#include "sql/statement.h"
[email protected]4350e322013-06-18 22:18:1011#include "sql/test/scoped_error_ignorer.h"
[email protected]e5ffd0e42009-09-11 21:30:5612#include "testing/gtest/include/gtest/gtest.h"
[email protected]e33cba42010-08-18 23:37:0313#include "third_party/sqlite/sqlite3.h"
[email protected]e5ffd0e42009-09-11 21:30:5614
15class SQLConnectionTest : public testing::Test {
16 public:
17 SQLConnectionTest() {}
18
[email protected]3dbbf7d2013-02-06 18:13:5319 virtual void SetUp() {
[email protected]3a305db2011-04-12 13:40:5320 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
[email protected]8e0c01282012-04-06 19:36:4921 ASSERT_TRUE(db_.Open(db_path()));
[email protected]e5ffd0e42009-09-11 21:30:5622 }
23
[email protected]3dbbf7d2013-02-06 18:13:5324 virtual void TearDown() {
[email protected]e5ffd0e42009-09-11 21:30:5625 db_.Close();
[email protected]e5ffd0e42009-09-11 21:30:5626 }
27
28 sql::Connection& db() { return db_; }
29
[email protected]a3ef4832013-02-02 05:12:3330 base::FilePath db_path() {
[email protected]8e0c01282012-04-06 19:36:4931 return temp_dir_.path().AppendASCII("SQLConnectionTest.db");
32 }
33
[email protected]e5ffd0e42009-09-11 21:30:5634 private:
[email protected]ea1a3f62012-11-16 20:34:2335 base::ScopedTempDir temp_dir_;
[email protected]e5ffd0e42009-09-11 21:30:5636 sql::Connection db_;
37};
38
39TEST_F(SQLConnectionTest, Execute) {
40 // Valid statement should return true.
41 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
42 EXPECT_EQ(SQLITE_OK, db().GetErrorCode());
43
44 // Invalid statement should fail.
[email protected]eff1fa522011-12-12 23:50:5945 ASSERT_EQ(SQLITE_ERROR,
46 db().ExecuteAndReturnErrorCode("CREATE TAB foo (a, b"));
[email protected]e5ffd0e42009-09-11 21:30:5647 EXPECT_EQ(SQLITE_ERROR, db().GetErrorCode());
48}
49
[email protected]eff1fa522011-12-12 23:50:5950TEST_F(SQLConnectionTest, ExecuteWithErrorCode) {
51 ASSERT_EQ(SQLITE_OK,
52 db().ExecuteAndReturnErrorCode("CREATE TABLE foo (a, b)"));
53 ASSERT_EQ(SQLITE_ERROR,
54 db().ExecuteAndReturnErrorCode("CREATE TABLE TABLE"));
55 ASSERT_EQ(SQLITE_ERROR,
56 db().ExecuteAndReturnErrorCode(
57 "INSERT INTO foo(a, b) VALUES (1, 2, 3, 4)"));
58}
59
[email protected]e5ffd0e42009-09-11 21:30:5660TEST_F(SQLConnectionTest, CachedStatement) {
61 sql::StatementID id1("foo", 12);
62
63 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
64 ASSERT_TRUE(db().Execute("INSERT INTO foo(a, b) VALUES (12, 13)"));
65
66 // Create a new cached statement.
67 {
68 sql::Statement s(db().GetCachedStatement(id1, "SELECT a FROM foo"));
[email protected]eff1fa522011-12-12 23:50:5969 ASSERT_TRUE(s.is_valid());
[email protected]e5ffd0e42009-09-11 21:30:5670
71 ASSERT_TRUE(s.Step());
72 EXPECT_EQ(12, s.ColumnInt(0));
73 }
74
75 // The statement should be cached still.
76 EXPECT_TRUE(db().HasCachedStatement(id1));
77
78 {
79 // Get the same statement using different SQL. This should ignore our
80 // SQL and use the cached one (so it will be valid).
81 sql::Statement s(db().GetCachedStatement(id1, "something invalid("));
[email protected]eff1fa522011-12-12 23:50:5982 ASSERT_TRUE(s.is_valid());
[email protected]e5ffd0e42009-09-11 21:30:5683
84 ASSERT_TRUE(s.Step());
85 EXPECT_EQ(12, s.ColumnInt(0));
86 }
87
88 // Make sure other statements aren't marked as cached.
89 EXPECT_FALSE(db().HasCachedStatement(SQL_FROM_HERE));
90}
91
[email protected]eff1fa522011-12-12 23:50:5992TEST_F(SQLConnectionTest, IsSQLValidTest) {
93 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
94 ASSERT_TRUE(db().IsSQLValid("SELECT a FROM foo"));
95 ASSERT_FALSE(db().IsSQLValid("SELECT no_exist FROM foo"));
96}
97
[email protected]e5ffd0e42009-09-11 21:30:5698TEST_F(SQLConnectionTest, DoesStuffExist) {
99 // Test DoesTableExist.
100 EXPECT_FALSE(db().DoesTableExist("foo"));
101 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
102 EXPECT_TRUE(db().DoesTableExist("foo"));
103
104 // Should be case sensitive.
105 EXPECT_FALSE(db().DoesTableExist("FOO"));
106
107 // Test DoesColumnExist.
108 EXPECT_FALSE(db().DoesColumnExist("foo", "bar"));
109 EXPECT_TRUE(db().DoesColumnExist("foo", "a"));
110
[email protected]e7afe2452010-08-22 16:19:13111 // Testing for a column on a nonexistent table.
[email protected]e5ffd0e42009-09-11 21:30:56112 EXPECT_FALSE(db().DoesColumnExist("bar", "b"));
113}
114
115TEST_F(SQLConnectionTest, GetLastInsertRowId) {
116 ASSERT_TRUE(db().Execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"));
117
118 ASSERT_TRUE(db().Execute("INSERT INTO foo (value) VALUES (12)"));
119
120 // Last insert row ID should be valid.
121 int64 row = db().GetLastInsertRowId();
122 EXPECT_LT(0, row);
123
124 // It should be the primary key of the row we just inserted.
125 sql::Statement s(db().GetUniqueStatement("SELECT value FROM foo WHERE id=?"));
126 s.BindInt64(0, row);
127 ASSERT_TRUE(s.Step());
128 EXPECT_EQ(12, s.ColumnInt(0));
129}
[email protected]44ad7d902012-03-23 00:09:05130
131TEST_F(SQLConnectionTest, Rollback) {
132 ASSERT_TRUE(db().BeginTransaction());
133 ASSERT_TRUE(db().BeginTransaction());
134 EXPECT_EQ(2, db().transaction_nesting());
135 db().RollbackTransaction();
136 EXPECT_FALSE(db().CommitTransaction());
137 EXPECT_TRUE(db().BeginTransaction());
138}
[email protected]8e0c01282012-04-06 19:36:49139
[email protected]4350e322013-06-18 22:18:10140// Test the scoped error ignorer by attempting to insert a duplicate
141// value into an index.
142TEST_F(SQLConnectionTest, ScopedIgnoreError) {
143 const char* kCreateSql = "CREATE TABLE foo (id INTEGER UNIQUE)";
144 ASSERT_TRUE(db().Execute(kCreateSql));
145 ASSERT_TRUE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
146
147 sql::ScopedErrorIgnorer ignore_errors;
148 ignore_errors.IgnoreError(SQLITE_CONSTRAINT);
149 ASSERT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
150 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
151}
152
[email protected]8e0c01282012-04-06 19:36:49153// Test that sql::Connection::Raze() results in a database without the
154// tables from the original database.
155TEST_F(SQLConnectionTest, Raze) {
156 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
157 ASSERT_TRUE(db().Execute(kCreateSql));
158 ASSERT_TRUE(db().Execute("INSERT INTO foo (value) VALUES (12)"));
159
[email protected]69c58452012-08-06 19:22:42160 int pragma_auto_vacuum = 0;
161 {
162 sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum"));
163 ASSERT_TRUE(s.Step());
164 pragma_auto_vacuum = s.ColumnInt(0);
165 ASSERT_TRUE(pragma_auto_vacuum == 0 || pragma_auto_vacuum == 1);
166 }
167
168 // If auto_vacuum is set, there's an extra page to maintain a freelist.
169 const int kExpectedPageCount = 2 + pragma_auto_vacuum;
170
[email protected]8e0c01282012-04-06 19:36:49171 {
172 sql::Statement s(db().GetUniqueStatement("PRAGMA page_count"));
173 ASSERT_TRUE(s.Step());
[email protected]69c58452012-08-06 19:22:42174 EXPECT_EQ(kExpectedPageCount, s.ColumnInt(0));
[email protected]8e0c01282012-04-06 19:36:49175 }
176
177 {
178 sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master"));
179 ASSERT_TRUE(s.Step());
180 EXPECT_EQ("table", s.ColumnString(0));
181 EXPECT_EQ("foo", s.ColumnString(1));
182 EXPECT_EQ("foo", s.ColumnString(2));
[email protected]69c58452012-08-06 19:22:42183 // Table "foo" is stored in the last page of the file.
184 EXPECT_EQ(kExpectedPageCount, s.ColumnInt(3));
[email protected]8e0c01282012-04-06 19:36:49185 EXPECT_EQ(kCreateSql, s.ColumnString(4));
186 }
187
188 ASSERT_TRUE(db().Raze());
189
190 {
191 sql::Statement s(db().GetUniqueStatement("PRAGMA page_count"));
192 ASSERT_TRUE(s.Step());
193 EXPECT_EQ(1, s.ColumnInt(0));
194 }
195
196 {
197 sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master"));
198 ASSERT_FALSE(s.Step());
199 }
[email protected]69c58452012-08-06 19:22:42200
201 {
202 sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum"));
203 ASSERT_TRUE(s.Step());
[email protected]6d42f152012-11-10 00:38:24204 // The new database has the same auto_vacuum as a fresh database.
[email protected]69c58452012-08-06 19:22:42205 EXPECT_EQ(pragma_auto_vacuum, s.ColumnInt(0));
206 }
[email protected]8e0c01282012-04-06 19:36:49207}
208
209// Test that Raze() maintains page_size.
210TEST_F(SQLConnectionTest, RazePageSize) {
[email protected]e73e89222012-07-13 18:55:22211 // Fetch the default page size and double it for use in this test.
[email protected]8e0c01282012-04-06 19:36:49212 // Scoped to release statement before Close().
[email protected]e73e89222012-07-13 18:55:22213 int default_page_size = 0;
[email protected]8e0c01282012-04-06 19:36:49214 {
215 sql::Statement s(db().GetUniqueStatement("PRAGMA page_size"));
216 ASSERT_TRUE(s.Step());
[email protected]e73e89222012-07-13 18:55:22217 default_page_size = s.ColumnInt(0);
[email protected]8e0c01282012-04-06 19:36:49218 }
[email protected]e73e89222012-07-13 18:55:22219 ASSERT_GT(default_page_size, 0);
220 const int kPageSize = 2 * default_page_size;
[email protected]8e0c01282012-04-06 19:36:49221
222 // Re-open the database to allow setting the page size.
223 db().Close();
224 db().set_page_size(kPageSize);
225 ASSERT_TRUE(db().Open(db_path()));
226
227 // page_size should match the indicated value.
228 sql::Statement s(db().GetUniqueStatement("PRAGMA page_size"));
229 ASSERT_TRUE(s.Step());
230 ASSERT_EQ(kPageSize, s.ColumnInt(0));
231
232 // After raze, page_size should still match the indicated value.
233 ASSERT_TRUE(db().Raze());
[email protected]389e0a42012-04-25 21:36:41234 s.Reset(true);
[email protected]8e0c01282012-04-06 19:36:49235 ASSERT_TRUE(s.Step());
236 ASSERT_EQ(kPageSize, s.ColumnInt(0));
237}
238
239// Test that Raze() results are seen in other connections.
240TEST_F(SQLConnectionTest, RazeMultiple) {
241 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
242 ASSERT_TRUE(db().Execute(kCreateSql));
243
244 sql::Connection other_db;
245 ASSERT_TRUE(other_db.Open(db_path()));
246
247 // Check that the second connection sees the table.
248 const char *kTablesQuery = "SELECT COUNT(*) FROM sqlite_master";
249 sql::Statement s(other_db.GetUniqueStatement(kTablesQuery));
250 ASSERT_TRUE(s.Step());
251 ASSERT_EQ(1, s.ColumnInt(0));
252 ASSERT_FALSE(s.Step()); // Releases the shared lock.
253
254 ASSERT_TRUE(db().Raze());
255
256 // The second connection sees the updated database.
[email protected]389e0a42012-04-25 21:36:41257 s.Reset(true);
[email protected]8e0c01282012-04-06 19:36:49258 ASSERT_TRUE(s.Step());
259 ASSERT_EQ(0, s.ColumnInt(0));
260}
261
262TEST_F(SQLConnectionTest, RazeLocked) {
263 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
264 ASSERT_TRUE(db().Execute(kCreateSql));
265
266 // Open a transaction and write some data in a second connection.
267 // This will acquire a PENDING or EXCLUSIVE transaction, which will
268 // cause the raze to fail.
269 sql::Connection other_db;
270 ASSERT_TRUE(other_db.Open(db_path()));
271 ASSERT_TRUE(other_db.BeginTransaction());
272 const char* kInsertSql = "INSERT INTO foo VALUES (1, 'data')";
273 ASSERT_TRUE(other_db.Execute(kInsertSql));
274
275 ASSERT_FALSE(db().Raze());
276
277 // Works after COMMIT.
278 ASSERT_TRUE(other_db.CommitTransaction());
279 ASSERT_TRUE(db().Raze());
280
281 // Re-create the database.
282 ASSERT_TRUE(db().Execute(kCreateSql));
283 ASSERT_TRUE(db().Execute(kInsertSql));
284
285 // An unfinished read transaction in the other connection also
286 // blocks raze.
287 const char *kQuery = "SELECT COUNT(*) FROM foo";
288 sql::Statement s(other_db.GetUniqueStatement(kQuery));
289 ASSERT_TRUE(s.Step());
290 ASSERT_FALSE(db().Raze());
291
292 // Complete the statement unlocks the database.
293 ASSERT_FALSE(s.Step());
294 ASSERT_TRUE(db().Raze());
295}
296
[email protected]41a97c812013-02-07 02:35:38297// Basic test of RazeAndClose() operation.
298TEST_F(SQLConnectionTest, RazeAndClose) {
299 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
300 const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)";
301
302 // Test that RazeAndClose() closes the database, and that the
303 // database is empty when re-opened.
304 ASSERT_TRUE(db().Execute(kCreateSql));
305 ASSERT_TRUE(db().Execute(kPopulateSql));
306 ASSERT_TRUE(db().RazeAndClose());
307 ASSERT_FALSE(db().is_open());
308 db().Close();
309 ASSERT_TRUE(db().Open(db_path()));
310 {
311 sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master"));
312 ASSERT_FALSE(s.Step());
313 }
314
315 // Test that RazeAndClose() can break transactions.
316 ASSERT_TRUE(db().Execute(kCreateSql));
317 ASSERT_TRUE(db().Execute(kPopulateSql));
318 ASSERT_TRUE(db().BeginTransaction());
319 ASSERT_TRUE(db().RazeAndClose());
320 ASSERT_FALSE(db().is_open());
321 ASSERT_FALSE(db().CommitTransaction());
322 db().Close();
323 ASSERT_TRUE(db().Open(db_path()));
324 {
325 sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master"));
326 ASSERT_FALSE(s.Step());
327 }
328}
329
330// Test that various operations fail without crashing after
331// RazeAndClose().
332TEST_F(SQLConnectionTest, RazeAndCloseDiagnostics) {
333 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
334 const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)";
335 const char* kSimpleSql = "SELECT 1";
336
337 ASSERT_TRUE(db().Execute(kCreateSql));
338 ASSERT_TRUE(db().Execute(kPopulateSql));
339
340 // Test baseline expectations.
341 db().Preload();
342 ASSERT_TRUE(db().DoesTableExist("foo"));
343 ASSERT_TRUE(db().IsSQLValid(kSimpleSql));
344 ASSERT_EQ(SQLITE_OK, db().ExecuteAndReturnErrorCode(kSimpleSql));
345 ASSERT_TRUE(db().Execute(kSimpleSql));
346 ASSERT_TRUE(db().is_open());
347 {
348 sql::Statement s(db().GetUniqueStatement(kSimpleSql));
349 ASSERT_TRUE(s.Step());
350 }
351 {
352 sql::Statement s(db().GetCachedStatement(SQL_FROM_HERE, kSimpleSql));
353 ASSERT_TRUE(s.Step());
354 }
355 ASSERT_TRUE(db().BeginTransaction());
356 ASSERT_TRUE(db().CommitTransaction());
357 ASSERT_TRUE(db().BeginTransaction());
358 db().RollbackTransaction();
359
360 ASSERT_TRUE(db().RazeAndClose());
361
362 // At this point, they should all fail, but not crash.
363 db().Preload();
364 ASSERT_FALSE(db().DoesTableExist("foo"));
365 ASSERT_FALSE(db().IsSQLValid(kSimpleSql));
366 ASSERT_EQ(SQLITE_ERROR, db().ExecuteAndReturnErrorCode(kSimpleSql));
367 ASSERT_FALSE(db().Execute(kSimpleSql));
368 ASSERT_FALSE(db().is_open());
369 {
370 sql::Statement s(db().GetUniqueStatement(kSimpleSql));
371 ASSERT_FALSE(s.Step());
372 }
373 {
374 sql::Statement s(db().GetCachedStatement(SQL_FROM_HERE, kSimpleSql));
375 ASSERT_FALSE(s.Step());
376 }
377 ASSERT_FALSE(db().BeginTransaction());
378 ASSERT_FALSE(db().CommitTransaction());
379 ASSERT_FALSE(db().BeginTransaction());
380 db().RollbackTransaction();
381
382 // Close normally to reset the poisoned flag.
383 db().Close();
384
385 // DEATH tests not supported on Android or iOS.
386#if !defined(OS_ANDROID) && !defined(OS_IOS)
387 // Once the real Close() has been called, various calls enforce API
388 // usage by becoming fatal in debug mode. Since DEATH tests are
389 // expensive, just test one of them.
390 if (DLOG_IS_ON(FATAL)) {
391 ASSERT_DEATH({
392 db().IsSQLValid(kSimpleSql);
393 }, "Illegal use of connection without a db");
394 }
395#endif
396}
397
398// TODO(shess): Spin up a background thread to hold other_db, to more
399// closely match real life. That would also allow testing
400// RazeWithTimeout().
401
[email protected]1348765a2012-07-24 08:25:53402#if defined(OS_ANDROID)
403TEST_F(SQLConnectionTest, SetTempDirForSQL) {
404
405 sql::MetaTable meta_table;
406 // Below call needs a temporary directory in sqlite3
407 // On Android, it can pass only when the temporary directory is set.
408 // Otherwise, sqlite3 doesn't find the correct directory to store
409 // temporary files and will report the error 'unable to open
410 // database file'.
411 ASSERT_TRUE(meta_table.Init(&db(), 4, 4));
412}
413#endif