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:
parent
1e7f4b98c7
commit
f5be4095ae
@ -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>;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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>;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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>;
|
||||
};
|
||||
|
@ -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>>;
|
||||
|
||||
|
@ -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,
|
||||
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
|
||||
|
@ -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...>;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -158,10 +158,11 @@ 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,
|
||||
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
|
||||
@ -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
|
||||
|
@ -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;
|
||||
|
@ -35,8 +35,6 @@
|
||||
#include "TabFoo.h"
|
||||
#include "make_test_connection.h"
|
||||
|
||||
SQLPP_ALIAS_PROVIDER(returnVal)
|
||||
|
||||
namespace sql = sqlpp::postgresql;
|
||||
int Exceptions(int, char*[])
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user