1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
// -*- C++ -*-
#ifndef _SQLSTMT_H_
#define _SQLSTMT_H_ 1
#include <cassert>
#include <string>
#include <tuple>
#include <stdexcept>
#include <sqlite3.h>
using i64 = sqlite3_int64;
struct sqlerr_t : public std::runtime_error {
sqlerr_t (const std::string &msg) : std::runtime_error (msg) {}
};
/* A sqldone_t is thrown if you ask for data when no rows are left */
struct sqldone_t : public std::runtime_error {
sqldone_t (const std::string &msg) : std::runtime_error (msg) {}
};
class sqlstmt_t {
sqlite3_stmt *stmt_;
int status_ = SQLITE_OK;
sqlstmt_t &set_status (int status);
void fail ();
void ensure_row () { if (status_ != SQLITE_ROW) fail(); }
public:
explicit sqlstmt_t(sqlite3_stmt *stmt) : stmt_(stmt) {}
explicit sqlstmt_t(sqlite3 *db, const char *fmt, ...);
sqlstmt_t(const sqlstmt_t &r);
sqlstmt_t(sqlstmt_t &&r) : stmt_ (r.stmt_) { r.stmt_ = nullptr; }
~sqlstmt_t() { sqlite3_finalize (stmt_); }
sqlite3_stmt *get() { return stmt_; }
sqlite3 *getdb() { return sqlite3_db_handle(stmt_); }
int status() const { return status_; }
bool row() {
if (status_ == SQLITE_ROW)
return true;
// Something like SQLITE_OK indicates row() not used after step()
assert (status_ == SQLITE_DONE);
return false;
}
bool done() { return !row(); }
sqlstmt_t &step() { return set_status(sqlite3_step (stmt_)); }
sqlstmt_t &reset() { return set_status(sqlite3_reset (stmt_)); }
/* Access columns */
template<typename T> T column(int);
bool null(int i) {
ensure_row();
return sqlite3_column_type (stmt_, i) == SQLITE_NULL;
}
sqlite3_int64 integer(int i) {
ensure_row();
return sqlite3_column_int64 (stmt_, i);
}
double real(int i) {
ensure_row();
return sqlite3_column_double (stmt_, i);
}
std::string str(int i) {
ensure_row();
return { static_cast<const char *> (sqlite3_column_blob (stmt_, i)),
size_t (sqlite3_column_bytes (stmt_, i)) };
}
const char *c_str(int i) {
ensure_row();
return reinterpret_cast<const char *> (sqlite3_column_text (stmt_, i));
}
sqlite3_value *value(int i) {
ensure_row();
return sqlite3_column_value(stmt_, i);
}
/* Bind parameters */
sqlstmt_t &bind_null(int i) {
return set_status (sqlite3_bind_null(stmt_, i));
}
sqlstmt_t &bind_int(int i, sqlite3_int64 v) {
return set_status (sqlite3_bind_int64(stmt_, i, v));
}
sqlstmt_t &bind_real(int i, double v) {
return set_status (sqlite3_bind_double(stmt_, i, v));
}
sqlstmt_t &bind_text(int i, const std::string &v) {
return set_status (sqlite3_bind_text(stmt_, i, v.data(), v.size(),
SQLITE_STATIC));
}
sqlstmt_t &bind_text(int i, std::string &&v) {
return set_status (sqlite3_bind_text(stmt_, i, v.data(), v.size(),
SQLITE_TRANSIENT));
}
sqlstmt_t &bind_text(int i, const char *p, int len = -1) {
return set_status (sqlite3_bind_text(stmt_, i, p, len, SQLITE_STATIC));
}
sqlstmt_t &bind_blob(int i, const void *p, int len) {
return set_status (sqlite3_bind_blob(stmt_, i, p, len, SQLITE_STATIC));
}
sqlstmt_t &bind_value(int i, const sqlite3_value *v) {
return set_status (sqlite3_bind_value (stmt_, i, v));
}
/* Overloaded bind */
sqlstmt_t &bind(int i, std::nullptr_t) { return bind_null(i); }
sqlstmt_t &bind(int i, sqlite3_int64 v) { return bind_int(i, v); }
sqlstmt_t &bind(int i, int v) { return bind_int(i, v); }
sqlstmt_t &bind(int i, unsigned v) { return bind_int(i, v); }
sqlstmt_t &bind(int i, const double &v) { return bind_real(i, v); }
sqlstmt_t &bind(int i, const std::string &v) { return bind_text(i, v); }
sqlstmt_t &bind(int i, std::string &&v) { return bind_text(i, std::move(v)); }
sqlstmt_t &bind(int i, const char *v) { return bind_text(i, v); }
sqlstmt_t &bind(int i, const sqlite3_value *v) { return bind_value(i, v); }
/* Bind multiple parameters at once */
sqlstmt_t &_param(int) { return *this; }
template<typename H, typename... T>
sqlstmt_t &_param(int i, H&& h, T&&... t) {
return this->bind(i, std::forward<H>(h))._param(i+1, std::forward<T>(t)...);
}
template<typename... Args> sqlstmt_t ¶m(Args&&... args) {
return _param (1, std::forward<Args> (args)...);
}
/* Bind tuple */
template<size_t N> struct _tparm_helper {
template<typename... Args>
static sqlstmt_t &go(sqlstmt_t &s, const std::tuple<Args...> &t) {
return _tparm_helper<N-1>::go(s.bind(N, std::get<N-1>(t)), t);
}
};
template<typename... Args>
sqlstmt_t &tparam(const std::tuple<Args...> &t) {
return _tparm_helper<sizeof...(Args)>::go(*this, t);
}
};
template<> struct sqlstmt_t::_tparm_helper<0> {
template<typename... Args>
static sqlstmt_t &go(sqlstmt_t &s, const std::tuple<Args...> &t) { return s; }
};
template<> inline bool
sqlstmt_t::column(int i)
{
return null(i);
}
template<> inline i64
sqlstmt_t::column(int i)
{
return integer(i);
}
template<> inline double
sqlstmt_t::column(int i)
{
return real(i);
}
template<> inline std::string
sqlstmt_t::column(int i)
{
return str(i);
}
template<> inline const char *
sqlstmt_t::column(int i)
{
return c_str(i);
}
void sqlexec (sqlite3 *db, const char *fmt, ...);
#endif /* !_SQLSTMT_H_ */
|