mirror of
https://github.com/systemed/tilemaker.git
synced 2026-05-06 08:26:46 -04:00
552 lines
16 KiB
C++
552 lines
16 KiB
C++
#pragma once
|
|
#include<string>
|
|
#include<functional>
|
|
#include<stdexcept>
|
|
#include<iostream>
|
|
#include"sqlite3.h"
|
|
|
|
/*
|
|
This is an earlier version of sqlite_modern_cpp (current versions break on OS X), lightly patched
|
|
to include a database.init() method, and to use the && operator for inserting blobs.
|
|
-- Richard Fairhurst, 28.06.2015
|
|
*/
|
|
|
|
namespace sqlite {
|
|
|
|
#pragma region function_traits
|
|
template <typename T>
|
|
struct function_traits : public function_traits < decltype(&T::operator()) > {};
|
|
|
|
template <typename ClassType, typename ReturnType, typename... Args>
|
|
struct function_traits < ReturnType(ClassType::*)(Args...) const >
|
|
// we specialize for pointers to member function
|
|
{
|
|
enum { arity = sizeof...(Args) };
|
|
// arity is the number of arguments.
|
|
|
|
typedef ReturnType result_type;
|
|
|
|
template <size_t i>
|
|
struct arg {
|
|
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
|
|
// the i-th argument is equivalent to the i-th tuple element of a tuple
|
|
// composed of those arguments.
|
|
};
|
|
};
|
|
|
|
#pragma endregion
|
|
|
|
class database;
|
|
class database_binder;
|
|
|
|
template<int N>
|
|
class binder {
|
|
template<typename F>
|
|
static void run(database_binder& dbb, F l);
|
|
};
|
|
|
|
class database_binder {
|
|
private:
|
|
sqlite3 * _db;
|
|
std::string _sql;
|
|
sqlite3_stmt* _stmt;
|
|
int _inx;
|
|
|
|
void _extract(std::function<void(void)> call_back) {
|
|
int hresult;
|
|
while ((hresult = sqlite3_step(_stmt)) == SQLITE_ROW)
|
|
call_back();
|
|
|
|
if (hresult != SQLITE_DONE)
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
|
|
if (sqlite3_finalize(_stmt) != SQLITE_OK)
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
_stmt = nullptr;
|
|
}
|
|
void _extract_single_value(std::function<void(void)> call_back) {
|
|
int hresult;
|
|
if ((hresult = sqlite3_step(_stmt)) == SQLITE_ROW)
|
|
call_back();
|
|
|
|
if ((hresult = sqlite3_step(_stmt)) == SQLITE_ROW)
|
|
throw std::runtime_error("not every row extracted");
|
|
|
|
if (hresult != SQLITE_DONE)
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
|
|
if (sqlite3_finalize(_stmt) != SQLITE_OK)
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
_stmt = nullptr;
|
|
}
|
|
void _prepare() {
|
|
if (sqlite3_prepare_v2(_db, _sql.data(), -1, &_stmt, nullptr) != SQLITE_OK)
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
}
|
|
protected:
|
|
database_binder(sqlite3 * db, std::string const & sql) :
|
|
_db(db),
|
|
_sql(sql),
|
|
_stmt(nullptr),
|
|
_inx(1) {
|
|
_prepare();
|
|
}
|
|
|
|
public:
|
|
friend class database;
|
|
~database_binder() noexcept(false) {
|
|
/* Will be executed if no >>op is found */
|
|
if (_stmt) {
|
|
if (sqlite3_step(_stmt) != SQLITE_DONE) {
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
}
|
|
|
|
if (sqlite3_finalize(_stmt) != SQLITE_OK)
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
_stmt = nullptr;
|
|
}
|
|
}
|
|
#pragma region operator <<
|
|
database_binder& operator <<(double val) {
|
|
if (sqlite3_bind_double(_stmt, _inx, val) != SQLITE_OK)
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
++_inx;
|
|
return *this;
|
|
}
|
|
database_binder& operator <<(float val) {
|
|
if (sqlite3_bind_double(_stmt, _inx, double(val)) != SQLITE_OK)
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
++_inx;
|
|
return *this;
|
|
}
|
|
database_binder& operator <<(int val) {
|
|
if (sqlite3_bind_int(_stmt, _inx, val) != SQLITE_OK)
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
++_inx;
|
|
return *this;
|
|
}
|
|
database_binder& operator <<(sqlite_int64 val) {
|
|
if (sqlite3_bind_int64(_stmt, _inx, val) != SQLITE_OK)
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
++_inx;
|
|
return *this;
|
|
}
|
|
database_binder& operator <<(std::string const& txt) {
|
|
if (sqlite3_bind_text(_stmt, _inx, txt.data(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
++_inx;
|
|
return *this;
|
|
}
|
|
database_binder& operator &&(std::string const& txt) {
|
|
if (sqlite3_bind_blob(_stmt, _inx, txt.data(), txt.size(), SQLITE_TRANSIENT) != SQLITE_OK)
|
|
throw std::runtime_error(sqlite3_errmsg(_db));
|
|
++_inx;
|
|
return *this;
|
|
}
|
|
#pragma endregion
|
|
|
|
#pragma region get_col_from_db
|
|
void get_col_from_db(int inx, int& i) {
|
|
if (sqlite3_column_type(_stmt, inx) == SQLITE_NULL) i = 0;
|
|
else i = sqlite3_column_int(_stmt, inx);
|
|
}
|
|
void get_col_from_db(int inx, sqlite3_int64& i) {
|
|
if (sqlite3_column_type(_stmt, inx) == SQLITE_NULL) i = 0;
|
|
else i = sqlite3_column_int64(_stmt, inx);
|
|
}
|
|
void get_col_from_db(int inx, std::string& s) {
|
|
if (sqlite3_column_type(_stmt, inx) == SQLITE_NULL) s = std::string();
|
|
else {
|
|
sqlite3_column_bytes(_stmt, inx);
|
|
s = std::string((char*)sqlite3_column_text(_stmt, inx));
|
|
}
|
|
}
|
|
void get_col_from_db(int inx, std::vector<char>& v) {
|
|
if (sqlite3_column_type(_stmt, inx) == SQLITE_NULL) v = std::vector<char>();
|
|
else {
|
|
int size = sqlite3_column_bytes(_stmt, inx);
|
|
char* p = (char*)sqlite3_column_blob(_stmt,inx);
|
|
v = std::vector<char>(p, p+size);
|
|
}
|
|
}
|
|
void get_col_from_db(int inx, double& d) {
|
|
if (sqlite3_column_type(_stmt, inx) == SQLITE_NULL) d = 0;
|
|
else d = sqlite3_column_double(_stmt, inx);
|
|
}
|
|
void get_col_from_db(int inx, float& f) {
|
|
if (sqlite3_column_type(_stmt, inx) == SQLITE_NULL) f = 0;
|
|
else f = float(sqlite3_column_double(_stmt, inx));
|
|
}
|
|
#pragma endregion
|
|
|
|
#pragma region operator >>
|
|
|
|
void operator>>(int & val) {
|
|
_extract_single_value([&] {
|
|
get_col_from_db(0, val);
|
|
});
|
|
}
|
|
void operator>>(std::string& val) {
|
|
_extract_single_value([&] {
|
|
get_col_from_db(0, val);
|
|
});
|
|
}
|
|
void operator>>(std::vector<char>& val) {
|
|
_extract_single_value([&] {
|
|
get_col_from_db(0, val);
|
|
});
|
|
}
|
|
void operator>>(double & val) {
|
|
_extract_single_value([&] {
|
|
get_col_from_db(0, val);
|
|
});
|
|
}
|
|
void operator>>(float & val) {
|
|
_extract_single_value([&] {
|
|
get_col_from_db(0, val);
|
|
});
|
|
}
|
|
void operator>>(sqlite3_int64 & val) {
|
|
_extract_single_value([&] {
|
|
get_col_from_db(0, val);
|
|
});
|
|
}
|
|
|
|
template<typename FUNC>
|
|
void operator>>(FUNC l) {
|
|
typedef function_traits<decltype(l)> traits;
|
|
|
|
database_binder& dbb = *this;
|
|
_extract([&]() {
|
|
binder<traits::arity>::run(dbb, l);
|
|
});
|
|
|
|
}
|
|
#pragma endregion
|
|
|
|
};
|
|
|
|
class database {
|
|
private:
|
|
sqlite3 * _db = nullptr;
|
|
bool _connected = false;
|
|
bool _ownes_db = false;
|
|
public:
|
|
|
|
database() {};
|
|
|
|
void init(std::string const & db_name) {
|
|
_db = nullptr;
|
|
_ownes_db = false;
|
|
_connected = sqlite3_open(db_name.data(), &_db) == SQLITE_OK;
|
|
}
|
|
|
|
database(std::string const & db_name) : _db(nullptr), _connected(false), _ownes_db(true) {
|
|
_connected = sqlite3_open(db_name.data(), &_db) == SQLITE_OK;
|
|
}
|
|
|
|
database(sqlite3* db) {
|
|
_db = db;
|
|
_connected = SQLITE_OK;
|
|
_ownes_db = false;
|
|
}
|
|
|
|
~database() {
|
|
if (_db && _ownes_db) {
|
|
sqlite3_close_v2(_db);
|
|
_db = nullptr;
|
|
}
|
|
}
|
|
|
|
database_binder operator<<(std::string const& sql) const {
|
|
return database_binder(_db, sql);
|
|
}
|
|
|
|
operator bool() const {
|
|
return _connected;
|
|
}
|
|
operator std::string() {
|
|
return sqlite3_errmsg(_db);
|
|
}
|
|
};
|
|
|
|
#pragma region binder specialization
|
|
|
|
template<>
|
|
struct binder < 0 > {
|
|
template<typename F>
|
|
static void run(database_binder& dbb, F l) {
|
|
typedef function_traits<decltype(l)> traits;
|
|
|
|
l();
|
|
}
|
|
};
|
|
template<>
|
|
struct binder < 1 > {
|
|
template<typename F>
|
|
static void run(database_binder& dbb, F l) {
|
|
typedef function_traits<decltype(l)> traits;
|
|
typedef typename traits::template arg<0>::type type_1;
|
|
|
|
type_1 col_1;
|
|
dbb.get_col_from_db(0, col_1);
|
|
|
|
l(std::move(col_1));
|
|
}
|
|
};
|
|
template<>
|
|
struct binder < 2 > {
|
|
template<typename F>
|
|
static void run(database_binder& dbb, F l) {
|
|
typedef function_traits<decltype(l)> traits;
|
|
typedef typename traits::template arg<0>::type type_1;
|
|
typedef typename traits::template arg<1>::type type_2;
|
|
|
|
type_1 col_1;
|
|
type_2 col_2;
|
|
dbb.get_col_from_db(0, col_1);
|
|
dbb.get_col_from_db(1, col_2);
|
|
|
|
l(std::move(col_1), std::move(col_2));
|
|
}
|
|
};
|
|
template<>
|
|
struct binder < 3 > {
|
|
template<typename F>
|
|
static void run(database_binder& dbb, F l) {
|
|
typedef function_traits<decltype(l)> traits;
|
|
typedef typename traits::template arg<0>::type type_1;
|
|
typedef typename traits::template arg<1>::type type_2;
|
|
typedef typename traits::template arg<2>::type type_3;
|
|
|
|
type_1 col_1;
|
|
dbb.get_col_from_db(0, col_1);
|
|
type_2 col_2;
|
|
dbb.get_col_from_db(1, col_2);
|
|
type_3 col_3;
|
|
dbb.get_col_from_db(2, col_3);
|
|
|
|
l(std::move(col_1), std::move(col_2), std::move(col_3));
|
|
}
|
|
};
|
|
template<>
|
|
struct binder < 4 > {
|
|
template<typename F>
|
|
static void run(database_binder& dbb, F l) {
|
|
typedef function_traits<decltype(l)> traits;
|
|
typedef typename traits:: template arg<0>::type type_1;
|
|
typedef typename traits::template arg<1>::type type_2;
|
|
typedef typename traits::template arg<2>::type type_3;
|
|
typedef typename traits::template arg<3>::type type_4;
|
|
|
|
type_1 col_1;
|
|
dbb.get_col_from_db(0, col_1);
|
|
type_2 col_2;
|
|
dbb.get_col_from_db(1, col_2);
|
|
type_3 col_3;
|
|
dbb.get_col_from_db(2, col_3);
|
|
type_4 col_4;
|
|
dbb.get_col_from_db(3, col_4);
|
|
|
|
l(std::move(col_1), std::move(col_2), std::move(col_3), std::move(col_4));
|
|
}
|
|
};
|
|
template<>
|
|
struct binder < 5 > {
|
|
template<typename F>
|
|
static void run(database_binder& dbb, F l) {
|
|
typedef function_traits<decltype(l)> traits;
|
|
typedef typename traits:: template arg<0>::type type_1;
|
|
typedef typename traits::template arg<1>::type type_2;
|
|
typedef typename traits::template arg<2>::type type_3;
|
|
typedef typename traits::template arg<3>::type type_4;
|
|
typedef typename traits::template arg<4>::type type_5;
|
|
|
|
type_1 col_1;
|
|
dbb.get_col_from_db(0, col_1);
|
|
type_2 col_2;
|
|
dbb.get_col_from_db(1, col_2);
|
|
type_3 col_3;
|
|
dbb.get_col_from_db(2, col_3);
|
|
type_4 col_4;
|
|
dbb.get_col_from_db(3, col_4);
|
|
type_5 col_5;
|
|
dbb.get_col_from_db(4, col_5);
|
|
|
|
l(std::move(col_1), std::move(col_2), std::move(col_3), std::move(col_4), std::move(col_5));
|
|
}
|
|
};
|
|
template<>
|
|
struct binder < 6 > {
|
|
template<typename F>
|
|
static void run(database_binder& dbb, F l) {
|
|
typedef function_traits<decltype(l)> traits;
|
|
typedef typename traits:: template arg<0>::type type_1;
|
|
typedef typename traits::template arg<1>::type type_2;
|
|
typedef typename traits::template arg<2>::type type_3;
|
|
typedef typename traits::template arg<3>::type type_4;
|
|
typedef typename traits::template arg<4>::type type_5;
|
|
typedef typename traits::template arg<5>::type type_6;
|
|
|
|
type_1 col_1;
|
|
dbb.get_col_from_db(0, col_1);
|
|
type_2 col_2;
|
|
dbb.get_col_from_db(1, col_2);
|
|
type_3 col_3;
|
|
dbb.get_col_from_db(2, col_3);
|
|
type_4 col_4;
|
|
dbb.get_col_from_db(3, col_4);
|
|
type_5 col_5;
|
|
dbb.get_col_from_db(4, col_5);
|
|
type_6 col_6;
|
|
dbb.get_col_from_db(5, col_6);
|
|
|
|
l(std::move(col_1), std::move(col_2), std::move(col_3), std::move(col_4), std::move(col_5), std::move(col_6));
|
|
}
|
|
};
|
|
template<>
|
|
struct binder < 7 > {
|
|
template<typename F>
|
|
static void run(database_binder& dbb, F l) {
|
|
typedef function_traits<decltype(l)> traits;
|
|
typedef typename traits:: template arg<0>::type type_1;
|
|
typedef typename traits::template arg<1>::type type_2;
|
|
typedef typename traits::template arg<2>::type type_3;
|
|
typedef typename traits::template arg<3>::type type_4;
|
|
typedef typename traits::template arg<4>::type type_5;
|
|
typedef typename traits::template arg<5>::type type_6;
|
|
typedef typename traits::template arg<6>::type type_7;
|
|
|
|
type_1 col_1;
|
|
dbb.get_col_from_db(0, col_1);
|
|
type_2 col_2;
|
|
dbb.get_col_from_db(1, col_2);
|
|
type_3 col_3;
|
|
dbb.get_col_from_db(2, col_3);
|
|
type_4 col_4;
|
|
dbb.get_col_from_db(3, col_4);
|
|
type_5 col_5;
|
|
dbb.get_col_from_db(4, col_5);
|
|
type_6 col_6;
|
|
dbb.get_col_from_db(5, col_6);
|
|
type_7 col_7;
|
|
dbb.get_col_from_db(6, col_7);
|
|
|
|
l(std::move(col_1), std::move(col_2), std::move(col_3), std::move(col_4), std::move(col_5), std::move(col_6), std::move(col_7));
|
|
}
|
|
};
|
|
template<>
|
|
struct binder < 8 > {
|
|
template<typename F>
|
|
static void run(database_binder& dbb, F l) {
|
|
typedef function_traits<decltype(l)> traits;
|
|
typedef typename traits:: template arg<0>::type type_1;
|
|
typedef typename traits::template arg<1>::type type_2;
|
|
typedef typename traits::template arg<2>::type type_3;
|
|
typedef typename traits::template arg<3>::type type_4;
|
|
typedef typename traits::template arg<4>::type type_5;
|
|
typedef typename traits::template arg<5>::type type_6;
|
|
typedef typename traits::template arg<6>::type type_7;
|
|
typedef typename traits::template arg<7>::type type_8;
|
|
|
|
type_1 col_1;
|
|
dbb.get_col_from_db(0, col_1);
|
|
type_2 col_2;
|
|
dbb.get_col_from_db(1, col_2);
|
|
type_3 col_3;
|
|
dbb.get_col_from_db(2, col_3);
|
|
type_4 col_4;
|
|
dbb.get_col_from_db(3, col_4);
|
|
type_5 col_5;
|
|
dbb.get_col_from_db(4, col_5);
|
|
type_6 col_6;
|
|
dbb.get_col_from_db(5, col_6);
|
|
type_7 col_7;
|
|
dbb.get_col_from_db(6, col_7);
|
|
type_8 col_8;
|
|
dbb.get_col_from_db(7, col_8);
|
|
|
|
l(std::move(col_1), std::move(col_2), std::move(col_3), std::move(col_4), std::move(col_5), std::move(col_6), std::move(col_7), std::move(col_8));
|
|
}
|
|
};
|
|
template<>
|
|
struct binder < 9 > {
|
|
template<typename F>
|
|
static void run(database_binder& dbb, F l) {
|
|
typedef function_traits<decltype(l)> traits;
|
|
typedef typename traits:: template arg<0>::type type_1;
|
|
typedef typename traits::template arg<1>::type type_2;
|
|
typedef typename traits::template arg<2>::type type_3;
|
|
typedef typename traits::template arg<3>::type type_4;
|
|
typedef typename traits::template arg<4>::type type_5;
|
|
typedef typename traits::template arg<5>::type type_6;
|
|
typedef typename traits::template arg<6>::type type_7;
|
|
typedef typename traits::template arg<7>::type type_8;
|
|
typedef typename traits::template arg<8>::type type_9;
|
|
|
|
type_1 col_1;
|
|
dbb.get_col_from_db(0, col_1);
|
|
type_2 col_2;
|
|
dbb.get_col_from_db(1, col_2);
|
|
type_3 col_3;
|
|
dbb.get_col_from_db(2, col_3);
|
|
type_4 col_4;
|
|
dbb.get_col_from_db(3, col_4);
|
|
type_5 col_5;
|
|
dbb.get_col_from_db(4, col_5);
|
|
type_6 col_6;
|
|
dbb.get_col_from_db(5, col_6);
|
|
type_7 col_7;
|
|
dbb.get_col_from_db(6, col_7);
|
|
type_8 col_8;
|
|
dbb.get_col_from_db(7, col_8);
|
|
type_9 col_9;
|
|
dbb.get_col_from_db(8, col_9);
|
|
|
|
l(std::move(col_1), std::move(col_2), std::move(col_3), std::move(col_4), std::move(col_5), std::move(col_6), std::move(col_7), std::move(col_8), std::move(col_9));
|
|
}
|
|
};
|
|
template<>
|
|
struct binder < 10 > {
|
|
template<typename F>
|
|
static void run(database_binder& dbb, F l) {
|
|
typedef function_traits<decltype(l)> traits;
|
|
typedef typename traits:: template arg<0>::type type_1;
|
|
typedef typename traits::template arg<1>::type type_2;
|
|
typedef typename traits::template arg<2>::type type_3;
|
|
typedef typename traits::template arg<3>::type type_4;
|
|
typedef typename traits::template arg<4>::type type_5;
|
|
typedef typename traits::template arg<5>::type type_6;
|
|
typedef typename traits::template arg<6>::type type_7;
|
|
typedef typename traits::template arg<7>::type type_8;
|
|
typedef typename traits::template arg<8>::type type_9;
|
|
typedef typename traits::template arg<9>::type type_10;
|
|
|
|
type_1 col_1;
|
|
dbb.get_col_from_db(0, col_1);
|
|
type_2 col_2;
|
|
dbb.get_col_from_db(1, col_2);
|
|
type_3 col_3;
|
|
dbb.get_col_from_db(2, col_3);
|
|
type_4 col_4;
|
|
dbb.get_col_from_db(3, col_4);
|
|
type_5 col_5;
|
|
dbb.get_col_from_db(4, col_5);
|
|
type_6 col_6;
|
|
dbb.get_col_from_db(5, col_6);
|
|
type_7 col_7;
|
|
dbb.get_col_from_db(6, col_7);
|
|
type_8 col_8;
|
|
dbb.get_col_from_db(7, col_8);
|
|
type_9 col_9;
|
|
dbb.get_col_from_db(8, col_9);
|
|
type_9 col_10;
|
|
dbb.get_col_from_db(9, col_10);
|
|
|
|
l(std::move(col_1), std::move(col_2), std::move(col_3), std::move(col_4), std::move(col_5), std::move(col_6), std::move(col_7), std::move(col_8), std::move(col_9), std::move(col_10));
|
|
}
|
|
};
|
|
#pragma endregion
|
|
|
|
}
|