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

Merge branch 'feature/with_cte' into develop

This commit is contained in:
rbock 2015-02-15 16:07:15 +01:00
commit 80bc0fcf5e
40 changed files with 1065 additions and 219 deletions

53
.clang-format Normal file
View File

@ -0,0 +1,53 @@
Language: Cpp
AccessModifierOffset: -2
ConstructorInitializerIndentWidth: 4
AlignEscapedNewlinesLeft: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AlwaysBreakTemplateDeclarations: true
AlwaysBreakBeforeMultilineStrings: false
BreakBeforeBinaryOperators: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: false
ColumnLimit: 160
ConstructorInitializerAllOnOneLineOrOnePerLine: true
DerivePointerAlignment: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: true
IndentWrappedFunctionNames: false
IndentFunctionDeclarationAfterType: false
MaxEmptyLinesToKeep: 1
KeepEmptyLinesAtTheStartOfBlocks: false
NamespaceIndentation: All
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
SpacesBeforeTrailingComments: 2
Cpp11BracedListStyle: true
Standard: Cpp11
IndentWidth: 2
TabWidth: 2
UseTab: Never
BreakBeforeBraces: Allman
SpacesInParentheses: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 4
CommentPragmas: '^ IWYU pragma:'
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
SpaceBeforeParens: ControlStatements
DisableFormat: false

View File

@ -36,6 +36,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "-std=c++11 -Wall ${CMAKE_CXX_FLAGS}")
endif () endif ()
set(CMAKE_CXX_FLAGS "-Wconversion -Wpedantic ${CMAKE_CXX_FLAGS}")
set(include_dir "${PROJECT_SOURCE_DIR}/include") set(include_dir "${PROJECT_SOURCE_DIR}/include")
file(GLOB_RECURSE sqlpp_headers "${include_dir}/*.h") file(GLOB_RECURSE sqlpp_headers "${include_dir}/*.h")

View File

@ -37,7 +37,7 @@
static constexpr bool some_condition = true; static constexpr bool some_condition = true;
static constexpr bool some_other_condition = false; static constexpr bool some_other_condition = false;
SQLPP_ALIAS_PROVIDER(cheesecake); SQLPP_ALIAS_PROVIDER(cheesecake)
MockDb db; MockDb db;
@ -110,7 +110,7 @@ int main()
.from(p.join(x).on(p.feature == x.cheesecake)) .from(p.join(x).on(p.feature == x.cheesecake))
.where(true))) .where(true)))
{ {
int id = row.id; int64_t id = row.id;
std::string name = row.name; std::string name = row.name;
std::string x_name = row.x.name; std::string x_name = row.x.name;
int cheesecake = row.x.cheesecake; int cheesecake = row.x.cheesecake;

View File

@ -62,35 +62,35 @@ namespace sqlpp
static constexpr bool value = true; static constexpr bool value = true;
}; };
namespace alias inline namespace alias
{ {
SQLPP_ALIAS_PROVIDER(a); SQLPP_ALIAS_PROVIDER(a)
SQLPP_ALIAS_PROVIDER(b); SQLPP_ALIAS_PROVIDER(b)
SQLPP_ALIAS_PROVIDER(c); SQLPP_ALIAS_PROVIDER(c)
SQLPP_ALIAS_PROVIDER(d); SQLPP_ALIAS_PROVIDER(d)
SQLPP_ALIAS_PROVIDER(e); SQLPP_ALIAS_PROVIDER(e)
SQLPP_ALIAS_PROVIDER(f); SQLPP_ALIAS_PROVIDER(f)
SQLPP_ALIAS_PROVIDER(g); SQLPP_ALIAS_PROVIDER(g)
SQLPP_ALIAS_PROVIDER(h); SQLPP_ALIAS_PROVIDER(h)
SQLPP_ALIAS_PROVIDER(i); SQLPP_ALIAS_PROVIDER(i)
SQLPP_ALIAS_PROVIDER(j); SQLPP_ALIAS_PROVIDER(j)
SQLPP_ALIAS_PROVIDER(k); SQLPP_ALIAS_PROVIDER(k)
SQLPP_ALIAS_PROVIDER(l); SQLPP_ALIAS_PROVIDER(l)
SQLPP_ALIAS_PROVIDER(m); SQLPP_ALIAS_PROVIDER(m)
SQLPP_ALIAS_PROVIDER(n); SQLPP_ALIAS_PROVIDER(n)
SQLPP_ALIAS_PROVIDER(o); SQLPP_ALIAS_PROVIDER(o)
SQLPP_ALIAS_PROVIDER(p); SQLPP_ALIAS_PROVIDER(p)
SQLPP_ALIAS_PROVIDER(q); SQLPP_ALIAS_PROVIDER(q)
SQLPP_ALIAS_PROVIDER(s); SQLPP_ALIAS_PROVIDER(s)
SQLPP_ALIAS_PROVIDER(t); SQLPP_ALIAS_PROVIDER(t)
SQLPP_ALIAS_PROVIDER(u); SQLPP_ALIAS_PROVIDER(u)
SQLPP_ALIAS_PROVIDER(v); SQLPP_ALIAS_PROVIDER(v)
SQLPP_ALIAS_PROVIDER(w); SQLPP_ALIAS_PROVIDER(w)
SQLPP_ALIAS_PROVIDER(x); SQLPP_ALIAS_PROVIDER(x)
SQLPP_ALIAS_PROVIDER(y); SQLPP_ALIAS_PROVIDER(y)
SQLPP_ALIAS_PROVIDER(z); SQLPP_ALIAS_PROVIDER(z)
SQLPP_ALIAS_PROVIDER(left); SQLPP_ALIAS_PROVIDER(left)
SQLPP_ALIAS_PROVIDER(right); SQLPP_ALIAS_PROVIDER(right)
} }
} }

View File

@ -54,11 +54,13 @@ namespace sqlpp
struct _recursive_traits struct _recursive_traits
{ {
using _parameters = std::tuple<>; using _required_ctes = detail::type_set<>;
using _provided_ctes = detail::type_set<>;
using _required_tables = detail::type_set<Table>;
using _provided_tables = detail::type_set<>; using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>;
using _required_tables = detail::type_set<Table>;
using _extra_tables = detail::type_set<>; using _extra_tables = detail::type_set<>;
using _parameters = std::tuple<>;
using _tags = typename std::conditional<column_spec_can_be_null_t<ColumnSpec>::value, using _tags = typename std::conditional<column_spec_can_be_null_t<ColumnSpec>::value,
detail::type_set<tag::can_be_null>, detail::type_set<tag::can_be_null>,
detail::type_set<>>::type; detail::type_set<>>::type;

View File

@ -41,6 +41,8 @@ namespace sqlpp
using _traits = make_traits<integral, tag::is_expression, tag::is_selectable>; using _traits = make_traits<integral, tag::is_expression, tag::is_selectable>;
struct _recursive_traits struct _recursive_traits
{ {
using _required_ctes = required_ctes_of<Expr>;
using _provided_ctes = detail::type_set<>;
using _required_tables = required_tables_of<Expr>; using _required_tables = required_tables_of<Expr>;
using _provided_tables = provided_tables_of<Expr>; using _provided_tables = provided_tables_of<Expr>;
using _provided_outer_tables = provided_outer_tables_of<Expr>; using _provided_outer_tables = provided_outer_tables_of<Expr>;

286
include/sqlpp11/cte.h Normal file
View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 2013-2014, Roland Bock
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SQLPP_CTE_H
#define SQLPP_CTE_H
#include <sqlpp11/table_ref.h>
#include <sqlpp11/select_flags.h>
#include <sqlpp11/result_row.h>
#include <sqlpp11/statement_fwd.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/expression.h>
#include <sqlpp11/interpret_tuple.h>
#include <sqlpp11/interpretable_list.h>
#include <sqlpp11/logic.h>
namespace sqlpp
{
template<typename Flag, typename Lhs, typename Rhs>
struct cte_union_t
{
struct _recursive_traits
{
using _required_ctes = detail::make_joined_set_t<required_ctes_of<Lhs>, required_ctes_of<Rhs>>;
using _provided_ctes = detail::type_set<>;
using _required_tables = detail::type_set<>;
using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>;
using _parameters = detail::make_parameter_tuple_t<parameters_of<Lhs>, parameters_of<Rhs>>;
using _tags = detail::type_set<>;
};
cte_union_t(Lhs lhs, Rhs rhs):
_lhs(lhs),
_rhs(rhs)
{}
cte_union_t(const cte_union_t&) = default;
cte_union_t(cte_union_t&&) = default;
cte_union_t& operator=(const cte_union_t&) = default;
cte_union_t& operator=(cte_union_t&&) = default;
~cte_union_t() = default;
Lhs _lhs;
Rhs _rhs;
};
// Interpreters
template<typename Context, typename Flag, typename Lhs, typename Rhs>
struct serializer_t<Context, cte_union_t<Flag, Lhs, Rhs>>
{
using _serialize_check = serialize_check_of<Context, Lhs, Rhs>;
using T = cte_union_t<Flag, Lhs, Rhs>;
static Context& _(const T& t, Context& context)
{
context << '(';
serialize(t._lhs, context);
context << ") UNION ";
serialize(Flag{}, context);
context << " (";
serialize(t._rhs, context);
context << ')';
return context;
}
};
template<typename AliasProvider, typename Statement, typename... FieldSpecs>
struct cte_t;
template<typename AliasProvider>
struct cte_ref_t;
template<typename AliasProvider, typename Statement, typename... FieldSpecs>
auto from_table(cte_t<AliasProvider, Statement, FieldSpecs...> t) -> cte_ref_t<AliasProvider>
{
return cte_ref_t<AliasProvider>{};
}
template<typename AliasProvider, typename Statement, typename... FieldSpecs>
struct from_table_impl<cte_t<AliasProvider, Statement, FieldSpecs...>>
{
using type = cte_ref_t<AliasProvider>;
};
template<typename FieldSpec>
struct cte_column_spec_t
{
using _alias_t = typename FieldSpec::_alias_t;
using _traits = make_traits<value_type_of<FieldSpec>,
tag::must_not_insert,
tag::must_not_update,
tag_if<tag::can_be_null, column_spec_can_be_null_t<FieldSpec>::value>
>;
};
template<typename AliasProvider, typename Statement, typename ResultRow>
struct make_cte_impl
{
using type = void;
};
template<typename AliasProvider, typename Statement, typename... FieldSpecs>
struct make_cte_impl<AliasProvider, Statement, result_row_t<void, FieldSpecs...>>
{
using type = cte_t<AliasProvider, Statement, FieldSpecs...>;
};
template<typename AliasProvider, typename Statement>
using make_cte_t = typename make_cte_impl<AliasProvider, Statement, get_result_row_t<Statement>>::type;
template<typename AliasProvider, typename Statement, typename... FieldSpecs>
struct cte_t: public member_t<cte_column_spec_t<FieldSpecs>, column_t<AliasProvider, cte_column_spec_t<FieldSpecs>>>...
{
using _traits = make_traits<no_value_t, tag::is_cte, tag::is_table>; // FIXME: is table? really?
struct _recursive_traits
{
using _required_ctes = detail::make_joined_set_t<required_ctes_of<Statement>, detail::type_set<AliasProvider>>;
using _provided_ctes = detail::type_set<>;
using _required_tables = detail::type_set<>;
using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>;
using _parameters = parameters_of<Statement>;
using _tags = detail::type_set<>;
};
using _alias_t = typename AliasProvider::_alias_t;
constexpr static bool _is_recursive = detail::is_element_of<AliasProvider, required_ctes_of<Statement>>::value;
using _column_tuple_t = std::tuple<column_t<AliasProvider, cte_column_spec_t<FieldSpecs>>...>;
template<typename... T>
using _check = logic::all_t<is_statement_t<T>::value...>;
using _result_row_t = result_row_t<void, FieldSpecs...>;
template<typename Rhs>
auto union_distinct(Rhs rhs) const
-> typename std::conditional<_check<Rhs>::value, cte_t<AliasProvider, cte_union_t<distinct_t, Statement, Rhs>, FieldSpecs...>, bad_statement>::type
{
static_assert(is_statement_t<Rhs>::value, "argument of union call has to be a statement");
static_assert(has_policy_t<Rhs, is_select_t>::value, "argument of union call has to be a select");
static_assert(has_result_row_t<Rhs>::value, "argument of a union has to be a (complete) select statement");
static_assert(std::is_same<_result_row_t, get_result_row_t<Rhs>>::value, "both select statements in a union have to have the same result columns (type and name)");
return _union_impl<void, distinct_t>(_check<Rhs>{}, rhs);
}
template<typename Rhs>
auto union_all(Rhs rhs) const
-> typename std::conditional<_check<Rhs>::value, cte_t<AliasProvider, cte_union_t<all_t, Statement, Rhs>, FieldSpecs...>, bad_statement>::type
{
static_assert(is_statement_t<Rhs>::value, "argument of union call has to be a statement");
static_assert(has_policy_t<Rhs, is_select_t>::value, "argument of union call has to be a select");
static_assert(has_result_row_t<Rhs>::value, "argument of a union has to be a (complete) select statement");
static_assert(std::is_same<_result_row_t, get_result_row_t<Rhs>>::value, "both select statements in a union have to have the same result columns (type and name)");
return _union_impl<all_t>(_check<Rhs>{}, rhs);
}
private:
template<typename Flag, typename Rhs>
auto _union_impl(const std::false_type&, Rhs rhs) const
-> bad_statement;
template<typename Flag, typename Rhs>
auto _union_impl(const std::true_type&, Rhs rhs) const
-> cte_t<AliasProvider, cte_union_t<Flag, Statement, Rhs>, FieldSpecs...>
{
return cte_union_t<Flag, Statement, Rhs>{_statement, rhs};
}
public:
cte_t(Statement statement): _statement(statement){}
cte_t(const cte_t&) = default;
cte_t(cte_t&&) = default;
cte_t& operator=(const cte_t&) = default;
cte_t& operator=(cte_t&&) = default;
~cte_t() = default;
Statement _statement;
};
template<typename Context, typename AliasProvider, typename Statement, typename... ColumnSpecs>
struct serializer_t<Context, cte_t<AliasProvider, Statement, ColumnSpecs...>>
{
using _serialize_check = serialize_check_of<Context, Statement>;
using T = cte_t<AliasProvider, Statement, ColumnSpecs...>;
static Context& _(const T& t, Context& context)
{
context << name_of<T>::char_ptr() << " AS (";
serialize(t._statement, context);
context << ")";
return context;
}
};
// The cte_t is displayed as AliasProviderName except within the with:
// - the with needs the
// AliasProviderName AS (ColumnNames) (select/union)
// The result row of the select should not have dynamic parts
template<typename AliasProvider>
struct cte_ref_t
{
using _traits = make_traits<no_value_t, tag::is_alias, tag::is_cte, tag::is_table>; // FIXME: is table? really?
struct _recursive_traits
{
using _required_ctes = detail::make_type_set_t<AliasProvider>;
using _provided_ctes = detail::type_set<>;
using _required_tables = detail::type_set<>;
using _provided_tables = detail::type_set<AliasProvider>;
using _provided_outer_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>;
using _parameters = std::tuple<>;
using _tags = detail::type_set<>;
};
using _alias_t = typename AliasProvider::_alias_t;
template<typename Statement>
auto as(Statement statement)
-> make_cte_t<AliasProvider, Statement>
{
static_assert(required_tables_of<Statement>::size::value == 0, "common table expression must not use unknown tables");
static_assert(not detail::is_element_of<AliasProvider, required_ctes_of<Statement>>::value, "common table expression must not self-reference in the first part, use union_all/union_distinct for recursion");
static_assert(is_static_result_row_t<get_result_row_t<Statement>>::value, "ctes must not have dynamically added columns");
return { statement };
}
};
template<typename Context, typename AliasProvider>
struct serializer_t<Context, cte_ref_t<AliasProvider>>
{
using _serialize_check = consistent_t;
using T = cte_ref_t<AliasProvider>;
static Context& _(const T& t, Context& context)
{
context << name_of<T>::char_ptr();
return context;
}
};
template<typename AliasProvider>
auto cte(const AliasProvider&)
-> cte_ref_t<AliasProvider>
{
return {};
}
}
#endif

View File

@ -37,20 +37,20 @@ namespace sqlpp
typename Target::_data_t pick_arg_impl(Statement statement, Term term, const std::true_type&) typename Target::_data_t pick_arg_impl(Statement statement, Term term, const std::true_type&)
{ {
return term; return term;
}; }
template<typename Target, typename Statement, typename Term> template<typename Target, typename Statement, typename Term>
typename Target::_data_t pick_arg_impl(Statement statement, Term term, const std::false_type&) typename Target::_data_t pick_arg_impl(Statement statement, Term term, const std::false_type&)
{ {
return Target::_get_member(statement)._data; return Target::_get_member(statement)._data;
}; }
// Returns a statement's term either by picking the term from the statement or using the new term // Returns a statement's term either by picking the term from the statement or using the new term
template<typename Target, typename Statement, typename Term> template<typename Target, typename Statement, typename Term>
typename Target::_data_t pick_arg(Statement statement, Term term) typename Target::_data_t pick_arg(Statement statement, Term term)
{ {
return pick_arg_impl<Target>(statement, term, std::is_same<typename Target::_data_t, Term>()); return pick_arg_impl<Target>(statement, term, std::is_same<typename Target::_data_t, Term>());
}; }
} }
} }

View File

@ -54,11 +54,13 @@ namespace sqlpp
using _traits = make_traits<no_value_t, tag::is_extra_tables>; using _traits = make_traits<no_value_t, tag::is_extra_tables>;
struct _recursive_traits struct _recursive_traits
{ {
using _parameters = std::tuple<>; using _required_ctes = detail::make_joined_set_t<required_ctes_of<Tables>...>;
using _provided_ctes = detail::type_set<>;
using _required_tables = detail::type_set<>; using _required_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>;
using _provided_tables = detail::type_set<>; using _provided_tables = detail::type_set<>;
using _extra_tables = detail::type_set<Tables...>; using _extra_tables = detail::type_set<Tables...>;
using _parameters = std::tuple<>;
using _tags = detail::type_set<>; using _tags = detail::type_set<>;
}; };

View File

@ -27,6 +27,7 @@
#ifndef SQLPP_FROM_H #ifndef SQLPP_FROM_H
#define SQLPP_FROM_H #define SQLPP_FROM_H
#include <sqlpp11/table_ref.h>
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/no_data.h> #include <sqlpp11/no_data.h>
#include <sqlpp11/interpretable_list.h> #include <sqlpp11/interpretable_list.h>
@ -90,7 +91,7 @@ namespace sqlpp
template<typename Table> template<typename Table>
void _add_impl(Table table, const std::true_type&) void _add_impl(Table table, const std::true_type&)
{ {
return _data._dynamic_tables.emplace_back(table); return _data._dynamic_tables.emplace_back(from_table(table));
} }
template<typename Table> template<typename Table>
@ -164,7 +165,7 @@ namespace sqlpp
template<typename... Tables> template<typename... Tables>
auto from(Tables... tables) const auto from(Tables... tables) const
-> _new_statement_t<_check<Tables...>, from_t<void, Tables...>> -> _new_statement_t<_check<Tables...>, from_t<void, from_table_t<Tables>...>>
{ {
static_assert(_check<Tables...>::value, "at least one argument is not a table or join in from()"); static_assert(_check<Tables...>::value, "at least one argument is not a table or join in from()");
static_assert(sizeof...(Tables), "at least one table or join argument required in from()"); static_assert(sizeof...(Tables), "at least one table or join argument required in from()");
@ -173,7 +174,7 @@ namespace sqlpp
template<typename... Tables> template<typename... Tables>
auto dynamic_from(Tables... tables) const auto dynamic_from(Tables... tables) const
-> _new_statement_t<_check<Tables...>, from_t<_database_t, Tables...>> -> _new_statement_t<_check<Tables...>, from_t<_database_t, from_table_t<Tables>...>>
{ {
static_assert(not std::is_same<_database_t, void>::value, "dynamic_from must not be called in a static statement"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_from must not be called in a static statement");
static_assert(_check<Tables...>::value, "at least one argument is not a table or join in from()"); static_assert(_check<Tables...>::value, "at least one argument is not a table or join in from()");
@ -187,7 +188,7 @@ namespace sqlpp
template<typename Database, typename... Tables> template<typename Database, typename... Tables>
auto _from_impl(const std::true_type&, Tables... tables) const auto _from_impl(const std::true_type&, Tables... tables) const
-> _new_statement_t<std::true_type, from_t<Database, Tables...>> -> _new_statement_t<std::true_type, from_t<Database, from_table_t<Tables>...>>
{ {
static_assert(required_tables_of<from_t<Database, Tables...>>::size::value == 0, "at least one table depends on another table in from()"); static_assert(required_tables_of<from_t<Database, Tables...>>::size::value == 0, "at least one table depends on another table in from()");
@ -197,7 +198,7 @@ namespace sqlpp
static_assert(_number_of_tables == _unique_tables::size::value, "at least one duplicate table detected in from()"); static_assert(_number_of_tables == _unique_tables::size::value, "at least one duplicate table detected in from()");
static_assert(_number_of_tables == _unique_table_names::size::value, "at least one duplicate table name detected in from()"); static_assert(_number_of_tables == _unique_table_names::size::value, "at least one duplicate table name detected in from()");
return { static_cast<const derived_statement_t<Policies>&>(*this), from_data_t<Database, Tables...>{tables...} }; return { static_cast<const derived_statement_t<Policies>&>(*this), from_data_t<Database, from_table_t<Tables>...>{from_table(tables)...} };
} }
}; };

View File

@ -211,7 +211,7 @@ namespace sqlpp
static_assert(not detail::has_duplicates<Expressions...>::value, "at least one duplicate argument detected in group_by()"); static_assert(not detail::has_duplicates<Expressions...>::value, "at least one duplicate argument detected in group_by()");
return { static_cast<const derived_statement_t<Policies>&>(*this), group_by_data_t<Database, Expressions...>{expressions...} }; return { static_cast<const derived_statement_t<Policies>&>(*this), group_by_data_t<Database, Expressions...>{expressions...} };
}; }
}; };
}; };

View File

@ -315,7 +315,7 @@ namespace sqlpp
static void _() static void _()
{ {
static_assert(wrong_t<T>::value, "insert values required, e.g. set(...) or default_values()"); static_assert(wrong_t<T>::value, "insert values required, e.g. set(...) or default_values()");
}; }
}; };
// NO INSERT COLUMNS/VALUES YET // NO INSERT COLUMNS/VALUES YET

View File

@ -54,7 +54,9 @@ namespace sqlpp
// See also: "http://stackoverflow.com/questions/6245735/pretty-print-stdtuple/6245777#6245777" // See also: "http://stackoverflow.com/questions/6245735/pretty-print-stdtuple/6245777#6245777"
// Beware of gcc-bug: "http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51253", otherwise an empty swallow struct could be used // Beware of gcc-bug: "http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51253", otherwise an empty swallow struct could be used
using swallow = int[]; using swallow = int[];
(void) swallow{(interpret_tuple_element(std::get<Is>(t), separator, context, useBraces, Is), 0)...}; (void) swallow{
0, //workaround against -Wpedantic GCC warning "zero-size array 'int [0]'"
(interpret_tuple_element(std::get<Is>(t), separator, context, useBraces, Is), 0)...};
return context; return context;
} }

View File

@ -68,6 +68,8 @@ namespace sqlpp
using _traits = make_traits<no_value_t, tag::is_table, tag::is_join>; using _traits = make_traits<no_value_t, tag::is_table, tag::is_join>;
struct _recursive_traits struct _recursive_traits
{ {
using _required_ctes = detail::make_joined_set_t<required_ctes_of<Lhs>, required_ctes_of<Rhs>>;
using _provided_ctes = detail::type_set<>;
using _required_tables = detail::make_joined_set_t<required_tables_of<Lhs>, required_tables_of<Rhs>>; using _required_tables = detail::make_joined_set_t<required_tables_of<Lhs>, required_tables_of<Rhs>>;
using _provided_tables = detail::make_joined_set_t<provided_tables_of<Lhs>, provided_tables_of<Rhs>>; using _provided_tables = detail::make_joined_set_t<provided_tables_of<Lhs>, provided_tables_of<Rhs>>;
using _provided_outer_tables = typename JoinType::template _provided_outer_tables<Lhs, Rhs>; using _provided_outer_tables = typename JoinType::template _provided_outer_tables<Lhs, Rhs>;

View File

@ -211,7 +211,7 @@ namespace sqlpp
static_assert(not detail::has_duplicates<Expressions...>::value, "at least one duplicate argument detected in order_by()"); static_assert(not detail::has_duplicates<Expressions...>::value, "at least one duplicate argument detected in order_by()");
return { static_cast<const derived_statement_t<Policies>&>(*this), order_by_data_t<Database, Expressions...>{expressions...} }; return { static_cast<const derived_statement_t<Policies>&>(*this), order_by_data_t<Database, Expressions...>{expressions...} };
}; }
}; };
}; };

View File

@ -40,11 +40,13 @@ namespace sqlpp
using _traits = make_traits<ValueType, tag::is_parameter, tag::is_expression>; using _traits = make_traits<ValueType, tag::is_parameter, tag::is_expression>;
struct _recursive_traits struct _recursive_traits
{ {
using _parameters = std::tuple<parameter_t>; using _required_ctes = detail::type_set<>;
using _provided_ctes = detail::type_set<>;
using _required_tables = detail::type_set<>;
using _provided_tables = detail::type_set<>; using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>;
using _required_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>; using _extra_tables = detail::type_set<>;
using _parameters = std::tuple<parameter_t>;
using _tags = detail::type_set<tag::can_be_null>; using _tags = detail::type_set<tag::can_be_null>;
}; };

View File

@ -83,11 +83,13 @@ namespace sqlpp
struct _recursive_traits struct _recursive_traits
{ {
using _parameters = std::tuple<>; using _required_ctes = detail::type_set<>;
using _provided_ctes = detail::type_set<>;
using _required_tables = detail::type_set<>;
using _provided_tables = detail::type_set<>; using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>;
using _required_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>; using _extra_tables = detail::type_set<>;
using _parameters = std::tuple<>;
using _tags = typename std::conditional<column_spec_can_be_null_t<_field_spec_t>::value, using _tags = typename std::conditional<column_spec_can_be_null_t<_field_spec_t>::value,
detail::type_set<tag::can_be_null>, detail::type_set<tag::can_be_null>,
detail::type_set<>>::type; detail::type_set<>>::type;

View File

@ -28,6 +28,7 @@
#define SQLPP_RESULT_ROW_H #define SQLPP_RESULT_ROW_H
#include <map> #include <map>
#include <sqlpp11/result_row_fwd.h>
#include <sqlpp11/field_spec.h> #include <sqlpp11/field_spec.h>
#include <sqlpp11/text.h> #include <sqlpp11/text.h>
#include <sqlpp11/detail/field_index_sequence.h> #include <sqlpp11/detail/field_index_sequence.h>
@ -265,6 +266,21 @@ namespace sqlpp
} }
} }
}; };
template<typename T>
struct is_static_result_row_impl
{
using type = std::false_type;
};
template<typename Db, typename... FieldSpecs>
struct is_static_result_row_impl<result_row_t<Db, FieldSpecs...>>
{
using type = std::true_type;
};
template<typename T>
using is_static_result_row_t = typename is_static_result_row_impl<T>::type;
} }
#endif #endif

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2013-2014, Roland Bock
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SQLPP_RESULT_ROW_FWD_H
#define SQLPP_RESULT_ROW_FWD_H
namespace sqlpp
{
template<typename Db, typename... FieldSpecs>
struct result_row_t;
template<typename Db, typename... FieldSpecs>
struct dynamic_result_row_t;
}
#endif

View File

@ -31,6 +31,7 @@
#include <sqlpp11/noop.h> #include <sqlpp11/noop.h>
#include <sqlpp11/connection.h> #include <sqlpp11/connection.h>
#include <sqlpp11/with.h>
#include <sqlpp11/select_flag_list.h> #include <sqlpp11/select_flag_list.h>
#include <sqlpp11/select_column_list.h> #include <sqlpp11/select_column_list.h>
#include <sqlpp11/from.h> #include <sqlpp11/from.h>
@ -69,6 +70,7 @@ namespace sqlpp
template<typename Database> template<typename Database>
using blank_select_t = statement_t<Database, using blank_select_t = statement_t<Database,
no_with_t,
select_t, select_t,
no_select_flag_list_t, no_select_flag_list_t,
no_select_column_list_t, no_select_column_list_t,

View File

@ -286,6 +286,7 @@ namespace sqlpp
template<typename AliasProvider> template<typename AliasProvider>
_alias_t<AliasProvider> as(const AliasProvider& aliasProvider) const _alias_t<AliasProvider> as(const AliasProvider& aliasProvider) const
{ {
consistency_check_t<_statement_t>::_();
static_assert(_statement_t::_can_be_used_as_table(), "statement cannot be used as table, e.g. due to missing tables"); static_assert(_statement_t::_can_be_used_as_table(), "statement cannot be used as table, e.g. due to missing tables");
static_assert(logic::none_t<is_multi_column_t<Columns>::value...>::value, "cannot use multi-columns in sub selects"); static_assert(logic::none_t<is_multi_column_t<Columns>::value...>::value, "cannot use multi-columns in sub selects");
return _table_t<AliasProvider>(_get_statement()).as(aliasProvider); return _table_t<AliasProvider>(_get_statement()).as(aliasProvider);
@ -340,7 +341,7 @@ namespace sqlpp
auto tuple_merge(Columns... columns) -> decltype(std::tuple_cat(as_tuple<Columns>::_(columns)...)) auto tuple_merge(Columns... columns) -> decltype(std::tuple_cat(as_tuple<Columns>::_(columns)...))
{ {
return std::tuple_cat(as_tuple<Columns>::_(columns)...); return std::tuple_cat(as_tuple<Columns>::_(columns)...);
}; }
template<typename Database, typename... Columns> template<typename Database, typename... Columns>
using make_select_column_list_t = using make_select_column_list_t =

View File

@ -31,6 +31,8 @@
namespace sqlpp namespace sqlpp
{ {
// FIXME: We might use field specs here (same as with cte)
//
// provide type information for sub-selects that are used as named expressions or tables // provide type information for sub-selects that are used as named expressions or tables
template<typename Select, typename NamedExpr> template<typename Select, typename NamedExpr>
struct select_column_spec_t struct select_column_spec_t

View File

@ -44,6 +44,17 @@ namespace sqlpp
template<typename Db, typename... Policies> template<typename Db, typename... Policies>
struct statement_t; struct statement_t;
struct assert_no_unknown_ctes_t
{
using type = std::false_type;
template<typename T = void>
static void _()
{
static_assert(wrong_t<T>::value, "one clause requires common table expressions which are otherwise not known in the statement");
}
};
struct assert_no_unknown_tables_t struct assert_no_unknown_tables_t
{ {
using type = std::false_type; using type = std::false_type;
@ -84,6 +95,8 @@ namespace sqlpp
template<typename Needle, typename Replacement> template<typename Needle, typename Replacement>
using _new_statement_t = typename _policies_update_t<Needle, Replacement>::type; using _new_statement_t = typename _policies_update_t<Needle, Replacement>::type;
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_required_tables = detail::make_joined_set_t<required_tables_of<Policies>...>; using _all_required_tables = detail::make_joined_set_t<required_tables_of<Policies>...>;
using _all_provided_tables = detail::make_joined_set_t<provided_tables_of<Policies>...>; using _all_provided_tables = detail::make_joined_set_t<provided_tables_of<Policies>...>;
using _all_provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of<Policies>...>; using _all_provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of<Policies>...>;
@ -94,12 +107,21 @@ namespace sqlpp
template<typename Expression> template<typename Expression>
using _no_unknown_tables = detail::is_subset_of<required_tables_of<Expression>, _known_tables>; using _no_unknown_tables = detail::is_subset_of<required_tables_of<Expression>, _known_tables>;
template<template<typename> class Predicate>
using any_t = logic::any_t<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< using _required_tables = detail::make_difference_set_t<
_all_required_tables, _all_required_tables,
_all_provided_tables // Hint: extra_tables are not used here because they are just a helper for dynamic .add_*() _all_provided_tables // Hint: extra_tables are not used here because they are just a helper for dynamic .add_*()
>; >;
// The common table expressions not covered by the with.
using _required_ctes = detail::make_difference_set_t<
_all_required_ctes,
_all_provided_ctes
>;
using _result_type_provider = detail::get_last_if<is_return_value_t, noop, Policies...>; using _result_type_provider = detail::get_last_if<is_return_value_t, noop, Policies...>;
struct _result_methods_t: public _result_type_provider::template _result_methods_t<_statement_t> struct _result_methods_t: public _result_type_provider::template _result_methods_t<_statement_t>
@ -108,10 +130,12 @@ namespace sqlpp
// A select can be used as a pseudo table if // A select can be used as a pseudo table if
// - at least one column is selected // - at least one column is selected
// - the select is complete (leaks no tables) // - the select is complete (leaks no table requirements)
static constexpr bool _can_be_used_as_table() static constexpr bool _can_be_used_as_table()
{ {
return is_select_column_list_t<_result_type_provider>::value and _required_tables::size::value == 0 return has_result_row_t<_statement_t>::value
and _required_tables::size::value == 0
and _all_provided_ctes::size::value == 0 // a sub-select must not contain a WITH
? true ? true
: false; : false;
} }
@ -133,6 +157,8 @@ namespace sqlpp
struct _recursive_traits struct _recursive_traits
{ {
using _required_ctes = statement_policies_t::_required_ctes;
using _provided_ctes = detail::type_set<>;
using _required_tables = statement_policies_t::_required_tables; using _required_tables = statement_policies_t::_required_tables;
using _provided_tables = detail::type_set<>; using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>;
@ -143,6 +169,8 @@ namespace sqlpp
detail::type_set<>>::type; detail::type_set<>>::type;
}; };
using _cte_check = typename std::conditional<_required_ctes::size::value == 0,
consistent_t, assert_no_unknown_ctes_t>::type;
using _table_check = typename std::conditional<_required_tables::size::value == 0, using _table_check = typename std::conditional<_required_tables::size::value == 0,
consistent_t, assert_no_unknown_tables_t>::type; consistent_t, assert_no_unknown_tables_t>::type;
using _parameter_check = typename std::conditional<std::tuple_size<typename _recursive_traits::_parameters>::value == 0, using _parameter_check = typename std::conditional<std::tuple_size<typename _recursive_traits::_parameters>::value == 0,
@ -158,13 +186,15 @@ namespace sqlpp
{ {
using _policies_t = typename detail::statement_policies_t<Db, Policies...>; using _policies_t = typename detail::statement_policies_t<Db, Policies...>;
using _run_check = detail::get_first_if<is_inconsistent_t, consistent_t, using _consistency_check = detail::get_first_if<is_inconsistent_t, consistent_t,
typename _policies_t::_parameter_check,
typename Policies::template _base_t<_policies_t>::_consistency_check..., typename Policies::template _base_t<_policies_t>::_consistency_check...,
typename _policies_t::_table_check>; typename _policies_t::_table_check>;
using _prepare_check = detail::get_first_if<is_inconsistent_t, consistent_t, using _prepare_check = detail::get_first_if<is_inconsistent_t, consistent_t,
typename Policies::template _base_t<_policies_t>::_consistency_check..., typename _policies_t::_cte_check,
typename _policies_t::_table_check>; _consistency_check>;
using _run_check = detail::get_first_if<is_inconsistent_t, consistent_t,
typename _policies_t::_parameter_check,
_prepare_check>;
using _result_type_provider = typename _policies_t::_result_type_provider; using _result_type_provider = typename _policies_t::_result_type_provider;
template<typename Composite> template<typename Composite>

View File

@ -48,11 +48,13 @@ namespace sqlpp
struct _recursive_traits struct _recursive_traits
{ {
using _parameters = std::tuple<>; using _required_ctes = detail::type_set<>;
using _provided_ctes = detail::type_set<>;
using _required_tables = detail::type_set<>; using _required_tables = detail::type_set<>;
using _provided_tables = detail::type_set<Table>; using _provided_tables = detail::type_set<Table>;
using _provided_outer_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>; using _extra_tables = detail::type_set<>;
using _parameters = std::tuple<>;
using _tags = detail::type_set<>; using _tags = detail::type_set<>;
}; };

View File

@ -44,11 +44,13 @@ namespace sqlpp
struct _recursive_traits struct _recursive_traits
{ {
using _parameters = std::tuple<>; using _required_ctes = required_ctes_of<Table>;
using _provided_ctes = detail::type_set<>;
using _required_tables = detail::type_set<>; using _required_tables = detail::type_set<>;
using _provided_tables = detail::type_set<AliasProvider>; using _provided_tables = detail::type_set<AliasProvider>;
using _provided_outer_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>; using _extra_tables = detail::type_set<>;
using _parameters = std::tuple<>;
using _tags = detail::type_set<>; using _tags = detail::type_set<>;
}; };

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2013-2014, Roland Bock
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SQLPP_TABLE_REF_H
#define SQLPP_TABLE_REF_H
#include <utility>
namespace sqlpp
{
template<typename T>
auto from_table(T t) -> T
{
return t;
}
template<typename T>
struct from_table_impl
{
using type = T;
};
template<typename T>
using from_table_t = typename from_table_impl<T>::type;
template<typename T>
auto table_ref(T t) -> T
{
return t;
}
}
#endif

View File

@ -90,7 +90,7 @@ namespace sqlpp
transaction_t<Db> start_transaction(Db& db, bool report_unfinished_transaction = report_auto_rollback) transaction_t<Db> start_transaction(Db& db, bool report_unfinished_transaction = report_auto_rollback)
{ {
return { db, report_unfinished_transaction }; return { db, report_unfinished_transaction };
}; }
} }
#endif #endif

View File

@ -39,7 +39,7 @@ namespace sqlpp
{ {
struct can_be_null{}; struct can_be_null{};
struct contains_aggregate_function{}; struct contains_aggregate_function{};
}; }
namespace detail namespace detail
{ {
@ -74,7 +74,7 @@ namespace sqlpp
namespace tag namespace tag
{ {
struct is_expression{}; struct is_expression{};
}; }
namespace detail namespace detail
{ {
template<typename T, typename Enable = void> template<typename T, typename Enable = void>
@ -92,7 +92,7 @@ namespace sqlpp
namespace tag\ namespace tag\
{\ {\
struct name{};\ struct name{};\
};\ }\
namespace detail\ namespace detail\
{\ {\
template<typename T, typename Enable = void>\ template<typename T, typename Enable = void>\
@ -103,68 +103,71 @@ namespace sqlpp
template<typename T>\ template<typename T>\
using name##_t = typename detail::name##_impl<T>::type; using name##_t = typename detail::name##_impl<T>::type;
SQLPP_VALUE_TRAIT_GENERATOR(is_value_type); SQLPP_VALUE_TRAIT_GENERATOR(is_value_type)
SQLPP_VALUE_TRAIT_GENERATOR(is_sql_null); SQLPP_VALUE_TRAIT_GENERATOR(is_sql_null)
SQLPP_VALUE_TRAIT_GENERATOR(is_boolean); SQLPP_VALUE_TRAIT_GENERATOR(is_boolean)
SQLPP_VALUE_TRAIT_GENERATOR(is_integral); SQLPP_VALUE_TRAIT_GENERATOR(is_integral)
SQLPP_VALUE_TRAIT_GENERATOR(is_floating_point); SQLPP_VALUE_TRAIT_GENERATOR(is_floating_point)
template<typename T> template<typename T>
using is_numeric_t = logic::any_t< using is_numeric_t = logic::any_t<
detail::is_element_of<tag::is_integral, typename T::_traits::_tags>::value, detail::is_element_of<tag::is_integral, typename T::_traits::_tags>::value,
detail::is_element_of<tag::is_floating_point, typename T::_traits::_tags>::value>; detail::is_element_of<tag::is_floating_point, typename T::_traits::_tags>::value>;
SQLPP_VALUE_TRAIT_GENERATOR(is_text);
SQLPP_VALUE_TRAIT_GENERATOR(is_wrapped_value);
SQLPP_VALUE_TRAIT_GENERATOR(is_selectable);
SQLPP_VALUE_TRAIT_GENERATOR(is_multi_expression);
SQLPP_VALUE_TRAIT_GENERATOR(is_alias);
SQLPP_VALUE_TRAIT_GENERATOR(is_select_flag);
SQLPP_VALUE_TRAIT_GENERATOR(is_result_field);
SQLPP_VALUE_TRAIT_GENERATOR(must_not_insert); SQLPP_VALUE_TRAIT_GENERATOR(is_text)
SQLPP_VALUE_TRAIT_GENERATOR(must_not_update); SQLPP_VALUE_TRAIT_GENERATOR(is_wrapped_value)
SQLPP_VALUE_TRAIT_GENERATOR(require_insert); SQLPP_VALUE_TRAIT_GENERATOR(is_selectable)
SQLPP_VALUE_TRAIT_GENERATOR(trivial_value_is_null); SQLPP_VALUE_TRAIT_GENERATOR(is_multi_expression)
SQLPP_VALUE_TRAIT_GENERATOR(null_is_trivial_value); SQLPP_VALUE_TRAIT_GENERATOR(is_alias)
SQLPP_VALUE_TRAIT_GENERATOR(is_select_flag)
SQLPP_VALUE_TRAIT_GENERATOR(is_result_field)
SQLPP_VALUE_TRAIT_GENERATOR(is_statement); SQLPP_VALUE_TRAIT_GENERATOR(must_not_insert)
SQLPP_VALUE_TRAIT_GENERATOR(is_prepared_statement); SQLPP_VALUE_TRAIT_GENERATOR(must_not_update)
SQLPP_VALUE_TRAIT_GENERATOR(is_noop); SQLPP_VALUE_TRAIT_GENERATOR(require_insert)
SQLPP_VALUE_TRAIT_GENERATOR(is_missing); SQLPP_VALUE_TRAIT_GENERATOR(trivial_value_is_null)
SQLPP_VALUE_TRAIT_GENERATOR(is_return_value); SQLPP_VALUE_TRAIT_GENERATOR(null_is_trivial_value)
SQLPP_VALUE_TRAIT_GENERATOR(is_table);
SQLPP_VALUE_TRAIT_GENERATOR(is_join);
SQLPP_VALUE_TRAIT_GENERATOR(is_pseudo_table);
SQLPP_VALUE_TRAIT_GENERATOR(is_column);
SQLPP_VALUE_TRAIT_GENERATOR(is_select);
SQLPP_VALUE_TRAIT_GENERATOR(is_select_flag_list);
SQLPP_VALUE_TRAIT_GENERATOR(is_select_column_list);
SQLPP_VALUE_TRAIT_GENERATOR(is_from);
SQLPP_VALUE_TRAIT_GENERATOR(is_single_table);
SQLPP_VALUE_TRAIT_GENERATOR(is_into);
SQLPP_VALUE_TRAIT_GENERATOR(is_extra_tables);
SQLPP_VALUE_TRAIT_GENERATOR(is_on);
SQLPP_VALUE_TRAIT_GENERATOR(is_where);
SQLPP_VALUE_TRAIT_GENERATOR(is_group_by);
SQLPP_VALUE_TRAIT_GENERATOR(is_having);
SQLPP_VALUE_TRAIT_GENERATOR(is_order_by);
SQLPP_VALUE_TRAIT_GENERATOR(is_limit);
SQLPP_VALUE_TRAIT_GENERATOR(is_offset);
SQLPP_VALUE_TRAIT_GENERATOR(is_union);
SQLPP_VALUE_TRAIT_GENERATOR(is_using_);
SQLPP_VALUE_TRAIT_GENERATOR(is_column_list);
SQLPP_VALUE_TRAIT_GENERATOR(is_multi_column);
SQLPP_VALUE_TRAIT_GENERATOR(is_value_list);
SQLPP_VALUE_TRAIT_GENERATOR(is_assignment);
SQLPP_VALUE_TRAIT_GENERATOR(is_update_list);
SQLPP_VALUE_TRAIT_GENERATOR(is_insert_list);
SQLPP_VALUE_TRAIT_GENERATOR(is_insert_value);
SQLPP_VALUE_TRAIT_GENERATOR(is_insert_value_list);
SQLPP_VALUE_TRAIT_GENERATOR(is_sort_order);
SQLPP_VALUE_TRAIT_GENERATOR(is_parameter);
SQLPP_VALUE_TRAIT_GENERATOR(requires_braces); SQLPP_VALUE_TRAIT_GENERATOR(is_statement)
SQLPP_VALUE_TRAIT_GENERATOR(is_prepared_statement)
SQLPP_VALUE_TRAIT_GENERATOR(is_union)
SQLPP_VALUE_TRAIT_GENERATOR(is_with)
SQLPP_VALUE_TRAIT_GENERATOR(is_cte)
SQLPP_VALUE_TRAIT_GENERATOR(is_noop)
SQLPP_VALUE_TRAIT_GENERATOR(is_missing)
SQLPP_VALUE_TRAIT_GENERATOR(is_return_value)
SQLPP_VALUE_TRAIT_GENERATOR(is_table)
SQLPP_VALUE_TRAIT_GENERATOR(is_join)
SQLPP_VALUE_TRAIT_GENERATOR(is_pseudo_table)
SQLPP_VALUE_TRAIT_GENERATOR(is_column)
SQLPP_VALUE_TRAIT_GENERATOR(is_select)
SQLPP_VALUE_TRAIT_GENERATOR(is_select_flag_list)
SQLPP_VALUE_TRAIT_GENERATOR(is_select_column_list)
SQLPP_VALUE_TRAIT_GENERATOR(is_from)
SQLPP_VALUE_TRAIT_GENERATOR(is_single_table)
SQLPP_VALUE_TRAIT_GENERATOR(is_into)
SQLPP_VALUE_TRAIT_GENERATOR(is_extra_tables)
SQLPP_VALUE_TRAIT_GENERATOR(is_on)
SQLPP_VALUE_TRAIT_GENERATOR(is_where)
SQLPP_VALUE_TRAIT_GENERATOR(is_group_by)
SQLPP_VALUE_TRAIT_GENERATOR(is_having)
SQLPP_VALUE_TRAIT_GENERATOR(is_order_by)
SQLPP_VALUE_TRAIT_GENERATOR(is_limit)
SQLPP_VALUE_TRAIT_GENERATOR(is_offset)
SQLPP_VALUE_TRAIT_GENERATOR(is_using_)
SQLPP_VALUE_TRAIT_GENERATOR(is_column_list)
SQLPP_VALUE_TRAIT_GENERATOR(is_multi_column)
SQLPP_VALUE_TRAIT_GENERATOR(is_value_list)
SQLPP_VALUE_TRAIT_GENERATOR(is_assignment)
SQLPP_VALUE_TRAIT_GENERATOR(is_update_list)
SQLPP_VALUE_TRAIT_GENERATOR(is_insert_list)
SQLPP_VALUE_TRAIT_GENERATOR(is_insert_value)
SQLPP_VALUE_TRAIT_GENERATOR(is_insert_value_list)
SQLPP_VALUE_TRAIT_GENERATOR(is_sort_order)
SQLPP_VALUE_TRAIT_GENERATOR(is_parameter)
SQLPP_VALUE_TRAIT_GENERATOR(enforce_null_result_treatment); SQLPP_VALUE_TRAIT_GENERATOR(requires_braces)
SQLPP_VALUE_TRAIT_GENERATOR(enforce_null_result_treatment)
template<typename Tag, bool Condition> template<typename Tag, bool Condition>
using tag_if = typename std::conditional<Condition, Tag, void>::type; using tag_if = typename std::conditional<Condition, Tag, void>::type;
@ -183,6 +186,12 @@ namespace sqlpp
template<typename T> template<typename T>
using cpp_value_type_of = typename value_type_of<T>::_cpp_value_type; using cpp_value_type_of = typename value_type_of<T>::_cpp_value_type;
template<typename T>
using required_ctes_of = typename T::_recursive_traits::_required_ctes;
template<typename T>
using provided_ctes_of = typename T::_recursive_traits::_provided_ctes;
template<typename T> template<typename T>
using required_tables_of = typename T::_recursive_traits::_required_tables; using required_tables_of = typename T::_recursive_traits::_required_tables;
@ -217,6 +226,8 @@ namespace sqlpp
template<typename... Arguments> template<typename... Arguments>
struct make_recursive_traits struct make_recursive_traits
{ {
using _required_ctes = detail::make_joined_set_t<required_ctes_of<Arguments>...>;
using _provided_ctes = detail::make_joined_set_t<provided_ctes_of<Arguments>...>;
using _required_tables = detail::make_joined_set_t<required_tables_of<Arguments>...>; using _required_tables = detail::make_joined_set_t<required_tables_of<Arguments>...>;
using _provided_tables = detail::make_joined_set_t<provided_tables_of<Arguments>...>; using _provided_tables = detail::make_joined_set_t<provided_tables_of<Arguments>...>;
using _provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of<Arguments>...>; using _provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of<Arguments>...>;
@ -228,6 +239,8 @@ namespace sqlpp
template<typename... Tags> template<typename... Tags>
struct recursive_tags struct recursive_tags
{ {
using _required_ctes = detail::type_set<>;
using _provided_ctes = detail::type_set<>;
using _required_tables = detail::type_set<>; using _required_tables = detail::type_set<>;
using _provided_tables = detail::type_set<>; using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>;
@ -269,7 +282,7 @@ namespace sqlpp
static void _() static void _()
{ {
static_assert(wrong_t<T>::value, "connection cannot run something that is neither statement nor prepared statement"); static_assert(wrong_t<T>::value, "connection cannot run something that is neither statement nor prepared statement");
}; }
}; };
struct assert_prepare_statement_t struct assert_prepare_statement_t
@ -280,9 +293,24 @@ namespace sqlpp
static void _() static void _()
{ {
static_assert(wrong_t<T>::value, "connection cannot prepare something that is not a statement"); static_assert(wrong_t<T>::value, "connection cannot prepare something that is not a statement");
}; }
}; };
template<typename T, typename Enable = void>
struct consistency_check
{
using type = assert_run_statement_or_prepared_t;
};
template<typename T>
struct consistency_check<T, typename std::enable_if<is_statement_t<T>::value or is_prepared_statement_t<T>::value>::type>
{
using type = typename T::_consistency_check;
};
template<typename T>
using consistency_check_t = typename consistency_check<T>::type;
template<typename T, typename Enable = void> template<typename T, typename Enable = void>
struct run_check struct run_check
{ {
@ -329,6 +357,57 @@ namespace sqlpp
template<typename Context, typename T> template<typename Context, typename T>
using serialize_check_t = typename serialize_check<Context, T>::type; using serialize_check_t = typename serialize_check<Context, T>::type;
template<typename Statement, typename Enable = void>
struct has_result_row_impl
{
using type = std::false_type;
};
template<typename Statement>
struct has_result_row_impl<Statement,
typename std::enable_if<
not wrong_t<typename Statement::template _result_methods_t<Statement>::template _result_row_t<void>>::value,
void>::type>
{
using type = std::true_type;
};
template<typename Statement>
using has_result_row_t = typename has_result_row_impl<Statement>::type;
template<typename Statement, typename Enable = void>
struct get_result_row_impl
{
using type = void;
};
template<typename Statement>
struct get_result_row_impl<Statement,
typename std::enable_if<
not wrong_t<typename Statement::template _result_methods_t<Statement>::template _result_row_t<void>>::value,
void>::type>
{
using type = typename Statement::template _result_methods_t<Statement>::template _result_row_t<void>;
};
template<typename Statement>
using get_result_row_t = typename get_result_row_impl<Statement>::type;
template<typename Statement, template<typename> class Predicate, typename Enable=void>
struct has_policy_impl
{
using type = std::false_type;
};
template<typename Statement, template<typename> class Predicate>
struct has_policy_impl<Statement, Predicate, typename std::enable_if<is_statement_t<Statement>::value>::type>
{
using type = std::true_type;
};
template<typename Statement, template<typename> class Predicate>
using has_policy_t = typename has_policy_impl<Statement, Predicate>::type;
} }
#endif #endif

View File

@ -27,53 +27,19 @@
#ifndef SQLPP_UNION_H #ifndef SQLPP_UNION_H
#define SQLPP_UNION_H #define SQLPP_UNION_H
#include <sqlpp11/union_data.h>
#include <sqlpp11/select_flags.h>
#include <sqlpp11/statement_fwd.h> #include <sqlpp11/statement_fwd.h>
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/parameter_list.h> #include <sqlpp11/parameter_list.h>
#include <sqlpp11/expression.h> #include <sqlpp11/expression.h>
#include <sqlpp11/interpret_tuple.h> #include <sqlpp11/interpret_tuple.h>
#include <sqlpp11/interpretable_list.h> #include <sqlpp11/interpretable_list.h>
#include <sqlpp11/result_row.h>
#include <sqlpp11/logic.h> #include <sqlpp11/logic.h>
namespace sqlpp namespace sqlpp
{ {
template<typename Statement, typename Enable = void>
struct has_result_row_impl
{
using type = std::false_type;
};
template<typename Statement>
struct has_result_row_impl<Statement,
typename std::enable_if<
not wrong_t<typename Statement::template _result_methods_t<Statement>::template _result_row_t<void>>::value,
void>::type>
{
using type = std::true_type;
};
template<typename Statement>
using has_result_row_t = typename has_result_row_impl<Statement>::type;
template<typename Statement, typename Enable = void>
struct get_result_row_impl
{
using type = void;
};
template<typename Statement>
struct get_result_row_impl<Statement,
typename std::enable_if<
not wrong_t<typename Statement::template _result_methods_t<Statement>::template _result_row_t<void>>::value,
void>::type>
{
using type = typename Statement::template _result_methods_t<Statement>::template _result_row_t<void>;
};
template<typename Statement>
using get_result_row_t = typename get_result_row_impl<Statement>::type;
struct no_union_t; struct no_union_t;
using blank_union_t = statement_t<void, using blank_union_t = statement_t<void,
@ -83,7 +49,7 @@ namespace sqlpp
template<bool, typename Union> template<bool, typename Union>
struct union_statement_impl struct union_statement_impl
{ {
using type = statement_t<void, Union>; using type = statement_t<void, Union, no_union_t>;
}; };
template<typename Union> template<typename Union>
@ -95,31 +61,11 @@ namespace sqlpp
template<bool Check, typename Union> template<bool Check, typename Union>
using union_statement_t = typename union_statement_impl<Check, Union>::type; using union_statement_t = typename union_statement_impl<Check, Union>::type;
// UNION DATA
template<typename Database, typename Flag, typename Lhs, typename Rhs>
struct union_data_t
{
union_data_t(Lhs lhs, Rhs rhs):
_lhs(lhs),
_rhs(rhs)
{}
union_data_t(const union_data_t&) = default;
union_data_t(union_data_t&&) = default;
union_data_t& operator=(const union_data_t&) = default;
union_data_t& operator=(union_data_t&&) = default;
~union_data_t() = default;
Lhs _lhs;
Rhs _rhs;
};
// UNION(EXPR) // UNION(EXPR)
template<typename Database, typename Flag, typename Lhs, typename Rhs> template<typename Database, typename Flag, typename Lhs, typename Rhs>
struct union_t struct union_t
{ {
using _traits = make_traits<no_value_t, tag::is_union, tag::is_select_column_list, tag::is_return_value>; using _traits = make_traits<no_value_t, tag::is_union, tag::is_return_value>;
using _recursive_traits = make_recursive_traits<Lhs, Rhs>; using _recursive_traits = make_recursive_traits<Lhs, Rhs>;
using _alias_t = struct{}; using _alias_t = struct{};
@ -145,9 +91,9 @@ namespace sqlpp
_impl_t<Policies>& operator()() { return union_; } _impl_t<Policies>& operator()() { return union_; }
const _impl_t<Policies>& operator()() const { return union_; } const _impl_t<Policies>& operator()() const { return union_; }
using _selected_columns_t = decltype(union_._data._lhs.selected_columns); using _selected_columns_t = typename std::decay<decltype(union_._data._lhs.get_selected_columns())>::type;
_selected_columns_t& get_selected_columns() { return union_._data._lhs.selected_columns;} _selected_columns_t& get_selected_columns() { return union_._data._lhs.get_selected_columns(); }
const _selected_columns_t& get_selected_columns() const { return union_._data._lhs.selected_columns; } const _selected_columns_t& get_selected_columns() const { return union_._data._lhs.get_selected_columns(); }
template<typename T> template<typename T>
static auto _get_member(T t) -> decltype(t.union_) static auto _get_member(T t) -> decltype(t.union_)
@ -155,7 +101,9 @@ namespace sqlpp
return t.union_; return t.union_;
} }
using _consistency_check = consistent_t; using _consistency_check = detail::get_first_if<is_inconsistent_t, consistent_t,
typename Lhs::_consistency_check,
typename Rhs::_consistency_check>;
}; };
template<typename Statement> template<typename Statement>
@ -197,7 +145,7 @@ namespace sqlpp
using _database_t = typename Policies::_database_t; using _database_t = typename Policies::_database_t;
template<typename... T> template<typename... T>
using _check = logic::all_t<is_statement_t<T>::value...>; // FIXME and consistent/runnable using _check = logic::all_t<is_statement_t<T>::value...>;
template<typename Check, typename T> template<typename Check, typename T>
using _new_statement_t = union_statement_t<Check::value, T>; using _new_statement_t = union_statement_t<Check::value, T>;
@ -209,9 +157,13 @@ namespace sqlpp
-> _new_statement_t<_check<Rhs>, union_t<void, distinct_t, derived_statement_t<Policies>, Rhs>> -> _new_statement_t<_check<Rhs>, union_t<void, distinct_t, derived_statement_t<Policies>, Rhs>>
{ {
static_assert(is_statement_t<Rhs>::value, "argument of union call has to be a statement"); static_assert(is_statement_t<Rhs>::value, "argument of union call has to be a statement");
static_assert(has_result_row_t<Rhs>::value, "argument of a union has to be a (complete) select statement"); static_assert(has_policy_t<Rhs, is_select_t>::value, "argument of union call has to be a select");
static_assert(has_result_row_t<derived_statement_t<Policies>>::value, "left hand side argument of a union has to be a (complete) select statement"); static_assert(has_result_row_t<Rhs>::value, "argument of a union has to be a complete select statement");
static_assert(std::is_same<get_result_row_t<derived_statement_t<Policies>>, get_result_row_t<Rhs>>::value, "both select statements in a union have to have the same result columns (type and name)"); static_assert(has_result_row_t<derived_statement_t<Policies>>::value, "left hand side argument of a union has to be a complete select statement or union");
using _result_row_t = get_result_row_t<Rhs>;
static_assert(std::is_same<get_result_row_t<derived_statement_t<Policies>>, _result_row_t>::value, "both arguments in a union have to have the same result columns (type and name)");
static_assert(is_static_result_row_t<_result_row_t>::value, "unions must not have dynamically added columns");
return _union_impl<void, distinct_t>(_check<derived_statement_t<Policies>, Rhs>{}, rhs); return _union_impl<void, distinct_t>(_check<derived_statement_t<Policies>, Rhs>{}, rhs);
} }
@ -221,10 +173,13 @@ namespace sqlpp
-> _new_statement_t<_check<Rhs>, union_t<void, all_t, derived_statement_t<Policies>, Rhs>> -> _new_statement_t<_check<Rhs>, union_t<void, all_t, derived_statement_t<Policies>, Rhs>>
{ {
static_assert(is_statement_t<Rhs>::value, "argument of union call has to be a statement"); static_assert(is_statement_t<Rhs>::value, "argument of union call has to be a statement");
static_assert(has_policy_t<Rhs, is_select_t>::value, "argument of union call has to be a select");
static_assert(has_result_row_t<Rhs>::value, "argument of a union has to be a (complete) select statement"); static_assert(has_result_row_t<Rhs>::value, "argument of a union has to be a (complete) select statement");
static_assert(has_result_row_t<derived_statement_t<Policies>>::value, "left hand side argument of a union has to be a (complete) select statement"); static_assert(has_result_row_t<derived_statement_t<Policies>>::value, "left hand side argument of a union has to be a (complete) select statement");
static_assert(std::is_same<get_result_row_t<derived_statement_t<Policies>>, get_result_row_t<Rhs>>::value, "both select statements in a union have to have the same result columns (type and name)");
using _result_row_t = get_result_row_t<Rhs>;
static_assert(std::is_same<get_result_row_t<derived_statement_t<Policies>>, _result_row_t>::value, "both arguments in a union have to have the same result columns (type and name)");
static_assert(is_static_result_row_t<_result_row_t>::value, "unions must not have dynamically added columns");
return _union_impl<void, all_t>(_check<derived_statement_t<Policies>, Rhs>{}, rhs); return _union_impl<void, all_t>(_check<derived_statement_t<Policies>, Rhs>{}, rhs);
} }
@ -245,26 +200,6 @@ namespace sqlpp
}; };
}; };
// Interpreters
template<typename Context, typename Database, typename Flag, typename Lhs, typename Rhs>
struct serializer_t<Context, union_data_t<Database, Flag, Lhs, Rhs>>
{
using _serialize_check = serialize_check_of<Context, Lhs, Rhs>;
using T = union_data_t<Database, Flag, Lhs, Rhs>;
static Context& _(const T& t, Context& context)
{
context << '(';
serialize(t._lhs, context);
context << ") UNION ";
serialize(Flag{}, context);
context << " (";
serialize(t._rhs, context);
context << ')';
return context;
}
};
} }
#endif #endif

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2013-2014, Roland Bock
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SQLPP_UNION_DATA_H
#define SQLPP_UNION_DATA_H
#include <sqlpp11/serializer.h>
namespace sqlpp
{
template<typename Database, typename Flag, typename Lhs, typename Rhs>
struct union_data_t
{
union_data_t(Lhs lhs, Rhs rhs):
_lhs(lhs),
_rhs(rhs)
{}
union_data_t(const union_data_t&) = default;
union_data_t(union_data_t&&) = default;
union_data_t& operator=(const union_data_t&) = default;
union_data_t& operator=(union_data_t&&) = default;
~union_data_t() = default;
Lhs _lhs;
Rhs _rhs;
};
// Interpreters
template<typename Context, typename Database, typename Flag, typename Lhs, typename Rhs>
struct serializer_t<Context, union_data_t<Database, Flag, Lhs, Rhs>>
{
using _serialize_check = serialize_check_of<Context, Lhs, Rhs>;
using T = union_data_t<Database, Flag, Lhs, Rhs>;
static Context& _(const T& t, Context& context)
{
context << '(';
serialize(t._lhs, context);
context << ") UNION ";
serialize(Flag{}, context);
context << " (";
serialize(t._rhs, context);
context << ')';
return context;
}
};
}
#endif

View File

@ -147,7 +147,7 @@ namespace sqlpp
static void _() static void _()
{ {
static_assert(wrong_t<T>::value, "update assignments required, i.e. set(...)"); static_assert(wrong_t<T>::value, "update assignments required, i.e. set(...)");
}; }
}; };
struct no_update_list_t struct no_update_list_t

View File

@ -192,7 +192,7 @@ namespace sqlpp
static_assert(not detail::has_duplicates<Args...>::value, "at least one duplicate argument detected in using()"); static_assert(not detail::has_duplicates<Args...>::value, "at least one duplicate argument detected in using()");
return { static_cast<const derived_statement_t<Policies>&>(*this), using_data_t<Database, Args...>{args...} }; return { static_cast<const derived_statement_t<Policies>&>(*this), using_data_t<Database, Args...>{args...} };
}; }
}; };
}; };

View File

@ -190,7 +190,7 @@ namespace sqlpp
static void _() static void _()
{ {
static_assert(wrong_t<T>::value, "where expression required, e.g. where(true)"); static_assert(wrong_t<T>::value, "where expression required, e.g. where(true)");
}; }
}; };
// NO WHERE YET // NO WHERE YET

196
include/sqlpp11/with.h Normal file
View File

@ -0,0 +1,196 @@
/*
* Copyright (c) 2013-2014, Roland Bock
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SQLPP_WITH_H
#define SQLPP_WITH_H
#include <sqlpp11/assignment.h>
#include <sqlpp11/column_fwd.h>
#include <sqlpp11/statement_fwd.h>
#include <sqlpp11/type_traits.h>
#include <sqlpp11/no_data.h>
#include <sqlpp11/policy_update.h>
#include <sqlpp11/parameter_list.h>
#include <sqlpp11/expression.h>
#include <sqlpp11/interpret_tuple.h>
#include <sqlpp11/interpretable_list.h>
#include <sqlpp11/logic.h>
#include <sqlpp11/cte.h>
namespace sqlpp
{
template<typename Database, typename... Expressions>
struct with_data_t
{
using _is_recursive = logic::any_t<Expressions::_is_recursive...>;
with_data_t(Expressions... expressions):
_expressions(expressions...)
{}
with_data_t(const with_data_t&) = default;
with_data_t(with_data_t&&) = default;
with_data_t& operator=(const with_data_t&) = default;
with_data_t& operator=(with_data_t&&) = default;
~with_data_t() = default;
std::tuple<Expressions...> _expressions;
};
template<typename Database, typename... Expressions>
struct with_t
{
using _traits = make_traits<no_value_t, tag::is_with>;
struct _recursive_traits
{
using _required_ctes = detail::type_set<>;
using _provided_ctes = detail::make_joined_set_t<required_ctes_of<Expressions>...>; // with provides common table expressions
using _required_tables = detail::type_set<>;
using _provided_tables = detail::type_set<>;
using _provided_outer_tables = detail::type_set<>;
using _extra_tables = detail::type_set<>;
using _parameters = detail::make_parameter_tuple_t<parameters_of<Expressions>...>;
using _tags = detail::type_set<>;
};
using _is_dynamic = is_database<Database>;
// Data
using _data_t = with_data_t<Database, Expressions...>;
// Member implementation with data and methods
template <typename Policies>
struct _impl_t
{
public:
_data_t _data;
};
// Base template to be inherited by the statement
template<typename Policies>
struct _base_t
{
using _data_t = with_data_t<Database, Expressions...>;
_impl_t<Policies> with;
_impl_t<Policies>& operator()() { return with; }
const _impl_t<Policies>& operator()() const { return with; }
template<typename T>
static auto _get_member(T t) -> decltype(t.with)
{
return t.with;
}
// FIXME: Need real checks here
using _consistency_check = consistent_t;
};
};
struct no_with_t
{
using _traits = make_traits<no_value_t, tag::is_with>;
using _recursive_traits = make_recursive_traits<>;
// Data
using _data_t = no_data_t;
// Member implementation with data and methods
template<typename Policies>
struct _impl_t
{
_data_t _data;
};
// Base template to be inherited by the statement
template<typename Policies>
struct _base_t
{
using _data_t = no_data_t;
_impl_t<Policies> no_with;
_impl_t<Policies>& operator()() { return no_with; }
const _impl_t<Policies>& operator()() const { return no_with; }
template<typename T>
static auto _get_member(T t) -> decltype(t.no_with)
{
return t.no_with;
}
using _consistency_check = consistent_t;
};
};
template<typename Database, typename... Expressions>
struct blank_with_t
{
with_data_t<Database, Expressions...> _data;
template<typename Statement>
auto operator()(Statement statement)
-> new_statement_t<true, typename Statement::_policies_t, no_with_t, with_t<Database, Expressions...>>
{
// FIXME need checks here
// check that no cte refers to any of the ctes to the right
return { statement, _data };
}
};
// Interpreters
template<typename Context, typename Database, typename... Expressions>
struct serializer_t<Context, with_data_t<Database, Expressions...>>
{
using _serialize_check = serialize_check_of<Context, Expressions...>;
using T = with_data_t<Database, Expressions...>;
static Context& _(const T& t, Context& context)
{
// FIXME: If there is a recursive CTE, add a "RECURSIVE" here
context << " WITH ";
if (T::_is_recursive::value)
context << "RECURSIVE ";
interpret_tuple(t._expressions, ',', context);
context << ' ';
return context;
}
};
template<typename... Expressions>
auto with(Expressions... cte)
-> blank_with_t<void, Expressions...>
{
static_assert(logic::all_t<is_cte_t<Expressions>::value...>::value, "at least one expression in with is not a common table expression");
static_assert(logic::none_t<is_alias_t<Expressions>::value...>::value, "at least one expression in with is an incomplete common table expression");
return { {cte...} };
}
}
#endif

View File

@ -19,6 +19,7 @@ endmacro ()
#build_and_run(Minimalistic) #build_and_run(Minimalistic)
#build_and_run(ResultTest) #build_and_run(ResultTest)
build_and_run(UnionTest) build_and_run(UnionTest)
build_and_run(WithTest)
# if you want to use the generator, you can do something like this: # if you want to use the generator, you can do something like this:
#find_package(PythonInterp REQUIRED) #find_package(PythonInterp REQUIRED)

View File

@ -33,7 +33,7 @@
#include <iostream> #include <iostream>
MockDb db = {}; MockDb db = {};
SQLPP_ALIAS_PROVIDER(kaesekuchen); SQLPP_ALIAS_PROVIDER(kaesekuchen)
int main() int main()
{ {

View File

@ -103,7 +103,7 @@ struct MockDbT: public sqlpp::connection
void next(ResultRow& result_row) void next(ResultRow& result_row)
{ {
result_row._invalidate(); result_row._invalidate();
}; }
}; };
// Directly executed statements start here // Directly executed statements start here

View File

@ -38,10 +38,10 @@ MockDb::_serializer_context_t printer;
namespace alias namespace alias
{ {
SQLPP_ALIAS_PROVIDER(a); SQLPP_ALIAS_PROVIDER(a)
SQLPP_ALIAS_PROVIDER(b); SQLPP_ALIAS_PROVIDER(b)
SQLPP_ALIAS_PROVIDER(left); SQLPP_ALIAS_PROVIDER(left)
SQLPP_ALIAS_PROVIDER(right); SQLPP_ALIAS_PROVIDER(right)
} }
int main() int main()

View File

@ -37,12 +37,17 @@ int main()
test::TabBar t; test::TabBar t;
test::TabFoo f; test::TabFoo f;
db(select(t.alpha).from(t).union_distinct(select(f.epsilon.as(t.alpha)).from(f))); db(select(t.alpha).from(t).where(true)
db(select(t.alpha).from(t).union_all(select(f.epsilon.as(t.alpha)).from(f))); .union_distinct(select(f.epsilon.as(t.alpha)).from(f).where(true)));
db(select(t.alpha).from(t).where(true)
.union_all(select(f.epsilon.as(t.alpha)).from(f).where(true)));
auto u = select(t.alpha).from(t).union_all(select(f.epsilon.as(t.alpha)).from(f)).as(sqlpp::alias::u); auto u = select(t.alpha).from(t).where(true).union_all(select(f.epsilon.as(t.alpha)).from(f).where(true)).as(sqlpp::alias::u);
db(select(all_of(u)).from(u).union_all(select(t.delta.as(t.alpha)).from(t))); db(select(all_of(u)).from(u).where(true).union_all(select(t.delta.as(t.alpha)).from(t).where(true)));
db(select(u.alpha).from(u).where(true).union_all(select(t.delta.as(t.alpha)).from(t).where(true)));
db(select(t.alpha).from(t).where(true).union_all(select(t.alpha).from(t).where(true)).union_all(select(t.alpha).from(t).where(true)));
return 0; return 0;
} }

52
tests/WithTest.cpp Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2013-2014, Roland Bock
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Sample.h"
#include "MockDb.h"
#include <sqlpp11/select.h>
#include <sqlpp11/alias_provider.h>
#include <iostream>
MockDb db;
MockDb::_serializer_context_t printer;
int main()
{
const auto t = test::TabBar{};
auto x = cte(sqlpp::x).as(select(all_of(t)).from(t));
db(with(x)(select(x.alpha).from(x).where(true)));
auto y0 = cte(sqlpp::y).as(select(all_of(t)).from(t));
auto y = y0.union_all(select(all_of(y0)).from(y0).where(false));
std::cout << serialize(y, printer).str() << std::endl; printer.reset();
std::cout << serialize(from_table(y), printer).str() << std::endl;
db(with(y)(select(y.alpha).from(y).where(true)));
return 0;
}