52 inline void checkSQLiteError(
int code,
const std::string& prefix =
"")
54 if (code != SQLITE_OK)
throw SQLiteError(code, prefix);
69 void operator()(
int index,
int& col) { col = sqlite3_column_int(
m_stmt, index); }
71 void operator()(
int index, int64_t& col) { col = sqlite3_column_int(
m_stmt, index); }
73 void operator()(
int index,
double& col) { col = sqlite3_column_double(
m_stmt, index); }
78 if (
auto ptr =
reinterpret_cast<const char*
>(sqlite3_column_text(
m_stmt, index)); ptr !=
nullptr) {
86 if (
auto ptr =
reinterpret_cast<const std::byte*
>(sqlite3_column_blob(
m_stmt, index)); ptr !=
nullptr) {
87 size_t bytes = sqlite3_column_bytes(
m_stmt, index);
88 col = std::vector<std::byte>(ptr, ptr + bytes);
93 void operator()(
int index, std::optional<T>& col)
95 if (sqlite3_column_type(
m_stmt, index) != SQLITE_NULL) {
121 checkSQLiteError(
bind(index + 1, std::forward<T>(param)));
125 int bind(
int index,
int param) {
return sqlite3_bind_int(
m_stmt, index, param);}
127 int bind(
int index, int64_t param) {
return sqlite3_bind_int64(
m_stmt, index, param); }
129 int bind(
int index,
double param) {
return sqlite3_bind_double(
m_stmt, index, param);}
131 int bind(
int index,
const std::string& param)
133 return sqlite3_bind_text(
m_stmt, index, param.data(), param.size(), SQLITE_TRANSIENT);
136 int bind(
int index,
const std::vector<std::byte>& param)
138 return sqlite3_bind_blob(
m_stmt, index, param.data(), param.size(), SQLITE_TRANSIENT);
142 int bind(
int index,
const std::optional<T>& param)
144 if (param.has_value())
return bind(*param);
145 return sqlite3_bind_null(
m_stmt, index);
151 template<
class Tuple,
class Func, std::size_t ...Is>
152 void visitTupleWithIndexImpl(Tuple&& t, Func&& f, std::index_sequence<Is...>)
155 (f(std::integral_constant<std::size_t, Is> {}, std::get<Is>(t)), ...);
164 template<
class ... T,
class Func>
165 void visitTupleWithIndex(std::tuple<T...>& t, Func&& f)
167 visitTupleWithIndexImpl(t, std::forward<Func>(f), std::make_index_sequence<
sizeof...(T)> {});
194 template<
class ObjectType,
class ... Columns>
195 class ObjectStatement {
201 class iterator:
public std::iterator<std::input_iterator_tag, value_type, size_t> {
213 if (
m_row < 0)
return *
this;
239 ObjectStatement(sqlite3* db,
const std::string& query,
bool persistent)
241 detail::checkSQLiteError(sqlite3_prepare_v3(db, query.data(), query.size(), persistent ? SQLITE_PREPARE_PERSISTENT : 0,
243 if (
auto cols = sqlite3_column_count(
m_statement); cols !=
sizeof...(Columns)) {
244 throw std::runtime_error(
"Number of column (" + std::to_string(cols) +
") doesn't match number of template parameters (" +
245 std::to_string(
sizeof...(Columns)) +
')');
252 template<
class ... Parameters>
255 if (
auto params = sqlite3_bind_parameter_count(
m_statement); params !=
sizeof...(Parameters)) {
256 throw std::runtime_error(
"Number of arguments (" + std::to_string(
sizeof...(Parameters)) +
257 ") doesn't match number of statement parameters (" + std::to_string(params) +
")");
260 auto parameter_tuple = std::make_tuple(parameters...);
270 if (
auto ret = sqlite3_step(
m_statement); ret != SQLITE_ROW) {
271 if (ret == SQLITE_DONE)
return false;
272 detail::checkSQLiteError(ret);
280 std::tuple<Columns...> result;
282 return std::make_from_tuple<value_type>(std::move(result));
290 template<
class ... Columns>
using Statement = ObjectStatement<std::tuple<Columns...>, Columns...>;
300 detail::checkSQLiteError(sqlite3_open_v2(filename.c_str(), &
m_connection, SQLITE_OPEN_READONLY,
nullptr));
305 template<
class ... Columns>