From 598218e9e1d6e97b7793b0cff2c0d50cab879fa4 Mon Sep 17 00:00:00 2001 From: Max Kusatz Date: Sat, 22 Aug 2020 14:08:46 +0200 Subject: Mensa working sort of with JSON --- src/Utilities/sqdb.cpp | 506 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 506 insertions(+) create mode 100644 src/Utilities/sqdb.cpp (limited to 'src/Utilities/sqdb.cpp') diff --git a/src/Utilities/sqdb.cpp b/src/Utilities/sqdb.cpp new file mode 100644 index 0000000..0b88139 --- /dev/null +++ b/src/Utilities/sqdb.cpp @@ -0,0 +1,506 @@ +#include +#include +#include +#include + +#include + +#include "sqdb.hpp" + +#include + +using namespace sqdb; + +Exception::Exception(sqlite3* db) +{ + m_errorCode = sqlite3_errcode(db); + auto* c = (SQDB_CHAR*) +#ifdef SQDB_UTF8 + sqlite3_errmsg +#else + sqlite3_errmsg16 +#endif + (db); + m_errorMsg = SQDB_STRDUP(c); +} + +Exception::Exception(sqlite3* db, int errorCode) + : m_errorCode(errorCode) +{ + auto* c = (SQDB_CHAR*) +#ifdef SQDB_UTF8 + sqlite3_errmsg +#else + sqlite3_errmsg16 +#endif + (db); + m_errorMsg = SQDB_STRDUP(c); +} + +Exception::Exception(const SQDB_CHAR* errorMsg) + : m_errorCode(-1) +{ + m_errorMsg = SQDB_STRDUP(errorMsg); +} + +Exception::~Exception() +{ + free(m_errorMsg); +} + +int Exception::GetErrorCode() const +{ + return m_errorCode; +} + +const SQDB_CHAR* Exception::GetErrorMsg() const +{ + return m_errorMsg; +} + +RefCount::RefCount() + : m_refCount(nullptr) +{ +} + +RefCount::RefCount(const RefCount& x) + : m_refCount(x.m_refCount) +{ +} + +RefCount& RefCount::operator=(const RefCount& x) +{ + if ( this != &x ) + { + m_refCount = x.m_refCount; + } + return *this; +} + +void RefCount::IncRef() +{ + if ( !m_refCount ) + { + m_refCount = new unsigned; + *m_refCount = 0; + } + ++*m_refCount; +} + +unsigned RefCount::DecRef() +{ + assert(m_refCount); + unsigned value = --*m_refCount; + if ( value == 0 ) + { + delete m_refCount; + m_refCount = nullptr; + } + return value; +} + +Blob::Blob(const void* data, int size) + : m_size(size) +{ + m_data = new char[size]; + std::uninitialized_copy((char*)data, (char*)data + size, m_data); + IncRef(); +} + +Blob::Blob(const Blob& x) + : RefCount(x), m_data(x.m_data), m_size(x.m_size) +{ + IncRef(); +} + +Blob& Blob::operator=(const Blob& x) +{ + if ( this != &x ) + { + RefCount::operator=(x); + IncRef(); + m_data = x.m_data; + m_size = x.m_size; + } + return *this; +} + +int Blob::GetSize() const +{ + return m_size; +} + +const char* Blob::GetData() const +{ + return m_data; +} + +Blob::~Blob() +{ + if ( DecRef() == 0 ) + { + delete[] m_data; + } +} + +Convertor::Convertor(sqlite3* db, sqlite3_stmt* stmt, int field) + : m_db(db), m_stmt(stmt), m_field(field) +{ +} + +Convertor::operator int() const +{ + return GetInt(); +} + +Convertor::operator unsigned long() const +{ + return GetUnsignedLong(); +} + +Convertor::operator long long() const +{ + return GetLongLong(); +} + +Convertor::operator double() const +{ + return GetDouble(); +} + +Convertor::operator SQDB_STD_STRING() const +{ + return GetString(); +} + +Convertor::operator const SQDB_CHAR*() const +{ + return GetText(); +} + +Convertor::operator Blob() const +{ + return GetBlob(); +} + +int Convertor::GetInt() const +{ + assert(m_stmt); + return sqlite3_column_int(m_stmt, m_field); +} + +unsigned long Convertor::GetUnsignedLong() const +{ + assert(m_stmt); + const char* data = (char*) sqlite3_column_blob(m_stmt, m_field); + return strtoul(data, nullptr, 10); +} + +long long Convertor::GetLongLong() const +{ + assert(m_stmt); + return sqlite3_column_int64(m_stmt, m_field); +} + +double Convertor::GetDouble() const +{ + assert(m_stmt); + return sqlite3_column_double(m_stmt, m_field); +} + +SQDB_STD_STRING Convertor::GetString() const +{ + assert(m_stmt); + const auto* result = (const SQDB_CHAR*) +#ifdef SQDB_UTF8 + sqlite3_column_text +#else + sqlite3_column_text16 +#endif + (m_stmt, m_field); + return result; +} + +const SQDB_CHAR* Convertor::GetText() const +{ + assert(m_stmt); + const auto* result = (const SQDB_CHAR*) +#ifdef SQDB_UTF8 + sqlite3_column_text +#else + sqlite3_column_text16 +#endif + (m_stmt, m_field); + return result; +} + +Blob Convertor::GetBlob() const +{ + assert(m_stmt); + const void* data = sqlite3_column_blob(m_stmt, m_field); + int size = sqlite3_column_bytes(m_stmt, m_field); + return Blob(data, size); +} + +Statement::Statement(sqlite3* db, sqlite3_stmt* stmt) + : RefCount(), m_db(db), m_stmt(stmt), m_needReset(false) +{ + IncRef(); +} + +Statement::Statement(const Statement& x) + : RefCount(x), m_db(x.m_db), m_stmt(x.m_stmt), m_needReset(false) +{ + IncRef(); +} + +Statement& Statement::operator=(const Statement& x) +{ + if ( this != &x ) + { + RefCount::operator=(x); + IncRef(); + m_db = x.m_db; + m_stmt = x.m_stmt; + m_needReset = x.m_needReset; + } + return *this; +} + +bool Statement::Next() { + assert(m_stmt); + int ret = SQLITE_BUSY; + + while (ret == SQLITE_BUSY) { + ret = sqlite3_step(m_stmt); + m_needReset = true; + if ( ret == SQLITE_DONE ) { + return false; + } else if ( ret == SQLITE_ROW ) { + return true; + } else if ( ret == SQLITE_BUSY ) { + sleep(1); + continue; + } else { + throw Exception(m_db, ret); + } + } + return false; +} + +Convertor Statement::GetField(int field) const +{ + return {m_db, m_stmt, field}; +} + +Statement::~Statement() +{ + if ( DecRef() == 0 ) + { + sqlite3_finalize(m_stmt); + } +} + +void Statement::BindBlob(int i, const void* value, int n) +{ + if ( m_needReset ) + Reset(); + DoBind(i, value, n); +} + +void Statement::BindNull(int i) +{ + if ( m_needReset ) + Reset(); + DoBind(i); +} + +void Statement::DoBind(int i, int value) +{ + const int ret = sqlite3_bind_int(m_stmt, i, value); + CHECK(m_db, ret); +} + +void Statement::DoBind(int i, long long value) +{ + const int ret = sqlite3_bind_int64(m_stmt, i, value); + CHECK(m_db, ret); +} + +void Statement::DoBind(int i, double value) +{ + const int ret = sqlite3_bind_double(m_stmt, i, value); + CHECK(m_db, ret); +} + +void Statement::DoBind(int i, const SQDB_STD_STRING& value) +{ + const int ret = +#ifdef SQDB_UTF8 + sqlite3_bind_text +#else + sqlite3_bind_text16 +#endif + (m_stmt, i, value.c_str(), value.size() * sizeof(SQDB_STD_STRING::value_type), SQLITE_TRANSIENT); + CHECK(m_db, ret); +} + +void Statement::DoBind(int i, const SQDB_CHAR* value) +{ + const int len = SQDB_STRLEN(value); + + const int ret = +#ifdef SQDB_UTF8 + sqlite3_bind_text +#else + sqlite3_bind_text16 +#endif + (m_stmt, i, value, len * sizeof(SQDB_CHAR), SQLITE_TRANSIENT); + + CHECK(m_db, ret); +} + +void Statement::DoBind(int i, const void* value, int n) +{ + const int ret = sqlite3_bind_blob(m_stmt, i, value, n, SQLITE_TRANSIENT); + CHECK(m_db, ret); +} + +void Statement::DoBind(int i) +{ + const int ret = sqlite3_bind_null(m_stmt, i); + CHECK(m_db, ret); +} + +void Statement::Reset() +{ + assert(m_needReset); + assert(m_stmt); + + sqlite3_reset(m_stmt); + m_needReset = false; +} + +QueryStr::QueryStr() + : m_buf(nullptr) +{ +} + +const SQDB_CHAR* QueryStr::Format(const SQDB_CHAR* fmt, ...) +{ + va_list va; + va_start(va, fmt); +#ifdef SQDB_UTF8 + sqlite3_free(m_buf); + m_buf = sqlite3_vmprintf(fmt, va); +#else + free(m_buf); + int len = _vscwprintf(fmt, va) + 1; + m_buf = (SQDB_CHAR*)malloc(len * sizeof(SQDB_CHAR)); + vswprintf(m_buf, len, fmt, va); +#endif + + va_end(va); + + return m_buf; +} + +const SQDB_CHAR* QueryStr::Get() const +{ + return m_buf; +} + +QueryStr::~QueryStr() +{ +#ifdef SQDB_UTF8 + sqlite3_free(m_buf); +#else + free(m_buf); +#endif +} + +Db::Db(const SQDB_CHAR* fileName) + : RefCount() +{ +#ifdef SQDB_UTF8 + const int ret = sqlite3_open(fileName, &m_db); +#else + const int ret = sqlite3_open16(fileName, &m_db); +#endif + CHECK(m_db, ret); + + IncRef(); +} + +void Db::BeginTransaction() +{ + Query(SQDB_MAKE_TEXT("BEGIN;")).Next(); +} + +void Db::CommitTransaction() +{ + Query(SQDB_MAKE_TEXT("COMMIT;")).Next(); +} + +void Db::RollbackTransaction() +{ + Query(SQDB_MAKE_TEXT("ROLLBACK;")).Next(); +} + +bool Db::TableExists(const SQDB_CHAR* tableName) +{ + QueryStr str; + Statement s = + Query( + str.Format(SQDB_MAKE_TEXT("select count(*) from sqlite_master where type='table' and name='%s';"), tableName)); + s.Next(); + const int count = s.GetField(0); + return count > 0; +} + +Statement Db::Query(const SQDB_CHAR* queryStr) +{ + sqlite3_stmt* stmt = nullptr; +#ifdef SQDB_UTF8 + const int ret = sqlite3_prepare(m_db, queryStr, -1, &stmt, nullptr); +#else + const int ret = sqlite3_prepare16(m_db, queryStr, -1, &stmt, NULL); +#endif + CHECK(m_db, ret); + + return Statement(m_db, stmt); +} + +long long Db::LastId() +{ + long long ret = sqlite3_last_insert_rowid(m_db); + return ret; +} + +Db::Db(const Db& x) + : RefCount(x), + m_db(x.m_db) +{ + IncRef(); +} + +Db& Db::operator=(const Db& x) +{ + if ( this != &x ) + { + RefCount::operator=(x); + + IncRef(); + m_db = x.m_db; + } + return *this; +} + +Db::~Db() +{ + if ( DecRef() == 0 ) + { + sqlite3_close(m_db); + } +} + -- cgit v1.2.3-54-g00ecf