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)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
77d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/bind.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/scoped_temp_dir.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/connection.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/statement.h"
127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "sql/test/error_callback_support.h"
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#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)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SQLStatementTest : public testing::Test {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void SetUp() {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(db_.Open(temp_dir_.path().AppendASCII("SQLStatementTest.db")));
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void TearDown() {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_.Close();
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Connection& db() { return db_; }
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ScopedTempDir temp_dir_;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Connection db_;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLStatementTest, Assign) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement s;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(s.is_valid());
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.Assign(db().GetUniqueStatement("CREATE TABLE foo (a, b)"));
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(s.is_valid());
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLStatementTest, Run) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (3, 12)"));
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement s(db().GetUniqueStatement("SELECT b FROM foo WHERE a=?"));
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(s.Succeeded());
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stepping it won't work since we haven't bound the value.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(s.Step());
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run should fail since this produces output, and we should use Step(). This
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // gets a bit wonky since sqlite says this is OK so succeeded is set.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.Reset(true);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.BindInt(0, 3);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(s.Run());
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(SQLITE_ROW, db().GetErrorCode());
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(s.Succeeded());
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Resetting it should put it back to the previous state (not runnable).
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.Reset(true);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(s.Succeeded());
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Binding and stepping should produce one row.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.BindInt(0, 3);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(s.Step());
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(s.Succeeded());
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(12, s.ColumnInt(0));
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(s.Step());
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(s.Succeeded());
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Error callback called for error running a statement.
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochTEST_F(SQLStatementTest, ErrorCallback) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a INTEGER PRIMARY KEY, b)"));
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int error = SQLITE_OK;
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sql::ScopedErrorCallback sec(
847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      &db(), base::Bind(&sql::CaptureErrorCallback, &error));
857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Insert in the foo table the primary key. It is an error to insert
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // something other than an number. This error causes the error callback
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // handler to be called with SQLITE_MISMATCH as error code.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement s(db().GetUniqueStatement("INSERT INTO foo (a) VALUES (?)"));
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(s.is_valid());
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.BindCString(0, "bad bad");
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(s.Run());
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_EQ(SQLITE_MISMATCH, error);
947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Error ignorer works for error running a statement.
977dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochTEST_F(SQLStatementTest, ScopedIgnoreError) {
987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a INTEGER PRIMARY KEY, b)"));
997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sql::Statement s(db().GetUniqueStatement("INSERT INTO foo (a) VALUES (?)"));
1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_TRUE(s.is_valid());
1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sql::ScopedErrorIgnorer ignore_errors;
1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ignore_errors.IgnoreError(SQLITE_MISMATCH);
1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  s.BindCString(0, "bad bad");
1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_FALSE(s.Run());
1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SQLStatementTest, Reset) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (3, 12)"));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (4, 13)"));
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement s(db().GetUniqueStatement(
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT b FROM foo WHERE a = ? "));
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.BindInt(0, 3);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(s.Step());
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(12, s.ColumnInt(0));
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(s.Step());
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.Reset(false);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that we can get all rows again.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(s.Step());
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(12, s.ColumnInt(0));
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(s.Step());
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.Reset(true);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(s.Step());
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
131