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:
parent
8ede5c7a93
commit
ae2f1948ac
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)...
|
||||||
|
4
include/sqlpp11/vendor/from.h
vendored
4
include/sqlpp11/vendor/from.h
vendored
@ -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...)
|
||||||
|
9
include/sqlpp11/vendor/insert_value_list.h
vendored
9
include/sqlpp11/vendor/insert_value_list.h
vendored
@ -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; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
5
include/sqlpp11/vendor/single_table.h
vendored
5
include/sqlpp11/vendor/single_table.h
vendored
@ -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; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
12
include/sqlpp11/vendor/wrong.h
vendored
12
include/sqlpp11/vendor/wrong.h
vendored
@ -32,21 +32,15 @@
|
|||||||
namespace sqlpp
|
namespace sqlpp
|
||||||
{
|
{
|
||||||
namespace vendor
|
namespace vendor
|
||||||
{
|
|
||||||
namespace detail
|
|
||||||
{
|
{
|
||||||
// A template that always returns false
|
// A template that always returns false
|
||||||
// To be used with static assert, for instance, to ensure it
|
// To be used with static assert, for instance, to ensure it
|
||||||
// fires only when the template is instantiated.
|
// fires only when the template is instantiated.
|
||||||
template<class ...T> struct wrong_t
|
template<class ...T>
|
||||||
|
struct wrong_t
|
||||||
{
|
{
|
||||||
using type = std::false_type;
|
static constexpr bool value = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ...T>
|
|
||||||
using wrong_t = typename detail::wrong_t<T...>::type;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -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");
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
CREATE TABLE tab_foo
|
CREATE TABLE tab_foo
|
||||||
(
|
(
|
||||||
|
delta varchar(255),
|
||||||
epsilon bigint,
|
epsilon bigint,
|
||||||
omega double
|
omega double
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user