From 92e670118a63327f0b9190044158d66a02ea93cf Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 13 Jan 2015 21:53:29 +0100 Subject: [PATCH 01/24] Started to add common table expressions and 'with' --- include/sqlpp11/column.h | 6 +- include/sqlpp11/count.h | 2 + include/sqlpp11/cte.h | 61 ++++++++++ include/sqlpp11/extra_tables.h | 4 +- include/sqlpp11/join.h | 2 + include/sqlpp11/parameter.h | 6 +- include/sqlpp11/result_field_methods.h | 6 +- include/sqlpp11/select.h | 2 + include/sqlpp11/statement.h | 33 +++++- include/sqlpp11/table.h | 4 +- include/sqlpp11/table_alias.h | 4 +- include/sqlpp11/type_traits.h | 10 ++ include/sqlpp11/union.h | 3 +- include/sqlpp11/with.h | 158 +++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/WithTest.cpp | 40 +++++++ 16 files changed, 329 insertions(+), 13 deletions(-) create mode 100644 include/sqlpp11/cte.h create mode 100644 include/sqlpp11/with.h create mode 100644 tests/WithTest.cpp diff --git a/include/sqlpp11/column.h b/include/sqlpp11/column.h index 82d34183..83468e5b 100644 --- a/include/sqlpp11/column.h +++ b/include/sqlpp11/column.h @@ -54,11 +54,13 @@ namespace sqlpp 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_outer_tables = detail::type_set<>; - using _required_tables = detail::type_set
; using _extra_tables = detail::type_set<>; + using _parameters = std::tuple<>; using _tags = typename std::conditional::value, detail::type_set, detail::type_set<>>::type; diff --git a/include/sqlpp11/count.h b/include/sqlpp11/count.h index ffe74bc4..1403aa8b 100644 --- a/include/sqlpp11/count.h +++ b/include/sqlpp11/count.h @@ -41,6 +41,8 @@ namespace sqlpp using _traits = make_traits; struct _recursive_traits { + using _required_ctes = required_ctes_of; + using _provided_ctes = detail::type_set<>; using _required_tables = required_tables_of; using _provided_tables = provided_tables_of; using _provided_outer_tables = provided_outer_tables_of; diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h new file mode 100644 index 00000000..af31e09a --- /dev/null +++ b/include/sqlpp11/cte.h @@ -0,0 +1,61 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +namespace sqlpp +{ + template + struct pre_cte_t + { + template + auto as(Statement statement) + -> cte + { + // FIXME: Need to check stuff here. + return { statement }; + } + }; + + template + auto cte(const AliasProvider&) + -> pre_cte_t + { + return {}; + } + +} + +#endif diff --git a/include/sqlpp11/extra_tables.h b/include/sqlpp11/extra_tables.h index 884e1946..cd4e1068 100644 --- a/include/sqlpp11/extra_tables.h +++ b/include/sqlpp11/extra_tables.h @@ -54,11 +54,13 @@ namespace sqlpp using _traits = make_traits; struct _recursive_traits { - using _parameters = std::tuple<>; + using _required_ctes = detail::make_joined_set_t...>; + using _provided_ctes = detail::type_set<>; using _required_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>; using _provided_tables = detail::type_set<>; using _extra_tables = detail::type_set; + using _parameters = std::tuple<>; using _tags = detail::type_set<>; }; diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index 99dbcdd0..e4dcb97f 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -68,6 +68,8 @@ namespace sqlpp using _traits = make_traits; struct _recursive_traits { + using _required_ctes = detail::make_joined_set_t, required_ctes_of>; + using _provided_ctes = detail::type_set<>; using _required_tables = detail::make_joined_set_t, required_tables_of>; using _provided_tables = detail::make_joined_set_t, provided_tables_of>; using _provided_outer_tables = typename JoinType::template _provided_outer_tables; diff --git a/include/sqlpp11/parameter.h b/include/sqlpp11/parameter.h index b5daaabc..542a5cb1 100644 --- a/include/sqlpp11/parameter.h +++ b/include/sqlpp11/parameter.h @@ -40,11 +40,13 @@ namespace sqlpp using _traits = make_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_outer_tables = detail::type_set<>; - using _required_tables = detail::type_set<>; using _extra_tables = detail::type_set<>; + using _parameters = std::tuple; using _tags = detail::type_set; }; diff --git a/include/sqlpp11/result_field_methods.h b/include/sqlpp11/result_field_methods.h index 5829ba91..4ab50af9 100644 --- a/include/sqlpp11/result_field_methods.h +++ b/include/sqlpp11/result_field_methods.h @@ -83,11 +83,13 @@ namespace sqlpp 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_outer_tables = detail::type_set<>; - using _required_tables = detail::type_set<>; using _extra_tables = detail::type_set<>; + using _parameters = std::tuple<>; using _tags = typename std::conditional::value, detail::type_set, detail::type_set<>>::type; diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index b663c7d4..89506245 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -69,6 +70,7 @@ namespace sqlpp template using blank_select_t = statement_t struct statement_t; + struct assert_no_unknown_ctes_t + { + using type = std::false_type; + + template + static void _() + { + static_assert(wrong_t::value, "one clause requires common table expressions which are otherwise not known in the statement"); + } + }; + struct assert_no_unknown_tables_t { using type = std::false_type; @@ -84,6 +95,8 @@ namespace sqlpp template using _new_statement_t = typename _policies_update_t::type; + using _all_required_ctes = detail::make_joined_set_t...>; + using _all_provided_ctes = detail::make_joined_set_t...>; using _all_required_tables = detail::make_joined_set_t...>; using _all_provided_tables = detail::make_joined_set_t...>; using _all_provided_outer_tables = detail::make_joined_set_t...>; @@ -100,6 +113,12 @@ namespace sqlpp _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; struct _result_methods_t: public _result_type_provider::template _result_methods_t<_statement_t> @@ -111,7 +130,9 @@ namespace sqlpp // - the select is complete (leaks no tables) 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 is_select_column_list_t<_result_type_provider>::value + and _required_tables::size::value == 0 + and _required_ctes::size::value == 0 ? true : false; } @@ -133,6 +154,8 @@ namespace sqlpp 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 _provided_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>; @@ -143,6 +166,8 @@ namespace sqlpp 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, consistent_t, assert_no_unknown_tables_t>::type; using _parameter_check = typename std::conditional::value == 0, @@ -161,10 +186,12 @@ namespace sqlpp using _run_check = detail::get_first_if::_consistency_check..., - typename _policies_t::_table_check>; + typename _policies_t::_table_check, + typename _policies_t::_cte_check>; using _prepare_check = detail::get_first_if::_consistency_check..., - typename _policies_t::_table_check>; + typename _policies_t::_table_check, + typename _policies_t::_cte_check>; using _result_type_provider = typename _policies_t::_result_type_provider; template diff --git a/include/sqlpp11/table.h b/include/sqlpp11/table.h index b7bd5065..e5e6549c 100644 --- a/include/sqlpp11/table.h +++ b/include/sqlpp11/table.h @@ -48,11 +48,13 @@ namespace sqlpp 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_outer_tables = detail::type_set<>; using _extra_tables = detail::type_set<>; + using _parameters = std::tuple<>; using _tags = detail::type_set<>; }; diff --git a/include/sqlpp11/table_alias.h b/include/sqlpp11/table_alias.h index e7befef0..4985a875 100644 --- a/include/sqlpp11/table_alias.h +++ b/include/sqlpp11/table_alias.h @@ -44,11 +44,13 @@ namespace sqlpp struct _recursive_traits { - using _parameters = std::tuple<>; + using _required_ctes = required_ctes_of
; + 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 = std::tuple<>; using _tags = detail::type_set<>; }; diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 04ffc42a..4cf352ec 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -183,6 +183,12 @@ namespace sqlpp template using cpp_value_type_of = typename value_type_of::_cpp_value_type; + template + using required_ctes_of = typename T::_recursive_traits::_required_ctes; + + template + using provided_ctes_of = typename T::_recursive_traits::_provided_ctes; + template using required_tables_of = typename T::_recursive_traits::_required_tables; @@ -217,6 +223,8 @@ namespace sqlpp template struct make_recursive_traits { + using _required_ctes = detail::make_joined_set_t...>; + using _provided_ctes = detail::make_joined_set_t...>; using _required_tables = detail::make_joined_set_t...>; using _provided_tables = detail::make_joined_set_t...>; using _provided_outer_tables = detail::make_joined_set_t...>; @@ -228,6 +236,8 @@ namespace sqlpp template struct recursive_tags { + 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_outer_tables = detail::type_set<>; diff --git a/include/sqlpp11/union.h b/include/sqlpp11/union.h index 615321dc..56559421 100644 --- a/include/sqlpp11/union.h +++ b/include/sqlpp11/union.h @@ -83,7 +83,7 @@ namespace sqlpp template struct union_statement_impl { - using type = statement_t; + using type = statement_t; }; template @@ -208,6 +208,7 @@ namespace sqlpp auto union_distinct(Rhs rhs) const -> _new_statement_t<_check, union_t, Rhs>> { +#warning: make sure that Rhs is a select, not a uninon static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_result_row_t::value, "argument of a union has to be a (complete) select statement"); static_assert(has_result_row_t>::value, "left hand side argument of a union has to be a (complete) select statement"); diff --git a/include/sqlpp11/with.h b/include/sqlpp11/with.h new file mode 100644 index 00000000..4811c8d7 --- /dev/null +++ b/include/sqlpp11/with.h @@ -0,0 +1,158 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sqlpp +{ + template + struct with_data_t + { + 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; + interpretable_list_t _dynamic_expressions; + }; + + template + struct with_t + { + using _traits = make_traits; + using _recursive_traits = make_recursive_traits; + + using _is_dynamic = is_database; + + // Data + using _data_t = with_data_t; + + // Member implementation with data and methods + template + struct _impl_t + { + public: + _data_t _data; + }; + + // Base template to be inherited by the statement + template + struct _base_t + { + using _data_t = with_data_t; + + _impl_t where; + _impl_t& operator()() { return where; } + const _impl_t& operator()() const { return where; } + + template + static auto _get_member(T t) -> decltype(t.where) + { + return t.where; + } + +#warning: Need real checks here + using _consistency_check = consistent_t; + }; + }; + + + struct no_with_t + { + using _traits = make_traits; + using _recursive_traits = make_recursive_traits<>; + + // Data + using _data_t = no_data_t; + + // Member implementation with data and methods + template + struct _impl_t + { + _data_t _data; + }; + + // Base template to be inherited by the statement + template + struct _base_t + { + using _data_t = no_data_t; + + _impl_t no_with; + _impl_t& operator()() { return no_with; } + const _impl_t& operator()() const { return no_with; } + + template + static auto _get_member(T t) -> decltype(t.no_with) + { + return t.no_with; + } + + using _consistency_check = consistent_t; + + }; + }; + + template + struct blank_with_t + { + with_data_t _data; + + template + auto operator()(Statement statement) + -> new_statement_t> + { + // FIXME need checks here, e.g. if there is recursion + return { statement, _data }; + } + }; + + template + auto with(Expressions... cte) + -> blank_with_t + { + return { {cte...} }; + } +} + +#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f3127acf..74505083 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,6 +19,7 @@ endmacro () #build_and_run(Minimalistic) #build_and_run(ResultTest) build_and_run(UnionTest) +build_and_run(WithTest) # if you want to use the generator, you can do something like this: #find_package(PythonInterp REQUIRED) diff --git a/tests/WithTest.cpp b/tests/WithTest.cpp new file mode 100644 index 00000000..6932966e --- /dev/null +++ b/tests/WithTest.cpp @@ -0,0 +1,40 @@ +/* + * 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 +#include +#include + +MockDb db; +MockDb::_serializer_context_t printer; + +int main() +{ + // to be done + + return 0; +} From 61b0bd9ff8fe9f64f8c2ec2443397cc6e84b3013 Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 15 Jan 2015 19:43:56 +0100 Subject: [PATCH 02/24] Can chain unions And a few more checks --- include/sqlpp11/select_column_list.h | 1 + include/sqlpp11/statement.h | 18 +++++----- include/sqlpp11/type_traits.h | 51 ++++++++++++++++++++++++++++ include/sqlpp11/union.h | 50 +++++---------------------- tests/UnionTest.cpp | 13 ++++--- 5 files changed, 79 insertions(+), 54 deletions(-) diff --git a/include/sqlpp11/select_column_list.h b/include/sqlpp11/select_column_list.h index 76a61c76..727e7513 100644 --- a/include/sqlpp11/select_column_list.h +++ b/include/sqlpp11/select_column_list.h @@ -286,6 +286,7 @@ namespace sqlpp template _alias_t as(const AliasProvider& aliasProvider) const { + run_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(logic::none_t::value...>::value, "cannot use multi-columns in sub selects"); return _table_t(_get_statement()).as(aliasProvider); diff --git a/include/sqlpp11/statement.h b/include/sqlpp11/statement.h index 02aaca64..3b4f5b56 100644 --- a/include/sqlpp11/statement.h +++ b/include/sqlpp11/statement.h @@ -107,6 +107,9 @@ namespace sqlpp template using _no_unknown_tables = detail::is_subset_of, _known_tables>; + template class Predicate> + using any_t = logic::any_t::value...>; + // The tables not covered by the from. using _required_tables = detail::make_difference_set_t< _all_required_tables, @@ -130,7 +133,7 @@ namespace sqlpp // - the select is complete (leaks no tables) static constexpr bool _can_be_used_as_table() { - return is_select_column_list_t<_result_type_provider>::value + return has_result_row_t<_statement_t>::value and _required_tables::size::value == 0 and _required_ctes::size::value == 0 ? true @@ -183,15 +186,14 @@ namespace sqlpp { using _policies_t = typename detail::statement_policies_t; + using _consistency_check = detail::get_first_if::_consistency_check..., + typename _policies_t::_table_check, + typename _policies_t::_cte_check>; using _run_check = detail::get_first_if::_consistency_check..., - typename _policies_t::_table_check, - typename _policies_t::_cte_check>; - using _prepare_check = detail::get_first_if::_consistency_check..., - typename _policies_t::_table_check, - typename _policies_t::_cte_check>; + _consistency_check>; + using _prepare_check = _consistency_check; using _result_type_provider = typename _policies_t::_result_type_provider; template diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 4cf352ec..31f6a68e 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -339,6 +339,57 @@ namespace sqlpp template using serialize_check_t = typename serialize_check::type; + template + struct has_result_row_impl + { + using type = std::false_type; + }; + + template + struct has_result_row_impl::template _result_row_t>::value, + void>::type> + { + using type = std::true_type; + }; + + template + using has_result_row_t = typename has_result_row_impl::type; + + template + struct get_result_row_impl + { + using type = void; + }; + + template + struct get_result_row_impl::template _result_row_t>::value, + void>::type> + { + using type = typename Statement::template _result_methods_t::template _result_row_t; + }; + + template + using get_result_row_t = typename get_result_row_impl::type; + + template class Predicate, typename Enable=void> + struct has_policy_impl + { + using type = std::false_type; + }; + + template class Predicate> + struct has_policy_impl::value>::type> + { + using type = std::true_type; + }; + + template class Predicate> + using has_policy_t = typename has_policy_impl::type; + } #endif diff --git a/include/sqlpp11/union.h b/include/sqlpp11/union.h index 56559421..d68ab63b 100644 --- a/include/sqlpp11/union.h +++ b/include/sqlpp11/union.h @@ -37,42 +37,6 @@ namespace sqlpp { - template - struct has_result_row_impl - { - using type = std::false_type; - }; - - template - struct has_result_row_impl::template _result_row_t>::value, - void>::type> - { - using type = std::true_type; - }; - - template - using has_result_row_t = typename has_result_row_impl::type; - - template - struct get_result_row_impl - { - using type = void; - }; - - template - struct get_result_row_impl::template _result_row_t>::value, - void>::type> - { - using type = typename Statement::template _result_methods_t::template _result_row_t; - }; - - template - using get_result_row_t = typename get_result_row_impl::type; - struct no_union_t; @@ -119,7 +83,7 @@ namespace sqlpp template struct union_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits; using _alias_t = struct{}; @@ -145,9 +109,9 @@ namespace sqlpp _impl_t& operator()() { return union_; } const _impl_t& operator()() const { return union_; } - using _selected_columns_t = decltype(union_._data._lhs.selected_columns); - _selected_columns_t& get_selected_columns() { return union_._data._lhs.selected_columns;} - const _selected_columns_t& get_selected_columns() const { return union_._data._lhs.selected_columns; } + using _selected_columns_t = typename std::decay::type; + _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.get_selected_columns(); } template static auto _get_member(T t) -> decltype(t.union_) @@ -155,7 +119,9 @@ namespace sqlpp return t.union_; } - using _consistency_check = consistent_t; + using _consistency_check = detail::get_first_if; }; template @@ -208,8 +174,8 @@ namespace sqlpp auto union_distinct(Rhs rhs) const -> _new_statement_t<_check, union_t, Rhs>> { -#warning: make sure that Rhs is a select, not a uninon static_assert(is_statement_t::value, "argument of union call has to be a statement"); + static_assert(has_policy_t::value, "argument of union call has to be a select"); static_assert(has_result_row_t::value, "argument of a union has to be a (complete) select statement"); static_assert(has_result_row_t>::value, "left hand side argument of a union has to be a (complete) select statement"); static_assert(std::is_same>, get_result_row_t>::value, "both select statements in a union have to have the same result columns (type and name)"); diff --git a/tests/UnionTest.cpp b/tests/UnionTest.cpp index b4462ded..ca88841c 100644 --- a/tests/UnionTest.cpp +++ b/tests/UnionTest.cpp @@ -37,12 +37,17 @@ int main() test::TabBar t; 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).union_all(select(f.epsilon.as(t.alpha)).from(f))); + db(select(t.alpha).from(t).where(true) + .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; } From 1fb83ed9fa62dfae6d5c87145444eb008758ed36 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 19 Jan 2015 07:26:04 +0100 Subject: [PATCH 03/24] Consistency < Prepare < Run Consistency: No missing table Prepare: No missing cte Run: No parameter --- include/sqlpp11/statement.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/sqlpp11/statement.h b/include/sqlpp11/statement.h index 3b4f5b56..8fe803d7 100644 --- a/include/sqlpp11/statement.h +++ b/include/sqlpp11/statement.h @@ -188,12 +188,13 @@ namespace sqlpp using _consistency_check = detail::get_first_if::_consistency_check..., - typename _policies_t::_table_check, - typename _policies_t::_cte_check>; + typename _policies_t::_table_check>; + using _prepare_check = detail::get_first_if; using _run_check = detail::get_first_if; - using _prepare_check = _consistency_check; + _prepare_check>; using _result_type_provider = typename _policies_t::_result_type_provider; template From 08de44e8a8053ac96c62fee5361a2abe80d27dae Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 19 Jan 2015 09:16:41 +0100 Subject: [PATCH 04/24] Union works with static results only --- include/sqlpp11/result_row.h | 15 +++++++++++++++ include/sqlpp11/union.h | 10 +++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index f9e21fcf..628edc76 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -265,6 +265,21 @@ namespace sqlpp } } }; + + template + struct is_static_result_row_impl + { + using type = std::false_type; + }; + + template + struct is_static_result_row_impl> + { + using type = std::true_type; + }; + + template + using is_static_result_row_t = typename is_static_result_row_impl::type; } #endif diff --git a/include/sqlpp11/union.h b/include/sqlpp11/union.h index d68ab63b..575f2b08 100644 --- a/include/sqlpp11/union.h +++ b/include/sqlpp11/union.h @@ -33,6 +33,7 @@ #include #include #include +#include #include namespace sqlpp @@ -176,9 +177,12 @@ namespace sqlpp { static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_policy_t::value, "argument of union call has to be a select"); - static_assert(has_result_row_t::value, "argument of a union has to be a (complete) select statement"); - static_assert(has_result_row_t>::value, "left hand side argument of a union has to be a (complete) select statement"); - static_assert(std::is_same>, get_result_row_t>::value, "both select statements in a union have to have the same result columns (type and name)"); + static_assert(has_result_row_t::value, "argument of a union has to be a complete select statement"); + static_assert(has_result_row_t>::value, "left hand side argument of a union has to be a complete select statement or union"); + static_assert(std::is_same>, get_result_row_t>::value, "both arguments in a union have to have the same result columns (type and name)"); + + using _result_row_t = get_result_row_t; + static_assert(is_static_result_row_t<_result_row_t>::value, "unions must not have dynamically added columns"); return _union_impl(_check, Rhs>{}, rhs); } From 4112448b5bcaed5140cd6a8f0b5c5499b1589f5c Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 19 Jan 2015 09:17:21 +0100 Subject: [PATCH 05/24] Some ideas --- include/sqlpp11/cte.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h index af31e09a..fb84e3c7 100644 --- a/include/sqlpp11/cte.h +++ b/include/sqlpp11/cte.h @@ -37,6 +37,10 @@ namespace sqlpp { +// The cte 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 struct pre_cte_t { From 12a0d9d6989018a5c8f78bbc9b99a479c5f7ef30 Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 27 Jan 2015 08:29:10 +0100 Subject: [PATCH 06/24] cte.h compiles --- include/sqlpp11/cte.h | 57 ++++++++++++++++++++++++++- include/sqlpp11/result_row.h | 1 + include/sqlpp11/result_row_fwd.h | 39 ++++++++++++++++++ include/sqlpp11/select_pseudo_table.h | 2 + include/sqlpp11/with.h | 3 ++ 5 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 include/sqlpp11/result_row_fwd.h diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h index fb84e3c7..7920a35b 100644 --- a/include/sqlpp11/cte.h +++ b/include/sqlpp11/cte.h @@ -27,6 +27,7 @@ #ifndef SQLPP_CTE_H #define SQLPP_CTE_H +#include #include #include #include @@ -37,6 +38,60 @@ namespace sqlpp { + template + struct cte_t; + + template + struct cte_column_spec_t + { + using _alias_t = typename FieldSpec::_alias_t; + + using _traits = make_traits, + tag::must_not_insert, + tag::must_not_update, + tag_if::value> + >; + }; + + template + struct make_cte_impl + { + using type = void; + }; + + template + struct make_cte_impl> + { + using type = cte_t...>; + }; + + template + using make_cte_t = typename make_cte_impl>::type; + + template + struct cte_t: public member_t>... // FIXME + { + using _alias_t = typename AliasProvider::_alias_t; + + Statement _statement; + }; + + template + struct serializer_t> + { + using _serialize_check = serialize_check_of; + using T = cte_t; + + static Context& _(const T& t, Context& context) + { + context << name_of::char_ptr() << " AS ("; + serialize(t._statement, context); + context << ")"; + return context; + } + }; + + // The cte is displayed as AliasProviderName except within the with: // - the with needs the // AliasProviderName AS (ColumnNames) (select/union) @@ -46,7 +101,7 @@ namespace sqlpp { template auto as(Statement statement) - -> cte + -> make_cte_t { // FIXME: Need to check stuff here. return { statement }; diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 628edc76..67574354 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -28,6 +28,7 @@ #define SQLPP_RESULT_ROW_H #include +#include #include #include #include diff --git a/include/sqlpp11/result_row_fwd.h b/include/sqlpp11/result_row_fwd.h new file mode 100644 index 00000000..8df5b4ed --- /dev/null +++ b/include/sqlpp11/result_row_fwd.h @@ -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 + struct result_row_t; + + template + struct dynamic_result_row_t; +} + +#endif diff --git a/include/sqlpp11/select_pseudo_table.h b/include/sqlpp11/select_pseudo_table.h index 7e50d87a..c4dbd3b4 100644 --- a/include/sqlpp11/select_pseudo_table.h +++ b/include/sqlpp11/select_pseudo_table.h @@ -31,6 +31,8 @@ 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 template struct select_column_spec_t diff --git a/include/sqlpp11/with.h b/include/sqlpp11/with.h index 4811c8d7..8700641c 100644 --- a/include/sqlpp11/with.h +++ b/include/sqlpp11/with.h @@ -37,6 +37,9 @@ #include #include + +#include + namespace sqlpp { template From d9bd5f1b5c3d7c97b082af27a2b3477f7a69dc1a Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 27 Jan 2015 08:30:00 +0100 Subject: [PATCH 07/24] Adjusted .clang-format --- .clang-format | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..f94da0a4 --- /dev/null +++ b/.clang-format @@ -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 From abfde5c9a7e7f013891d372c6c440442626a2fba Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 27 Jan 2015 18:27:33 +0100 Subject: [PATCH 08/24] Turned alias into an inline namespace which helps with ADL in cte --- include/sqlpp11/alias_provider.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sqlpp11/alias_provider.h b/include/sqlpp11/alias_provider.h index 266ec51e..ba07cf9f 100644 --- a/include/sqlpp11/alias_provider.h +++ b/include/sqlpp11/alias_provider.h @@ -62,7 +62,7 @@ namespace sqlpp static constexpr bool value = true; }; - namespace alias + inline namespace alias { SQLPP_ALIAS_PROVIDER(a); SQLPP_ALIAS_PROVIDER(b); From da9ca737883905b81236e2d2d22fd8cf362fa0c6 Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 27 Jan 2015 18:28:36 +0100 Subject: [PATCH 09/24] First test constructing a cte --- include/sqlpp11/cte.h | 9 ++++++++- tests/WithTest.cpp | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h index 7920a35b..34b33506 100644 --- a/include/sqlpp11/cte.h +++ b/include/sqlpp11/cte.h @@ -73,6 +73,13 @@ namespace sqlpp { using _alias_t = typename AliasProvider::_alias_t; + 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; }; @@ -92,7 +99,7 @@ namespace sqlpp }; -// The cte is displayed as AliasProviderName except within the with: +// 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 diff --git a/tests/WithTest.cpp b/tests/WithTest.cpp index 6932966e..6992458a 100644 --- a/tests/WithTest.cpp +++ b/tests/WithTest.cpp @@ -34,6 +34,9 @@ MockDb::_serializer_context_t printer; int main() { + const auto t = test::TabBar{}; + + auto x = cte(sqlpp::x).as(select(all_of(t)).from(t)); // to be done return 0; From 2adf529445710bbdd5a86a5c5ba1e3a9a557ee00 Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 29 Jan 2015 19:17:24 +0100 Subject: [PATCH 10/24] First with-query compiles --- include/sqlpp11/cte.h | 13 +++++++++++++ include/sqlpp11/type_traits.h | 2 ++ include/sqlpp11/with.h | 32 +++++++++++++++++++++++--------- tests/WithTest.cpp | 3 ++- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h index 34b33506..86aea573 100644 --- a/include/sqlpp11/cte.h +++ b/include/sqlpp11/cte.h @@ -71,6 +71,19 @@ namespace sqlpp template struct cte_t: public member_t>... // FIXME { + using _traits = make_traits; + struct _recursive_traits + { + using _required_ctes = required_ctes_of; + using _provided_ctes = detail::make_type_set_t; + using _required_tables = required_tables_of; + using _provided_tables = detail::type_set; + using _provided_outer_tables = detail::type_set<>; + using _extra_tables = detail::type_set<>; + using _parameters = parameters_of; + using _tags = detail::type_set<>; + }; + using _alias_t = typename AliasProvider::_alias_t; cte_t(Statement statement): _statement(statement){} diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 31f6a68e..e1f0239c 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -126,6 +126,8 @@ namespace sqlpp SQLPP_VALUE_TRAIT_GENERATOR(trivial_value_is_null); SQLPP_VALUE_TRAIT_GENERATOR(null_is_trivial_value); + SQLPP_VALUE_TRAIT_GENERATOR(is_with); + SQLPP_VALUE_TRAIT_GENERATOR(is_cte); SQLPP_VALUE_TRAIT_GENERATOR(is_statement); SQLPP_VALUE_TRAIT_GENERATOR(is_prepared_statement); SQLPP_VALUE_TRAIT_GENERATOR(is_noop); diff --git a/include/sqlpp11/with.h b/include/sqlpp11/with.h index 8700641c..63ecf249 100644 --- a/include/sqlpp11/with.h +++ b/include/sqlpp11/with.h @@ -56,13 +56,12 @@ namespace sqlpp ~with_data_t() = default; std::tuple _expressions; - interpretable_list_t _dynamic_expressions; }; template struct with_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits; using _is_dynamic = is_database; @@ -84,14 +83,14 @@ namespace sqlpp { using _data_t = with_data_t; - _impl_t where; - _impl_t& operator()() { return where; } - const _impl_t& operator()() const { return where; } + _impl_t with; + _impl_t& operator()() { return with; } + const _impl_t& operator()() const { return with; } template - static auto _get_member(T t) -> decltype(t.where) + static auto _get_member(T t) -> decltype(t.with) { - return t.where; + return t.with; } #warning: Need real checks here @@ -102,7 +101,7 @@ namespace sqlpp struct no_with_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits<>; // Data @@ -143,13 +142,28 @@ namespace sqlpp template auto operator()(Statement statement) - -> new_statement_t> + -> new_statement_t> { // FIXME need checks here, e.g. if there is recursion return { statement, _data }; } }; + // Interpreters + template + struct serializer_t> + { + using _serialize_check = serialize_check_of; + using T = with_data_t; + + static Context& _(const T& t, Context& context) + { + context << " WITH "; + interpret_tuple(t._expressions, ',', context); + return context; + } + }; + template auto with(Expressions... cte) -> blank_with_t diff --git a/tests/WithTest.cpp b/tests/WithTest.cpp index 6992458a..32b27ed4 100644 --- a/tests/WithTest.cpp +++ b/tests/WithTest.cpp @@ -37,7 +37,8 @@ int main() const auto t = test::TabBar{}; auto x = cte(sqlpp::x).as(select(all_of(t)).from(t)); - // to be done + + db(with(x)(select(x.alpha).from(x).where(true))); return 0; } From aa9c8dcfce406527d16b059d7444892d536b39ad Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 7 Feb 2015 14:42:29 +0100 Subject: [PATCH 11/24] A few FIXME's regarding remaining stuff for with clauses and ctes --- include/sqlpp11/cte.h | 7 ++++++- include/sqlpp11/with.h | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h index 86aea573..fd40f789 100644 --- a/include/sqlpp11/cte.h +++ b/include/sqlpp11/cte.h @@ -69,7 +69,7 @@ namespace sqlpp using make_cte_t = typename make_cte_impl>::type; template - struct cte_t: public member_t>... // FIXME + struct cte_t: public member_t>... { using _traits = make_traits; struct _recursive_traits @@ -84,6 +84,9 @@ namespace sqlpp using _tags = detail::type_set<>; }; + // FIXME: need a union_distinct and union_all here + // unions can depend on the cte itself In that case the cte is recursive. + using _alias_t = typename AliasProvider::_alias_t; cte_t(Statement statement): _statement(statement){} @@ -124,6 +127,8 @@ namespace sqlpp -> make_cte_t { // FIXME: Need to check stuff here. + // e.g. make sure that the statement does not require this a cte of this name (other ctes are allowed) + // make sure that the statement does not depend on external tables return { statement }; } }; diff --git a/include/sqlpp11/with.h b/include/sqlpp11/with.h index 63ecf249..95dd3e68 100644 --- a/include/sqlpp11/with.h +++ b/include/sqlpp11/with.h @@ -144,7 +144,8 @@ namespace sqlpp auto operator()(Statement statement) -> new_statement_t> { - // FIXME need checks here, e.g. if there is recursion + // FIXME need checks here + // check that no cte refers to any of the ctes to the right return { statement, _data }; } }; @@ -158,6 +159,7 @@ namespace sqlpp static Context& _(const T& t, Context& context) { + // FIXME: If there is a recursive CTE, add a "RECURSIVE" here context << " WITH "; interpret_tuple(t._expressions, ',', context); return context; From 25883fc8ea9b44892f4768c7f5112f3fdcaef9bc Mon Sep 17 00:00:00 2001 From: TyRoXx Date: Wed, 4 Feb 2015 21:34:46 +0100 Subject: [PATCH 12/24] enable -Wconversion and fix a warning --- CMakeLists.txt | 1 + examples/select.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b1116b7f..ded9a29d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "-std=c++11 -Wall ${CMAKE_CXX_FLAGS}") endif () +set(CMAKE_CXX_FLAGS "-Wconversion ${CMAKE_CXX_FLAGS}") set(include_dir "${PROJECT_SOURCE_DIR}/include") file(GLOB_RECURSE sqlpp_headers "${include_dir}/*.h") diff --git a/examples/select.cpp b/examples/select.cpp index 8b4317c2..9c3a767f 100644 --- a/examples/select.cpp +++ b/examples/select.cpp @@ -110,7 +110,7 @@ int main() .from(p.join(x).on(p.feature == x.cheesecake)) .where(true))) { - int id = row.id; + int64_t id = row.id; std::string name = row.name; std::string x_name = row.x.name; int cheesecake = row.x.cheesecake; From 3cef1a12179b84e35811c4d854cb32a14cdf3d84 Mon Sep 17 00:00:00 2001 From: TyRoXx Date: Wed, 4 Feb 2015 21:43:10 +0100 Subject: [PATCH 13/24] enable -Wpedantic and fix all the warnings Conflicts: examples/select.cpp include/sqlpp11/interpret_tuple.h include/sqlpp11/type_traits.h --- CMakeLists.txt | 2 +- examples/select.cpp | 2 +- include/sqlpp11/alias_provider.h | 54 +++++++------- include/sqlpp11/detail/pick_arg.h | 6 +- include/sqlpp11/interpret_tuple.h | 4 +- include/sqlpp11/transaction.h | 2 +- include/sqlpp11/type_traits.h | 119 +++++++++++++++--------------- include/sqlpp11/with.h | 2 +- tests/FunctionTest.cpp | 2 +- tests/MockDb.h | 2 +- tests/SelectTypeTest.cpp | 8 +- 11 files changed, 103 insertions(+), 100 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ded9a29d..69ca76f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "-std=c++11 -Wall ${CMAKE_CXX_FLAGS}") endif () -set(CMAKE_CXX_FLAGS "-Wconversion ${CMAKE_CXX_FLAGS}") +set(CMAKE_CXX_FLAGS "-Wconversion -Wpedantic ${CMAKE_CXX_FLAGS}") set(include_dir "${PROJECT_SOURCE_DIR}/include") file(GLOB_RECURSE sqlpp_headers "${include_dir}/*.h") diff --git a/examples/select.cpp b/examples/select.cpp index 9c3a767f..790fd96b 100644 --- a/examples/select.cpp +++ b/examples/select.cpp @@ -37,7 +37,7 @@ static constexpr bool some_condition = true; static constexpr bool some_other_condition = false; -SQLPP_ALIAS_PROVIDER(cheesecake); +SQLPP_ALIAS_PROVIDER(cheesecake) MockDb db; diff --git a/include/sqlpp11/alias_provider.h b/include/sqlpp11/alias_provider.h index ba07cf9f..57d501ca 100644 --- a/include/sqlpp11/alias_provider.h +++ b/include/sqlpp11/alias_provider.h @@ -64,33 +64,33 @@ namespace sqlpp inline namespace alias { - SQLPP_ALIAS_PROVIDER(a); - SQLPP_ALIAS_PROVIDER(b); - SQLPP_ALIAS_PROVIDER(c); - SQLPP_ALIAS_PROVIDER(d); - SQLPP_ALIAS_PROVIDER(e); - SQLPP_ALIAS_PROVIDER(f); - SQLPP_ALIAS_PROVIDER(g); - SQLPP_ALIAS_PROVIDER(h); - SQLPP_ALIAS_PROVIDER(i); - SQLPP_ALIAS_PROVIDER(j); - SQLPP_ALIAS_PROVIDER(k); - SQLPP_ALIAS_PROVIDER(l); - SQLPP_ALIAS_PROVIDER(m); - SQLPP_ALIAS_PROVIDER(n); - SQLPP_ALIAS_PROVIDER(o); - SQLPP_ALIAS_PROVIDER(p); - SQLPP_ALIAS_PROVIDER(q); - SQLPP_ALIAS_PROVIDER(s); - SQLPP_ALIAS_PROVIDER(t); - SQLPP_ALIAS_PROVIDER(u); - SQLPP_ALIAS_PROVIDER(v); - SQLPP_ALIAS_PROVIDER(w); - SQLPP_ALIAS_PROVIDER(x); - SQLPP_ALIAS_PROVIDER(y); - SQLPP_ALIAS_PROVIDER(z); - SQLPP_ALIAS_PROVIDER(left); - SQLPP_ALIAS_PROVIDER(right); + SQLPP_ALIAS_PROVIDER(a) + SQLPP_ALIAS_PROVIDER(b) + SQLPP_ALIAS_PROVIDER(c) + SQLPP_ALIAS_PROVIDER(d) + SQLPP_ALIAS_PROVIDER(e) + SQLPP_ALIAS_PROVIDER(f) + SQLPP_ALIAS_PROVIDER(g) + SQLPP_ALIAS_PROVIDER(h) + SQLPP_ALIAS_PROVIDER(i) + SQLPP_ALIAS_PROVIDER(j) + SQLPP_ALIAS_PROVIDER(k) + SQLPP_ALIAS_PROVIDER(l) + SQLPP_ALIAS_PROVIDER(m) + SQLPP_ALIAS_PROVIDER(n) + SQLPP_ALIAS_PROVIDER(o) + SQLPP_ALIAS_PROVIDER(p) + SQLPP_ALIAS_PROVIDER(q) + SQLPP_ALIAS_PROVIDER(s) + SQLPP_ALIAS_PROVIDER(t) + SQLPP_ALIAS_PROVIDER(u) + SQLPP_ALIAS_PROVIDER(v) + SQLPP_ALIAS_PROVIDER(w) + SQLPP_ALIAS_PROVIDER(x) + SQLPP_ALIAS_PROVIDER(y) + SQLPP_ALIAS_PROVIDER(z) + SQLPP_ALIAS_PROVIDER(left) + SQLPP_ALIAS_PROVIDER(right) } } diff --git a/include/sqlpp11/detail/pick_arg.h b/include/sqlpp11/detail/pick_arg.h index 10cd512b..6c922516 100644 --- a/include/sqlpp11/detail/pick_arg.h +++ b/include/sqlpp11/detail/pick_arg.h @@ -37,20 +37,20 @@ namespace sqlpp typename Target::_data_t pick_arg_impl(Statement statement, Term term, const std::true_type&) { return term; - }; + } template typename Target::_data_t pick_arg_impl(Statement statement, Term term, const std::false_type&) { return Target::_get_member(statement)._data; - }; + } // Returns a statement's term either by picking the term from the statement or using the new term template typename Target::_data_t pick_arg(Statement statement, Term term) { return pick_arg_impl(statement, term, std::is_same()); - }; + } } } diff --git a/include/sqlpp11/interpret_tuple.h b/include/sqlpp11/interpret_tuple.h index 36c047b7..a51a8288 100644 --- a/include/sqlpp11/interpret_tuple.h +++ b/include/sqlpp11/interpret_tuple.h @@ -54,7 +54,9 @@ namespace sqlpp // 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 using swallow = int[]; - (void) swallow{(interpret_tuple_element(std::get(t), separator, context, useBraces, Is), 0)...}; + (void) swallow{ + 0, //workaround against -Wpedantic GCC warning "zero-size array 'int [0]'" + (interpret_tuple_element(std::get(t), separator, context, useBraces, Is), 0)...}; return context; } diff --git a/include/sqlpp11/transaction.h b/include/sqlpp11/transaction.h index b0d456cc..c140d168 100644 --- a/include/sqlpp11/transaction.h +++ b/include/sqlpp11/transaction.h @@ -90,7 +90,7 @@ namespace sqlpp transaction_t start_transaction(Db& db, bool report_unfinished_transaction = report_auto_rollback) { return { db, report_unfinished_transaction }; - }; + } } #endif diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index e1f0239c..8dee9b18 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -39,7 +39,7 @@ namespace sqlpp { struct can_be_null{}; struct contains_aggregate_function{}; - }; + } namespace detail { @@ -74,7 +74,7 @@ namespace sqlpp namespace tag { struct is_expression{}; - }; + } namespace detail { template @@ -92,7 +92,7 @@ namespace sqlpp namespace tag\ {\ struct name{};\ - };\ + }\ namespace detail\ {\ template\ @@ -103,70 +103,71 @@ namespace sqlpp template\ using name##_t = typename detail::name##_impl::type; - SQLPP_VALUE_TRAIT_GENERATOR(is_value_type); - SQLPP_VALUE_TRAIT_GENERATOR(is_sql_null); - SQLPP_VALUE_TRAIT_GENERATOR(is_boolean); - SQLPP_VALUE_TRAIT_GENERATOR(is_integral); - SQLPP_VALUE_TRAIT_GENERATOR(is_floating_point); + SQLPP_VALUE_TRAIT_GENERATOR(is_value_type) + SQLPP_VALUE_TRAIT_GENERATOR(is_sql_null) + SQLPP_VALUE_TRAIT_GENERATOR(is_boolean) + SQLPP_VALUE_TRAIT_GENERATOR(is_integral) + SQLPP_VALUE_TRAIT_GENERATOR(is_floating_point) template using is_numeric_t = logic::any_t< detail::is_element_of::value, detail::is_element_of::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(must_not_update); - SQLPP_VALUE_TRAIT_GENERATOR(require_insert); - SQLPP_VALUE_TRAIT_GENERATOR(trivial_value_is_null); - SQLPP_VALUE_TRAIT_GENERATOR(null_is_trivial_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(is_with); - SQLPP_VALUE_TRAIT_GENERATOR(is_cte); - SQLPP_VALUE_TRAIT_GENERATOR(is_statement); - SQLPP_VALUE_TRAIT_GENERATOR(is_prepared_statement); - 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_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(must_not_insert) + SQLPP_VALUE_TRAIT_GENERATOR(must_not_update) + SQLPP_VALUE_TRAIT_GENERATOR(require_insert) + SQLPP_VALUE_TRAIT_GENERATOR(trivial_value_is_null) + SQLPP_VALUE_TRAIT_GENERATOR(null_is_trivial_value) - 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 using tag_if = typename std::conditional::type; diff --git a/include/sqlpp11/with.h b/include/sqlpp11/with.h index 95dd3e68..48a2e5c3 100644 --- a/include/sqlpp11/with.h +++ b/include/sqlpp11/with.h @@ -93,7 +93,7 @@ namespace sqlpp return t.with; } -#warning: Need real checks here + // FIXME: Need real checks here using _consistency_check = consistent_t; }; }; diff --git a/tests/FunctionTest.cpp b/tests/FunctionTest.cpp index b0026480..bde10db5 100644 --- a/tests/FunctionTest.cpp +++ b/tests/FunctionTest.cpp @@ -33,7 +33,7 @@ #include MockDb db = {}; -SQLPP_ALIAS_PROVIDER(kaesekuchen); +SQLPP_ALIAS_PROVIDER(kaesekuchen) int main() { diff --git a/tests/MockDb.h b/tests/MockDb.h index 567866d2..9ec072a1 100644 --- a/tests/MockDb.h +++ b/tests/MockDb.h @@ -103,7 +103,7 @@ struct MockDbT: public sqlpp::connection void next(ResultRow& result_row) { result_row._invalidate(); - }; + } }; // Directly executed statements start here diff --git a/tests/SelectTypeTest.cpp b/tests/SelectTypeTest.cpp index bd0e9be8..70f61811 100644 --- a/tests/SelectTypeTest.cpp +++ b/tests/SelectTypeTest.cpp @@ -38,10 +38,10 @@ MockDb::_serializer_context_t printer; namespace alias { - SQLPP_ALIAS_PROVIDER(a); - SQLPP_ALIAS_PROVIDER(b); - SQLPP_ALIAS_PROVIDER(left); - SQLPP_ALIAS_PROVIDER(right); + SQLPP_ALIAS_PROVIDER(a) + SQLPP_ALIAS_PROVIDER(b) + SQLPP_ALIAS_PROVIDER(left) + SQLPP_ALIAS_PROVIDER(right) } int main() From b60df812e1a86381f67f0900b4a3b2a93b4abe5c Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 8 Feb 2015 18:26:00 +0100 Subject: [PATCH 14/24] Split union data from union, to be used in ctes, as well --- include/sqlpp11/union.h | 47 +++-------------------- include/sqlpp11/union_data.h | 74 ++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 42 deletions(-) create mode 100644 include/sqlpp11/union_data.h diff --git a/include/sqlpp11/union.h b/include/sqlpp11/union.h index 575f2b08..b45d1930 100644 --- a/include/sqlpp11/union.h +++ b/include/sqlpp11/union.h @@ -27,6 +27,7 @@ #ifndef SQLPP_UNION_H #define SQLPP_UNION_H +#include #include #include #include @@ -38,7 +39,6 @@ namespace sqlpp { - struct no_union_t; using blank_union_t = statement_t using union_statement_t = typename union_statement_impl::type; - - // UNION DATA - template - 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) template struct union_t @@ -164,7 +144,7 @@ namespace sqlpp using _database_t = typename Policies::_database_t; template - using _check = logic::all_t::value...>; // FIXME and consistent/runnable + using _check = logic::all_t::value...>; template using _new_statement_t = union_statement_t; @@ -192,10 +172,13 @@ namespace sqlpp -> _new_statement_t<_check, union_t, Rhs>> { static_assert(is_statement_t::value, "argument of union call has to be a statement"); + static_assert(has_policy_t::value, "argument of union call has to be a select"); static_assert(has_result_row_t::value, "argument of a union has to be a (complete) select statement"); static_assert(has_result_row_t>::value, "left hand side argument of a union has to be a (complete) select statement"); static_assert(std::is_same>, get_result_row_t>::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; + static_assert(is_static_result_row_t<_result_row_t>::value, "unions must not have dynamically added columns"); return _union_impl(_check, Rhs>{}, rhs); } @@ -216,26 +199,6 @@ namespace sqlpp }; }; - // Interpreters - template - struct serializer_t> - { - using _serialize_check = serialize_check_of; - using T = union_data_t; - - 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 diff --git a/include/sqlpp11/union_data.h b/include/sqlpp11/union_data.h new file mode 100644 index 00000000..fd9bba32 --- /dev/null +++ b/include/sqlpp11/union_data.h @@ -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 + +namespace sqlpp +{ + template + 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 + struct serializer_t> + { + using _serialize_check = serialize_check_of; + using T = union_data_t; + + 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 From ee3d803c33d351ddc7bba4609616ab1308510d69 Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 8 Feb 2015 18:26:36 +0100 Subject: [PATCH 15/24] Added a few cte checks, fixed logic of requiring and providing ctes --- include/sqlpp11/cte.h | 42 +++++++++++++++++++++++++++++------ include/sqlpp11/type_traits.h | 2 +- include/sqlpp11/with.h | 13 ++++++++++- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h index fd40f789..5fa9c177 100644 --- a/include/sqlpp11/cte.h +++ b/include/sqlpp11/cte.h @@ -71,12 +71,12 @@ namespace sqlpp template struct cte_t: public member_t>... { - using _traits = make_traits; + using _traits = make_traits; // FIXME: is table? really? struct _recursive_traits { - using _required_ctes = required_ctes_of; - using _provided_ctes = detail::make_type_set_t; - using _required_tables = required_tables_of; + using _required_ctes = detail::make_joined_set_t, detail::make_type_set_t>; + 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<>; @@ -122,17 +122,45 @@ namespace sqlpp template struct pre_cte_t { + using _traits = make_traits; // FIXME: is table? really? + struct _recursive_traits + { + using _required_ctes = detail::make_type_set_t; + 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 = std::tuple<>; + using _tags = detail::type_set<>; + }; + + using _alias_t = typename AliasProvider::_alias_t; + template auto as(Statement statement) -> make_cte_t { - // FIXME: Need to check stuff here. - // e.g. make sure that the statement does not require this a cte of this name (other ctes are allowed) - // make sure that the statement does not depend on external tables + static_assert(required_tables_of::size::value == 0, "common table expression must not use unknown tables"); + static_assert(not detail::is_element_of>::value, "common table expression must not self-reference in the first part, use union_all/union_distinct for recursion"); + return { statement }; } }; + template + struct serializer_t> + { + using _serialize_check = consistent_t; + using T = pre_cte_t; + + static Context& _(const T& t, Context& context) + { + context << name_of::char_ptr(); + return context; + } + }; + template auto cte(const AliasProvider&) -> pre_cte_t diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 8dee9b18..d11fa9f7 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -227,7 +227,7 @@ namespace sqlpp struct make_recursive_traits { using _required_ctes = detail::make_joined_set_t...>; - using _provided_ctes = detail::make_joined_set_t...>; + using _provided_ctes = detail::make_joined_set_t...>; using _required_tables = detail::make_joined_set_t...>; using _provided_tables = detail::make_joined_set_t...>; using _provided_outer_tables = detail::make_joined_set_t...>; diff --git a/include/sqlpp11/with.h b/include/sqlpp11/with.h index 48a2e5c3..399c94d8 100644 --- a/include/sqlpp11/with.h +++ b/include/sqlpp11/with.h @@ -62,7 +62,18 @@ namespace sqlpp struct with_t { using _traits = make_traits; - using _recursive_traits = make_recursive_traits; + struct _recursive_traits + { + using _required_ctes = detail::type_set<>; + using _provided_ctes = detail::make_joined_set_t...>; // 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...>; + using _tags = detail::type_set<>; + }; + using _is_dynamic = is_database; From c4d77372cf97dc6ff3c3755e982e2b303da8e489 Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 8 Feb 2015 19:47:33 +0100 Subject: [PATCH 16/24] The first recursive cte compiles --- include/sqlpp11/cte.h | 66 ++++++++++++++++++++++++++++++++++------- include/sqlpp11/union.h | 5 ++-- tests/WithTest.cpp | 3 ++ 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h index 5fa9c177..76aa337e 100644 --- a/include/sqlpp11/cte.h +++ b/include/sqlpp11/cte.h @@ -27,7 +27,9 @@ #ifndef SQLPP_CTE_H #define SQLPP_CTE_H -#include +#include +#include +#include #include #include #include @@ -38,7 +40,7 @@ namespace sqlpp { - template + template struct cte_t; template @@ -49,7 +51,7 @@ namespace sqlpp using _traits = make_traits, tag::must_not_insert, tag::must_not_update, - tag_if::value> + tag_if::value> >; }; @@ -62,14 +64,14 @@ namespace sqlpp template struct make_cte_impl> { - using type = cte_t...>; + using type = cte_t; }; template using make_cte_t = typename make_cte_impl>::type; - template - struct cte_t: public member_t>... + template + struct cte_t: public member_t, column_t>>... { using _traits = make_traits; // FIXME: is table? really? struct _recursive_traits @@ -83,12 +85,55 @@ namespace sqlpp using _parameters = parameters_of; using _tags = detail::type_set<>; }; - - // FIXME: need a union_distinct and union_all here - // unions can depend on the cte itself In that case the cte is recursive. - using _alias_t = typename AliasProvider::_alias_t; + using _column_tuple_t = std::tuple>...>; + + template + using _check = logic::all_t::value...>; + + template + auto union_distinct(Rhs rhs) const + -> typename std::conditional<_check::value, cte_t, FieldSpecs...>, bad_statement>::type + { + static_assert(is_statement_t::value, "argument of union call has to be a statement"); + static_assert(has_policy_t::value, "argument of union call has to be a select"); + static_assert(has_result_row_t::value, "argument of a union has to be a (complete) select statement"); + + using _result_row_t = result_row_t; + static_assert(std::is_same<_result_row_t, get_result_row_t>::value, "both select statements in a union have to have the same result columns (type and name)"); + + return _union_impl(_check{}, rhs); + } + + template + auto union_all(Rhs rhs) const + -> typename std::conditional<_check::value, cte_t, FieldSpecs...>, bad_statement>::type + { + static_assert(is_statement_t::value, "argument of union call has to be a statement"); + static_assert(has_policy_t::value, "argument of union call has to be a select"); + static_assert(has_result_row_t::value, "argument of a union has to be a (complete) select statement"); + + using _result_row_t = result_row_t; + static_assert(std::is_same<_result_row_t, get_result_row_t>::value, "both select statements in a union have to have the same result columns (type and name)"); + + return _union_impl(_check{}, rhs); + } + + private: + template + auto _union_impl(const std::false_type&, Rhs rhs) const + -> bad_statement; + + template + auto _union_impl(const std::true_type&, Rhs rhs) const + -> cte_t, FieldSpecs...> + { + return union_data_t{_statement, rhs}; + } + + public: + cte_t(Statement statement): _statement(statement){} cte_t(const cte_t&) = default; cte_t(cte_t&&) = default; @@ -143,6 +188,7 @@ namespace sqlpp { static_assert(required_tables_of::size::value == 0, "common table expression must not use unknown tables"); static_assert(not detail::is_element_of>::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>::value, "ctes must not have dynamically added columns"); return { statement }; } diff --git a/include/sqlpp11/union.h b/include/sqlpp11/union.h index b45d1930..066e73e3 100644 --- a/include/sqlpp11/union.h +++ b/include/sqlpp11/union.h @@ -28,6 +28,7 @@ #define SQLPP_UNION_H #include +#include #include #include #include @@ -159,9 +160,9 @@ namespace sqlpp static_assert(has_policy_t::value, "argument of union call has to be a select"); static_assert(has_result_row_t::value, "argument of a union has to be a complete select statement"); static_assert(has_result_row_t>::value, "left hand side argument of a union has to be a complete select statement or union"); - static_assert(std::is_same>, get_result_row_t>::value, "both arguments in a union have to have the same result columns (type and name)"); using _result_row_t = get_result_row_t; + static_assert(std::is_same>, _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(_check, Rhs>{}, rhs); @@ -175,9 +176,9 @@ namespace sqlpp static_assert(has_policy_t::value, "argument of union call has to be a select"); static_assert(has_result_row_t::value, "argument of a union has to be a (complete) select statement"); static_assert(has_result_row_t>::value, "left hand side argument of a union has to be a (complete) select statement"); - static_assert(std::is_same>, get_result_row_t>::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; + static_assert(std::is_same>, _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(_check, Rhs>{}, rhs); diff --git a/tests/WithTest.cpp b/tests/WithTest.cpp index 32b27ed4..f6bd4006 100644 --- a/tests/WithTest.cpp +++ b/tests/WithTest.cpp @@ -40,5 +40,8 @@ int main() 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)); + return 0; } From 7e36281e5d3bf19dba9504558787ae52f3ed9abb Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 9 Feb 2015 07:36:53 +0100 Subject: [PATCH 17/24] Fixed a few stray semicolons --- include/sqlpp11/select_column_list.h | 2 +- include/sqlpp11/type_traits.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sqlpp11/select_column_list.h b/include/sqlpp11/select_column_list.h index 727e7513..36e78c91 100644 --- a/include/sqlpp11/select_column_list.h +++ b/include/sqlpp11/select_column_list.h @@ -341,7 +341,7 @@ namespace sqlpp auto tuple_merge(Columns... columns) -> decltype(std::tuple_cat(as_tuple::_(columns)...)) { return std::tuple_cat(as_tuple::_(columns)...); - }; + } template using make_select_column_list_t = diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index d11fa9f7..630457a6 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -282,7 +282,7 @@ namespace sqlpp static void _() { static_assert(wrong_t::value, "connection cannot run something that is neither statement nor prepared statement"); - }; + } }; struct assert_prepare_statement_t @@ -293,7 +293,7 @@ namespace sqlpp static void _() { static_assert(wrong_t::value, "connection cannot prepare something that is not a statement"); - }; + } }; template From f50500ba8be36b909062315714db604bfd88ce14 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 9 Feb 2015 18:39:03 +0100 Subject: [PATCH 18/24] Fixed a few superflous semicolons --- include/sqlpp11/group_by.h | 2 +- include/sqlpp11/order_by.h | 2 +- include/sqlpp11/where.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sqlpp11/group_by.h b/include/sqlpp11/group_by.h index a8f73185..52c2d53d 100644 --- a/include/sqlpp11/group_by.h +++ b/include/sqlpp11/group_by.h @@ -211,7 +211,7 @@ namespace sqlpp static_assert(not detail::has_duplicates::value, "at least one duplicate argument detected in group_by()"); return { static_cast&>(*this), group_by_data_t{expressions...} }; - }; + } }; }; diff --git a/include/sqlpp11/order_by.h b/include/sqlpp11/order_by.h index daf50517..32f7a0b8 100644 --- a/include/sqlpp11/order_by.h +++ b/include/sqlpp11/order_by.h @@ -211,7 +211,7 @@ namespace sqlpp static_assert(not detail::has_duplicates::value, "at least one duplicate argument detected in order_by()"); return { static_cast&>(*this), order_by_data_t{expressions...} }; - }; + } }; }; diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index 161da725..81db3c95 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -190,7 +190,7 @@ namespace sqlpp static void _() { static_assert(wrong_t::value, "where expression required, e.g. where(true)"); - }; + } }; // NO WHERE YET From a5c8b40b077d517cd6c28db3e805cd2aa774c424 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 9 Feb 2015 18:44:25 +0100 Subject: [PATCH 19/24] Adjust WITH clause to serialize RECURSIVE where required --- include/sqlpp11/with.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/sqlpp11/with.h b/include/sqlpp11/with.h index 399c94d8..fe3d7bda 100644 --- a/include/sqlpp11/with.h +++ b/include/sqlpp11/with.h @@ -45,6 +45,8 @@ namespace sqlpp template struct with_data_t { + using _is_recursive = logic::any_t; + with_data_t(Expressions... expressions): _expressions(expressions...) {} @@ -74,7 +76,6 @@ namespace sqlpp using _tags = detail::type_set<>; }; - using _is_dynamic = is_database; // Data @@ -172,6 +173,8 @@ namespace sqlpp { // 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); return context; } From 73097e989f063871eb876a1aa15ede0a6e30860c Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 11 Feb 2015 19:06:16 +0100 Subject: [PATCH 20/24] Mapping ctes to cte_references when used in from, helping with serialization --- include/sqlpp11/cte.h | 52 +++++++++++++++++++++++++---------- include/sqlpp11/from.h | 11 ++++---- include/sqlpp11/table_ref.h | 55 +++++++++++++++++++++++++++++++++++++ include/sqlpp11/with.h | 3 ++ tests/WithTest.cpp | 5 ++++ 5 files changed, 107 insertions(+), 19 deletions(-) create mode 100644 include/sqlpp11/table_ref.h diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h index 76aa337e..d1c3432f 100644 --- a/include/sqlpp11/cte.h +++ b/include/sqlpp11/cte.h @@ -27,6 +27,7 @@ #ifndef SQLPP_CTE_H #define SQLPP_CTE_H +#include #include #include #include @@ -40,9 +41,25 @@ namespace sqlpp { - template + template struct cte_t; + template + struct cte_ref_t; + + template + auto from_table(cte_t t) -> cte_ref_t + { + return cte_ref_t{}; + } + + template + struct from_table_impl> + { + using type = cte_ref_t; + }; + + template struct cte_column_spec_t { @@ -64,13 +81,19 @@ namespace sqlpp template struct make_cte_impl> { - using type = cte_t; + using type = cte_t; }; template using make_cte_t = typename make_cte_impl>::type; - template + template + struct cte_union_is_recursive + { + static constexpr bool value = Lhs or detail::is_element_of>::value; + }; + + template struct cte_t: public member_t, column_t>>... { using _traits = make_traits; // FIXME: is table? really? @@ -86,6 +109,7 @@ namespace sqlpp using _tags = detail::type_set<>; }; using _alias_t = typename AliasProvider::_alias_t; + constexpr static bool _is_recursive = Recursive; using _column_tuple_t = std::tuple>...>; @@ -94,7 +118,7 @@ namespace sqlpp template auto union_distinct(Rhs rhs) const - -> typename std::conditional<_check::value, cte_t, FieldSpecs...>, bad_statement>::type + -> typename std::conditional<_check::value, cte_t::value, union_data_t, FieldSpecs...>, bad_statement>::type { static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_policy_t::value, "argument of union call has to be a select"); @@ -108,7 +132,7 @@ namespace sqlpp template auto union_all(Rhs rhs) const - -> typename std::conditional<_check::value, cte_t, FieldSpecs...>, bad_statement>::type + -> typename std::conditional<_check::value, cte_t::value, union_data_t, FieldSpecs...>, bad_statement>::type { static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_policy_t::value, "argument of union call has to be a select"); @@ -127,7 +151,7 @@ namespace sqlpp template auto _union_impl(const std::true_type&, Rhs rhs) const - -> cte_t, FieldSpecs...> + -> cte_t::value, union_data_t, FieldSpecs...> { return union_data_t{_statement, rhs}; } @@ -144,11 +168,11 @@ namespace sqlpp Statement _statement; }; - template - struct serializer_t> + template + struct serializer_t> { using _serialize_check = serialize_check_of; - using T = cte_t; + using T = cte_t; static Context& _(const T& t, Context& context) { @@ -165,9 +189,9 @@ namespace sqlpp // AliasProviderName AS (ColumnNames) (select/union) // The result row of the select should not have dynamic parts template - struct pre_cte_t + struct cte_ref_t { - using _traits = make_traits; // FIXME: is table? really? + using _traits = make_traits; // FIXME: is table? really? struct _recursive_traits { using _required_ctes = detail::make_type_set_t; @@ -195,10 +219,10 @@ namespace sqlpp }; template - struct serializer_t> + struct serializer_t> { using _serialize_check = consistent_t; - using T = pre_cte_t; + using T = cte_ref_t; static Context& _(const T& t, Context& context) { @@ -209,7 +233,7 @@ namespace sqlpp template auto cte(const AliasProvider&) - -> pre_cte_t + -> cte_ref_t { return {}; } diff --git a/include/sqlpp11/from.h b/include/sqlpp11/from.h index bbe7d939..37f5b68a 100644 --- a/include/sqlpp11/from.h +++ b/include/sqlpp11/from.h @@ -27,6 +27,7 @@ #ifndef SQLPP_FROM_H #define SQLPP_FROM_H +#include #include #include #include @@ -90,7 +91,7 @@ namespace sqlpp template 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 @@ -164,7 +165,7 @@ namespace sqlpp template auto from(Tables... tables) const - -> _new_statement_t<_check, from_t> + -> _new_statement_t<_check, from_t...>> { static_assert(_check::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()"); @@ -173,7 +174,7 @@ namespace sqlpp template auto dynamic_from(Tables... tables) const - -> _new_statement_t<_check, from_t<_database_t, Tables...>> + -> _new_statement_t<_check, from_t<_database_t, from_table_t...>> { static_assert(not std::is_same<_database_t, void>::value, "dynamic_from must not be called in a static statement"); static_assert(_check::value, "at least one argument is not a table or join in from()"); @@ -187,7 +188,7 @@ namespace sqlpp template auto _from_impl(const std::true_type&, Tables... tables) const - -> _new_statement_t> + -> _new_statement_t...>> { static_assert(required_tables_of>::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_table_names::size::value, "at least one duplicate table name detected in from()"); - return { static_cast&>(*this), from_data_t{tables...} }; + return { static_cast&>(*this), from_data_t...>{from_table(tables)...} }; } }; diff --git a/include/sqlpp11/table_ref.h b/include/sqlpp11/table_ref.h new file mode 100644 index 00000000..58211093 --- /dev/null +++ b/include/sqlpp11/table_ref.h @@ -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 + +namespace sqlpp +{ + template + auto from_table(T t) -> T + { + return t; + } + + template + struct from_table_impl + { + using type = T; + }; + template + using from_table_t = typename from_table_impl::type; + + template + auto table_ref(T t) -> T + { + return t; + } +} + +#endif diff --git a/include/sqlpp11/with.h b/include/sqlpp11/with.h index fe3d7bda..7f696567 100644 --- a/include/sqlpp11/with.h +++ b/include/sqlpp11/with.h @@ -176,6 +176,7 @@ namespace sqlpp if (T::_is_recursive::value) context << "RECURSIVE "; interpret_tuple(t._expressions, ',', context); + context << ' '; return context; } }; @@ -184,6 +185,8 @@ namespace sqlpp auto with(Expressions... cte) -> blank_with_t { + static_assert(logic::all_t::value...>::value, "at least one expression in with is not a common table expression"); + static_assert(logic::none_t::value...>::value, "at least one expression in with is an incomplete common table expression"); return { {cte...} }; } } diff --git a/tests/WithTest.cpp b/tests/WithTest.cpp index f6bd4006..1ee5cd14 100644 --- a/tests/WithTest.cpp +++ b/tests/WithTest.cpp @@ -43,5 +43,10 @@ int main() 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; } From 18b36bf46a3361767186dbcc41d669f29dc062e9 Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 12 Feb 2015 18:05:19 +0100 Subject: [PATCH 21/24] recursive ctes seem to be basically working --- include/sqlpp11/cte.h | 101 ++++++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 29 deletions(-) diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h index d1c3432f..f84f3816 100644 --- a/include/sqlpp11/cte.h +++ b/include/sqlpp11/cte.h @@ -28,7 +28,6 @@ #define SQLPP_CTE_H #include -#include #include #include #include @@ -41,20 +40,70 @@ namespace sqlpp { - template + template + struct cte_union_t + { + struct _recursive_traits + { + using _required_ctes = detail::make_joined_set_t, required_ctes_of>; + 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>; + 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 + struct serializer_t> + { + using _serialize_check = serialize_check_of; + using T = cte_union_t; + + 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 struct cte_t; template struct cte_ref_t; - template - auto from_table(cte_t t) -> cte_ref_t + template + auto from_table(cte_t t) -> cte_ref_t { return cte_ref_t{}; } - template - struct from_table_impl> + template + struct from_table_impl> { using type = cte_ref_t; }; @@ -81,50 +130,45 @@ namespace sqlpp template struct make_cte_impl> { - using type = cte_t; + using type = cte_t; }; template using make_cte_t = typename make_cte_impl>::type; - template - struct cte_union_is_recursive - { - static constexpr bool value = Lhs or detail::is_element_of>::value; - }; - - template + template struct cte_t: public member_t, column_t>>... { using _traits = make_traits; // FIXME: is table? really? struct _recursive_traits { - using _required_ctes = detail::make_joined_set_t, detail::make_type_set_t>; + using _required_ctes = detail::make_joined_set_t, 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 _extra_tables = detail::type_set<>; using _parameters = parameters_of; using _tags = detail::type_set<>; }; using _alias_t = typename AliasProvider::_alias_t; - constexpr static bool _is_recursive = Recursive; + constexpr static bool _is_recursive = detail::is_element_of>::value; using _column_tuple_t = std::tuple>...>; template using _check = logic::all_t::value...>; + using _result_row_t = result_row_t; + template auto union_distinct(Rhs rhs) const - -> typename std::conditional<_check::value, cte_t::value, union_data_t, FieldSpecs...>, bad_statement>::type + -> typename std::conditional<_check::value, cte_t, FieldSpecs...>, bad_statement>::type { static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_policy_t::value, "argument of union call has to be a select"); static_assert(has_result_row_t::value, "argument of a union has to be a (complete) select statement"); - using _result_row_t = result_row_t; static_assert(std::is_same<_result_row_t, get_result_row_t>::value, "both select statements in a union have to have the same result columns (type and name)"); return _union_impl(_check{}, rhs); @@ -132,28 +176,27 @@ namespace sqlpp template auto union_all(Rhs rhs) const - -> typename std::conditional<_check::value, cte_t::value, union_data_t, FieldSpecs...>, bad_statement>::type + -> typename std::conditional<_check::value, cte_t, FieldSpecs...>, bad_statement>::type { static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_policy_t::value, "argument of union call has to be a select"); static_assert(has_result_row_t::value, "argument of a union has to be a (complete) select statement"); - using _result_row_t = result_row_t; static_assert(std::is_same<_result_row_t, get_result_row_t>::value, "both select statements in a union have to have the same result columns (type and name)"); - return _union_impl(_check{}, rhs); + return _union_impl(_check{}, rhs); } private: - template + template auto _union_impl(const std::false_type&, Rhs rhs) const -> bad_statement; - template + template auto _union_impl(const std::true_type&, Rhs rhs) const - -> cte_t::value, union_data_t, FieldSpecs...> + -> cte_t, FieldSpecs...> { - return union_data_t{_statement, rhs}; + return cte_union_t{_statement, rhs}; } public: @@ -168,11 +211,11 @@ namespace sqlpp Statement _statement; }; - template - struct serializer_t> + template + struct serializer_t> { using _serialize_check = serialize_check_of; - using T = cte_t; + using T = cte_t; static Context& _(const T& t, Context& context) { From 2c463b2b515a60536aa9d80b015d5ebaf1e339e1 Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 13 Feb 2015 16:26:45 +0100 Subject: [PATCH 22/24] Added missing includes --- include/sqlpp11/with.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sqlpp11/with.h b/include/sqlpp11/with.h index 7f696567..71f8e3a1 100644 --- a/include/sqlpp11/with.h +++ b/include/sqlpp11/with.h @@ -27,6 +27,8 @@ #ifndef SQLPP_WITH_H #define SQLPP_WITH_H +#include +#include #include #include #include From a09c79b234df5b479016df0207eebac33554e820 Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 15 Feb 2015 13:10:39 +0100 Subject: [PATCH 23/24] Removed a few stray semicolons --- include/sqlpp11/insert_value_list.h | 2 +- include/sqlpp11/update_list.h | 2 +- include/sqlpp11/using.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sqlpp11/insert_value_list.h b/include/sqlpp11/insert_value_list.h index a0763799..1cc86f62 100644 --- a/include/sqlpp11/insert_value_list.h +++ b/include/sqlpp11/insert_value_list.h @@ -315,7 +315,7 @@ namespace sqlpp static void _() { static_assert(wrong_t::value, "insert values required, e.g. set(...) or default_values()"); - }; + } }; // NO INSERT COLUMNS/VALUES YET diff --git a/include/sqlpp11/update_list.h b/include/sqlpp11/update_list.h index ba5ddc8d..5b0d5bf2 100644 --- a/include/sqlpp11/update_list.h +++ b/include/sqlpp11/update_list.h @@ -147,7 +147,7 @@ namespace sqlpp static void _() { static_assert(wrong_t::value, "update assignments required, i.e. set(...)"); - }; + } }; struct no_update_list_t diff --git a/include/sqlpp11/using.h b/include/sqlpp11/using.h index cf1bdea8..f1d9537d 100644 --- a/include/sqlpp11/using.h +++ b/include/sqlpp11/using.h @@ -192,7 +192,7 @@ namespace sqlpp static_assert(not detail::has_duplicates::value, "at least one duplicate argument detected in using()"); return { static_cast&>(*this), using_data_t{args...} }; - }; + } }; }; From da0d47a805655b7398d832a72c2031cc13a93e02 Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 15 Feb 2015 16:06:14 +0100 Subject: [PATCH 24/24] Fixed conditions for using sub select as alias --- include/sqlpp11/select_column_list.h | 2 +- include/sqlpp11/statement.h | 4 ++-- include/sqlpp11/type_traits.h | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/sqlpp11/select_column_list.h b/include/sqlpp11/select_column_list.h index 36e78c91..7fae3d2e 100644 --- a/include/sqlpp11/select_column_list.h +++ b/include/sqlpp11/select_column_list.h @@ -286,7 +286,7 @@ namespace sqlpp template _alias_t as(const AliasProvider& aliasProvider) const { - run_check_t<_statement_t>::_(); + 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(logic::none_t::value...>::value, "cannot use multi-columns in sub selects"); return _table_t(_get_statement()).as(aliasProvider); diff --git a/include/sqlpp11/statement.h b/include/sqlpp11/statement.h index 8fe803d7..209a62e0 100644 --- a/include/sqlpp11/statement.h +++ b/include/sqlpp11/statement.h @@ -130,12 +130,12 @@ namespace sqlpp // A select can be used as a pseudo table if // - 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() { return has_result_row_t<_statement_t>::value and _required_tables::size::value == 0 - and _required_ctes::size::value == 0 + and _all_provided_ctes::size::value == 0 // a sub-select must not contain a WITH ? true : false; } diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 630457a6..e6dc033f 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -296,6 +296,21 @@ namespace sqlpp } }; + template + struct consistency_check + { + using type = assert_run_statement_or_prepared_t; + }; + + template + struct consistency_check::value or is_prepared_statement_t::value>::type> + { + using type = typename T::_consistency_check; + }; + + template + using consistency_check_t = typename consistency_check::type; + template struct run_check {