boost_sqlite 1
A sqlite C++ library
Loading...
Searching...
No Matches
window_function.hpp
1// Copyright (c) 2023 Klemens D. Morgenstern
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5#ifndef BOOST_SQLITE_IMPL_WINDOW_FUNCTION_HPP
6#define BOOST_SQLITE_IMPL_WINDOW_FUNCTION_HPP
7#if SQLITE_VERSION_NUMBER >= 3025000
8
9#include <boost/sqlite/detail/config.hpp>
10#include <boost/sqlite/cstring_ref.hpp>
11#include <boost/sqlite/memory.hpp>
12#include <boost/sqlite/result.hpp>
13#include <boost/sqlite/value.hpp>
14
15BOOST_SQLITE_BEGIN_NAMESPACE
16
17namespace detail
18{
19
20template<typename Func>
21int create_window_function(sqlite3 * db, cstring_ref name, Func && func,
22 std::true_type /* is void */)
23{
24 using args_type = callable_traits::args_t<decltype(&Func::step)>;
25 using context_type = typename std::remove_reference<typename std::tuple_element<1u, args_type>::type>::type;
26 using span_type = typename std::tuple_element<2U, args_type>::type;
27 using func_type = typename std::decay<Func>::type;
28
29 return sqlite3_create_window_function(
30 db, name.c_str(),
31 span_type::extent == boost::dynamic_extent ? -1 : static_cast<int>(span_type::extent),
32 SQLITE_UTF8,
33 new (memory_tag{}) func_type(std::forward<Func>(func)),
34 +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept //xStep
35 {
36 auto aa = reinterpret_cast<value*>(args);
37 auto f = reinterpret_cast<Func*>(sqlite3_user_data(ctx));
38 auto c = static_cast<context_type*>(sqlite3_aggregate_context(ctx, 0));
39
40 execute_context_function(
41 ctx,
42 [&]() -> result<void>
43 {
44 if (c == nullptr)
45 {
46 auto p = sqlite3_aggregate_context(ctx, sizeof(context_type));
47 if (!p)
48 return error(SQLITE_NOMEM);
49 c = new (p) context_type();
50 }
51 f->step(*c, span_type{aa, static_cast<std::size_t>(len)});
52 return {};
53 });
54
55 },
56 [](sqlite3_context* ctx) // xFinal
57 {
58 auto f = reinterpret_cast<Func*>(sqlite3_user_data(ctx));
59 auto c = static_cast<context_type*>(sqlite3_aggregate_context(ctx, 0));
60 execute_context_function(
61 ctx,
62 [&]() -> result<decltype(f->value(*c))>
63 {
64 if (c == nullptr)
65 {
66 auto p = sqlite3_aggregate_context(ctx, sizeof(context_type));
67 if (!p)
68 return error(SQLITE_NOMEM);
69 c = new (p) context_type();
70 }
71 struct reaper {void operator()(context_type * c) { c->~context_type();}};
72 std::unique_ptr<context_type, reaper> cl{c};
73
74 return f->value(*c);
75 });
76 },
77 [](sqlite3_context* ctx) //xValue
78 {
79 auto f = reinterpret_cast<Func*>(sqlite3_user_data(ctx));
80 auto c = static_cast<context_type*>(sqlite3_aggregate_context(ctx, 0));
81 execute_context_function(
82 ctx,
83 [&]() -> result<decltype(f->value(*c))>
84 {
85 if (c == nullptr)
86 {
87 auto p = sqlite3_aggregate_context(ctx, sizeof(context_type));
88 if (!p)
89 return error(SQLITE_NOMEM);
90 c = new (p) context_type();
91 }
92 return f->value(*c);
93 });
94
95 },
96 +[](sqlite3_context* ctx, int len, sqlite3_value** args) // xInverse
97 {
98 auto aa = reinterpret_cast<value*>(args);
99 auto f = reinterpret_cast<Func*>(sqlite3_user_data(ctx));
100 auto c = static_cast<context_type*>(sqlite3_aggregate_context(ctx, 0));
101 execute_context_function(
102 ctx,
103 [&]() -> result<decltype(f->inverse(*c, span_type{aa, static_cast<std::size_t>(len)}))>
104 {
105 if (c == nullptr)
106 {
107 auto p = sqlite3_aggregate_context(ctx, sizeof(context_type));
108 if (!p)
109 return error(SQLITE_NOMEM);
110 c = new (p) context_type();
111 }
112 f->inverse(*c, span_type{aa, static_cast<std::size_t>(len)});
113 return {};
114 });
115
116 },
117 [](void * ptr) /* xDestroy */ { delete_(static_cast<func_type*>(ptr));}
118 );
119}
120
121template<typename Func>
122int create_window_function(sqlite3 * db, cstring_ref name, Func && func,
123 std::false_type /* is void */)
124{
125 using args_type = callable_traits::args_t<decltype(&Func::step)>;
126 using context_type = typename std::remove_reference<typename std::tuple_element<1u, args_type>::type>::type;
127 using span_type = typename std::tuple_element<2U, args_type>::type;
128 using func_type = typename std::decay<Func>::type;
129
130 return sqlite3_create_window_function(
131 db, name.c_str(),
132 span_type::extent == boost::dynamic_extent ? -1 : static_cast<int>(span_type::extent),
133 SQLITE_UTF8,
134 new (memory_tag{}) func_type(std::forward<Func>(func)),
135 +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept //xStep
136 {
137 auto aa = reinterpret_cast<value*>(args);
138 auto f = reinterpret_cast<Func*>(sqlite3_user_data(ctx));
139 auto c = static_cast<context_type*>(sqlite3_aggregate_context(ctx, 0));
140
141 execute_context_function(
142 ctx,
143 [&]() -> result<decltype(f->step(*c, span_type{aa, static_cast<std::size_t>(len)}))>
144 {
145 if (c == nullptr)
146 {
147 auto p = sqlite3_aggregate_context(ctx, sizeof(context_type));
148 if (!p)
149 return error(SQLITE_NOMEM);
150 c = new (p) context_type();
151 }
152 return f->step(*c, span_type{aa, static_cast<std::size_t>(len)});
153 });
154
155 },
156 [](sqlite3_context* ctx) // xFinal
157 {
158 auto f = reinterpret_cast<Func*>(sqlite3_user_data(ctx));
159 auto c = static_cast<context_type*>(sqlite3_aggregate_context(ctx, 0));
160 execute_context_function(
161 ctx,
162 [&]() -> result<decltype(f->value(*c))>
163 {
164 if (c == nullptr)
165 {
166 auto p = sqlite3_aggregate_context(ctx, sizeof(context_type));
167 if (!p)
168 return error(SQLITE_NOMEM);
169 c = new (p) context_type();
170 }
171
172 struct reaper {void operator()(context_type * c) { c->~context_type();}};
173 std::unique_ptr<context_type, reaper> cl{c};
174 return f->value(*c);
175 });
176 },
177 [](sqlite3_context* ctx) //xValue
178 {
179 auto f = reinterpret_cast<Func*>(sqlite3_user_data(ctx));
180 auto c = static_cast<context_type*>(sqlite3_aggregate_context(ctx, 0));
181 execute_context_function(
182 ctx,
183 [&]() -> result<decltype(f->value(*c))>
184 {
185 if (c == nullptr)
186 {
187 auto p = sqlite3_aggregate_context(ctx, sizeof(context_type));
188 if (!p)
189 return error(SQLITE_NOMEM);
190 c = new (p) context_type();
191 }
192 return f->value(*c);
193 });
194
195 },
196 +[](sqlite3_context* ctx, int len, sqlite3_value** args) // xInverse
197 {
198 auto aa = reinterpret_cast<value*>(args);
199 auto f = reinterpret_cast<Func*>(sqlite3_user_data(ctx));
200 auto c = static_cast<context_type*>(sqlite3_aggregate_context(ctx, 0));
201 execute_context_function(
202 ctx,
203 [&]() -> result<decltype(f->inverse(*c, span_type{aa, static_cast<std::size_t>(len)}))>
204 {
205 if (c == nullptr)
206 {
207 auto p = sqlite3_aggregate_context(ctx, sizeof(context_type));
208 if (!p)
209 return error(SQLITE_NOMEM);
210 c = new (p) context_type();
211 }
212 return f->inverse(*c, span_type{aa, static_cast<std::size_t>(len)});
213 });
214
215 },
216 [](void * ptr) /* xDestroy */ { delete_(static_cast<func_type*>(ptr));}
217 );
218}
219
220
221}
222
223BOOST_SQLITE_END_NAMESPACE
224#endif // SQLITE_VERSION
225#endif //BOOST_SQLITE_IMPL_WINDOW_FUNCTION_HPP