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 _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>;

View File

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

View File

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

View File

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

View File

@ -59,7 +59,7 @@ namespace sqlpp
assert_having_no_unknown_tables_t,
"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
@ -142,9 +142,9 @@ namespace sqlpp
consistent_t,
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,
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>;
};

View File

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

View File

@ -92,6 +92,9 @@ namespace sqlpp
SQLPP_PORTABLE_STATIC_ASSERT(
assert_no_unknown_tables_in_selected_columns_t,
"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,
"not all selected columns are made of aggregates, despite group_by or similar");
@ -196,11 +199,19 @@ namespace sqlpp
consistent_t,
assert_no_unknown_tables_in_selected_columns_t>::type;
using _aggregate_check = typename std::conditional<Policies::template _no_unknown_aggregates<Columns...>::value,
consistent_t,
assert_no_unknown_aggregates_t>::type;
using _unknown_aggregate_check =
typename std::conditional<Policies::template _no_unknown_aggregates<Columns...>::value,
consistent_t,
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

View File

@ -99,9 +99,13 @@ namespace sqlpp
Expressions>::type::value...>::value>;
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>;
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>
using any_t = logic::any_t<Predicate<Policies>::value...>;

View File

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

View File

@ -320,9 +320,17 @@ namespace sqlpp
struct is_aggregate_expression_impl<
KnownAggregates,
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>
struct is_aggregate_expression_impl<KnownAggregates,
@ -341,6 +349,48 @@ namespace sqlpp
template <typename KnownAggregates, typename T>
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
{
template <typename T, typename Leaf = void>

View File

@ -109,9 +109,13 @@ namespace
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>(
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));
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));
}
}

View File

@ -158,11 +158,12 @@ namespace
// 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) > parameter(t.alpha));
// 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_no_non_aggregates_t>(select_without_group_by,
count(t.alpha) > 3 and 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_all_aggregates_t>(select_without_group_by,
count(t.alpha) > 3 and t.alpha > 17);
// Try foreign table
static_consistency_check<sqlpp::assert_having_no_unknown_tables_t>(select_without_group_by, f.omega > 17);
@ -175,8 +176,8 @@ namespace
static_consistency_check<sqlpp::consistent_t>(select_with_group_by, count(t.alpha) > 3 and t.alpha > 17);
// 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_no_non_aggregates_t>(select_with_group_by,
static_consistency_check<sqlpp::assert_having_all_aggregates_t>(select_with_group_by, t.beta > "17");
static_consistency_check<sqlpp::assert_having_all_aggregates_t>(select_with_group_by,
count(t.beta) > 3 and t.beta > "17");
// Try foreign table

View File

@ -159,7 +159,7 @@ int Select(int, char*[])
.dynamic_where()
.dynamic_group_by(t.alpha)
.dynamic_order_by()
.dynamic_having(sum(t.alpha) > 17)
.dynamic_having(sum(t.alpha) > parameter(t.delta))
.dynamic_limit()
.dynamic_offset();
s.select_flags.add(sqlpp::distinct);
@ -172,7 +172,7 @@ int Select(int, char*[])
s.group_by.add(t.beta);
s.order_by.add(t.beta.asc());
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;
std::cout << a << std::endl;

View File

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