// Copyright (c) 2023 Klemens D. Morgenstern // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_SQLITE_IMPL_WINDOW_FUNCTION_HPP #define BOOST_SQLITE_IMPL_WINDOW_FUNCTION_HPP #if SQLITE_VERSION_NUMBER >= 3025000 #include #include #include #include #include BOOST_SQLITE_BEGIN_NAMESPACE namespace detail { template struct window_function_maker { void * mem; template Func* operator()(Args && ... args) { return new (mem) Func(std::forward(args)...); } }; template int create_window_function(sqlite3 * db, cstring_ref name, Args && args, int flags, std::true_type /* is void */) { using args_type = callable_traits::args_t; using span_type = typename std::tuple_element<1U, args_type>::type; using func_type = typename std::decay::type; using func_args_type = typename std::decay::type; return sqlite3_create_window_function( db, name.c_str(), span_type::extent == boost::dynamic_extent ? -1 : static_cast(span_type::extent), SQLITE_UTF8 | flags, new (memory_tag{}) func_args_type(std::forward(args)), +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept //xStep { auto aa = reinterpret_cast(args); auto fa = reinterpret_cast(sqlite3_user_data(ctx)); auto c = static_cast(sqlite3_aggregate_context(ctx, 0)); execute_context_function( ctx, [&]() -> result { if (c == nullptr) { auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); if (!p) return error(SQLITE_NOMEM); c = mp11::tuple_apply(window_function_maker{p}, *fa); } c->step(span_type{aa, static_cast(len)}); return {}; }); }, [](sqlite3_context* ctx) // xFinal { auto fa = reinterpret_cast(sqlite3_user_data(ctx)); auto c = static_cast(sqlite3_aggregate_context(ctx, 0)); execute_context_function( ctx, [&]() -> resultvalue())> { if (c == nullptr) { auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); if (!p) return error(SQLITE_NOMEM); c = mp11::tuple_apply(window_function_maker{p}, *fa); } struct reaper {void operator()(func_type * c) { c->~func_type();}}; std::unique_ptr cl{c}; return c->value(); }); }, [](sqlite3_context* ctx) //xValue { auto fa = reinterpret_cast(sqlite3_user_data(ctx)); auto c = static_cast(sqlite3_aggregate_context(ctx, 0)); execute_context_function( ctx, [&]() -> resultvalue())> { if (c == nullptr) { auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); if (!p) return error(SQLITE_NOMEM); c = mp11::tuple_apply(window_function_maker{p}, *fa); } return c->value(); }); }, +[](sqlite3_context* ctx, int len, sqlite3_value** args) // xInverse { auto aa = reinterpret_cast(args); auto fa = reinterpret_cast(sqlite3_user_data(ctx)); auto c = static_cast(sqlite3_aggregate_context(ctx, 0)); execute_context_function( ctx, [&]() -> resultinverse(span_type{aa, static_cast(len)}))> { if (c == nullptr) { auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); if (!p) return error(SQLITE_NOMEM); c = mp11::tuple_apply(window_function_maker{p}, *fa); } c->inverse(span_type{aa, static_cast(len)}); return {}; }); }, [](void * ptr) /* xDestroy */ { delete_(static_cast(ptr));} ); } template int create_window_function(sqlite3 * db, cstring_ref name, Args && args, int flags, std::false_type /* is void */) { using args_type = callable_traits::args_t; using span_type = typename std::tuple_element<1U, args_type>::type; using func_type = typename std::decay::type; using func_args_type = typename std::decay::type; return sqlite3_create_window_function( db, name.c_str(), span_type::extent == boost::dynamic_extent ? -1 : static_cast(span_type::extent), SQLITE_UTF8 | flags, new (memory_tag{}) func_args_type(std::forward(args)), +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept //xStep { auto aa = reinterpret_cast(args); auto fa = reinterpret_cast(sqlite3_user_data(ctx)); auto c = static_cast(sqlite3_aggregate_context(ctx, 0)); execute_context_function( ctx, [&]() -> resultstep(span_type{aa, static_cast(len)}))> { if (c == nullptr) { auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); if (!p) return {system::in_place_error, error(SQLITE_NOMEM)}; c = mp11::tuple_apply(window_function_maker{p}, *fa); } return c->step(span_type{aa, static_cast(len)}); }); }, [](sqlite3_context* ctx) // xFinal { auto fa = reinterpret_cast(sqlite3_user_data(ctx)); auto c = static_cast(sqlite3_aggregate_context(ctx, 0)); execute_context_function( ctx, [&]() -> resultvalue())> { if (c == nullptr) { auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); if (!p) return {system::in_place_error, error(SQLITE_NOMEM)}; c = mp11::tuple_apply(window_function_maker{p}, *fa); } struct reaper {void operator()(func_type * c) { c->~func_type();}}; std::unique_ptr cl{c}; return c->value(); }); }, [](sqlite3_context* ctx) //xValue { auto fa = reinterpret_cast(sqlite3_user_data(ctx)); auto c = static_cast(sqlite3_aggregate_context(ctx, 0)); execute_context_function( ctx, [&]() -> resultvalue())> { if (c == nullptr) { auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); if (!p) return {system::in_place_error, error(SQLITE_NOMEM)}; c = mp11::tuple_apply(window_function_maker{p}, *fa); } return c->value(); }); }, +[](sqlite3_context* ctx, int len, sqlite3_value** args) // xInverse { auto aa = reinterpret_cast(args); auto fa = reinterpret_cast(sqlite3_user_data(ctx)); auto c = static_cast(sqlite3_aggregate_context(ctx, 0)); execute_context_function( ctx, [&]() -> resultinverse(span_type{aa, static_cast(len)}))> { if (c == nullptr) { auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); if (!p) return {system::in_place_error, error(SQLITE_NOMEM)}; c = mp11::tuple_apply(window_function_maker{p}, *fa); } return c->inverse(span_type{aa, static_cast(len)}); }); }, [](void * ptr) /* xDestroy */ { delete_(static_cast(ptr));} ); } } BOOST_SQLITE_END_NAMESPACE #endif // SQLITE_VERSION #endif //BOOST_SQLITE_IMPL_WINDOW_FUNCTION_HPP