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

Added checks to prevent non-matching columns from being inserted

This commit is contained in:
rbock 2014-02-09 15:06:42 +01:00
parent 8ede5c7a93
commit ae2f1948ac
9 changed files with 80 additions and 35 deletions

View File

@ -37,6 +37,7 @@
#include <sqlpp11/vendor/expression.h> #include <sqlpp11/vendor/expression.h>
#include <sqlpp11/vendor/interpreter.h> #include <sqlpp11/vendor/interpreter.h>
#include <sqlpp11/vendor/wrong.h> #include <sqlpp11/vendor/wrong.h>
#include <sqlpp11/detail/type_set.h>
namespace sqlpp namespace sqlpp
{ {
@ -46,6 +47,7 @@ namespace sqlpp
using _is_column = std::true_type; using _is_column = std::true_type;
using _spec_t = ColumnSpec; using _spec_t = ColumnSpec;
using _table = Table; using _table = Table;
using _table_set = detail::type_set<_table>;
using _column_type = typename ColumnSpec::_column_type; using _column_type = typename ColumnSpec::_column_type;
struct _value_type: ColumnSpec::_value_type struct _value_type: ColumnSpec::_value_type
{ {

View File

@ -27,6 +27,7 @@
#ifndef SQLPP_DETAIL_TYPE_SET_H #ifndef SQLPP_DETAIL_TYPE_SET_H
#define SQLPP_DETAIL_TYPE_SET_H #define SQLPP_DETAIL_TYPE_SET_H
#include <tuple>
#include <type_traits> #include <type_traits>
#include <sqlpp11/vendor/wrong.h> #include <sqlpp11/vendor/wrong.h>
#include <sqlpp11/detail/logic.h> #include <sqlpp11/detail/logic.h>
@ -39,17 +40,21 @@ namespace sqlpp
template<typename... T> template<typename... T>
struct make_set; struct make_set;
template<typename T>
class type_set_element {};
// A type set // A type set
template<typename... Element> template<typename... Element>
struct type_set: type_set_element<Element>... struct type_set
{ {
using size = std::integral_constant<size_t, sizeof...(Element)>; using _elements_t = std::tuple<Element...>;
using size = std::tuple_size<_elements_t>;
using _is_type_set = std::true_type;
template<typename T> template<typename T>
using count = std::is_base_of<type_set_element<T>, type_set>; struct count
{
template<typename E>
using same = std::is_same<T, E>;
static constexpr bool value = or_t<same, Element...>::value;
};
template<typename T> template<typename T>
struct is_superset_of struct is_superset_of
@ -59,7 +64,9 @@ namespace sqlpp
template<typename... T> template<typename... T>
struct is_superset_of<type_set<T...>> struct is_superset_of<type_set<T...>>
: and_t<count, T...> {}; {
static constexpr bool value = and_t<count, T...>::value;
};
template<typename T> template<typename T>
struct join struct join
@ -69,7 +76,9 @@ namespace sqlpp
template<typename... T> template<typename... T>
struct join<type_set<T...>> struct join<type_set<T...>>
: make_set<Element..., T...> {}; {
using type = typename make_set<Element..., T...>::type;
};
template<typename T> template<typename T>
struct is_subset_of struct is_subset_of
@ -79,7 +88,9 @@ namespace sqlpp
template<typename... T> template<typename... T>
struct is_subset_of<type_set<T...>> struct is_subset_of<type_set<T...>>
: type_set<T...>::template is_superset_of<type_set>{}; {
static constexpr bool value = type_set<T...>::template is_superset_of<type_set>::value;
};
template<typename T> template<typename T>
struct is_disjunct_from struct is_disjunct_from
@ -93,16 +104,12 @@ namespace sqlpp
static constexpr bool value = not(or_t<type_set::count, T...>::value or or_t<type_set<T...>::template count, Element...>::value); static constexpr bool value = not(or_t<type_set::count, T...>::value or or_t<type_set<T...>::template count, Element...>::value);
}; };
template<typename T, typename Enable = void> template<typename T>
struct insert struct insert
{ {
using type = type_set; using type = typename std::conditional<count<T>::value,
}; type_set,
type_set<Element..., T>>::type;
template<typename T>
struct insert<T, typename std::enable_if<not type_set::template count<T>::value>::type>
{
using type = type_set<Element..., T>;
}; };
template<template<typename A> class Predicate, typename T> template<template<typename A> class Predicate, typename T>
@ -152,6 +159,34 @@ namespace sqlpp
template<typename... T> template<typename... T>
using has_duplicates = std::integral_constant<bool, make_set<T...>::type::size::value != sizeof...(T)>; using has_duplicates = std::integral_constant<bool, make_set<T...>::type::size::value != sizeof...(T)>;
template<typename... T>
struct make_joined_set
{
static_assert(::sqlpp::vendor::wrong_t<T...>::value, "invalid argument for joined set");
};
template<>
struct make_joined_set<>
{
using type = type_set<>;
};
/*
template<typename... E>
struct make_joined_set<type_set<E...>>
{
using type = type_set<E...>;
};
*/
template<typename... E, typename... T>
struct make_joined_set<type_set<E...>, T...>
{
using _rest = typename make_joined_set<T...>::type;
using type = typename type_set<E...>::template join<_rest>::type;
};
} }
} }

View File

@ -48,6 +48,7 @@ namespace sqlpp
> >
struct check_insert_t struct check_insert_t
{ {
static_assert(Table::_table_set::template is_superset_of<typename InsertValueList::_table_set>::value, "inserted columns do not match the table in insert_into");
//static_assert(not (vendor::is_noop<InsertList>::value and vendor::is_noop<ColumnList>::value) , "calling set() or default_values()"); //static_assert(not (vendor::is_noop<InsertList>::value and vendor::is_noop<ColumnList>::value) , "calling set() or default_values()");
static constexpr bool value = true; static constexpr bool value = true;
}; };
@ -66,6 +67,8 @@ namespace sqlpp
insert_t() insert_t()
{} {}
static_assert(detail::check_insert_t<Policies...>::value, "invalid insert_into");
template<typename Whatever> template<typename Whatever>
insert_t(insert_t i, Whatever whatever): insert_t(insert_t i, Whatever whatever):
vendor::policy_t<Policies>(i, whatever)... vendor::policy_t<Policies>(i, whatever)...

View File

@ -48,11 +48,13 @@ namespace sqlpp
static_assert(_is_dynamic::value or sizeof...(Tables), "at least one table or join argument required in from()"); 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<Tables...>::value, "at least one duplicate argument detected in from()"); static_assert(not ::sqlpp::detail::has_duplicates<Tables...>::value, "at least one duplicate argument detected in from()");
static_assert(::sqlpp::detail::and_t<is_table_t, Tables...>::value, "at least one argument is not a table or join in from()"); static_assert(::sqlpp::detail::and_t<is_table_t, Tables...>::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<typename Tables::_table_set...>;
from_t(Tables... tables): from_t(Tables... tables):
_tables(tables...) _tables(tables...)

View File

@ -43,6 +43,7 @@ namespace sqlpp
struct insert_default_values_t struct insert_default_values_t
{ {
using _is_insert_list = std::true_type; using _is_insert_list = std::true_type;
using _table_set = ::sqlpp::detail::type_set<>;
using _is_dynamic = std::false_type; using _is_dynamic = std::false_type;
const insert_default_values_t& _insert_value_list() const { return *this; } const insert_default_values_t& _insert_value_list() const { return *this; }
}; };
@ -66,6 +67,9 @@ namespace sqlpp
static_assert(not sqlpp::detail::or_t<must_not_insert_t, typename Assignments::_column_t...>::value, "at least one assignment is prohibited by its column definition in set()"); static_assert(not sqlpp::detail::or_t<must_not_insert_t, typename Assignments::_column_t...>::value, "at least one assignment is prohibited by its column definition in set()");
using _table_set = typename ::sqlpp::detail::make_joined_set<typename Assignments::_column_t::_table_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): insert_list_t(Assignments... assignment):
_assignments(assignment...), _assignments(assignment...),
_columns({assignment._lhs}...), _columns({assignment._lhs}...),
@ -111,6 +115,9 @@ namespace sqlpp
static_assert(not ::sqlpp::detail::or_t<must_not_insert_t, Columns...>::value, "at least one column argument has a must_not_insert flag in its definition"); static_assert(not ::sqlpp::detail::or_t<must_not_insert_t, Columns...>::value, "at least one column argument has a must_not_insert flag in its definition");
using _value_tuple_t = std::tuple<vendor::insert_value_t<Columns>...>; using _value_tuple_t = std::tuple<vendor::insert_value_t<Columns>...>;
using _table_set = typename ::sqlpp::detail::make_joined_set<typename Columns::_table_set...>::type;
static_assert(_table_set::size::value == 1, "columns from multiple tables in columns()");
column_list_t(Columns... columns): column_list_t(Columns... columns):
_columns(simple_column_t<Columns>{columns}...) _columns(simple_column_t<Columns>{columns}...)
@ -139,7 +146,7 @@ namespace sqlpp
struct no_insert_value_list_t 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; } const no_insert_value_list_t& _insert_value_list() const { return *this; }
}; };

View File

@ -30,7 +30,7 @@
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/vendor/policy_update.h> #include <sqlpp11/vendor/policy_update.h>
#include <sqlpp11/vendor/crtp_wrapper.h> #include <sqlpp11/vendor/crtp_wrapper.h>
#include <iostream> // FIXME: REMOVE #include <sqlpp11/detail/type_set.h>
namespace sqlpp namespace sqlpp
{ {
@ -55,12 +55,13 @@ namespace sqlpp
~single_table_t() = default; ~single_table_t() = default;
const single_table_t& _single_table() const { return *this; } const single_table_t& _single_table() const { return *this; }
using _table_set = typename Table::_table_set;
Table _table; Table _table;
}; };
struct no_single_table_t 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; } const no_single_table_t& _single_table() const { return *this; }
}; };

View File

@ -33,20 +33,14 @@ namespace sqlpp
{ {
namespace vendor namespace vendor
{ {
namespace detail // A template that always returns false
{ // To be used with static assert, for instance, to ensure it
// A template that always returns false // fires only when the template is instantiated.
// To be used with static assert, for instance, to ensure it
// fires only when the template is instantiated.
template<class ...T> struct wrong_t
{
using type = std::false_type;
};
}
template<class ...T> template<class ...T>
using wrong_t = typename detail::wrong_t<T...>::type; struct wrong_t
{
static constexpr bool value = false;
};
} }
} }
#endif #endif

View File

@ -43,7 +43,7 @@ int main()
test::TabFoo f; test::TabFoo f;
test::TabBar t; 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); auto i = insert_into(t).columns(t.gamma, t.beta);
i.add_values(t.gamma = true, t.beta = "cheesecake"); i.add_values(t.gamma = true, t.beta = "cheesecake");

View File

@ -26,6 +26,7 @@
CREATE TABLE tab_foo CREATE TABLE tab_foo
( (
delta varchar(255),
epsilon bigint, epsilon bigint,
omega double omega double
); );