Sqlite: Use compiled statements for transactions

So we don't recompile them again and again.

Change-Id: I54c95e9d81df86f4944b9e3d45a7277f93f37312
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Marco Bubke
2018-03-29 18:33:59 +02:00
parent 549aa7ee02
commit 28da1261c8
3 changed files with 101 additions and 35 deletions

View File

@@ -27,6 +27,7 @@
#include "sqlitetable.h" #include "sqlitetable.h"
#include "sqlitetransaction.h" #include "sqlitetransaction.h"
#include "sqlitereadwritestatement.h"
#include <chrono> #include <chrono>
@@ -54,11 +55,14 @@ Database::Database(Utils::PathString &&databaseFilePath,
open(std::move(databaseFilePath)); open(std::move(databaseFilePath));
} }
Database::~Database() = default;
void Database::open() void Database::open()
{ {
m_databaseBackend.open(m_databaseFilePath, m_openMode); m_databaseBackend.open(m_databaseFilePath, m_openMode);
m_databaseBackend.setJournalMode(m_journalMode); m_databaseBackend.setJournalMode(m_journalMode);
m_databaseBackend.setBusyTimeout(m_busyTimeout); m_databaseBackend.setBusyTimeout(m_busyTimeout);
registerTransactionStatements();
initializeTables(); initializeTables();
m_isOpen = true; m_isOpen = true;
} }
@@ -129,12 +133,55 @@ void Database::execute(Utils::SmallStringView sqlStatement)
void Database::initializeTables() void Database::initializeTables()
{ {
ImmediateTransaction transaction(*this); try {
ImmediateTransaction transaction(*this);
for (Table &table : m_sqliteTables) for (Table &table : m_sqliteTables)
table.initialize(*this); table.initialize(*this);
transaction.commit(); transaction.commit();
} catch (const StatementIsBusy &) {
initializeTables();
}
}
void Database::registerTransactionStatements()
{
m_deferredBeginStatement = std::make_unique<ReadWriteStatement>("BEGIN", *this);
m_immediateBeginStatement = std::make_unique<ReadWriteStatement>("BEGIN IMMEDIATE", *this);
m_exclusiveBeginStatement = std::make_unique<ReadWriteStatement>("BEGIN EXCLUSIVE", *this);
m_commitBeginStatement = std::make_unique<ReadWriteStatement>("COMMIT", *this);
m_rollbackBeginStatement = std::make_unique<ReadWriteStatement>("ROLLBACK", *this);
}
void Database::deferredBegin()
{
m_databaseMutex.lock();
m_deferredBeginStatement->execute();
}
void Database::immediateBegin()
{
m_databaseMutex.lock();
m_immediateBeginStatement->execute();
}
void Database::exclusiveBegin()
{
m_databaseMutex.lock();
m_exclusiveBeginStatement->execute();
}
void Database::commit()
{
m_commitBeginStatement->execute();
m_databaseMutex.unlock();
}
void Database::rollback()
{
m_rollbackBeginStatement->execute();
m_databaseMutex.unlock();
} }
DatabaseBackend &Database::backend() DatabaseBackend &Database::backend()

View File

@@ -40,6 +40,7 @@ namespace Sqlite {
class ReadStatement; class ReadStatement;
class WriteStatement; class WriteStatement;
class ReadWriteStatement;
class SQLITE_EXPORT Database final : public TransactionInterface class SQLITE_EXPORT Database final : public TransactionInterface
{ {
@@ -54,10 +55,11 @@ public:
Database(); Database();
Database(Utils::PathString &&databaseFilePath, Database(Utils::PathString &&databaseFilePath,
JournalMode journalMode=JournalMode::Wal); JournalMode journalMode=JournalMode::Delete);
Database(Utils::PathString &&databaseFilePath, Database(Utils::PathString &&databaseFilePath,
std::chrono::milliseconds busyTimeout = {}, std::chrono::milliseconds busyTimeout = {},
JournalMode journalMode=JournalMode::Wal); JournalMode journalMode=JournalMode::Delete);
~Database();
Database(const Database &) = delete; Database(const Database &) = delete;
Database &operator=(const Database &) = delete; Database &operator=(const Database &) = delete;
@@ -104,44 +106,26 @@ public:
return m_databaseBackend.totalChangesCount(); return m_databaseBackend.totalChangesCount();
} }
void deferredBegin() void deferredBegin();
{ void immediateBegin();
m_databaseMutex.lock(); void exclusiveBegin();
execute("BEGIN"); void commit();
} void rollback();
void immediateBegin()
{
m_databaseMutex.lock();
execute("BEGIN IMMEDIATE");
}
void exclusiveBegin()
{
m_databaseMutex.lock();
execute("BEGIN EXCLUSIVE");
}
void commit()
{
execute("COMMIT");
m_databaseMutex.unlock();
}
void rollback()
{
execute("ROLLBACK");
m_databaseMutex.unlock();
}
private: private:
void initializeTables(); void initializeTables();
void registerTransactionStatements();
std::mutex &databaseMutex() { return m_databaseMutex; } std::mutex &databaseMutex() { return m_databaseMutex; }
private: private:
Utils::PathString m_databaseFilePath; Utils::PathString m_databaseFilePath;
DatabaseBackend m_databaseBackend; DatabaseBackend m_databaseBackend;
std::vector<Table> m_sqliteTables; std::vector<Table> m_sqliteTables;
std::unique_ptr<ReadWriteStatement> m_deferredBeginStatement;
std::unique_ptr<ReadWriteStatement> m_immediateBeginStatement;
std::unique_ptr<ReadWriteStatement> m_exclusiveBeginStatement;
std::unique_ptr<ReadWriteStatement> m_commitBeginStatement;
std::unique_ptr<ReadWriteStatement> m_rollbackBeginStatement;
std::mutex m_databaseMutex; std::mutex m_databaseMutex;
std::chrono::milliseconds m_busyTimeout; std::chrono::milliseconds m_busyTimeout;
JournalMode m_journalMode = JournalMode::Wal; JournalMode m_journalMode = JournalMode::Wal;

View File

@@ -140,6 +140,41 @@ TEST_F(SqliteDatabase, LastRowId)
ASSERT_THAT(database.lastInsertedRowId(), 42); ASSERT_THAT(database.lastInsertedRowId(), 42);
} }
TEST_F(SqliteDatabase, DeferredBegin)
{
ASSERT_ANY_THROW(database.deferredBegin());
database.commit();
}
TEST_F(SqliteDatabase, ImmediateBegin)
{
ASSERT_ANY_THROW(database.immediateBegin());
database.commit();
}
TEST_F(SqliteDatabase, ExclusiveBegin)
{
ASSERT_ANY_THROW(database.exclusiveBegin());
database.commit();
}
TEST_F(SqliteDatabase, Commit)
{
database.deferredBegin();
ASSERT_ANY_THROW(database.commit());
}
TEST_F(SqliteDatabase, Rollback)
{
database.deferredBegin();
ASSERT_ANY_THROW(database.rollback());
}
void SqliteDatabase::SetUp() void SqliteDatabase::SetUp()
{ {
database.setJournalMode(JournalMode::Memory); database.setJournalMode(JournalMode::Memory);