Clang: Fix reset for write and execute in the sqlite statement

We were not reset a statement if we got an exception. There are now test
for it.

Change-Id: Ife7b4437fece9369767605ba7387bd0564c1bb8d
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Marco Bubke
2018-04-04 10:41:11 +02:00
parent 9d7225d283
commit 42ecd2ed3d
6 changed files with 52 additions and 14 deletions

View File

@@ -54,8 +54,7 @@ BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &data
void BaseStatement::deleteCompiledStatement(sqlite3_stmt *compiledStatement) void BaseStatement::deleteCompiledStatement(sqlite3_stmt *compiledStatement)
{ {
if (compiledStatement) sqlite3_finalize(compiledStatement);
sqlite3_finalize(compiledStatement);
} }
class UnlockNotification class UnlockNotification
@@ -145,12 +144,6 @@ void BaseStatement::step() const
next(); next();
} }
void BaseStatement::execute() const
{
next();
reset();
}
int BaseStatement::columnCount() const int BaseStatement::columnCount() const
{ {
return m_columnCount; return m_columnCount;

View File

@@ -60,7 +60,6 @@ public:
bool next() const; bool next() const;
void step() const; void step() const;
void execute() const;
void reset() const; void reset() const;
int fetchIntValue(int column) const; int fetchIntValue(int column) const;
@@ -159,6 +158,13 @@ class StatementImplementation : public BaseStatement
public: public:
using BaseStatement::BaseStatement; using BaseStatement::BaseStatement;
void execute()
{
Resetter resetter{*this};
BaseStatement::next();
resetter.reset();
}
void bindValues() void bindValues()
{ {
} }
@@ -172,8 +178,10 @@ public:
template<typename... ValueType> template<typename... ValueType>
void write(const ValueType&... values) void write(const ValueType&... values)
{ {
Resetter resetter{*this};
bindValuesByIndex(1, values...); bindValuesByIndex(1, values...);
BaseStatement::execute(); BaseStatement::next();
resetter.reset();
} }
template<typename... ValueType> template<typename... ValueType>
@@ -185,8 +193,10 @@ public:
template<typename... ValueType> template<typename... ValueType>
void writeNamed(const ValueType&... values) void writeNamed(const ValueType&... values)
{ {
Resetter resetter{*this};
bindValuesByName(values...); bindValuesByName(values...);
BaseStatement::execute(); BaseStatement::next();
resetter.reset();
} }
template <typename ResultType, template <typename ResultType,

View File

@@ -178,7 +178,7 @@ void DatabaseBackend::setLastInsertedRowId(int64_t rowId)
void DatabaseBackend::execute(Utils::SmallStringView sqlStatement) void DatabaseBackend::execute(Utils::SmallStringView sqlStatement)
{ {
ReadWriteStatement statement(sqlStatement, m_database); ReadWriteStatement statement(sqlStatement, m_database);
statement.step(); statement.execute();
} }
void DatabaseBackend::close() void DatabaseBackend::close()

View File

@@ -64,6 +64,7 @@ public:
{ {
m_interface.commit(); m_interface.commit();
m_isAlreadyCommited = true; m_isAlreadyCommited = true;
m_locker.unlock();
} }
protected: protected:
@@ -76,7 +77,7 @@ protected:
protected: protected:
TransactionInterface &m_interface; TransactionInterface &m_interface;
std::lock_guard<TransactionInterface> m_locker{m_interface}; std::unique_lock<TransactionInterface> m_locker{m_interface};
bool m_isAlreadyCommited = false; bool m_isAlreadyCommited = false;
bool m_rollback = false; bool m_rollback = false;
}; };

View File

@@ -35,7 +35,6 @@ class BaseMockSqliteStatement
public: public:
MOCK_METHOD0(next, bool ()); MOCK_METHOD0(next, bool ());
MOCK_METHOD0(step, void ()); MOCK_METHOD0(step, void ());
MOCK_METHOD0(execute, void ());
MOCK_METHOD0(reset, void ()); MOCK_METHOD0(reset, void ());
MOCK_CONST_METHOD1(fetchIntValue, int (int)); MOCK_CONST_METHOD1(fetchIntValue, int (int));
@@ -53,6 +52,7 @@ public:
MOCK_METHOD2(bind, void (int, double)); MOCK_METHOD2(bind, void (int, double));
MOCK_METHOD2(bind, void (int, Utils::SmallStringView)); MOCK_METHOD2(bind, void (int, Utils::SmallStringView));
MOCK_METHOD2(bind, void (int, long)); MOCK_METHOD2(bind, void (int, long));
MOCK_CONST_METHOD1(bindingIndexForName, int (Utils::SmallStringView name));
MOCK_METHOD1(prepare, void (Utils::SmallStringView sqlStatement)); MOCK_METHOD1(prepare, void (Utils::SmallStringView sqlStatement));
}; };

View File

@@ -639,6 +639,40 @@ TEST_F(SqliteStatement, ThrowExceptionOnlyInReset)
Sqlite::StatementHasError); Sqlite::StatementHasError);
} }
TEST_F(SqliteStatement, ResetIfWriteIsThrowingException)
{
MockSqliteStatement mockStatement;
EXPECT_CALL(mockStatement, bind(1, TypedEq<Utils::SmallStringView>("bar")))
.WillOnce(Throw(Sqlite::StatementIsBusy("")));
EXPECT_CALL(mockStatement, reset());
ASSERT_ANY_THROW(mockStatement.write("bar"));
}
TEST_F(SqliteStatement, ResetIfWriteNamedIsThrowingException)
{
MockSqliteStatement mockStatement;
EXPECT_CALL(mockStatement, bindingIndexForName(TypedEq<Utils::SmallStringView>("@foo")))
.WillOnce(Return(1));
EXPECT_CALL(mockStatement, bind(1, TypedEq<Utils::SmallStringView>("bar")))
.WillOnce(Throw(Sqlite::StatementIsBusy("")));
EXPECT_CALL(mockStatement, reset());
ASSERT_ANY_THROW(mockStatement.writeNamed("@foo", "bar"));
}
TEST_F(SqliteStatement, ResetIfExecuteThrowsException)
{
MockSqliteStatement mockStatement;
EXPECT_CALL(mockStatement, next()).WillOnce(Throw(Sqlite::StatementIsBusy("")));
EXPECT_CALL(mockStatement, reset());
ASSERT_ANY_THROW(mockStatement.execute());
}
void SqliteStatement::SetUp() void SqliteStatement::SetUp()
{ {
database.execute("CREATE TABLE test(name TEXT UNIQUE, number NUMERIC, value NUMERIC)"); database.execute("CREATE TABLE test(name TEXT UNIQUE, number NUMERIC, value NUMERIC)");