#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); } }