15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/bind.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/scoped_temp_dir.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/connection.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/meta_table.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sql/statement.h"
127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "sql/test/error_callback_support.h"
137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "sql/test/scoped_error_ignorer.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/sqlite/sqlite3.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace {
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Helper to return the count of items in sqlite_master.  Return -1 in
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// case of error.
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochint SqliteMasterCount(sql::Connection* db) {
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const char* kMasterCount = "SELECT COUNT(*) FROM sqlite_master";
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sql::Statement s(db->GetUniqueStatement(kMasterCount));
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return s.Step() ? s.ColumnInt(0) : -1;
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Track the number of valid references which share the same pointer.
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// This is used to allow testing an implicitly use-after-free case by
297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// explicitly having the ref count live longer than the object.
307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass RefCounter {
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch public:
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  RefCounter(size_t* counter)
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      : counter_(counter) {
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    (*counter_)++;
357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  RefCounter(const RefCounter& other)
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      : counter_(other.counter_) {
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    (*counter_)++;
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ~RefCounter() {
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    (*counter_)--;
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch private:
457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  size_t* counter_;
467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DISALLOW_ASSIGN(RefCounter);
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch};
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Empty callback for implementation of ErrorCallbackSetHelper().
517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid IgnoreErrorCallback(int error, sql::Statement* stmt) {
527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ErrorCallbackSetHelper(sql::Connection* db,
557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            size_t* counter,
567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            const RefCounter& r,
577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            int error, sql::Statement* stmt) {
587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // The ref count should not go to zero when changing the callback.
597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_GT(*counter, 0u);
607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  db->set_error_callback(base::Bind(&IgnoreErrorCallback));
617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_GT(*counter, 0u);
627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ErrorCallbackResetHelper(sql::Connection* db,
657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                              size_t* counter,
667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                              const RefCounter& r,
677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                              int error, sql::Statement* stmt) {
687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // The ref count should not go to zero when clearing the callback.
697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_GT(*counter, 0u);
707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  db->reset_error_callback();
717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_GT(*counter, 0u);
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
749ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#if defined(OS_POSIX)
759ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Set a umask and restore the old mask on destruction.  Cribbed from
769ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// shared_memory_unittest.cc.  Used by POSIX-only UserPermission test.
779ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochclass ScopedUmaskSetter {
789ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch public:
799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  explicit ScopedUmaskSetter(mode_t target_mask) {
809ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    old_umask_ = umask(target_mask);
819ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
829ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ~ScopedUmaskSetter() { umask(old_umask_); }
839ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch private:
849ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  mode_t old_umask_;
859ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter);
869ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch};
879ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#endif
889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SQLConnectionTest : public testing::Test {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SQLConnectionTest() {}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void SetUp() {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(db_.Open(db_path()));
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void TearDown() {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_.Close();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Connection& db() { return db_; }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath db_path() {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return temp_dir_.path().AppendASCII("SQLConnectionTest.db");
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Handle errors by blowing away the database.
1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  void RazeErrorCallback(int expected_error, int error, sql::Statement* stmt) {
1107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    EXPECT_EQ(expected_error, error);
1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    db_.RazeAndClose();
1127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ScopedTempDir temp_dir_;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Connection db_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLConnectionTest, Execute) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Valid statement should return true.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(SQLITE_OK, db().GetErrorCode());
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Invalid statement should fail.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(SQLITE_ERROR,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            db().ExecuteAndReturnErrorCode("CREATE TAB foo (a, b"));
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(SQLITE_ERROR, db().GetErrorCode());
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLConnectionTest, ExecuteWithErrorCode) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(SQLITE_OK,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            db().ExecuteAndReturnErrorCode("CREATE TABLE foo (a, b)"));
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(SQLITE_ERROR,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            db().ExecuteAndReturnErrorCode("CREATE TABLE TABLE"));
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(SQLITE_ERROR,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            db().ExecuteAndReturnErrorCode(
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                "INSERT INTO foo(a, b) VALUES (1, 2, 3, 4)"));
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLConnectionTest, CachedStatement) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::StatementID id1("foo", 12);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("INSERT INTO foo(a, b) VALUES (12, 13)"));
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a new cached statement.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(db().GetCachedStatement(id1, "SELECT a FROM foo"));
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(s.is_valid());
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(s.Step());
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(12, s.ColumnInt(0));
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The statement should be cached still.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(db().HasCachedStatement(id1));
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the same statement using different SQL. This should ignore our
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // SQL and use the cached one (so it will be valid).
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(db().GetCachedStatement(id1, "something invalid("));
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(s.is_valid());
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(s.Step());
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(12, s.ColumnInt(0));
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure other statements aren't marked as cached.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(db().HasCachedStatement(SQL_FROM_HERE));
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLConnectionTest, IsSQLValidTest) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().IsSQLValid("SELECT a FROM foo"));
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(db().IsSQLValid("SELECT no_exist FROM foo"));
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLConnectionTest, DoesStuffExist) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test DoesTableExist.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(db().DoesTableExist("foo"));
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(db().DoesTableExist("foo"));
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Should be case sensitive.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(db().DoesTableExist("FOO"));
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test DoesColumnExist.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(db().DoesColumnExist("foo", "bar"));
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(db().DoesColumnExist("foo", "a"));
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Testing for a column on a nonexistent table.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(db().DoesColumnExist("bar", "b"));
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLConnectionTest, GetLastInsertRowId) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"));
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("INSERT INTO foo (value) VALUES (12)"));
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Last insert row ID should be valid.
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 row = db().GetLastInsertRowId();
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_LT(0, row);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It should be the primary key of the row we just inserted.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement s(db().GetUniqueStatement("SELECT value FROM foo WHERE id=?"));
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.BindInt64(0, row);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(s.Step());
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(12, s.ColumnInt(0));
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLConnectionTest, Rollback) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().BeginTransaction());
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().BeginTransaction());
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2, db().transaction_nesting());
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db().RollbackTransaction();
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(db().CommitTransaction());
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(db().BeginTransaction());
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Test the scoped error ignorer by attempting to insert a duplicate
2217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// value into an index.
2227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)TEST_F(SQLConnectionTest, ScopedIgnoreError) {
2237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const char* kCreateSql = "CREATE TABLE foo (id INTEGER UNIQUE)";
2247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ASSERT_TRUE(db().Execute(kCreateSql));
2257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ASSERT_TRUE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
2267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  sql::ScopedErrorIgnorer ignore_errors;
2287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ignore_errors.IgnoreError(SQLITE_CONSTRAINT);
2297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ASSERT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
2307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
2317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2337dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochTEST_F(SQLConnectionTest, ErrorCallback) {
2347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const char* kCreateSql = "CREATE TABLE foo (id INTEGER UNIQUE)";
2357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(db().Execute(kCreateSql));
2367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
2377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int error = SQLITE_OK;
2397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
2407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sql::ScopedErrorCallback sec(
2417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        &db(), base::Bind(&sql::CaptureErrorCallback, &error));
2427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    EXPECT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
2437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    EXPECT_EQ(SQLITE_CONSTRAINT, error);
2447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Callback is no longer in force due to reset.
2477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
2487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    error = SQLITE_OK;
2497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sql::ScopedErrorIgnorer ignore_errors;
2507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ignore_errors.IgnoreError(SQLITE_CONSTRAINT);
2517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
2527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
2537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    EXPECT_EQ(SQLITE_OK, error);
2547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // base::Bind() can curry arguments to be passed by const reference
2579ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // to the callback function.  If the callback function calls
2589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // re/set_error_callback(), the storage for those arguments can be
2599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // deleted while the callback function is still executing.
2607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  //
2617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // RefCounter() counts how many objects are live using an external
2627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // count.  The same counter is passed to the callback, so that it
2637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // can check directly even if the RefCounter object is no longer
2647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // live.
2657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
2667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    size_t count = 0;
2677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sql::ScopedErrorCallback sec(
2687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        &db(), base::Bind(&ErrorCallbackSetHelper,
2697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                          &db(), &count, RefCounter(&count)));
2707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    EXPECT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
2727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Same test, but reset_error_callback() case.
2757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
2767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    size_t count = 0;
2777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sql::ScopedErrorCallback sec(
2787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        &db(), base::Bind(&ErrorCallbackResetHelper,
2797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                          &db(), &count, RefCounter(&count)));
2807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    EXPECT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
2827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test that sql::Connection::Raze() results in a database without the
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// tables from the original database.
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLConnectionTest, Raze) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute(kCreateSql));
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("INSERT INTO foo (value) VALUES (12)"));
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pragma_auto_vacuum = 0;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum"));
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(s.Step());
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pragma_auto_vacuum = s.ColumnInt(0);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(pragma_auto_vacuum == 0 || pragma_auto_vacuum == 1);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If auto_vacuum is set, there's an extra page to maintain a freelist.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kExpectedPageCount = 2 + pragma_auto_vacuum;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(db().GetUniqueStatement("PRAGMA page_count"));
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(s.Step());
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(kExpectedPageCount, s.ColumnInt(0));
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master"));
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(s.Step());
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ("table", s.ColumnString(0));
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ("foo", s.ColumnString(1));
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ("foo", s.ColumnString(2));
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Table "foo" is stored in the last page of the file.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(kExpectedPageCount, s.ColumnInt(3));
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(kCreateSql, s.ColumnString(4));
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Raze());
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(db().GetUniqueStatement("PRAGMA page_count"));
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(s.Step());
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(1, s.ColumnInt(0));
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_EQ(0, SqliteMasterCount(&db()));
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum"));
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(s.Step());
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The new database has the same auto_vacuum as a fresh database.
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(pragma_auto_vacuum, s.ColumnInt(0));
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test that Raze() maintains page_size.
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLConnectionTest, RazePageSize) {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fetch the default page size and double it for use in this test.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Scoped to release statement before Close().
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int default_page_size = 0;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(db().GetUniqueStatement("PRAGMA page_size"));
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(s.Step());
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_page_size = s.ColumnInt(0);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_GT(default_page_size, 0);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kPageSize = 2 * default_page_size;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Re-open the database to allow setting the page size.
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db().Close();
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db().set_page_size(kPageSize);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Open(db_path()));
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // page_size should match the indicated value.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement s(db().GetUniqueStatement("PRAGMA page_size"));
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(s.Step());
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(kPageSize, s.ColumnInt(0));
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // After raze, page_size should still match the indicated value.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Raze());
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.Reset(true);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(s.Step());
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(kPageSize, s.ColumnInt(0));
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test that Raze() results are seen in other connections.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLConnectionTest, RazeMultiple) {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute(kCreateSql));
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Connection other_db;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(other_db.Open(db_path()));
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that the second connection sees the table.
3777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_EQ(1, SqliteMasterCount(&other_db));
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Raze());
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The second connection sees the updated database.
3827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_EQ(0, SqliteMasterCount(&other_db));
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLConnectionTest, RazeLocked) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute(kCreateSql));
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open a transaction and write some data in a second connection.
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This will acquire a PENDING or EXCLUSIVE transaction, which will
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cause the raze to fail.
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Connection other_db;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(other_db.Open(db_path()));
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(other_db.BeginTransaction());
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* kInsertSql = "INSERT INTO foo VALUES (1, 'data')";
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(other_db.Execute(kInsertSql));
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(db().Raze());
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Works after COMMIT.
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(other_db.CommitTransaction());
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Raze());
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Re-create the database.
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute(kCreateSql));
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute(kInsertSql));
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // An unfinished read transaction in the other connection also
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // blocks raze.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *kQuery = "SELECT COUNT(*) FROM foo";
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement s(other_db.GetUniqueStatement(kQuery));
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(s.Step());
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(db().Raze());
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Complete the statement unlocks the database.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(s.Step());
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Raze());
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Verify that Raze() can handle an empty file.  SQLite should treat
4217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// this as an empty database.
4227dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochTEST_F(SQLConnectionTest, RazeEmptyDB) {
4237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
4247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(db().Execute(kCreateSql));
4257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  db().Close();
4267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
4282385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    file_util::ScopedFILE file(file_util::OpenFile(db_path(), "rb+"));
4297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_TRUE(file.get() != NULL);
4307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_EQ(0, fseek(file.get(), 0, SEEK_SET));
4317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_TRUE(file_util::TruncateFile(file.get()));
4327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(db().Open(db_path()));
4357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(db().Raze());
4367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_EQ(0, SqliteMasterCount(&db()));
4377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
4387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Verify that Raze() can handle a file of junk.
4407dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochTEST_F(SQLConnectionTest, RazeNOTADB) {
4417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  db().Close();
4427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sql::Connection::Delete(db_path());
4437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_FALSE(base::PathExists(db_path()));
4447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
4462385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    file_util::ScopedFILE file(file_util::OpenFile(db_path(), "wb"));
4477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_TRUE(file.get() != NULL);
4487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const char* kJunk = "This is the hour of our discontent.";
4507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    fputs(kJunk, file.get());
4517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(base::PathExists(db_path()));
4537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // SQLite will successfully open the handle, but will fail with
4557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // SQLITE_IOERR_SHORT_READ on pragma statemenets which read the
4567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // header.
4577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
4587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sql::ScopedErrorIgnorer ignore_errors;
4597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ignore_errors.IgnoreError(SQLITE_IOERR_SHORT_READ);
4607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    EXPECT_TRUE(db().Open(db_path()));
4617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
4627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_TRUE(db().Raze());
4647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  db().Close();
4657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Now empty, the open should open an empty database.
4677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_TRUE(db().Open(db_path()));
4687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_EQ(0, SqliteMasterCount(&db()));
4697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
4707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Verify that Raze() can handle a database overwritten with garbage.
4727dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochTEST_F(SQLConnectionTest, RazeNOTADB2) {
4737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
4747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(db().Execute(kCreateSql));
4757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_EQ(1, SqliteMasterCount(&db()));
4767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  db().Close();
4777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
4792385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    file_util::ScopedFILE file(file_util::OpenFile(db_path(), "rb+"));
4807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_TRUE(file.get() != NULL);
4817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_EQ(0, fseek(file.get(), 0, SEEK_SET));
4827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const char* kJunk = "This is the hour of our discontent.";
4847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    fputs(kJunk, file.get());
4857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // SQLite will successfully open the handle, but will fail with
4887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // SQLITE_NOTADB on pragma statemenets which attempt to read the
4897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // corrupted header.
4907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
4917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sql::ScopedErrorIgnorer ignore_errors;
4927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ignore_errors.IgnoreError(SQLITE_NOTADB);
4937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    EXPECT_TRUE(db().Open(db_path()));
4947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
4957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_TRUE(db().Raze());
4977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  db().Close();
4987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Now empty, the open should succeed with an empty database.
5007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_TRUE(db().Open(db_path()));
5017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_EQ(0, SqliteMasterCount(&db()));
5027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
5037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Test that a callback from Open() can raze the database.  This is
5057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// essential for cases where the Open() can fail entirely, so the
5067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Raze() cannot happen later.  Additionally test that when the
5077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// callback does this during Open(), the open is retried and succeeds.
5087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch//
5097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Most corruptions seen in the wild seem to happen when two pages in
5107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// the database were not written transactionally (the transaction
5117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// changed both, but one wasn't successfully written for some reason).
5127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// A special case of that is when the header indicates that the
5137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// database contains more pages than are in the file.  This breaks
5147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// things at a very basic level, verify that Raze() can handle it.
5157dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochTEST_F(SQLConnectionTest, RazeCallbackReopen) {
5167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
5177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(db().Execute(kCreateSql));
5187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_EQ(1, SqliteMasterCount(&db()));
5197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int page_size = 0;
5207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
5217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sql::Statement s(db().GetUniqueStatement("PRAGMA page_size"));
5227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_TRUE(s.Step());
5237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    page_size = s.ColumnInt(0);
5247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
5257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  db().Close();
5267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Trim a single page from the end of the file.
5287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
5292385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    file_util::ScopedFILE file(file_util::OpenFile(db_path(), "rb+"));
5307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_TRUE(file.get() != NULL);
5317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_EQ(0, fseek(file.get(), -page_size, SEEK_END));
5327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_TRUE(file_util::TruncateFile(file.get()));
5337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
5347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Open() will succeed, even though the PRAGMA calls within will
5367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // fail with SQLITE_CORRUPT, as will this PRAGMA.
5377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
5387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sql::ScopedErrorIgnorer ignore_errors;
5397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ignore_errors.IgnoreError(SQLITE_CORRUPT);
5407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_TRUE(db().Open(db_path()));
5417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_FALSE(db().Execute("PRAGMA auto_vacuum"));
5427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    db().Close();
5437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
5447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
5457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  db().set_error_callback(base::Bind(&SQLConnectionTest::RazeErrorCallback,
5477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                     base::Unretained(this),
5487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                     SQLITE_CORRUPT));
5497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // When the PRAGMA calls in Open() raise SQLITE_CORRUPT, the error
5517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // callback will call RazeAndClose().  Open() will then fail and be
5527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // retried.  The second Open() on the empty database will succeed
5537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // cleanly.
5547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(db().Open(db_path()));
5557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(db().Execute("PRAGMA auto_vacuum"));
5567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_EQ(0, SqliteMasterCount(&db()));
5577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
5587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Basic test of RazeAndClose() operation.
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(SQLConnectionTest, RazeAndClose) {
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)";
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Test that RazeAndClose() closes the database, and that the
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // database is empty when re-opened.
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().Execute(kCreateSql));
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().Execute(kPopulateSql));
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().RazeAndClose());
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(db().is_open());
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db().Close();
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().Open(db_path()));
5727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_EQ(0, SqliteMasterCount(&db()));
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Test that RazeAndClose() can break transactions.
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().Execute(kCreateSql));
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().Execute(kPopulateSql));
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().BeginTransaction());
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().RazeAndClose());
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(db().is_open());
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(db().CommitTransaction());
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db().Close();
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().Open(db_path()));
5837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_EQ(0, SqliteMasterCount(&db()));
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Test that various operations fail without crashing after
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// RazeAndClose().
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(SQLConnectionTest, RazeAndCloseDiagnostics) {
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)";
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const char* kSimpleSql = "SELECT 1";
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().Execute(kCreateSql));
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().Execute(kPopulateSql));
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Test baseline expectations.
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db().Preload();
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().DoesTableExist("foo"));
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().IsSQLValid(kSimpleSql));
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(SQLITE_OK, db().ExecuteAndReturnErrorCode(kSimpleSql));
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().Execute(kSimpleSql));
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().is_open());
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sql::Statement s(db().GetUniqueStatement(kSimpleSql));
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(s.Step());
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sql::Statement s(db().GetCachedStatement(SQL_FROM_HERE, kSimpleSql));
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(s.Step());
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().BeginTransaction());
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().CommitTransaction());
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().BeginTransaction());
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db().RollbackTransaction();
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(db().RazeAndClose());
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // At this point, they should all fail, but not crash.
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db().Preload();
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(db().DoesTableExist("foo"));
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(db().IsSQLValid(kSimpleSql));
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(SQLITE_ERROR, db().ExecuteAndReturnErrorCode(kSimpleSql));
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(db().Execute(kSimpleSql));
6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(db().is_open());
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sql::Statement s(db().GetUniqueStatement(kSimpleSql));
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_FALSE(s.Step());
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sql::Statement s(db().GetCachedStatement(SQL_FROM_HERE, kSimpleSql));
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_FALSE(s.Step());
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(db().BeginTransaction());
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(db().CommitTransaction());
6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(db().BeginTransaction());
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db().RollbackTransaction();
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Close normally to reset the poisoned flag.
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  db().Close();
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // DEATH tests not supported on Android or iOS.
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(OS_ANDROID) && !defined(OS_IOS)
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Once the real Close() has been called, various calls enforce API
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // usage by becoming fatal in debug mode.  Since DEATH tests are
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // expensive, just test one of them.
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (DLOG_IS_ON(FATAL)) {
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_DEATH({
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        db().IsSQLValid(kSimpleSql);
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }, "Illegal use of connection without a db");
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(shess): Spin up a background thread to hold other_db, to more
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// closely match real life.  That would also allow testing
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// RazeWithTimeout().
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLConnectionTest, SetTempDirForSQL) {
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::MetaTable meta_table;
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Below call needs a temporary directory in sqlite3
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On Android, it can pass only when the temporary directory is set.
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Otherwise, sqlite3 doesn't find the correct directory to store
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // temporary files and will report the error 'unable to open
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // database file'.
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(meta_table.Init(&db(), 4, 4));
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
670eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
671eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_F(SQLConnectionTest, Delete) {
672eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_TRUE(db().Execute("CREATE TABLE x (x)"));
673eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  db().Close();
674eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
675eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Should have both a main database file and a journal file because
676eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // of journal_mode PERSIST.
677eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath journal(db_path().value() + FILE_PATH_LITERAL("-journal"));
6787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(base::PathExists(db_path()));
6797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(base::PathExists(journal));
680eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
681eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  sql::Connection::Delete(db_path());
6827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_FALSE(base::PathExists(db_path()));
6837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_FALSE(base::PathExists(journal));
684eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
6857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
6869ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#if defined(OS_POSIX)
6879ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Test that set_restrict_to_user() trims database permissions so that
6889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// only the owner (and root) can read.
6899ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochTEST_F(SQLConnectionTest, UserPermission) {
6909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // If the bots all had a restrictive umask setting such that
6919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // databases are always created with only the owner able to read
6929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // them, then the code could break without breaking the tests.
6939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Temporarily provide a more permissive umask.
6949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  db().Close();
6959ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  sql::Connection::Delete(db_path());
6969ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_FALSE(base::PathExists(db_path()));
6979ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ScopedUmaskSetter permissive_umask(S_IWGRP | S_IWOTH);
6989ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_TRUE(db().Open(db_path()));
6999ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7009ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Cause the journal file to be created.  If the default
7019ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // journal_mode is changed back to DELETE, then parts of this test
7029ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // will need to be updated.
7039ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_TRUE(db().Execute("CREATE TABLE x (x)"));
7049ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7059ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  base::FilePath journal(db_path().value() + FILE_PATH_LITERAL("-journal"));
7069ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  int mode;
7079ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7089ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Given a permissive umask, the database is created with permissive
7099ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // read access for the database and journal.
7109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_TRUE(base::PathExists(db_path()));
7119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_TRUE(base::PathExists(journal));
7129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  mode = file_util::FILE_PERMISSION_MASK;
7139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_TRUE(file_util::GetPosixFilePermissions(db_path(), &mode));
7149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_NE((mode & file_util::FILE_PERMISSION_USER_MASK), mode);
7159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  mode = file_util::FILE_PERMISSION_MASK;
7169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_TRUE(file_util::GetPosixFilePermissions(journal, &mode));
7179ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_NE((mode & file_util::FILE_PERMISSION_USER_MASK), mode);
7189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7199ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Re-open with restricted permissions and verify that the modes
7209ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // changed for both the main database and the journal.
7219ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  db().Close();
7229ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  db().set_restrict_to_user();
7239ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_TRUE(db().Open(db_path()));
7249ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_TRUE(base::PathExists(db_path()));
7259ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_TRUE(base::PathExists(journal));
7269ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  mode = file_util::FILE_PERMISSION_MASK;
7279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_TRUE(file_util::GetPosixFilePermissions(db_path(), &mode));
7289ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_EQ((mode & file_util::FILE_PERMISSION_USER_MASK), mode);
7299ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  mode = file_util::FILE_PERMISSION_MASK;
7309ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_TRUE(file_util::GetPosixFilePermissions(journal, &mode));
7319ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_EQ((mode & file_util::FILE_PERMISSION_USER_MASK), mode);
7329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7339ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Delete and re-create the database, the restriction should still apply.
7349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  db().Close();
7359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  sql::Connection::Delete(db_path());
7369ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_TRUE(db().Open(db_path()));
7379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_TRUE(base::PathExists(db_path()));
7389ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_FALSE(base::PathExists(journal));
7399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  mode = file_util::FILE_PERMISSION_MASK;
7409ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_TRUE(file_util::GetPosixFilePermissions(db_path(), &mode));
7419ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_EQ((mode & file_util::FILE_PERMISSION_USER_MASK), mode);
7429ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7439ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Verify that journal creation inherits the restriction.
7449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_TRUE(db().Execute("CREATE TABLE x (x)"));
7459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_TRUE(base::PathExists(journal));
7469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  mode = file_util::FILE_PERMISSION_MASK;
7479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  EXPECT_TRUE(file_util::GetPosixFilePermissions(journal, &mode));
7489ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  ASSERT_EQ((mode & file_util::FILE_PERMISSION_USER_MASK), mode);
7499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
7509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#endif  // defined(OS_POSIX)
7519ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
752ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Test that errors start happening once Poison() is called.
753ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochTEST_F(SQLConnectionTest, Poison) {
754ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_TRUE(db().Execute("CREATE TABLE x (x)"));
755ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
756ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Before the Poison() call, things generally work.
757ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_TRUE(db().IsSQLValid("INSERT INTO x VALUES ('x')"));
758ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_TRUE(db().Execute("INSERT INTO x VALUES ('x')"));
759ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  {
760ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    sql::Statement s(db().GetUniqueStatement("SELECT COUNT(*) FROM x"));
761ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ASSERT_TRUE(s.is_valid());
762ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ASSERT_TRUE(s.Step());
763ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
764ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
765ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Get a statement which is valid before and will exist across Poison().
766ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  sql::Statement valid_statement(
767ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      db().GetUniqueStatement("SELECT COUNT(*) FROM sqlite_master"));
768ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ASSERT_TRUE(valid_statement.is_valid());
769ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ASSERT_TRUE(valid_statement.Step());
770ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  valid_statement.Reset(true);
771ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
772ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  db().Poison();
773ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
774ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // After the Poison() call, things fail.
775ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_FALSE(db().IsSQLValid("INSERT INTO x VALUES ('x')"));
776ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_FALSE(db().Execute("INSERT INTO x VALUES ('x')"));
777ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  {
778ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    sql::Statement s(db().GetUniqueStatement("SELECT COUNT(*) FROM x"));
779ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ASSERT_FALSE(s.is_valid());
780ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ASSERT_FALSE(s.Step());
781ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
782ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
783ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // The existing statement has become invalid.
784ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ASSERT_FALSE(valid_statement.is_valid());
785ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ASSERT_FALSE(valid_statement.Step());
786ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
787ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
788ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Test attaching and detaching databases from the connection.
789ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochTEST_F(SQLConnectionTest, Attach) {
790ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
791ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
792ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Create a database to attach to.
793ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::FilePath attach_path =
794ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      db_path().DirName().AppendASCII("SQLConnectionAttach.db");
795ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  const char kAttachmentPoint[] = "other";
796ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  {
797ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    sql::Connection other_db;
798ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ASSERT_TRUE(other_db.Open(attach_path));
799ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    EXPECT_TRUE(other_db.Execute("CREATE TABLE bar (a, b)"));
800ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    EXPECT_TRUE(other_db.Execute("INSERT INTO bar VALUES ('hello', 'world')"));
801ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
802ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
803ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Cannot see the attached database, yet.
804ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_FALSE(db().IsSQLValid("SELECT count(*) from other.bar"));
805ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
806ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Attach fails in a transaction.
807ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_TRUE(db().BeginTransaction());
808ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  {
809ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    sql::ScopedErrorIgnorer ignore_errors;
810ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ignore_errors.IgnoreError(SQLITE_ERROR);
811ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    EXPECT_FALSE(db().AttachDatabase(attach_path, kAttachmentPoint));
812ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
813ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
814ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
815ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Attach succeeds when the transaction is closed.
816ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  db().RollbackTransaction();
817ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_TRUE(db().AttachDatabase(attach_path, kAttachmentPoint));
818ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_TRUE(db().IsSQLValid("SELECT count(*) from other.bar"));
819ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
820ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Queries can touch both databases.
821ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_TRUE(db().Execute("INSERT INTO foo SELECT a, b FROM other.bar"));
822ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  {
823ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    sql::Statement s(db().GetUniqueStatement("SELECT COUNT(*) FROM foo"));
824ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ASSERT_TRUE(s.Step());
825ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    EXPECT_EQ(1, s.ColumnInt(0));
826ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
827ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
828ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Detach also fails in a transaction.
829ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_TRUE(db().BeginTransaction());
830ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  {
831ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    sql::ScopedErrorIgnorer ignore_errors;
832ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ignore_errors.IgnoreError(SQLITE_ERROR);
833ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    EXPECT_FALSE(db().DetachDatabase(kAttachmentPoint));
834ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    EXPECT_TRUE(db().IsSQLValid("SELECT count(*) from other.bar"));
835ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
836ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
837ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
838ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Detach succeeds outside of a transaction.
839ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  db().RollbackTransaction();
840ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_TRUE(db().DetachDatabase(kAttachmentPoint));
841ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
842ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  EXPECT_FALSE(db().IsSQLValid("SELECT count(*) from other.bar"));
843ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
844ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
8457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}  // namespace
846