33#ifndef GUARD_SQLITE_FUNCTION_HPP_INCLUDED
34#define GUARD_SQLITE_FUNCTION_HPP_INCLUDED
85 template <
typename R,
typename... Args>
struct callable_traits<R(Args...), void> {
88 static constexpr std::size_t
arity =
sizeof...(Args);
90 template <std::
size_t Index>
91 using argument = std::tuple_element_t<Index, arguments_tuple>;
94 template <
typename R,
typename... Args>
97 template <
typename R,
typename... Args>
100 template <
typename Class,
typename R,
typename... Args>
103 template <
typename Class,
typename R,
typename... Args>
106#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510
107 template <
typename Class,
typename R,
typename... Args>
111 template <
typename Class,
typename R,
typename... Args>
112 struct callable_traits<R (Class::*)(Args...) const noexcept, void>
113 : callable_traits<R(Args...)> {};
115 template <
typename R,
typename... Args>
116 struct callable_traits<R (*)(Args...)
noexcept,
void> : callable_traits<R(Args...)> {};
118 template <
typename R,
typename... Args>
119 struct callable_traits<R (&)(Args...) noexcept,
void> : callable_traits<R(Args...)> {};
122 template <
typename Callable>
126 template <
typename Callable>
128 std::enable_if_t<!std::is_function_v<Callable>, void>>
131 template <
typename Callable>
133 std::enable_if_t<!std::is_function_v<Callable>, void>>
136 template <
typename Callable>
138 std::enable_if_t<!std::is_function_v<Callable>, void>>
141 template <
typename Callable>
144 std::enable_if_t<!std::is_function_v<std::remove_reference_t<Callable>>,
void>>
147 template <
typename Callable>
150 std::enable_if_t<!std::is_function_v<std::remove_reference_t<Callable>>,
void>>
153 template <
typename T>
using decay_t = std::remove_cvref_t<T>;
157 template <
typename U>
struct is_optional<std::optional<U>> : std::true_type {};
161 "NULL passed to SQL function argument but callable parameter is not nullable.");
166 template <
typename T>
167 requires(std::is_integral_v<decay_t<T>> && !std::is_same_v<decay_t<T>,
bool>)
170 if (sqlite3_value_type(value) == SQLITE_NULL) {
173 return static_cast<decay_t<T>>(sqlite3_value_int64(value));
179 if (sqlite3_value_type(value) == SQLITE_NULL) {
182 return sqlite3_value_int(value) != 0;
186 template <
typename T>
187 requires std::is_floating_point_v<decay_t<T>>
188 struct argument_converter<T> {
190 if (sqlite3_value_type(value) == SQLITE_NULL) {
193 return static_cast<decay_t<T>>(sqlite3_value_double(value));
198 static std::string_view
convert(sqlite3_value *value) {
199 if (sqlite3_value_type(value) == SQLITE_NULL) {
202 auto const len = sqlite3_value_bytes(value);
203 auto const *
text =
reinterpret_cast<char const *
>(sqlite3_value_text(value));
205 return std::string_view();
207 return std::string_view(
text,
static_cast<std::size_t
>(len));
211 template <
typename Text>
212 requires(!std::is_same_v<decay_t<Text>, std::string_view> &&
213 std::constructible_from<decay_t<Text>, std::string_view>)
221 static std::span<const unsigned char>
convert(sqlite3_value *value) {
222 if (sqlite3_value_type(value) == SQLITE_NULL) {
225 auto const len = sqlite3_value_bytes(value);
226 auto const *data =
static_cast<unsigned char const *
>(sqlite3_value_blob(value));
227 return std::span<const unsigned char>(data,
static_cast<std::size_t
>(len));
232 static std::span<const std::byte>
convert(sqlite3_value *value) {
234 auto ptr =
reinterpret_cast<std::byte
const *
>(bytes.data());
235 return std::span<const std::byte>(ptr, bytes.size());
239 template <
typename Vector>
240 requires(std::is_same_v<decay_t<Vector>, std::vector<unsigned char>> ||
241 std::is_same_v<decay_t<Vector>, std::vector<std::byte>>)
245 std::is_same_v<decay_t<Vector>, std::vector<unsigned char>>,
246 std::span<const unsigned char>, std::span<const std::byte>>>
::convert(value);
252 static sqlite3_value *
convert(sqlite3_value *value) {
258 static sqlite3_value
const *
convert(sqlite3_value *value) {
265 "Nested std::optional values are not supported.");
266 static std::optional<T>
convert(sqlite3_value *value) {
267 if (sqlite3_value_type(value) == SQLITE_NULL) {
277 static void apply(sqlite3_context *ctx,
void const *) {
278 sqlite3_result_null(ctx);
284 sqlite3_result_null(ctx);
289 static void apply(sqlite3_context *ctx, std::nullptr_t) {
290 sqlite3_result_null(ctx);
294 template <
typename T>
295 requires(std::is_integral_v<decay_t<T>> && !std::is_same_v<decay_t<T>,
bool>)
297 static void apply(sqlite3_context *ctx, T value) {
298 sqlite3_result_int64(ctx,
static_cast<sqlite3_int64
>(value));
303 static void apply(sqlite3_context *ctx,
bool value) {
304 sqlite3_result_int(ctx, value ? 1 : 0);
308 template <
typename T>
309 requires std::is_floating_point_v<decay_t<T>>
310 struct result_writer<T> {
311 static void apply(sqlite3_context *ctx, T value) {
312 sqlite3_result_double(ctx,
static_cast<double>(value));
317 sqlite3_result_text(ctx,
view.data(),
static_cast<int>(
view.size()), SQLITE_TRANSIENT);
321 static void apply(sqlite3_context *ctx, std::string_view value) {
326 template <
typename Text>
327 requires(!std::is_same_v<decay_t<Text>, std::string_view> &&
328 std::constructible_from<std::string_view, decay_t<Text>>)
330 static void apply(sqlite3_context *ctx, Text
const &value) {
336 static void apply(sqlite3_context *ctx, std::span<const unsigned char> value) {
337 sqlite3_result_blob(ctx, value.data(),
static_cast<int>(value.size()),
343 static void apply(sqlite3_context *ctx, std::span<const std::byte> value) {
344 auto ptr =
reinterpret_cast<unsigned char const *
>(value.data());
345 sqlite3_result_blob(ctx, ptr,
static_cast<int>(value.size()), SQLITE_TRANSIENT);
349 template <
typename Vector>
350 requires(std::is_same_v<decay_t<Vector>, std::vector<unsigned char>> ||
351 std::is_same_v<decay_t<Vector>, std::vector<std::byte>>)
353 static void apply(sqlite3_context *ctx, Vector
const &value) {
354 sqlite3_result_blob(ctx,
reinterpret_cast<unsigned char const *
>(value.data()),
355 static_cast<int>(value.size()), SQLITE_TRANSIENT);
360 static void apply(sqlite3_context *ctx, std::optional<T>
const &value) {
362 sqlite3_result_null(ctx);
369 template <
typename Callable, std::size_t... Index>
371 sqlite3_value **argv, std::index_sequence<Index...>) {
373 if constexpr (
sizeof...(Index) == 0) {
374 return std::invoke(holder.
callable);
387 template <
typename Callable>
392 sqlite3_result_error(ctx,
"SQL function metadata missing.", -1);
395 if (argc !=
static_cast<int>(traits::arity)) {
396 sqlite3_result_error(ctx,
"Unexpected number of arguments for SQL function.", -1);
400 if constexpr (std::is_void_v<typename traits::return_type>) {
402 std::make_index_sequence<traits::arity>{});
403 sqlite3_result_null(ctx);
406 *holder, argv, std::make_index_sequence<traits::arity>{});
410 sqlite3_result_error(ctx, ex.what(), -1);
411 }
catch (std::exception
const &ex) {
412 sqlite3_result_error(ctx, ex.what(), -1);
414 sqlite3_result_error(ctx,
"Unhandled exception in SQL function.", -1);
420#ifdef SQLITE_DETERMINISTIC
422 rep |= SQLITE_DETERMINISTIC;
425#ifdef SQLITE_DIRECTONLY
427 rep |= SQLITE_DIRECTONLY;
430#ifdef SQLITE_INNOCUOUS
432 rep |= SQLITE_INNOCUOUS;
440 return "Failed to register SQL function.";
442 return std::format(
"Failed to register SQL function '{}'.", name);
446 template <
typename Callable>
449 using callable_t = std::decay_t<Callable>;
450 using traits = detail::callable_traits<callable_t>;
451 static_assert(traits::arity <= static_cast<std::size_t>(std::numeric_limits<int>::max()),
452 "SQL functions cannot expose more than INT_MAX parameters.");
454 constexpr auto max_arity =
static_cast<int>(traits::arity);
455 int arity = options.arity;
459 if (arity != max_arity) {
460 throw database_exception(
"Explicit arity override does not match callable signature.");
464 std::make_unique<detail::function_holder<callable_t>>(std::forward<Callable>(callable));
468 std::string name_buffer(name);
471 int rc = sqlite3_create_function_v2(handle, name_buffer.c_str(), arity, text_rep,
475 if (rc != SQLITE_OK) {
476 auto err = sqlite3_errmsg(handle);
Exception hierarchy mirroring common SQLite failure categories.
void throw_null_argument_error()
std::remove_cvref_t< T > decay_t
void destroy_holder(void *data)
int compose_text_rep(function_options const &options)
void function_entry(sqlite3_context *ctx, int argc, sqlite3_value **argv)
decltype(auto) invoke_with_arguments(function_holder< Callable > &holder, sqlite3_value **argv, std::index_sequence< Index... >)
void result_text(sqlite3_context *ctx, std::string_view view)
std::string make_function_error(std::string_view name)
void create_function(connection &con, std::string_view name, Callable &&callable, function_options options={})
connection is used to open, close, attach and detach a database. Further it has to be passed to all c...
Exception that carries the original SQLite error code and optional SQL snippet.
Generic runtime failure raised for most SQLite errors.
static decay_t< T > convert(sqlite3_value *value)
static decay_t< Text > convert(sqlite3_value *value)
static decay_t< Vector > convert(sqlite3_value *value)
static bool convert(sqlite3_value *value)
static sqlite3_value * convert(sqlite3_value *value)
static sqlite3_value const * convert(sqlite3_value *value)
static std::optional< T > convert(sqlite3_value *value)
static std::span< const std::byte > convert(sqlite3_value *value)
static std::span< const unsigned char > convert(sqlite3_value *value)
static std::string_view convert(sqlite3_value *value)
static constexpr std::size_t arity
std::tuple< Args... > arguments_tuple
std::tuple_element_t< Index, arguments_tuple > argument
std::decay_t< Callable > callable
static void apply(sqlite3_context *ctx, T value)
static void apply(sqlite3_context *ctx, Text const &value)
static void apply(sqlite3_context *ctx, Vector const &value)
static void apply(sqlite3_context *ctx, bool value)
static void apply(sqlite3_context *ctx, null_type const &)
static void apply(sqlite3_context *ctx, std::nullptr_t)
static void apply(sqlite3_context *ctx, std::optional< T > const &value)
static void apply(sqlite3_context *ctx, std::span< const std::byte > value)
static void apply(sqlite3_context *ctx, std::span< const unsigned char > value)
static void apply(sqlite3_context *ctx, std::string_view value)
static void apply(sqlite3_context *ctx, void const *)
Options passed alongside a callable when registering it with sqlite3_create_function_v2.
null_type is an empty type used to represent NULL values
static void acccess_check(connection &m_con)
static struct sqlite3 * get_handle(connection &m_con)
Forward-only cursor over the rows produced by a prepared statement.
view is used to create views. In SQLite a view can only be queried. INSERT, DELETE and UPDATE will fa...