aboutsummaryrefslogtreecommitdiffstats
path: root/src/Utilities/sqdb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Utilities/sqdb.cpp')
-rw-r--r--src/Utilities/sqdb.cpp506
1 files changed, 506 insertions, 0 deletions
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 <cassert>
+#include <cstdio>
+#include <cstring>
+#include <memory>
+
+#include <cstdlib>
+
+#include "sqdb.hpp"
+
+#include <unistd.h>
+
+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);
+ }
+}
+