0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-16 12:51:13 +08:00

Prepared for advanced table checks

This commit is contained in:
Roland Bock 2024-08-29 12:18:46 +02:00
parent 6e7d05d6db
commit 9349f56d68
7 changed files with 152 additions and 36 deletions

View File

@ -34,7 +34,7 @@
#include <sqlpp11/core/default_value.h> #include <sqlpp11/core/default_value.h>
#include <sqlpp11/core/type_traits.h> #include <sqlpp11/core/type_traits.h>
#include <sqlpp11/core/wrong.h> #include <sqlpp11/core/wrong.h>
#include <sqlpp11/core/detail/type_set.h> #include <sqlpp11/core/detail/type_vector.h>
namespace sqlpp namespace sqlpp
{ {
@ -104,13 +104,18 @@ namespace sqlpp
{ {
}; };
template<typename Table> template <typename Table>
struct table_t; struct table_t;
template<typename Table, typename ColumnSpec> template<typename Table, typename ColumnSpec>
struct required_tables_of<column_t<Table, ColumnSpec>> struct required_tables_of<column_t<Table, ColumnSpec>>
{ {
using type = detail::type_set<table_t<Table>>; using type = detail::type_vector<table_t<Table>>;
};
template <typename Table, typename ColumnSpec>
struct required_static_tables_of<column_t<Table, ColumnSpec>> : public required_tables_of<column_t<Table, ColumnSpec>>
{
}; };
template <typename Context, typename Table, typename ColumnSpec> template <typename Context, typename Table, typename ColumnSpec>

View File

@ -67,18 +67,36 @@ namespace sqlpp
#warning: We should mix dynamic and optional into the provided_tables_of (instead of having separate traits for each). #warning: We should mix dynamic and optional into the provided_tables_of (instead of having separate traits for each).
#warning: it might be great to search for missing tables and return something like `missing_table_for<column_t<SomeSpec>>`. #warning: it might be great to search for missing tables and return something like `missing_table_for<column_t<SomeSpec>>`.
template<typename T>
struct is_dynamic : public std::false_type {};
template<typename T>
struct is_dynamic<dynamic_t<T>> : public std::true_type {};
template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
struct provided_tables_of<join_t<Lhs, JoinType, Rhs, Condition>>
{
using type = detail::type_vector_cat_t<provided_tables_of_t<Lhs>, provided_tables_of_t<Rhs>>;
};
template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
struct provided_static_tables_of<join_t<Lhs, JoinType, Rhs, Condition>>
{
using type = typename std::conditional<
is_dynamic<Rhs>::value,
provided_static_tables_of<Lhs>,
detail::type_vector_cat_t<provided_static_tables_of<Lhs>, provided_static_tables_of<Rhs>>>::type;
};
template <typename Lhs, typename JoinType, typename Rhs, typename Condition> template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
struct provided_optional_tables_of<join_t<Lhs, JoinType, Rhs, Condition>> struct provided_optional_tables_of<join_t<Lhs, JoinType, Rhs, Condition>>
{ {
using type = typename std::conditional< using type = detail::type_vector_cat_t<
std::is_same<JoinType, left_outer_join_t>::value, typename std::conditional<detail::type_vector<right_outer_join_t, full_outer_join_t>::contains<JoinType>(),
sqlpp::detail::type_set<Rhs>, provided_tables_of_t<Lhs>,
typename std::conditional< detail::type_vector<>>::type,
std::is_same<JoinType, right_outer_join_t>::value, typename std::conditional<detail::type_vector<left_outer_join_t, full_outer_join_t>::contains<JoinType>(),
sqlpp::detail::type_set<Lhs>, provided_tables_of_t<Rhs>,
typename std::conditional<std::is_same<JoinType, full_outer_join_t>::value, detail::type_vector<>>::type>;
detail::make_joined_set_t<provided_tables_of_t<Lhs>, provided_tables_of_t<Rhs>>,
detail::type_set<>>::type>::type>::type;
}; };
template <typename Lhs, typename JoinType, typename Rhs, typename Condition> template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
@ -124,8 +142,36 @@ namespace sqlpp
#warning: Verify that the Expr does not require tables other than Lhs, Rhs #warning: Verify that the Expr does not require tables other than Lhs, Rhs
//and detail::make_joined_set_t<provided_tables_of_t<Lhs>, provided_tables_of_t<Rhs>>::is_superset_of<required_tables_of_t<Expr>::value //and detail::make_joined_set_t<provided_tables_of_t<Lhs>, provided_tables_of_t<Rhs>>::is_superset_of<required_tables_of_t<Expr>::value
template <typename Expr, typename StaticTableTypeVector, typename AllTableTypeVector>
struct are_table_requirements_satisfied
: std::integral_constant<bool,
StaticTableTypeVector::contains_all(required_static_tables_of_t<Expr>{}) and
AllTableTypeVector::contains_all(required_tables_of_t<Expr>{})>
{
};
template <typename Lhs, typename Rhs, typename Expr> template <typename Lhs, typename Rhs, typename Expr>
using check_on_args = sqlpp::enable_if_t<sqlpp::is_boolean<Expr>::value>; struct are_join_table_requirements_satisfied
: public std::integral_constant<
bool,
is_dynamic<Rhs>::value ?
// In case of a dynamic join, we can use all tables in the ON expr.
are_table_requirements_satisfied<
Expr,
provided_tables_of_t<join_t<Lhs, cross_join_t, Rhs, unconditional_t>>,
provided_tables_of_t<join_t<Lhs, cross_join_t, Rhs, unconditional_t>>>::value
:
// In case of a static join, we can use static tables in the static part of the ON
// expression and dynamic tables in any potential dynamic part of the expression.
are_table_requirements_satisfied<
Expr,
provided_static_tables_of_t<join_t<Lhs, cross_join_t, Rhs, unconditional_t>>,
provided_tables_of_t<join_t<Lhs, cross_join_t, Rhs, unconditional_t>>>::value>
{
};
template <typename Lhs, typename Rhs, typename Expr>
using check_on_args = sqlpp::enable_if_t<sqlpp::is_boolean<Expr>::value and are_join_table_requirements_satisfied<Lhs, Rhs, Expr>::value>;
template <typename Lhs, typename JoinType, typename Rhs> template <typename Lhs, typename JoinType, typename Rhs>
struct pre_join_t struct pre_join_t

View File

@ -69,6 +69,16 @@ namespace sqlpp
using type = sqlpp::detail::type_set<table_t<TableSpec>>; using type = sqlpp::detail::type_set<table_t<TableSpec>>;
}; };
template <typename TableSpec>
struct provided_static_tables_of<table_t<TableSpec>> : public provided_tables_of<table_t<TableSpec>>
{
};
template <typename TableSpec>
struct provided_optional_tables_of<table_t<TableSpec>> : public provided_tables_of<table_t<TableSpec>>
{
};
template <typename Context, typename TableSpec> template <typename Context, typename TableSpec>
auto to_sql_string(Context& context, const table_t<TableSpec>& /*unused*/) -> std::string auto to_sql_string(Context& context, const table_t<TableSpec>& /*unused*/) -> std::string
{ {

View File

@ -159,7 +159,7 @@ namespace sqlpp
using _new_statement_t = new_statement_t<Check, Policies, no_where_t, T>; using _new_statement_t = new_statement_t<Check, Policies, no_where_t, T>;
using _consistency_check = using _consistency_check =
typename std::conditional<WhereRequired and (Policies::_all_provided_tables::size::value > 0), typename std::conditional<WhereRequired and (Policies::_all_provided_tables::size() > 0),
assert_where_or_unconditionally_called_t, assert_where_or_unconditionally_called_t,
consistent_t>::type; consistent_t>::type;

View File

@ -36,16 +36,26 @@ namespace sqlpp
template <typename... T> template <typename... T>
struct type_vector struct type_vector
{ {
template<typename X> template <typename X>
using contains = std::integral_constant<bool, ::sqlpp::logic::any<std::is_same<T, X>::value...>::value>; static constexpr bool contains()
{
return ::sqlpp::logic::any<std::is_same<T, X>::value...>::value;
}
template <template <typename> class Transform> template <typename... X>
using transform = type_vector<typename Transform<T>::type...>; static constexpr bool contains_all(type_vector<X...>)
{
return ::sqlpp::logic::all<contains<X>()...>::value;
}
static constexpr bool size = sizeof...(T); static constexpr size_t size()
{
return sizeof...(T);
}
static constexpr bool empty() { static constexpr bool empty()
return size == 0; {
return size() == 0;
} }
}; };
@ -82,5 +92,17 @@ namespace sqlpp
template <typename... T> template <typename... T>
using type_vector_cat_t = typename type_vector_cat_impl<T...>::type; using type_vector_cat_t = typename type_vector_cat_impl<T...>::type;
template <typename TypeVector, template <typename> class Transform>
struct transform;
template <template <typename> class Transform, typename... T>
struct transform<type_vector<T...>, Transform>
{
using type = type_vector<typename Transform<T>::type...>;
};
template <typename TypeVector, template <typename> class Transform>
using transform_t = typename transform<TypeVector, Transform>::type;
} // namespace detail } // namespace detail
} // namespace sqlpp } // namespace sqlpp

View File

@ -78,12 +78,15 @@ namespace sqlpp
using _all_required_ctes = detail::make_joined_set_t<required_ctes_of<Policies>...>; using _all_required_ctes = detail::make_joined_set_t<required_ctes_of<Policies>...>;
using _all_provided_ctes = detail::make_joined_set_t<provided_ctes_of<Policies>...>; using _all_provided_ctes = detail::make_joined_set_t<provided_ctes_of<Policies>...>;
using _all_required_tables = detail::make_joined_set_t<required_tables_of_t<Policies>...>; using _all_required_tables = detail::make_joined_set_t<required_tables_of_t<Policies>...>;
using _all_provided_tables = detail::make_joined_set_t<provided_tables_of_t<Policies>...>; using _all_provided_tables = detail::type_vector_cat_t<provided_tables_of_t<Policies>...>;
using _all_provided_outer_tables = detail::make_joined_set_t<provided_optional_tables_of_t<Policies>...>; //using _all_provided_outer_tables = detail::make_joined_set_t<provided_optional_tables_of_t<Policies>...>;
using _all_provided_aggregates = detail::make_joined_set_t<provided_aggregates_of<Policies>...>; using _all_provided_aggregates = detail::make_joined_set_t<provided_aggregates_of<Policies>...>;
#warning reactivate
/*
template <typename Expression> template <typename Expression>
using _no_unknown_tables = detail::is_subset_of<required_tables_of_t<Expression>, _all_provided_tables>; using _no_unknown_tables = detail::is_subset_of<required_tables_of_t<Expression>, _all_provided_tables>;
*/
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2086629 // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2086629
// template <typename... Expressions> // template <typename... Expressions>
@ -109,7 +112,7 @@ namespace sqlpp
using any_t = logic::any<Predicate<Policies>::value...>; using any_t = logic::any<Predicate<Policies>::value...>;
// The tables not covered by the from. // The tables not covered by the from.
using _required_tables = detail::make_difference_set_t<_all_required_tables, _all_provided_tables>; //using _required_tables = detail::make_difference_set_t<_all_required_tables, _all_provided_tables>;
// The common table expressions not covered by the with. // The common table expressions not covered by the with.
using _required_ctes = detail::make_difference_set_t<_all_required_ctes, _all_provided_ctes>; using _required_ctes = detail::make_difference_set_t<_all_required_ctes, _all_provided_ctes>;
@ -125,7 +128,8 @@ namespace sqlpp
// - the select is complete (leaks no table requirements or cte requirements) // - the select is complete (leaks no table requirements or cte requirements)
static constexpr bool _can_be_used_as_table() static constexpr bool _can_be_used_as_table()
{ {
return has_result_row_t<_statement_t>::value and _required_tables::size::value == 0 and #warning: reactivate
return has_result_row_t<_statement_t>::value and /*_required_tables::size::value == 0 and*/
_required_ctes::size::value == 0; _required_ctes::size::value == 0;
} }
@ -147,8 +151,9 @@ namespace sqlpp
using _cte_check = using _cte_check =
typename std::conditional<_required_ctes::size::value == 0, consistent_t, assert_no_unknown_ctes_t>::type; typename std::conditional<_required_ctes::size::value == 0, consistent_t, assert_no_unknown_ctes_t>::type;
using _table_check = #warning: reactivate
typename std::conditional<_required_tables::size::value == 0, consistent_t, assert_no_unknown_tables_t>::type; using _table_check = std::true_type;
//typename std::conditional<_required_tables::size::value == 0, consistent_t, assert_no_unknown_tables_t>::type;
using _parameter_check = typename std:: using _parameter_check = typename std::
conditional<_parameters::empty(), consistent_t, assert_no_parameters_t>::type; conditional<_parameters::empty(), consistent_t, assert_no_parameters_t>::type;
}; };
@ -206,7 +211,7 @@ namespace sqlpp
>; >;
using _name_tag_of = name_tag_of<_result_type_provider>; using _name_tag_of = name_tag_of<_result_type_provider>;
using _nodes = detail::type_vector<_policies_t>; using _nodes = detail::type_vector<_policies_t>;
using _used_outer_tables = typename _policies_t::_all_provided_outer_tables; //using _used_outer_tables = typename _policies_t::_all_provided_outer_tables;
// Constructors // Constructors
statement_t() = default; statement_t() = default;

View File

@ -45,12 +45,27 @@ namespace sqlpp
template<typename... T> template<typename... T>
struct required_tables_of<detail::type_vector<T...>> struct required_tables_of<detail::type_vector<T...>>
{ {
using type = detail::make_joined_set_t<typename required_tables_of<T>::type...>; using type = detail::type_vector_cat_t<typename required_tables_of<T>::type...>;
}; };
template<typename T> template<typename T>
using required_tables_of_t = typename required_tables_of<T>::type; using required_tables_of_t = typename required_tables_of<T>::type;
template<typename T>
struct required_static_tables_of
{
using type = typename required_static_tables_of<nodes_of_t<T>>::type;
};
template<typename... T>
struct required_static_tables_of<detail::type_vector<T...>>
{
using type = detail::type_vector_cat_t<typename required_static_tables_of<T>::type...>;
};
template<typename T>
using required_static_tables_of_t = typename required_static_tables_of<T>::type;
#warning: need type tests... #warning: need type tests...
//static_assert(required_tables_of_t<int>::size::value == 0, ""); //static_assert(required_tables_of_t<int>::size::value == 0, "");
@ -66,16 +81,27 @@ namespace sqlpp
template <typename... T> template <typename... T>
struct provided_tables_of<detail::type_vector<T...>> struct provided_tables_of<detail::type_vector<T...>>
{ {
using type = detail::make_joined_set_t<typename provided_tables_of<T>::type...>; using type = detail::type_vector_cat_t<typename provided_tables_of<T>::type...>;
}; };
template <typename T> template <typename T>
using provided_tables_of_t = typename provided_tables_of<T>::type; using provided_tables_of_t = typename provided_tables_of<T>::type;
static_assert(provided_tables_of_t<int>::size::value == 0, ""); template <typename T>
struct provided_static_tables_of
{
using type = typename provided_static_tables_of<nodes_of_t<T>>::type;
};
template <typename... T>
struct provided_static_tables_of<detail::type_vector<T...>>
{
using type = detail::type_vector_cat_t<typename provided_static_tables_of<T>::type...>;
};
template <typename T>
using provided_static_tables_of_t = typename provided_static_tables_of<T>::type;
// provided_optional_tables_of is similar to provided_tables_of but only references the tables that have optional
// rows in outer joins (e.g. the right hand side table in a LEFT OUTER JOIN).
template <typename T> template <typename T>
struct provided_optional_tables_of struct provided_optional_tables_of
{ {
@ -85,11 +111,13 @@ namespace sqlpp
template <typename... T> template <typename... T>
struct provided_optional_tables_of<detail::type_vector<T...>> struct provided_optional_tables_of<detail::type_vector<T...>>
{ {
using type = detail::make_joined_set_t<typename provided_optional_tables_of<T>::type...>; using type = detail::type_vector_cat_t<typename provided_optional_tables_of<T>::type...>;
}; };
template <typename T> template <typename T>
using provided_optional_tables_of_t = typename provided_optional_tables_of<T>::type; using provided_optional_tables_of_t = typename provided_optional_tables_of<T>::type;
static_assert(provided_tables_of_t<int>::empty(), "");
} // namespace sqlpp } // namespace sqlpp