0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-15 20:31:16 +08:00

Allow parameter in having clause, see #443

Disallow mixing aggregate and non-aggregate columns in select, too.
This commit is contained in:
Roland Bock 2022-05-22 13:50:53 +02:00
parent 1e7f4b98c7
commit f5be4095ae
19 changed files with 99 additions and 31 deletions

View File

@ -39,7 +39,7 @@ namespace sqlpp
{ {
using _traits = make_traits<blob, tag::is_expression, tag::is_wrapped_value>; using _traits = make_traits<blob, tag::is_expression, tag::is_wrapped_value>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _is_aggregate_expression = std::true_type; using _is_literal_expression = std::true_type;
using _value_t = std::vector<std::uint8_t>; using _value_t = std::vector<std::uint8_t>;

View File

@ -40,7 +40,7 @@ namespace sqlpp
{ {
using _traits = make_traits<boolean, tag::is_expression, tag::is_wrapped_value>; using _traits = make_traits<boolean, tag::is_expression, tag::is_wrapped_value>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _is_aggregate_expression = std::true_type; using _is_literal_expression = std::true_type;
using _value_t = bool; using _value_t = bool;

View File

@ -40,7 +40,7 @@ namespace sqlpp
{ {
using _traits = make_traits<day_point, tag::is_expression, tag::is_wrapped_value>; using _traits = make_traits<day_point, tag::is_expression, tag::is_wrapped_value>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _is_aggregate_expression = std::true_type; using _is_literal_expression = std::true_type;
using _value_t = ::sqlpp::chrono::day_point; using _value_t = ::sqlpp::chrono::day_point;

View File

@ -36,7 +36,7 @@ namespace sqlpp
{ {
using _traits = make_traits<floating_point, tag::is_expression, tag::is_wrapped_value>; using _traits = make_traits<floating_point, tag::is_expression, tag::is_wrapped_value>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _is_aggregate_expression = std::true_type; using _is_literal_expression = std::true_type;
using _value_t = double; using _value_t = double;

View File

@ -38,7 +38,7 @@ namespace sqlpp
{ {
using _traits = make_traits<integral, tag::is_expression, tag::is_wrapped_value>; using _traits = make_traits<integral, tag::is_expression, tag::is_wrapped_value>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _is_aggregate_expression = std::true_type; using _is_literal_expression = std::true_type;
using _value_t = int64_t; using _value_t = int64_t;

View File

@ -43,7 +43,7 @@ namespace sqlpp
{ {
using _traits = make_traits<text, tag::is_expression, tag::is_wrapped_value>; using _traits = make_traits<text, tag::is_expression, tag::is_wrapped_value>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _is_aggregate_expression = std::true_type; using _is_literal_expression = std::true_type;
using _value_t = std::string; using _value_t = std::string;

View File

@ -40,7 +40,7 @@ namespace sqlpp
{ {
using _traits = make_traits<time_of_day, tag::is_expression, tag::is_wrapped_value>; using _traits = make_traits<time_of_day, tag::is_expression, tag::is_wrapped_value>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _is_aggregate_expression = std::true_type; using _is_literal_expression = std::true_type;
using _value_t = std::chrono::microseconds; using _value_t = std::chrono::microseconds;

View File

@ -40,7 +40,7 @@ namespace sqlpp
{ {
using _traits = make_traits<time_point, tag::is_expression, tag::is_wrapped_value>; using _traits = make_traits<time_point, tag::is_expression, tag::is_wrapped_value>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _is_aggregate_expression = std::true_type; using _is_literal_expression = std::true_type;
using _value_t = std::chrono::time_point<std::chrono::system_clock, Period>; using _value_t = std::chrono::time_point<std::chrono::system_clock, Period>;

View File

@ -38,7 +38,7 @@ namespace sqlpp
{ {
using _traits = make_traits<unsigned_integral, tag::is_expression, tag::is_wrapped_value>; using _traits = make_traits<unsigned_integral, tag::is_expression, tag::is_wrapped_value>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _is_aggregate_expression = std::true_type; using _is_literal_expression = std::true_type;
using _value_t = uint64_t; using _value_t = uint64_t;

View File

@ -59,7 +59,7 @@ namespace sqlpp
assert_having_no_unknown_tables_t, assert_having_no_unknown_tables_t,
"at least one having-expression requires a table which is otherwise not known in the statement"); "at least one having-expression requires a table which is otherwise not known in the statement");
SQLPP_PORTABLE_STATIC_ASSERT(assert_having_no_non_aggregates_t, SQLPP_PORTABLE_STATIC_ASSERT(assert_having_all_aggregates_t,
"having expression not built out of aggregate expressions"); "having expression not built out of aggregate expressions");
// HAVING // HAVING
@ -142,9 +142,9 @@ namespace sqlpp
consistent_t, consistent_t,
assert_having_no_unknown_tables_t>::type; assert_having_no_unknown_tables_t>::type;
using _aggregate_check = typename std::conditional<Policies::template _no_non_aggregates<Expression>::value, using _aggregate_check = typename std::conditional<Policies::template _all_aggregates<Expression>::value,
consistent_t, consistent_t,
assert_having_no_non_aggregates_t>::type; assert_having_all_aggregates_t>::type;
using _consistency_check = detail::get_first_if<is_inconsistent_t, consistent_t, _table_check, _aggregate_check>; using _consistency_check = detail::get_first_if<is_inconsistent_t, consistent_t, _table_check, _aggregate_check>;
}; };

View File

@ -44,6 +44,7 @@ namespace sqlpp
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _parameters = detail::type_vector<parameter_t>; using _parameters = detail::type_vector<parameter_t>;
using _can_be_null = std::true_type; using _can_be_null = std::true_type;
using _is_literal_expression = std::true_type;
using _instance_t = member_t<NameType, parameter_value_t<ValueType>>; using _instance_t = member_t<NameType, parameter_value_t<ValueType>>;

View File

@ -92,6 +92,9 @@ namespace sqlpp
SQLPP_PORTABLE_STATIC_ASSERT( SQLPP_PORTABLE_STATIC_ASSERT(
assert_no_unknown_tables_in_selected_columns_t, assert_no_unknown_tables_in_selected_columns_t,
"at least one selected column requires a table which is otherwise not known in the statement"); "at least one selected column requires a table which is otherwise not known in the statement");
SQLPP_PORTABLE_STATIC_ASSERT(assert_no_aggregate_mix_t,
"selected columns contain a mix of aggregates and non-aggregates");
SQLPP_PORTABLE_STATIC_ASSERT(assert_no_unknown_aggregates_t, SQLPP_PORTABLE_STATIC_ASSERT(assert_no_unknown_aggregates_t,
"not all selected columns are made of aggregates, despite group_by or similar"); "not all selected columns are made of aggregates, despite group_by or similar");
@ -196,11 +199,19 @@ namespace sqlpp
consistent_t, consistent_t,
assert_no_unknown_tables_in_selected_columns_t>::type; assert_no_unknown_tables_in_selected_columns_t>::type;
using _aggregate_check = typename std::conditional<Policies::template _no_unknown_aggregates<Columns...>::value, using _unknown_aggregate_check =
typename std::conditional<Policies::template _no_unknown_aggregates<Columns...>::value,
consistent_t, consistent_t,
assert_no_unknown_aggregates_t>::type; assert_no_unknown_aggregates_t>::type;
using _consistency_check = detail::get_first_if<is_inconsistent_t, consistent_t, _table_check, _aggregate_check>; using _no_aggregate_mix_check =
typename std::conditional<Policies::template _all_aggregates<Columns...>::value ||
Policies::template _no_aggregates<Columns...>::value,
consistent_t,
assert_no_aggregate_mix_t>::type;
using _consistency_check = detail::
get_first_if<is_inconsistent_t, consistent_t, _table_check, _no_aggregate_mix_check, _unknown_aggregate_check>;
}; };
// Result methods // Result methods

View File

@ -99,9 +99,13 @@ namespace sqlpp
Expressions>::type::value...>::value>; Expressions>::type::value...>::value>;
template <typename... Expressions> template <typename... Expressions>
using _no_non_aggregates = logic::any_t<logic::all_t< using _all_aggregates = logic::any_t<logic::all_t<
detail::is_aggregate_expression_impl<_all_provided_aggregates, Expressions>::type::value...>::value>; detail::is_aggregate_expression_impl<_all_provided_aggregates, Expressions>::type::value...>::value>;
template <typename... Expressions>
using _no_aggregates = logic::any_t<logic::all_t<
detail::is_non_aggregate_expression_impl<_all_provided_aggregates, Expressions>::type::value...>::value>;
template <template <typename> class Predicate> template <template <typename> class Predicate>
using any_t = logic::any_t<Predicate<Policies>::value...>; using any_t = logic::any_t<Predicate<Policies>::value...>;

View File

@ -63,7 +63,6 @@ namespace sqlpp
using _nodes = detail::type_vector<Expr>; using _nodes = detail::type_vector<Expr>;
using _can_be_null = can_be_null_t<Expr>; using _can_be_null = can_be_null_t<Expr>;
using _is_aggregate_expression = std::false_type;
using _auto_alias_t = trim_alias_t; using _auto_alias_t = trim_alias_t;

View File

@ -320,9 +320,17 @@ namespace sqlpp
struct is_aggregate_expression_impl< struct is_aggregate_expression_impl<
KnownAggregates, KnownAggregates,
T, T,
typename std::enable_if<std::is_class<typename T::_is_aggregate_expression>::value>::type> typename std::enable_if<T::_is_aggregate_expression::value>::type>
{ {
using type = typename T::_is_aggregate_expression; using type = std::true_type;
};
template <typename KnownAggregates, typename T>
struct is_aggregate_expression_impl<
KnownAggregates,
T,
typename std::enable_if<T::_is_literal_expression::value>::type>
{
using type = std::true_type;
}; };
template <typename KnownAggregates, typename T> template <typename KnownAggregates, typename T>
struct is_aggregate_expression_impl<KnownAggregates, struct is_aggregate_expression_impl<KnownAggregates,
@ -341,6 +349,48 @@ namespace sqlpp
template <typename KnownAggregates, typename T> template <typename KnownAggregates, typename T>
using is_aggregate_expression_t = typename detail::is_aggregate_expression_impl<KnownAggregates, T>::type; using is_aggregate_expression_t = typename detail::is_aggregate_expression_impl<KnownAggregates, T>::type;
namespace detail
{
template <typename KnownAggregates, typename T, typename Leaf = void>
struct is_non_aggregate_expression_impl
{
using type = typename is_non_aggregate_expression_impl<KnownAggregates, nodes_of<T>>::type;
};
template <typename KnownAggregates, typename T>
struct is_non_aggregate_expression_impl<
KnownAggregates,
T,
typename std::enable_if<T::_is_aggregate_expression::value>::type>
{
using type = std::false_type;
};
template <typename KnownAggregates, typename T>
struct is_non_aggregate_expression_impl<
KnownAggregates,
T,
typename std::enable_if<T::_is_literal_expression::value>::type>
{
using type = std::true_type;
};
template <typename KnownAggregates, typename T>
struct is_non_aggregate_expression_impl<KnownAggregates,
T,
typename std::enable_if<detail::is_element_of<T, KnownAggregates>::value>::type>
{
using type = std::false_type;
};
template <typename KnownAggregates, typename... Nodes>
struct is_non_aggregate_expression_impl<KnownAggregates, type_vector<Nodes...>, void>
{
using type =
logic::any_t<sizeof...(Nodes) == 0,
logic::all_t<sizeof...(Nodes) != 0,
is_non_aggregate_expression_impl<KnownAggregates, Nodes>::type::value...>::value>;
};
} // namespace detail
template <typename KnownAggregates, typename T>
using is_non_aggregate_expression_t = typename detail::is_non_aggregate_expression_impl<KnownAggregates, T>::type;
namespace detail namespace detail
{ {
template <typename T, typename Leaf = void> template <typename T, typename Leaf = void>

View File

@ -109,9 +109,13 @@ namespace
void static_group_by_nok() void static_group_by_nok()
{ {
static_run_check<sqlpp::assert_no_unknown_aggregates_t>(select(t.beta).from(t).unconditionally().group_by(t.alpha)); static_run_check<sqlpp::assert_no_unknown_aggregates_t>(select(t.beta).from(t).unconditionally().group_by(t.alpha));
static_run_check<sqlpp::assert_no_unknown_aggregates_t>( static_run_check<sqlpp::assert_no_aggregate_mix_t>(
select(t.alpha, t.delta).from(t).unconditionally().group_by(t.alpha));
static_run_check<sqlpp::assert_no_aggregate_mix_t>(
select(t.alpha, t.beta).from(t).unconditionally().group_by(t.alpha));
static_run_check<sqlpp::assert_no_aggregate_mix_t>(
select((t.alpha + t.delta).as(whatever)).from(t).unconditionally().group_by(t.alpha)); select((t.alpha + t.delta).as(whatever)).from(t).unconditionally().group_by(t.alpha));
static_run_check<sqlpp::assert_no_unknown_aggregates_t>( static_run_check<sqlpp::assert_no_aggregate_mix_t>(
select((t.alpha + t.delta).as(whatever)).from(t).unconditionally().group_by(t.alpha, t.alpha + t.delta * 17)); select((t.alpha + t.delta).as(whatever)).from(t).unconditionally().group_by(t.alpha, t.alpha + t.delta * 17));
} }
} }

View File

@ -158,10 +158,11 @@ namespace
// OK // OK
static_consistency_check<sqlpp::consistent_t>(select_without_group_by, avg(t.alpha) > 17); static_consistency_check<sqlpp::consistent_t>(select_without_group_by, avg(t.alpha) > 17);
static_consistency_check<sqlpp::consistent_t>(select_without_group_by, avg(t.alpha) > parameter(t.alpha));
// Try non aggregate // Try non aggregate
static_consistency_check<sqlpp::assert_having_no_non_aggregates_t>(select_without_group_by, t.alpha > 17); static_consistency_check<sqlpp::assert_having_all_aggregates_t>(select_without_group_by, t.alpha > 17);
static_consistency_check<sqlpp::assert_having_no_non_aggregates_t>(select_without_group_by, static_consistency_check<sqlpp::assert_having_all_aggregates_t>(select_without_group_by,
count(t.alpha) > 3 and t.alpha > 17); count(t.alpha) > 3 and t.alpha > 17);
// Try foreign table // Try foreign table
@ -175,8 +176,8 @@ namespace
static_consistency_check<sqlpp::consistent_t>(select_with_group_by, count(t.alpha) > 3 and t.alpha > 17); static_consistency_check<sqlpp::consistent_t>(select_with_group_by, count(t.alpha) > 3 and t.alpha > 17);
// Try non aggregate // Try non aggregate
static_consistency_check<sqlpp::assert_having_no_non_aggregates_t>(select_with_group_by, t.beta > "17"); static_consistency_check<sqlpp::assert_having_all_aggregates_t>(select_with_group_by, t.beta > "17");
static_consistency_check<sqlpp::assert_having_no_non_aggregates_t>(select_with_group_by, static_consistency_check<sqlpp::assert_having_all_aggregates_t>(select_with_group_by,
count(t.beta) > 3 and t.beta > "17"); count(t.beta) > 3 and t.beta > "17");
// Try foreign table // Try foreign table

View File

@ -159,7 +159,7 @@ int Select(int, char*[])
.dynamic_where() .dynamic_where()
.dynamic_group_by(t.alpha) .dynamic_group_by(t.alpha)
.dynamic_order_by() .dynamic_order_by()
.dynamic_having(sum(t.alpha) > 17) .dynamic_having(sum(t.alpha) > parameter(t.delta))
.dynamic_limit() .dynamic_limit()
.dynamic_offset(); .dynamic_offset();
s.select_flags.add(sqlpp::distinct); s.select_flags.add(sqlpp::distinct);
@ -172,7 +172,7 @@ int Select(int, char*[])
s.group_by.add(t.beta); s.group_by.add(t.beta);
s.order_by.add(t.beta.asc()); s.order_by.add(t.beta.asc());
s.order_by.add(t.delta.order(sqlpp::sort_type::desc)); s.order_by.add(t.delta.order(sqlpp::sort_type::desc));
for (const auto& row : db(s)) for (const auto& row : db(db.prepare(s)))
{ {
int64_t a = row.alpha; int64_t a = row.alpha;
std::cout << a << std::endl; std::cout << a << std::endl;

View File

@ -35,8 +35,6 @@
#include "TabFoo.h" #include "TabFoo.h"
#include "make_test_connection.h" #include "make_test_connection.h"
SQLPP_ALIAS_PROVIDER(returnVal)
namespace sql = sqlpp::postgresql; namespace sql = sqlpp::postgresql;
int Exceptions(int, char*[]) int Exceptions(int, char*[])
{ {