/* * 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_STATEMENT_H #define SQLPP_STATEMENT_H #include #include #include #include #include #include #include #include #include #include namespace sqlpp { template struct statement_t; struct assert_no_unknown_tables_t { using type = std::false_type; template static void _() { static_assert(wrong_t::value, "one clause requires tables which are otherwise not known in the statement"); } }; struct assert_no_parameters_t { using type = std::false_type; template static void _() { static_assert(wrong_t::value, "cannot run statements with parameters directly, use prepare instead"); } }; namespace detail { template struct statement_policies_t { using _database_t = Db; using _statement_t = statement_t; template struct _policies_update_t { static_assert(detail::is_element_of>::value, "policies update for non-policy class detected"); using type = statement_t...>; }; template using _new_statement_t = typename _policies_update_t::type; 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...>; using _all_extra_tables = detail::make_joined_set_t...>; using _known_tables = detail::make_joined_set_t<_all_provided_tables, _all_extra_tables>; template using _no_unknown_tables = detail::is_subset_of, _known_tables>; // The tables not covered by the from. using _required_tables = detail::make_difference_set_t< _all_required_tables, _all_provided_tables // Hint: extra_tables are not used here because they are just a helper for dynamic .add_*() >; using _result_type_provider = detail::get_last_if; struct _result_methods_t: public _result_type_provider::template _result_methods_t<_statement_t> {}; // A select can be used as a pseudo table if // - at least one column is selected // - 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 ? true : false; } using _value_type = typename std::conditional< logic::none_t::value...>::value, value_type_of<_result_type_provider>, no_value_t // if a required statement part is missing (e.g. columns in a select), then the statement cannot be used as a value >::type; using _can_be_null = logic::any_t< can_be_null_t<_result_type_provider>::value, detail::make_intersect_set_t< required_tables_of<_result_type_provider>, _all_provided_outer_tables >::size::value != 0>; using _traits = make_traits<_value_type, tag_if::value>>; struct _recursive_traits { using _required_tables = statement_policies_t::_required_tables; 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 = typename std::conditional<_can_be_null::value, detail::type_set, detail::type_set<>>::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, consistent_t, assert_no_parameters_t>::type; }; } template struct statement_t: public Policies::template _base_t>..., public expression_operators, value_type_of>>, public detail::statement_policies_t::_result_methods_t { using _policies_t = typename detail::statement_policies_t; using _run_check = detail::get_first_if::_consistency_check..., typename _policies_t::_table_check>; using _prepare_check = detail::get_first_if::_consistency_check..., typename _policies_t::_table_check>; using _result_type_provider = typename _policies_t::_result_type_provider; template using _result_methods_t = typename _result_type_provider::template _result_methods_t; using _traits = make_traits, tag::is_statement, tag_if::value...>::value>, tag_if::value>, tag_if::value>, tag_if::value>::value>, tag::requires_braces>; using _recursive_traits = typename _policies_t::_recursive_traits; using _used_outer_tables = typename _policies_t::_all_provided_outer_tables; using _name_t = typename _result_type_provider::_name_t; // Constructors statement_t() {} template statement_t(Statement statement, Term term): Policies::template _base_t<_policies_t>{ typename Policies::template _impl_t<_policies_t>{ detail::pick_arg>(statement, term) }}... {} statement_t(const statement_t& r) = default; statement_t(statement_t&& r) = default; statement_t& operator=(const statement_t& r) = default; statement_t& operator=(statement_t&& r) = default; ~statement_t() = default; static constexpr size_t _get_static_no_of_parameters() { return std::tuple_size>::value; } size_t _get_no_of_parameters() const { return _get_static_no_of_parameters(); } static constexpr bool _can_be_used_as_table() { return _policies_t::_can_be_used_as_table(); } template auto _run(Database& db) const -> decltype(std::declval<_result_methods_t>()._run(db)) { _run_check::_(); return _result_methods_t::_run(db); } template auto _prepare(Database& db) const -> decltype(std::declval<_result_methods_t>()._prepare(db)) { _prepare_check::_(); return _result_methods_t::_prepare(db); } }; template struct serializer_t> { using P = detail::statement_policies_t; using _serialize_check = serialize_check_of::_data_t...>; using T = statement_t; static Context& _(const T& t, Context& context) { using swallow = int[]; (void) swallow{(serialize(static_cast&>(t)()._data, context), 0)...}; return context; } }; template struct statement_name_t { using _traits = make_traits; using _recursive_traits = make_recursive_traits<>; // Data using _data_t = NameData; // 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 = NameData; _impl_t statement_name; _impl_t& operator()() { return statement_name; } const _impl_t& operator()() const { return statement_name; } template static auto _get_member(T t) -> decltype(t.statement_name) { return t.statement_name; } using _consistency_check = consistent_t; }; }; } #endif