From ae2f1948ac3f1c03151bfcf6583052db7745a0e8 Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 9 Feb 2014 15:06:42 +0100 Subject: [PATCH] Added checks to prevent non-matching columns from being inserted --- include/sqlpp11/column.h | 2 + include/sqlpp11/detail/type_set.h | 69 ++++++++++++++++------ include/sqlpp11/insert.h | 3 + include/sqlpp11/vendor/from.h | 4 +- include/sqlpp11/vendor/insert_value_list.h | 9 ++- include/sqlpp11/vendor/single_table.h | 5 +- include/sqlpp11/vendor/wrong.h | 20 +++---- tests/InterpretTest.cpp | 2 +- tests/sample.sql | 1 + 9 files changed, 80 insertions(+), 35 deletions(-) diff --git a/include/sqlpp11/column.h b/include/sqlpp11/column.h index 1e5de615..95c334bb 100644 --- a/include/sqlpp11/column.h +++ b/include/sqlpp11/column.h @@ -37,6 +37,7 @@ #include #include #include +#include namespace sqlpp { @@ -46,6 +47,7 @@ namespace sqlpp using _is_column = std::true_type; using _spec_t = ColumnSpec; using _table = Table; + using _table_set = detail::type_set<_table>; using _column_type = typename ColumnSpec::_column_type; struct _value_type: ColumnSpec::_value_type { diff --git a/include/sqlpp11/detail/type_set.h b/include/sqlpp11/detail/type_set.h index d367101f..e9b8d6e5 100644 --- a/include/sqlpp11/detail/type_set.h +++ b/include/sqlpp11/detail/type_set.h @@ -27,6 +27,7 @@ #ifndef SQLPP_DETAIL_TYPE_SET_H #define SQLPP_DETAIL_TYPE_SET_H +#include #include #include #include @@ -39,17 +40,21 @@ namespace sqlpp template struct make_set; - template - class type_set_element {}; - // A type set template - struct type_set: type_set_element... + struct type_set { - using size = std::integral_constant; + using _elements_t = std::tuple; + using size = std::tuple_size<_elements_t>; + using _is_type_set = std::true_type; template - using count = std::is_base_of, type_set>; + struct count + { + template + using same = std::is_same; + static constexpr bool value = or_t::value; + }; template struct is_superset_of @@ -59,7 +64,9 @@ namespace sqlpp template struct is_superset_of> - : and_t {}; + { + static constexpr bool value = and_t::value; + }; template struct join @@ -69,7 +76,9 @@ namespace sqlpp template struct join> - : make_set {}; + { + using type = typename make_set::type; + }; template struct is_subset_of @@ -79,7 +88,9 @@ namespace sqlpp template struct is_subset_of> - : type_set::template is_superset_of{}; + { + static constexpr bool value = type_set::template is_superset_of::value; + }; template struct is_disjunct_from @@ -93,16 +104,12 @@ namespace sqlpp static constexpr bool value = not(or_t::value or or_t::template count, Element...>::value); }; - template + template struct insert { - using type = type_set; - }; - - template - struct insert::value>::type> - { - using type = type_set; + using type = typename std::conditional::value, + type_set, + type_set>::type; }; template class Predicate, typename T> @@ -152,6 +159,34 @@ namespace sqlpp template using has_duplicates = std::integral_constant::type::size::value != sizeof...(T)>; + template + struct make_joined_set + { + static_assert(::sqlpp::vendor::wrong_t::value, "invalid argument for joined set"); + }; + + template<> + struct make_joined_set<> + { + using type = type_set<>; + }; + + /* + template + struct make_joined_set> + { + using type = type_set; + }; + */ + + template + struct make_joined_set, T...> + { + using _rest = typename make_joined_set::type; + + using type = typename type_set::template join<_rest>::type; + }; + } } diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index ccd4583b..e0c0f6b0 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -48,6 +48,7 @@ namespace sqlpp > struct check_insert_t { + static_assert(Table::_table_set::template is_superset_of::value, "inserted columns do not match the table in insert_into"); //static_assert(not (vendor::is_noop::value and vendor::is_noop::value) , "calling set() or default_values()"); static constexpr bool value = true; }; @@ -66,6 +67,8 @@ namespace sqlpp insert_t() {} + static_assert(detail::check_insert_t::value, "invalid insert_into"); + template insert_t(insert_t i, Whatever whatever): vendor::policy_t(i, whatever)... diff --git a/include/sqlpp11/vendor/from.h b/include/sqlpp11/vendor/from.h index e94a8c5f..c01f24e7 100644 --- a/include/sqlpp11/vendor/from.h +++ b/include/sqlpp11/vendor/from.h @@ -48,11 +48,13 @@ namespace sqlpp static_assert(_is_dynamic::value or sizeof...(Tables), "at least one table or join argument required in from()"); + // FIXME: Joins contain two tables. This is not being dealt with at the moment when looking at duplicates, for instance static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in from()"); static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a table or join in from()"); - // FIXME: Joins contain two tables. This is not being dealt with at the moment when looking at duplicates, for instance + using _table_set = typename ::sqlpp::detail::make_joined_set; + from_t(Tables... tables): _tables(tables...) diff --git a/include/sqlpp11/vendor/insert_value_list.h b/include/sqlpp11/vendor/insert_value_list.h index 5d750be6..ac6586cb 100644 --- a/include/sqlpp11/vendor/insert_value_list.h +++ b/include/sqlpp11/vendor/insert_value_list.h @@ -43,6 +43,7 @@ namespace sqlpp struct insert_default_values_t { using _is_insert_list = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; using _is_dynamic = std::false_type; const insert_default_values_t& _insert_value_list() const { return *this; } }; @@ -66,6 +67,9 @@ namespace sqlpp static_assert(not sqlpp::detail::or_t::value, "at least one assignment is prohibited by its column definition in set()"); + using _table_set = typename ::sqlpp::detail::make_joined_set::type; + static_assert(_is_dynamic::value ? (_table_set::size::value < 2) : (_table_set::size::value == 1), "set() contains assignments for tables from several columns"); + insert_list_t(Assignments... assignment): _assignments(assignment...), _columns({assignment._lhs}...), @@ -111,6 +115,9 @@ namespace sqlpp static_assert(not ::sqlpp::detail::or_t::value, "at least one column argument has a must_not_insert flag in its definition"); using _value_tuple_t = std::tuple...>; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; + + static_assert(_table_set::size::value == 1, "columns from multiple tables in columns()"); column_list_t(Columns... columns): _columns(simple_column_t{columns}...) @@ -139,7 +146,7 @@ namespace sqlpp struct no_insert_value_list_t { - using _is_insert_value_list = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; const no_insert_value_list_t& _insert_value_list() const { return *this; } }; diff --git a/include/sqlpp11/vendor/single_table.h b/include/sqlpp11/vendor/single_table.h index eb77b0cf..2a728ea8 100644 --- a/include/sqlpp11/vendor/single_table.h +++ b/include/sqlpp11/vendor/single_table.h @@ -30,7 +30,7 @@ #include #include #include -#include // FIXME: REMOVE +#include namespace sqlpp { @@ -55,12 +55,13 @@ namespace sqlpp ~single_table_t() = default; const single_table_t& _single_table() const { return *this; } + using _table_set = typename Table::_table_set; Table _table; }; struct no_single_table_t { - using _is_single_table = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; const no_single_table_t& _single_table() const { return *this; } }; diff --git a/include/sqlpp11/vendor/wrong.h b/include/sqlpp11/vendor/wrong.h index a37462ba..5694fd6a 100644 --- a/include/sqlpp11/vendor/wrong.h +++ b/include/sqlpp11/vendor/wrong.h @@ -33,20 +33,14 @@ namespace sqlpp { namespace vendor { - namespace detail - { - // A template that always returns false - // To be used with static assert, for instance, to ensure it - // fires only when the template is instantiated. - template struct wrong_t - { - using type = std::false_type; - }; - } - + // A template that always returns false + // To be used with static assert, for instance, to ensure it + // fires only when the template is instantiated. template - using wrong_t = typename detail::wrong_t::type; + struct wrong_t + { + static constexpr bool value = false; + }; } - } #endif diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index b8f74d3d..9772e10f 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -43,7 +43,7 @@ int main() test::TabFoo f; test::TabBar t; - interpret(insert_into(t).columns(t.gamma, t.beta), printer).flush(); + interpret(insert_into(t).columns(t.beta, t.gamma), printer).flush(); { auto i = insert_into(t).columns(t.gamma, t.beta); i.add_values(t.gamma = true, t.beta = "cheesecake"); diff --git a/tests/sample.sql b/tests/sample.sql index 87e26c94..4fa7e01c 100644 --- a/tests/sample.sql +++ b/tests/sample.sql @@ -26,6 +26,7 @@ CREATE TABLE tab_foo ( + delta varchar(255), epsilon bigint, omega double );