5#ifndef BOOST_SQLITE_STATEMENT_HPP
6#define BOOST_SQLITE_STATEMENT_HPP
8#include <boost/sqlite/detail/config.hpp>
9#include <boost/sqlite/detail/exception.hpp>
10#include <boost/sqlite/blob.hpp>
11#include <boost/sqlite/resultset.hpp>
13#include <boost/mp11/algorithm.hpp>
14#include <boost/core/ignore_unused.hpp>
15#include <boost/variant2/variant.hpp>
20BOOST_SQLITE_BEGIN_NAMESPACE
23struct static_resultset;
32 param_ref(variant2::monostate) : impl_{variant2::in_place_type_t<variant2::monostate>{}} {}
34 param_ref(std::nullptr_t) : impl_{variant2::in_place_type_t<variant2::monostate>{}} {}
37 typename =
typename std::enable_if<std::is_integral<I>::value>::type>
40 BOOST_IF_CONSTEXPR ((
sizeof(I) ==
sizeof(
int) && std::is_unsigned<I>::value)
41 || (
sizeof(I) >
sizeof(
int)))
42 impl_.emplace<sqlite3_int64>(
static_cast<sqlite3_int64
>(
value));
44 impl_.emplace<
int>(
static_cast<int>(
value));
51 template<
typename StringLike>
53 typename std::enable_if<std::is_constructible<string_view, StringLike>::value>::type * =
nullptr)
54 : impl_(variant2::in_place_type_t<string_view>{}, text) {}
56 template<
typename BlobLike>
57 param_ref(BlobLike && text,
58 typename std::enable_if<
59 !std::is_constructible<string_view, BlobLike>::value
60 && std::is_constructible<blob_view, BlobLike>::value>::type * =
nullptr)
61 : impl_(variant2::in_place_type_t<blob_view>{},
text) {}
68#if SQLITE_VERSION_NUMBER >= 3020000
72 : impl_(variant2::in_place_index_t<7>{},
73 std::unique_ptr<void, void(*)(void*)>(
74 static_cast<void*
>(ptr.release()),
75 +[](
void * ptr){delete static_cast<T*>(ptr);}),
83 : impl_(variant2::in_place_index_t<7>{},
84 std::unique_ptr<void, void(*)(void*)>(
85 static_cast<void*
>(ptr.release()),
86 +[](
void * ptr){delete static_cast<T*>(ptr);}),
93 template<
typename T,
typename Deleter>
95 typename std::enable_if<std::is_empty<Deleter>::value &&
96 std::is_default_constructible<Deleter>::value,
int>::type * =
nullptr)
97 : impl_(variant2::in_place_index_t<7>{},
98 std::unique_ptr<void, void(*)(void*)>(
99 static_cast<void*
>(ptr.release()),
100 +[](
void * ptr){delete static_cast<T*>(ptr);}),
107 int apply(sqlite3_stmt * stmt,
int c)
const
109 return variant2::visit(visitor{stmt, c}, impl_);
116 auto operator()(T&& t)
const ->
typename std::enable_if<std::is_constructible<param_ref, T&&>::value,
param_ref>::type
126 decltype(variant2::visit(make_visitor(), std::forward<T>(t))) * =
nullptr)
127 :
param_ref(variant2::visit(make_visitor(), std::forward<T>(t)))
136 int operator()(variant2::monostate )
138 return sqlite3_bind_null(stmt, col);
140 int operator()(
int i )
142 return sqlite3_bind_int(stmt, col, i);
144 int operator()(sqlite3_int64 i64 )
146 return sqlite3_bind_int64(stmt, col, i64);
149 int operator()(blob_view blob)
151 if (
blob.size() >
static_cast<std::size_t
>(std::numeric_limits<int>::max()))
152 return sqlite3_bind_blob64(stmt, col,
blob.data(),
blob.size(), SQLITE_STATIC);
154 return sqlite3_bind_blob(stmt, col,
blob.data(),
blob.size(), SQLITE_STATIC);
157 int operator()(string_view text)
159 if (
text.size() > std::numeric_limits<int>::max())
160 return sqlite3_bind_text64(stmt, col,
text.data(),
text.size(), SQLITE_STATIC, SQLITE_UTF8);
162 return sqlite3_bind_text(stmt, col,
text.data(),
text.size(), SQLITE_STATIC);
164 int operator()(
double value)
166 return sqlite3_bind_double(stmt, col, value);
168 int operator()(zero_blob zb)
170 if (
static_cast<std::size_t
>(zb) >
static_cast<std::size_t
>(std::numeric_limits<int>::max()))
171 return sqlite3_bind_zeroblob64(stmt, col,
static_cast<sqlite3_uint64
>(zb));
173 return sqlite3_bind_zeroblob(stmt, col,
static_cast<int>(zb));
175#if SQLITE_VERSION_NUMBER >= 3020000
176 int operator()(std::pair<std::unique_ptr<
void,
void(*)(
void*)>,
const char*> & p)
178 auto d =p.first.get_deleter();
179 return sqlite3_bind_pointer(stmt, col, p.first.release(), p.second, d);
185 variant2::variant<variant2::monostate, int, sqlite3_int64,
186 blob_view, string_view, double,
zero_blob
187#if SQLITE_VERSION_NUMBER >= 3020000
188 , std::pair<std::unique_ptr<void, void(*)(
void*)>,
const char*>
215 template <
typename ArgRange = std::initializer_list<param_ref>>
218 system::error_code& ec,
221 bind_impl(std::forward<ArgRange>(params), ec, info);
223 rs.impl_.reset(impl_.release());
225 rs.read_next(ec, info);
229 template <
typename ArgRange = std::initializer_list<param_ref>>
232 system::error_code ec;
234 auto tmp = std::move(*this).execute(std::forward<ArgRange>(params), ec, ei);
236 detail::throw_error_code(ec, ei);
241 std::initializer_list<std::pair<string_view, param_ref>> params,
242 system::error_code& ec,
245 bind_impl(std::move(params), ec, info);
247 rs.impl_.reset(impl_.release());
249 rs.read_next(ec, info);
255 system::error_code ec;
257 auto tmp = std::move(*this).execute(std::move(params), ec, ei);
259 detail::throw_error_code(ec, ei);
263 template<
typename T,
typename ArgRange = std::initializer_list<param_ref>>
266 system::error_code & ec,
269 static_resultset<T> tmp = std::move(*this).execute(std::forward<ArgRange>(params), ec, ei);
272 tmp.check_columns_(ec, ei);
279 template<
typename T,
typename ArgRange = std::initializer_list<param_ref>>
280 static_resultset<T>
execute(ArgRange && params) &&
282 system::error_code ec;
284 auto tmp = std::move(*this).execute<T>(std::forward<ArgRange>(params), ec, ei);
286 throw_exception(system::system_error(ec, ei.message()));
292 std::initializer_list<std::pair<string_view, param_ref>> params,
293 system::error_code & ec,
296 static_resultset<T> tmp = std::move(*this).execute(std::move(params), ec, ei);
299 tmp.check_columns_(ec, ei);
307 static_resultset<T>
execute(std::initializer_list<std::pair<string_view, param_ref>> params) &&
309 system::error_code ec;
311 auto tmp = std::move(*this).execute<T>(std::move(params), ec, ei);
313 throw_exception(system::system_error(ec, ei.message()));
338 template <
typename ArgRange = std::initializer_list<param_ref>>
341 system::error_code& ec,
344 bind_impl(std::forward<ArgRange>(params), ec, info);
346 rs.impl_.get_deleter().delete_ =
false;
347 rs.impl_.reset(impl_.get());
349 rs.read_next(ec, info);
354 template <
typename ArgRange = std::initializer_list<param_ref>>
357 system::error_code ec;
359 auto tmp = execute(std::forward<ArgRange>(params), ec, ei);
361 detail::throw_error_code(ec, ei);
367 std::initializer_list<std::pair<string_view, param_ref>> params,
368 system::error_code& ec,
371 bind_impl(std::move(params), ec, info);
373 rs.impl_.get_deleter().delete_ =
false;
374 rs.impl_.reset(impl_.get());
376 rs.read_next(ec, info);
382 system::error_code ec;
384 auto tmp = execute(std::move(params), ec, ei);
386 detail::throw_error_code(ec, ei);
390 template<
typename T,
typename ArgRange = std::initializer_list<param_ref>>
393 system::error_code & ec,
396 static_resultset<T> tmp = execute(std::forward<ArgRange>(params), ec, ei);
399 tmp.check_columns_(ec, ei);
406 template<
typename T,
typename ArgRange = std::initializer_list<param_ref>>
407 static_resultset<T>
execute(ArgRange && params) &
409 system::error_code ec;
411 auto tmp = execute<T>(std::forward<ArgRange>(params), ec, ei);
413 throw_exception(system::system_error(ec, ei.message()));
419 std::initializer_list<std::pair<string_view, param_ref>> params,
420 system::error_code & ec,
423 static_resultset<T> tmp = execute(std::move(params), ec, ei);
426 tmp.check_columns_(ec, ei);
434 static_resultset<T>
execute(std::initializer_list<std::pair<string_view, param_ref>> params) &
436 system::error_code ec;
438 auto tmp = execute<T>(std::move(params), ec, ei);
440 throw_exception(system::system_error(ec, ei.message()));
450 return sqlite3_sql(impl_.get());
453#if SQLITE_VERSION_NUMBER >= 3014000
457 return sqlite3_expanded_sql(impl_.get());
462#ifdef SQLITE_ENABLE_NORMALIZE
463 core::string_view normalized_sql()
465 return sqlite3_normalized_sql(impl_.get());
472 return sqlite3_column_decltype(impl_.get(),
id);
477 template<
typename ... Args>
478 void bind_impl(std::tuple<Args...> && vec,
479 system::error_code & ec,
482 const auto sz = sqlite3_bind_parameter_count(impl_.get());
483 if (
sizeof...(Args) <
static_cast<std::size_t
>(sz))
485 BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_ERROR);
486 ei.format(
"To few parameters provided. Needed %ld got %ld",
487 sz,
sizeof...(Args));
491 int i = 1, ar = SQLITE_OK;
492 mp11::tuple_for_each(std::move(vec),
496 ar = pr.apply(impl_.get(), i++);
500 BOOST_SQLITE_ASSIGN_EC(ec, ar);
501 ei.
set_message(sqlite3_errmsg(sqlite3_db_handle(impl_.get())));
507 template<
typename ... Args>
508 void bind_impl(
const std::tuple<Args...> & vec,
509 system::error_code & ec,
512 const auto sz = sqlite3_bind_parameter_count(impl_.get());
513 if (
static_cast<int>(
sizeof...(Args)) < sz)
515 BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_ERROR);
516 ei.format(
"To few parameters provided. Needed %ld got %ld",
517 sz,
sizeof...(Args));
521 int i = 1, ar = SQLITE_OK;
522 mp11::tuple_for_each(std::move(vec),
526 ar = pr.apply(impl_.get(), i++);
530 BOOST_SQLITE_ASSIGN_EC(ec, ar);
531 ei.set_message(sqlite3_errmsg(sqlite3_db_handle(impl_.get())));
536 template<
typename ParamVector>
537 void bind_impl(ParamVector && vec, system::error_code & ec, error_info & ei,
538 typename std::enable_if<std::is_convertible<
539 typename std::decay<ParamVector>::type::value_type, param_ref>::value>::type * =
nullptr)
541 const auto sz = sqlite3_bind_parameter_count(impl_.get());
542 if (vec.size() <
static_cast<std::size_t
>(sz))
544 BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_ERROR);
545 ei.format(
"To few parameters provided. Needed %ld got %ld",
549 for (
const param_ref & pr : std::forward<ParamVector>(vec))
551 int ar = pr.apply(impl_.get(), i++);
555 BOOST_SQLITE_ASSIGN_EC(ec, ar);
556 ei.set_message(sqlite3_errmsg(sqlite3_db_handle(impl_.get())));
562 template<
typename ParamMap>
563 void bind_impl(ParamMap && vec, system::error_code & ec, error_info & ei,
564 typename std::enable_if<
565 std::is_convertible<
typename std::decay<ParamMap>::type::key_type, string_view>::value &&
566 std::is_convertible<
typename std::decay<ParamMap>::type::mapped_type, param_ref>::value
569 for (
auto i = 1; i <= sqlite3_bind_parameter_count(impl_.get()); i ++)
571 auto c = sqlite3_bind_parameter_name(impl_.get(), i);
574 BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISUSE);
575 ei.set_message(
"Parameter maps require all parameters to be named.");
578 auto itr = vec.find(c+1);
579 if (itr == vec.end())
581 BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISUSE);
582 ei.format(
"Can't find value for key '%s'", c+1);
586 if (std::is_rvalue_reference<ParamMap&&>::value)
587 ar = param_ref(std::move(itr->second)).apply(impl_.get(), i);
589 ar = param_ref(itr->second).apply(impl_.get(), i);
594 BOOST_SQLITE_ASSIGN_EC(ec, ar);
595 ei.set_message(sqlite3_errmsg(sqlite3_db_handle(impl_.get())));
601 void bind_impl(std::initializer_list<std::pair<string_view, param_ref>> params,
602 system::error_code & ec, error_info & ei)
604 for (
auto i = 1; i <= sqlite3_bind_parameter_count(impl_.get()); i ++)
606 auto c = sqlite3_bind_parameter_name(impl_.get(), i);
609 BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISUSE);
610 ei.set_message(
"Parameter maps require all parameters to be named.");
614 auto itr = std::find_if(params.begin(), params.end(),
615 [&](
const std::pair<string_view, param_ref> & p)
617 return p.first == (c+1);
619 if (itr == params.end())
621 BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISUSE);
622 ei.format(
"Can't find value for key '%s'", c+1);
625 auto ar = itr->second.apply(impl_.get(), i);
629 BOOST_SQLITE_ASSIGN_EC(ec, ar);
630 ei.set_message(sqlite3_errmsg(sqlite3_db_handle(impl_.get())));
641 void operator()(sqlite3_stmt * sm)
643 sqlite3_finalize(sm);
646 std::unique_ptr<sqlite3_stmt, deleter_> impl_;
649BOOST_SQLITE_END_NAMESPACE
zero_blob
Helper type to pass a blob full of zeroes without allocating extra memory.
a view to a binary large object
An object that owns a binary large object.
Additional information about error conditions stored in an sqlite-allocate string.
void set_message(core::string_view msg)
set the message by copy
A reference to a value to temporary bind for an execute statement. Most values are captures by refere...
param_ref(zero_blob zb)
Bind a zero_blob value, i.e. a blob that initialized by zero.
param_ref(std::unique_ptr< T > ptr)
Bind pointer value to the parameter.
param_ref(T &&t, decltype(variant2::visit(make_visitor(), std::forward< T >(t))) *=nullptr)
Construct param_ref from a variant.
param_ref(std::nullptr_t)
Bind null.
param_ref(double value)
Bind a floating point value.
param_ref(blob_view blob)
Bind a blob.
int apply(sqlite3_stmt *stmt, int c) const
Apply the param_ref to a statement.
param_ref(string_view text)
Bind a string.
param_ref()=default
Default construct a parameter, gives null.
param_ref(std::unique_ptr< T, Deleter > ptr, typename std::enable_if< std::is_empty< Deleter >::value &&std::is_default_constructible< Deleter >::value, int >::type *=nullptr)
Bind pointer value with a function custom deleter to the parameter. The deleter needs to be default c...
param_ref(std::unique_ptr< T, void(*)(T *)> ptr)
Bind pointer value with a function as deleter to the parameter.
param_ref(I value)
Bind an integer.
param_ref(variant2::monostate)
Bind null.
Representation of a result from a database.
A statement used for a prepared-statement.
resultset execute(ArgRange &¶ms, system::error_code &ec, error_info &info) &&
execute the prepared statement once.
static_resultset< T > execute(std::initializer_list< std::pair< string_view, param_ref > > params) &&
execute the prepared statement once.
core::string_view sql()
Returns the sql used to construct the prepared statement.
resultset execute(ArgRange &¶ms) &
execute the prepared statement and reset it afterwards.
resultset execute(ArgRange &¶ms) &&
execute the prepared statement once.
static_resultset< T > execute(ArgRange &¶ms, system::error_code &ec, error_info &ei) &
execute the prepared statement and reset it afterwards.
static_resultset< T > execute(std::initializer_list< std::pair< string_view, param_ref > > params, system::error_code &ec, error_info &ei) &
execute the prepared statement and reset it afterwards.
resultset execute(std::initializer_list< std::pair< string_view, param_ref > > params, system::error_code &ec, error_info &info) &
execute the prepared statement and reset it afterwards.
resultset execute(std::initializer_list< std::pair< string_view, param_ref > > params, system::error_code &ec, error_info &info) &&
execute the prepared statement once.
static_resultset< T > execute(ArgRange &¶ms, system::error_code &ec, error_info &ei) &&
execute the prepared statement once.
static_resultset< T > execute(std::initializer_list< std::pair< string_view, param_ref > > params) &
execute the prepared statement and reset it afterwards.
resultset execute(std::initializer_list< std::pair< string_view, param_ref > > params) &&
execute the prepared statement once.
core::string_view expanded_sql()
Returns the expanded sql used to construct the prepared statement.
core::string_view declared_type(int id) const
Returns the expanded sql used to construct the prepared statement.
static_resultset< T > execute(ArgRange &¶ms) &&
execute the prepared statement once.
resultset execute(std::initializer_list< std::pair< string_view, param_ref > > params) &
execute the prepared statement and reset it afterwards.
static_resultset< T > execute(ArgRange &¶ms) &
execute the prepared statement and reset it afterwards.
static_resultset< T > execute(std::initializer_list< std::pair< string_view, param_ref > > params, system::error_code &ec, error_info &ei) &&
execute the prepared statement once.
resultset execute(ArgRange &¶ms, system::error_code &ec, error_info &info) &
execute the prepared statement and reset it afterwards.
A holder for a sqlite values used for internal APIs.