1
\$\begingroup\$

this is a simple wrapper for sqlite3 to make working with databases easier it isn't a professional implementation but it is much better than the raw c interface I saved much time and code using this wrapper instead of the raw interface any improvements will be appreciated

HandleBase.hpp

#pragma once
#include <type_traits>

template <class T, T null_value, bool no_negative = true>
class HandleWrapper
{
public:
    HandleWrapper() : handle(null_value)
    {}
    HandleWrapper(T h) : handle(h)
    {
        if constexpr (no_negative)
        {
            if constexpr (std::is_integral_v<T>)
            {
                if constexpr (null_value >= 0)
                {
                    if (handle < 0)
                        handle = null_value;
                }
            }
            else
            {
                if constexpr ((intptr_t)null_value >= 0)
                {
                    if ((intptr_t)handle < 0)
                        handle = null_value;
                }
            }
        }
    }

    bool operator==(const HandleWrapper& rhs)
    {
        return handle == rhs.handle;
    }

    bool operator!=(const HandleWrapper& rhs)
    {
        return handle != rhs.handle;
    }

    bool operator>(const HandleWrapper& rhs)
    {
        return handle > rhs.handle;
    }

    bool operator>=(const HandleWrapper& rhs)
    {
        return handle >= rhs.handle;
    }

    bool operator<(const HandleWrapper& rhs)
    {
        return handle < rhs.handle;
    }

    bool operator<=(const HandleWrapper& rhs)
    {
        return handle < rhs.handle;
    }

    explicit operator bool() const
    {
        return handle != null_value;
    }

    operator T()
    {
        return handle;
    }

private:
    T handle;
};

template <class T, T null_value, bool no_negative, auto Deleter>
struct HandleHelper
{
    using pointer = HandleWrapper<T, null_value, no_negative>;
    void operator()(pointer p)
    {
        Deleter(T(p));
    }
};

sqlite++.h

#pragma once
#include <HandleBase.hpp>
#include <memory>
#include <sqlite3.h>
#include <string>

using SqlHandle = std::unique_ptr<HandleWrapper<sqlite3*, nullptr, false>, HandleHelper<sqlite3*, nullptr, false, sqlite3_close> >;

using SqlStatementHandle = std::unique_ptr<HandleWrapper<sqlite3_stmt*, nullptr, false>, HandleHelper<sqlite3_stmt*, nullptr, false, sqlite3_finalize>>;

enum class SqlOpenFlags
{
    Read = SQLITE_OPEN_READONLY,
    ReadWrite = SQLITE_OPEN_READWRITE,
    ReadWriteCreate = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
};

class SqlDb
{
    SqlHandle handle;
public:
    SqlDb() {}
    SqlDb(const std::string& path);
    SqlDb(const std::wstring& path);
    SqlDb(const std::string& path, SqlOpenFlags flags);
    SqlDb(SqlDb&& rhs) : handle(std::move(rhs.handle)) {}

    SqlDb& operator=(SqlDb&& rhs)
    {
        handle = std::move(rhs.handle);
        return *this;
    }

    bool Open(const std::string& path);

    bool Open(const std::wstring& path);

    bool Open(const std::string& path, SqlOpenFlags flags);

    void Close()
    {
        handle.reset();
    }

    explicit operator bool() const { return bool(handle); }

    sqlite3 * native_handle() { return handle.get(); }

    SqlHandle Release() { return std::move(handle); }

    int ErrorCode();

    int ErrorCodeExt();

    std::string ErrorStr();

    std::wstring ErrorStrW();

};


class SqlQuery
{
    SqlStatementHandle statement;
    std::string statement_str;

public :
    SqlQuery() {}
    SqlQuery(SqlDb& db, const char *stmt, ...);
    SqlQuery(SqlDb& db, const wchar_t *stmt, ...);
    SqlQuery(SqlQuery&& rhs) : statement(std::move(rhs.statement)) {}

    bool Prepare(SqlDb& db, const char *stmt, ...);
    bool Prepare(SqlDb& db, const wchar_t *stmt, ...);

    void Close() { statement.reset(); }

    sqlite3_stmt * native_handle() { return statement.get(); }

    SqlStatementHandle Release() { return std::move(statement); }

    explicit operator bool() const { return bool(statement); }

    std::string GetStatement();

    bool execute();

    bool next();

    int ColumnsCount();

    int ColumnSize(int index);

    std::string GetStr(int index);

    std::wstring GetStrW(int index);

    int GetInt(int index);

    int64_t GetInt64(int index);

    double GetDouble(int index);

    const void *GetBlob(int index);

};

sqlite++.cpp

#include "sqlite++.h"

using namespace std;

SqlDb::SqlDb(const std::string & path)
{
    sqlite3 *temp_handle;
    sqlite3_open(path.c_str(), &temp_handle);
    handle.reset(temp_handle);
}

SqlDb::SqlDb(const std::wstring & path)
{
    sqlite3 *temp_handle;
    sqlite3_open16(path.c_str(), &temp_handle);
    handle.reset(temp_handle);
}

SqlDb::SqlDb(const std::string & path, SqlOpenFlags flags)
{
    sqlite3 *temp_handle;
    sqlite3_open_v2(path.c_str(), &temp_handle, (int)flags, nullptr);
    handle.reset(temp_handle);
}

bool SqlDb::Open(const std::string & path)
{
    sqlite3 *temp_handle;
    sqlite3_open(path.c_str(), &temp_handle);
    handle.reset(temp_handle);
    return bool(handle);
}

bool SqlDb::Open(const std::wstring & path)
{
    sqlite3 *temp_handle;
    sqlite3_open16(path.c_str(), &temp_handle);
    handle.reset(temp_handle);
    return bool(handle);
}

bool SqlDb::Open(const std::string & path, SqlOpenFlags flags)
{
    sqlite3 *temp_handle;
    sqlite3_open_v2(path.c_str(), &temp_handle, (int)flags, nullptr);
    handle.reset(temp_handle);
    return bool(handle);
}

int SqlDb::ErrorCode()
{
    return sqlite3_errcode(handle.get());
}

int SqlDb::ErrorCodeExt()
{
    return sqlite3_extended_errcode(handle.get());
}

std::string SqlDb::ErrorStr()
{
    return sqlite3_errmsg(handle.get());
}

std::wstring SqlDb::ErrorStrW()
{
    return (wchar_t*)sqlite3_errmsg16(handle.get());
}

SqlQuery::SqlQuery(SqlDb & db, const char * stmt, ...)
{
    va_list args;
    va_start(args, stmt);
    size_t required_size = vsnprintf(nullptr, 0, stmt, args);
    if (!required_size)
        return;
    unique_ptr<char> buff(new char[required_size + 1]);
    vsnprintf(buff.get(), required_size + 1, stmt, args);
    va_end(args);
    sqlite3_stmt *temp_stmt;
    sqlite3_prepare_v2(db.native_handle(), buff.get(), -1, &temp_stmt, nullptr);
    statement_str = buff.get();
    statement.reset(temp_stmt);
}

SqlQuery::SqlQuery(SqlDb & db, const wchar_t * stmt, ...)
{
    va_list args;
    va_start(args, stmt);
    size_t required_size = vswprintf(nullptr, 0, stmt, args);
    if (!required_size)
        return;
    unique_ptr<wchar_t> buff(new wchar_t[required_size + 1]);
    vswprintf(buff.get(), required_size + 1, stmt, args);
    va_end(args);
    sqlite3_stmt *temp_stmt;
    sqlite3_prepare16_v2(db.native_handle(), buff.get(), -1, &temp_stmt, nullptr);
    statement.reset(temp_stmt);
}

bool SqlQuery::Prepare(SqlDb & db, const char * stmt, ...)
{
    statement.reset();
    va_list args;
    va_start(args, stmt);
    size_t required_size = vsnprintf(nullptr, 0, stmt, args);
    if (!required_size)
        return false;
    unique_ptr<char> buff(new char[required_size + 1]);
    vsnprintf(buff.get(), required_size + 1, stmt, args);
    va_end(args);
    sqlite3_stmt *temp_stmt;
    sqlite3_prepare_v2(db.native_handle(), buff.get(), -1, &temp_stmt, nullptr);
    statement_str = buff.get();
    statement.reset(temp_stmt);
    return bool(statement);
}

bool SqlQuery::Prepare(SqlDb & db, const wchar_t * stmt, ...)
{
    statement.reset();
    va_list args;
    va_start(args, stmt);
    size_t required_size = vswprintf(nullptr, 0, stmt, args);
    if (!required_size)
        return false;
    unique_ptr<wchar_t> buff(new wchar_t[required_size + 1]);
    vswprintf(buff.get(), required_size + 1, stmt, args);
    va_end(args);
    sqlite3_stmt *temp_stmt;
    sqlite3_prepare16_v2(db.native_handle(), buff.get(), -1, &temp_stmt, nullptr);
    statement.reset(temp_stmt);
    return bool(statement);
}

std::string SqlQuery::GetStatement()
{
    return statement_str;
    //const char *str = sqlite3_sql(statement.get()); always returns null , don't know why ?
    //return str ? string(str) : string();
}

bool SqlQuery::execute()
{
    return sqlite3_step(statement.get()) == SQLITE_DONE;
}

bool SqlQuery::next()
{
    return sqlite3_step(statement.get()) == SQLITE_ROW;
}

int SqlQuery::ColumnsCount()
{
    return sqlite3_column_count(statement.get());
}

int SqlQuery::ColumnSize(int index)
{
    return sqlite3_column_bytes(statement.get(), index);
}

std::string SqlQuery::GetStr(int index)
{
    const char *str = (char*)sqlite3_column_text(statement.get(), index);
    return str ? string(str) : string();
}

std::wstring SqlQuery::GetStrW(int index)
{
    const wchar_t *str = (wchar_t*)sqlite3_column_text16(statement.get(), index);
    return str ? wstring(str) : wstring();
}

int SqlQuery::GetInt(int index)
{
    return sqlite3_column_int(statement.get(), index);
}

int64_t SqlQuery::GetInt64(int index)
{
    return sqlite3_column_int64(statement.get(), index);
}

double SqlQuery::GetDouble(int index)
{
    return sqlite3_column_double(statement.get(), index);
}

const void * SqlQuery::GetBlob(int index)
{
    return sqlite3_column_blob(statement.get(), index);
}
\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.