Skip to content

Commit 8f71f41

Browse files
authored
Merge pull request #1325 from fnc12/fix-aggregate-functions
Fixed aggregate functions
2 parents 6c2f2f9 + 43d3103 commit 8f71f41

14 files changed

+565
-347
lines changed

.clang-format

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,12 @@ SpacesInCStyleCastParentheses: false
114114
SpacesInParentheses: false
115115
SpacesInSquareBrackets: false
116116
Standard: Cpp11
117+
AttributeMacros: [SQLITE_ORM_CPP_LIKELY, SQLITE_ORM_CPP_UNLIKELY]
117118
StatementMacros:
118119
- __pragma
119120
- _Pragma
120121
- Q_UNUSED
121122
- QT_REQUIRE_VERSION
122-
TabWidth: 8
123+
TabWidth: 4
123124
UseTab: Never
124125
...
125-

dev/carray.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ namespace sqlite_orm {
119119
#endif
120120

121121
/**
122-
* Generalized form of the 'remember' SQL function that is a pass-through for values
122+
* Base for a generalized form of the 'remember' SQL function that is a pass-through for values
123123
* (it returns its argument unchanged using move semantics) but also saves the
124124
* value that is passed through into a bound variable.
125125
*/
@@ -131,10 +131,6 @@ namespace sqlite_orm {
131131
}
132132
return std::move(value);
133133
}
134-
135-
static constexpr const char* name() {
136-
return "note_value";
137-
}
138134
};
139135

140136
/**

dev/function.h

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
#pragma once
22

3-
#include <type_traits> // std::enable_if, std::is_member_function_pointer, std::is_function, std::remove_const, std::remove_pointer, std::decay, std::is_same, std::false_type, std::true_type
3+
#include <type_traits> // std::enable_if, std::is_member_function_pointer, std::is_function, std::remove_const, std::decay, std::is_convertible, std::is_same, std::false_type, std::true_type
44
#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED
55
#include <concepts> // std::copy_constructible
66
#endif
77
#include <tuple> // std::tuple, std::tuple_size, std::tuple_element
88
#include <algorithm> // std::min, std::copy_n
99
#include <utility> // std::move, std::forward
1010

11-
#include "functional/cxx_universal.h" // ::size_t
11+
#include "functional/cxx_universal.h" // ::size_t, ::nullptr_t
1212
#include "functional/cxx_type_traits_polyfill.h"
1313
#include "functional/cstring_literal.h"
1414
#include "functional/function_traits.h"
@@ -229,98 +229,115 @@ namespace sqlite_orm {
229229
template<class T>
230230
using unpacked_arg_t = typename unpacked_arg<T>::type;
231231

232-
template<size_t I, class FnArg, class CallArg>
232+
template<size_t I, class FnParam, class CallArg>
233233
SQLITE_ORM_CONSTEVAL bool expected_pointer_value() {
234-
static_assert(polyfill::always_false_v<FnArg, CallArg>, "Expected a pointer value for I-th argument");
234+
static_assert(polyfill::always_false_v<FnParam, CallArg>, "Expected a pointer value for I-th argument");
235235
return false;
236236
}
237237

238-
template<size_t I, class FnArg, class CallArg, class EnableIfTag = void>
239-
constexpr bool is_same_pvt_v = expected_pointer_value<I, FnArg, CallArg>();
238+
template<size_t I, class FnParam, class CallArg, class EnableIfTag = void>
239+
constexpr bool is_same_pvt_v = expected_pointer_value<I, FnParam, CallArg>();
240240

241241
// Always allow binding nullptr to a pointer argument
242242
template<size_t I, class PointerArg>
243243
constexpr bool is_same_pvt_v<I, PointerArg, nullptr_t, polyfill::void_t<typename PointerArg::tag>> = true;
244+
// Always allow binding nullptr to a pointer argument
245+
template<size_t I, class P, class T, class D>
246+
constexpr bool is_same_pvt_v<I, pointer_arg<P, T>, pointer_binding<nullptr_t, T, D>, void> = true;
247+
248+
template<size_t I, class PointerArgDataType, class BindingDataType>
249+
SQLITE_ORM_CONSTEVAL bool assert_same_pointer_data_type() {
250+
constexpr bool valid = std::is_convertible<BindingDataType*, PointerArgDataType*>::value;
251+
static_assert(valid, "Pointer data types of I-th argument do not match");
252+
return valid;
253+
}
244254

245255
#if __cplusplus >= 201703L // C++17 or later
246256
template<size_t I, const char* PointerArg, const char* Binding>
247-
SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() {
257+
SQLITE_ORM_CONSTEVAL bool assert_same_pointer_tag() {
248258
constexpr bool valid = Binding == PointerArg;
249-
static_assert(valid, "Pointer value types of I-th argument do not match");
259+
static_assert(valid, "Pointer types (tags) of I-th argument do not match");
250260
return valid;
251261
}
252-
253262
template<size_t I, class PointerArg, class Binding>
254263
constexpr bool
255264
is_same_pvt_v<I, PointerArg, Binding, polyfill::void_t<typename PointerArg::tag, typename Binding::tag>> =
256-
assert_same_pointer_type<I, PointerArg::tag::value, Binding::tag::value>();
265+
assert_same_pointer_tag<I, PointerArg::tag::value, Binding::tag::value>() &&
266+
assert_same_pointer_data_type<I,
267+
typename PointerArg::qualified_type,
268+
typename Binding::qualified_type>();
257269
#else
258270
template<size_t I, class PointerArg, class Binding>
259-
SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() {
271+
constexpr bool assert_same_pointer_tag() {
260272
constexpr bool valid = Binding::value == PointerArg::value;
261-
static_assert(valid, "Pointer value types of I-th argument do not match");
273+
static_assert(valid, "Pointer types (tags) of I-th argument do not match");
262274
return valid;
263275
}
264276

265277
template<size_t I, class PointerArg, class Binding>
266278
constexpr bool
267279
is_same_pvt_v<I, PointerArg, Binding, polyfill::void_t<typename PointerArg::tag, typename Binding::tag>> =
268-
assert_same_pointer_type<I, typename PointerArg::tag, typename Binding::tag>();
280+
assert_same_pointer_tag<I, typename PointerArg::tag, typename Binding::tag>();
269281
#endif
270282

271-
template<size_t I, class FnArg, class CallArg>
283+
// not a pointer value, currently leave it unchecked
284+
template<size_t I, class FnParam, class CallArg>
272285
SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::false_type) {
273286
return true;
274287
}
275288

276-
template<size_t I, class FnArg, class CallArg>
289+
// check the type of pointer values
290+
template<size_t I, class FnParam, class CallArg>
277291
SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::true_type) {
278-
return is_same_pvt_v<I, FnArg, CallArg>;
292+
return is_same_pvt_v<I, FnParam, CallArg>;
279293
}
280294

281-
template<class FnArgs, class CallArgs>
295+
template<class FnParams, class CallArgs>
282296
SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant<size_t(-1)>) {
283297
return true;
284298
}
285-
template<class FnArgs, class CallArgs, size_t I>
299+
template<class FnParams, class CallArgs, size_t I>
286300
SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant<I>) {
287-
using func_arg_t = std::tuple_element_t<I, FnArgs>;
288-
using passed_arg_t = unpacked_arg_t<std::tuple_element_t<I, CallArgs>>;
301+
using func_param_type = std::tuple_element_t<I, FnParams>;
302+
using call_arg_type = unpacked_arg_t<std::tuple_element_t<I, CallArgs>>;
289303

290304
#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED
291305
constexpr bool valid = validate_pointer_value_type<I,
292-
std::tuple_element_t<I, FnArgs>,
306+
std::tuple_element_t<I, FnParams>,
293307
unpacked_arg_t<std::tuple_element_t<I, CallArgs>>>(
294-
polyfill::bool_constant < (polyfill::is_specialization_of_v<func_arg_t, pointer_arg>) ||
295-
(polyfill::is_specialization_of_v<passed_arg_t, pointer_binding>) > {});
308+
polyfill::bool_constant < (polyfill::is_specialization_of_v<func_param_type, pointer_arg>) ||
309+
(polyfill::is_specialization_of_v<call_arg_type, pointer_binding>) > {});
296310

297-
return validate_pointer_value_types<FnArgs, CallArgs>(polyfill::index_constant<I - 1>{}) && valid;
311+
return validate_pointer_value_types<FnParams, CallArgs>(polyfill::index_constant<I - 1>{}) && valid;
298312
#else
299-
return validate_pointer_value_types<FnArgs, CallArgs>(polyfill::index_constant<I - 1>{}) &&
313+
return validate_pointer_value_types<FnParams, CallArgs>(polyfill::index_constant<I - 1>{}) &&
300314
validate_pointer_value_type<I,
301-
std::tuple_element_t<I, FnArgs>,
315+
std::tuple_element_t<I, FnParams>,
302316
unpacked_arg_t<std::tuple_element_t<I, CallArgs>>>(
303-
polyfill::bool_constant < (polyfill::is_specialization_of_v<func_arg_t, pointer_arg>) ||
304-
(polyfill::is_specialization_of_v<passed_arg_t, pointer_binding>) > {});
317+
polyfill::bool_constant < (polyfill::is_specialization_of_v<func_param_type, pointer_arg>) ||
318+
(polyfill::is_specialization_of_v<call_arg_type, pointer_binding>) > {});
305319
#endif
306320
}
307321

322+
/*
323+
* Note: Currently the number of call arguments is checked and whether the types of pointer values match,
324+
* but other call argument types are not checked against the parameter types of the function.
325+
*/
308326
template<typename UDF, typename... CallArgs>
309327
#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED
310-
SQLITE_ORM_CONSTEVAL
328+
SQLITE_ORM_CONSTEVAL void check_function_call() {
329+
#else
330+
void check_function_call() {
311331
#endif
312-
void
313-
check_function_call() {
314-
using args_tuple = std::tuple<CallArgs...>;
315-
using function_args_tuple = typename callable_arguments<UDF>::args_tuple;
316-
constexpr size_t argsCount = std::tuple_size<args_tuple>::value;
317-
constexpr size_t functionArgsCount = std::tuple_size<function_args_tuple>::value;
318-
static_assert((argsCount == functionArgsCount &&
319-
!std::is_same<function_args_tuple, std::tuple<arg_values>>::value &&
320-
validate_pointer_value_types<function_args_tuple, args_tuple>(
321-
polyfill::index_constant<std::min(functionArgsCount, argsCount) - 1>{})) ||
322-
std::is_same<function_args_tuple, std::tuple<arg_values>>::value,
323-
"The number of arguments does not match");
332+
using call_args_tuple = std::tuple<CallArgs...>;
333+
using function_params_tuple = typename callable_arguments<UDF>::args_tuple;
334+
constexpr size_t callArgsCount = std::tuple_size<call_args_tuple>::value;
335+
constexpr size_t functionParamsCount = std::tuple_size<function_params_tuple>::value;
336+
static_assert(std::is_same<function_params_tuple, std::tuple<arg_values>>::value ||
337+
(callArgsCount == functionParamsCount &&
338+
validate_pointer_value_types<function_params_tuple, call_args_tuple>(
339+
polyfill::index_constant<std::min(functionParamsCount, callArgsCount) - 1>{})),
340+
"Check the number and types of the function call arguments");
324341
}
325342

326343
/*
@@ -475,6 +492,9 @@ namespace sqlite_orm {
475492

476493
/** @short Call a user-defined function.
477494
*
495+
* Note: Currently the number of call arguments is checked and whether the types of pointer values match,
496+
* but other call argument types are not checked against the parameter types of the function.
497+
*
478498
* Example:
479499
* struct IdFunc { int oeprator(int arg)() const { return arg; } };
480500
* // inline:

dev/mapped_iterator.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,9 @@ namespace sqlite_orm {
8383
mapped_iterator& operator=(mapped_iterator&&) = default;
8484

8585
value_type& operator*() const {
86-
if(!this->stmt)
87-
SQLITE_ORM_CPP_UNLIKELY {
88-
throw std::system_error{orm_error_code::trying_to_dereference_null_iterator};
89-
}
86+
if(!this->stmt) SQLITE_ORM_CPP_UNLIKELY {
87+
throw std::system_error{orm_error_code::trying_to_dereference_null_iterator};
88+
}
9089
return *this->current;
9190
}
9291

dev/pointer_value.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ namespace sqlite_orm {
6262
#endif
6363

6464
using tag = T;
65+
using qualified_type = P;
66+
6567
P* p_;
6668

6769
P* ptr() const noexcept {

dev/serializing_util.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,10 @@ namespace sqlite_orm {
3030
for(size_t offset = 0, next; true; offset = next + 1) {
3131
next = str.find(char2Escape, offset);
3232

33-
if(next == str.npos)
34-
SQLITE_ORM_CPP_LIKELY {
35-
os.write(str.data() + offset, str.size() - offset);
36-
break;
37-
}
33+
if(next == str.npos) SQLITE_ORM_CPP_LIKELY {
34+
os.write(str.data() + offset, str.size() - offset);
35+
break;
36+
}
3837

3938
os.write(str.data() + offset, next - offset + 1);
4039
os.write(&char2Escape, 1);

dev/storage_base.h

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -735,26 +735,24 @@ namespace sqlite_orm {
735735
? -1
736736
: int(std::tuple_size<args_tuple>::value);
737737
using is_stateless = std::is_empty<F>;
738-
auto udfStorage = allocate_udf_storage<F>();
738+
auto udfMemorySpace = preallocate_udf_memory<F>();
739739
if SQLITE_ORM_CONSTEXPR_IF(is_stateless::value) {
740-
constructAt(udfStorage.first);
740+
constructAt(udfMemorySpace.first);
741741
}
742742
this->scalarFunctions.emplace_back(
743743
udfName(),
744744
argsCount,
745745
is_stateless::value ? nullptr : std::move(constructAt),
746746
/* destroy = */
747-
obtain_xdestroy_for<F>(udf_proxy::destruct_only_deleter{}),
747+
obtain_xdestroy_for<F>(udf_destruct_only_deleter{}),
748748
/* call = */
749749
[](sqlite3_context* context, int argsCount, sqlite3_value** values) {
750750
auto udfPointer = proxy_get_scalar_udf<F>(is_stateless{}, context, argsCount);
751751
args_tuple argsTuple = tuple_from_values<args_tuple>{}(values, argsCount);
752752
auto result = polyfill::apply(*udfPointer, std::move(argsTuple));
753753
statement_binder<return_type>().result(context, result);
754754
},
755-
/* finalCall = */
756-
nullptr,
757-
udfStorage);
755+
udfMemorySpace);
758756

759757
if(this->connection->retain_count() > 0) {
760758
sqlite3* db = this->connection->get();
@@ -775,17 +773,23 @@ namespace sqlite_orm {
775773
argsCount,
776774
std::move(constructAt),
777775
/* destroy = */
778-
obtain_xdestroy_for<F>(udf_proxy::destruct_only_deleter{}),
776+
obtain_xdestroy_for<F>(udf_destruct_only_deleter{}),
779777
/* step = */
780778
[](sqlite3_context* context, int argsCount, sqlite3_value** values) {
781-
F& udf = *proxy_get_aggregate_step_udf<F>(context, argsCount);
779+
F* udfPointer;
780+
try {
781+
udfPointer = proxy_get_aggregate_step_udf<F>(context, argsCount);
782+
} catch(const std::bad_alloc&) {
783+
sqlite3_result_error_nomem(context);
784+
return;
785+
}
782786
args_tuple argsTuple = tuple_from_values<args_tuple>{}(values, argsCount);
783787
#if __cpp_lib_bind_front >= 201907L
784-
std::apply(std::bind_front(&F::step, &udf), std::move(argsTuple));
788+
std::apply(std::bind_front(&F::step, udfPointer), std::move(argsTuple));
785789
#else
786790
polyfill::apply(
787-
[&udf](auto&&... args) {
788-
udf.step(std::forward<decltype(args)>(args)...);
791+
[udfPointer](auto&&... args) {
792+
udfPointer->step(std::forward<decltype(args)>(args)...);
789793
},
790794
std::move(argsTuple));
791795
#endif
@@ -796,7 +800,7 @@ namespace sqlite_orm {
796800
auto result = udf.fin();
797801
statement_binder<return_type>().result(context, result);
798802
},
799-
allocate_udf_storage<F>());
803+
obtain_udf_allocator<F>());
800804

801805
if(this->connection->retain_count() > 0) {
802806
sqlite3* db = this->connection->get();

0 commit comments

Comments
 (0)