#pragma once /* * Copyright (c) 2013-2016, 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 #include #include #include #include #include #include #include #include #include namespace sqlpp { template struct cte_union_t { using _nodes = detail::type_vector<>; using _required_ctes = detail::make_joined_set_t, required_ctes_of>; using _parameters = detail::type_vector_cat_t, parameters_of>; 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 Context& serialize(const cte_union_t& t, Context& context) { serialize(t._lhs, context); context << " UNION "; serialize(Flag{}, context); context << " "; serialize(t._rhs, context); return context; } template struct cte_t; template struct cte_ref_t; template auto from_table(cte_t /*unused*/) -> cte_ref_t { return cte_ref_t{}; } template struct from_table_impl> { using type = cte_ref_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; // workaround for msvc unknown internal error // template // struct cte_t // : public member_t, column_t>>... template struct cte_base { using type = member_t, column_t>>; }; template struct union_cte_impl { using type = Check; }; template struct union_cte_impl { using type = Union; }; template using union_cte_impl_t = typename union_cte_impl::type; SQLPP_PORTABLE_STATIC_ASSERT(assert_cte_union_args_are_statements_t, "argument for union() must be a statement"); template struct check_cte_union { using type = static_combined_check_t< static_check_t::value...>::value, assert_cte_union_args_are_statements_t>>; }; template using check_cte_union_t = typename check_cte_union::type; template struct cte_t : public cte_base::type... { using _traits = make_traits; // FIXME: is table? really? using _nodes = detail::type_vector<>; using _provided_tables = detail::type_set; using _required_ctes = detail::make_joined_set_t, detail::type_set>; using _parameters = parameters_of; using _alias_t = typename AliasProvider::_alias_t; constexpr static bool _is_recursive = required_ctes_of::template count(); using _column_tuple_t = std::tuple>...>; using _result_row_t = result_row_t; template auto union_distinct(Rhs rhs) const -> union_cte_impl_t, cte_t, FieldSpecs...>> { 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(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_cte_union_t{}, rhs); } template auto union_all(Rhs rhs) const -> union_cte_impl_t, cte_t, FieldSpecs...>> { 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(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_cte_union_t{}, rhs); } private: template auto _union_impl(Check, Rhs rhs) const -> inconsistent; template auto _union_impl(consistent_t /*unused*/, Rhs rhs) const -> cte_t, FieldSpecs...> { return cte_union_t{_statement, rhs}; } public: cte_t(Statement statement) : _statement(statement) { } cte_t(const cte_t&) = default; cte_t(cte_t&&) = default; cte_t& operator=(const cte_t&) = default; cte_t& operator=(cte_t&&) = default; ~cte_t() = default; Statement _statement; }; template Context& serialize(const cte_t& t, Context& context) { using T = cte_t; context << name_of::template char_ptr() << " AS ("; serialize(t._statement, context); context << ")"; return context; } // The cte_t is displayed as AliasProviderName except within the with: // - the with needs the // AliasProviderName AS (ColumnNames) (select/union) // The result row of the select should not have dynamic parts template struct cte_ref_t { using _traits = make_traits; // FIXME: is table? really? using _nodes = detail::type_vector<>; using _required_ctes = detail::make_type_set_t; using _provided_tables = detail::type_set; using _alias_t = typename AliasProvider::_alias_t; template auto as(Statement statement) -> make_cte_t { static_assert(required_tables_of::size::value == 0, "common table expression must not use unknown tables"); static_assert(not required_ctes_of::template count(), "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}; } }; template Context& serialize(const cte_ref_t&, Context& context) { context << name_of>::template char_ptr(); return context; } template auto cte(const AliasProvider & /*unused*/) -> cte_ref_t { return {}; } } // namespace sqlpp