diff --git a/cmake/Modules/FindHinnantDate.cmake b/cmake/Modules/FindHinnantDate.cmake index d582f949..affb0a38 100644 --- a/cmake/Modules/FindHinnantDate.cmake +++ b/cmake/Modules/FindHinnantDate.cmake @@ -53,8 +53,10 @@ set(HinnantDate_NOT_FOUND_MESSAGE "Could NOT find HinnantDate. Maybe you need to adjust the search paths or HinnantDate_ROOT_DIR.") find_file(HinnantDate_INCLUDE_FILE - date.h date/date.h - HINTS ${HinnantDate_ROOT_DIR} + date.h date/date.h include/date/date.h + HINTS + ${HinnantDate_ROOT_DIR} + ${HinnantDate_ROOT_DIR}/include ) mark_as_advanced(HinnantDate_INCLUDE_FILE) diff --git a/include/sqlpp11/alias.h b/include/sqlpp11/alias.h index 197862cf..ea2c28ee 100644 --- a/include/sqlpp11/alias.h +++ b/include/sqlpp11/alias.h @@ -66,7 +66,7 @@ namespace sqlpp { serialize_operand(t._expression, context); context << " AS "; - context << name_of::char_ptr(); + context << name_of::template char_ptr(); return context; } }; diff --git a/include/sqlpp11/alias_provider.h b/include/sqlpp11/alias_provider.h index b77a9e20..7982193a 100644 --- a/include/sqlpp11/alias_provider.h +++ b/include/sqlpp11/alias_provider.h @@ -54,6 +54,30 @@ }; \ constexpr name##_t name = {}; +#define SQLPP_QUOTED_ALIAS_PROVIDER(name) \ + struct name##_t \ + { \ + struct _alias_t \ + { \ + static constexpr const char _literal[] = "!" #name; \ + using _name_t = sqlpp::make_char_sequence; \ + template \ + struct _member_t \ + { \ + T name; \ + T& operator()() \ + { \ + return name; \ + } \ + const T& operator()() const \ + { \ + return name; \ + } \ + }; \ + }; \ + }; \ + constexpr name##_t name = {}; + namespace sqlpp { template diff --git a/include/sqlpp11/char_sequence.h b/include/sqlpp11/char_sequence.h index 58d294dd..57595258 100644 --- a/include/sqlpp11/char_sequence.h +++ b/include/sqlpp11/char_sequence.h @@ -34,11 +34,24 @@ namespace sqlpp template struct char_sequence { + template static const char* char_ptr() { - static char s[] = {Cs...}; + static char s[] = {Cs..., '\0'}; return s; - }; + } + }; + + template + struct char_sequence<'!', Cs...> + { + template + static const char* char_ptr() + { + static char s[] = {decltype(get_quote_left(std::declval()))::value, Cs..., + decltype(get_quote_right(std::declval()))::value, '\0'}; + return s; + } }; template @@ -52,7 +65,7 @@ namespace sqlpp template using make_char_sequence = - typename make_char_sequence_impl>::type; + typename make_char_sequence_impl>::type; } // namespace sqlpp #endif diff --git a/include/sqlpp11/column.h b/include/sqlpp11/column.h index 3b8497dd..7920b1f4 100644 --- a/include/sqlpp11/column.h +++ b/include/sqlpp11/column.h @@ -125,7 +125,8 @@ namespace sqlpp static Context& _(const T& /*unused*/, Context& context) { - context << name_of::char_ptr() << '.' << name_of::char_ptr(); + context << name_of::template char_ptr() << '.' + << name_of::template char_ptr(); return context; } }; diff --git a/include/sqlpp11/connection_pool.h b/include/sqlpp11/connection_pool.h index 67ce9ea9..c63141ba 100644 --- a/include/sqlpp11/connection_pool.h +++ b/include/sqlpp11/connection_pool.h @@ -1,28 +1,28 @@ /* -* Copyright (c) 2013 - 2017, Roland Bock, Frank Park -* 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. -*/ + * Copyright (c) 2013 - 2017, Roland Bock, Frank Park + * 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_CONNECTION_POOL_H #define SQLPP_CONNECTION_POOL_H @@ -39,154 +39,171 @@ namespace sqlpp { - namespace reconnect_policy - { - struct auto_reconnect { - template - void operator()(Connection* connection) - { - if(!connection->is_valid()) - connection->reconnect() - } - template - void clean(Connection* connection) {} - }; + namespace reconnect_policy + { + struct auto_reconnect + { + template + void operator()(Connection* connection) + { + if (!connection->is_valid()) + connection->reconnect(); + } + template + void clean(Connection* connection) + { + } + }; - using namespace std::chrono_literals; - class periodic_reconnect - { - private: - std::chrono::seconds revalidate_after; - std::unordered_map > last_checked; + class periodic_reconnect + { + private: + std::chrono::seconds revalidate_after; + std::unordered_map> last_checked; - public: - periodic_reconnect(const std::chrono::seconds r = 28800s) //default wait_timeout in MySQL - : revalidate_after(r), last_checked() {} + public: + periodic_reconnect(const std::chrono::seconds r = std::chrono::seconds(28800)) // default wait_timeout in MySQL + : revalidate_after(r), last_checked() + { + } - template - void operator()(Connection* con) - { - auto last = last_checked.find(con); - auto now = std::chrono::system_clock::now(); - if(last == last_checked.end()) - { - if (!con->is_valid()) - { - con->reconnect(); - } - last_checked.emplace_hint(last, con, now); - } - else if(now - last->second > revalidate_after) - { - if (!con->is_valid()) - { - con->reconnect(); - } - last = now; - } - } - template - void clean(Connection* con) { - auto itr = last_checked.find(con); - if(itr != last_checked.end()) - { - last_checked.erase(itr); - } - } - }; + template + void operator()(Connection* con) + { + auto last = last_checked.find(con); + auto now = std::chrono::system_clock::now(); + if (last == last_checked.end()) + { + if (!con->is_valid()) + { + con->reconnect(); + } + last_checked.emplace_hint(last, con, now); + } + else if (now - last->second > revalidate_after) + { + if (!con->is_valid()) + { + con->reconnect(); + } + last = now; + } + } + template + void clean(Connection* con) + { + auto itr = last_checked.find(con); + if (itr != last_checked.end()) + { + last_checked.erase(itr); + } + } + }; - struct never_reconnect { - template - void operator()(Connection*) {} - template - void clean(Connection*) {} - }; - } + struct never_reconnect + { + template + void operator()(Connection*) + { + } + template + void clean(Connection*) + { + } + }; + } - template ::value, Connection_config::connection>::type> - class connection_pool - { - friend pool_connection; + template ::value, + typename Connection_config::connection>::type> + class connection_pool + { + friend pool_connection; - private: - std::mutex connection_pool_mutex; - const std::shared_ptr config; - size_t maximum_pool_size = 0; - std::stack> free_connections; - Reconnect_policy reconnect_policy; + private: + std::mutex connection_pool_mutex; + const std::shared_ptr config; + size_t maximum_pool_size = 0; + std::stack> free_connections; + Reconnect_policy reconnect_policy; - void free_connection(std::unique_ptr& connection) - { - std::lock_guard lock(connection_pool_mutex); - if (free_connections.size() >= maximum_pool_size) - { - // Exceeds default size, do nothign and let connection self destroy. - } - else - { - if (connection.get()) - { - if (connection->is_valid()) - { - free_connections.push(std::move(connection)); - } - else - { - throw sqlpp::exception("Trying to free a connection with incompatible config."); - } - } - else - { - throw sqlpp::exception("Trying to free an empty connection."); - } - } - } + void free_connection(std::unique_ptr& connection) + { + std::lock_guard lock(connection_pool_mutex); + if (free_connections.size() >= maximum_pool_size) + { + // Exceeds default size, do nothign and let connection self destroy. + } + else + { + if (connection.get()) + { + if (connection->is_valid()) + { + free_connections.push(std::move(connection)); + } + else + { + throw sqlpp::exception("Trying to free a connection with incompatible config."); + } + } + else + { + throw sqlpp::exception("Trying to free an empty connection."); + } + } + } - public: - connection_pool(const std::shared_ptr& config, size_t pool_size) - : config(config), maximum_pool_size(pool_size), reconnect_policy(Reconnect_policy()) {} - ~connection_pool() = default; - connection_pool(const connection_pool&) = delete; - connection_pool(connection_pool&& other) - : config(std::move(other.config)), maximum_pool_size(std::move(other.maximum_pool_size)), - reconnect_policy(std::move(other.reconnect_policy)) {} - connection_pool& operator=(const connection_pool&) = delete; - connection_pool& operator=(connection_pool&&) = delete; + public: + connection_pool(const std::shared_ptr& config, size_t pool_size) + : config(config), maximum_pool_size(pool_size), reconnect_policy(Reconnect_policy()) + { + } + ~connection_pool() = default; + connection_pool(const connection_pool&) = delete; + connection_pool(connection_pool&& other) + : config(std::move(other.config)), + maximum_pool_size(std::move(other.maximum_pool_size)), + reconnect_policy(std::move(other.reconnect_policy)) + { + } + connection_pool& operator=(const connection_pool&) = delete; + connection_pool& operator=(connection_pool&&) = delete; - pool_connection get_connection() - { - std::lock_guard lock(connection_pool_mutex); - if (!free_connections.empty()) - { - auto connection = std::move(free_connections.top()); - free_connections.pop(); - return pool_connection(connection, this); - } + pool_connection get_connection() + { + std::lock_guard lock(connection_pool_mutex); + if (!free_connections.empty()) + { + auto connection = std::move(free_connections.top()); + free_connections.pop(); + return pool_connection(connection, this); + } - try - { - return pool_connection(std::move(std::make_unique(config)), this); - } - catch (const sqlpp::exception& e) - { - std::cerr << "Failed to spawn a new connection." << std::endl; - std::cerr << e.what() << std::endl; - throw; - } - } - }; + try + { + auto c = std::unique_ptr(new Connection(*(config.get()))); + return pool_connection(c, this); + } + catch (const sqlpp::exception& e) + { + std::cerr << "Failed to spawn a new connection." << std::endl; + std::cerr << e.what() << std::endl; + throw; + } + } + }; - template::value,Connection_config::connection>::type> - connection_pool make_connection_pool( - const std::shared_ptr& config, - size_t max_pool_size) - { - return connection_pool(config, max_pool_size); - } + template ::value, + typename Connection_config::connection>::type> + connection_pool make_connection_pool( + const std::shared_ptr& config, size_t max_pool_size) + { + return connection_pool(config, max_pool_size); + } } #endif diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h index 95cca8d3..9b3d40d4 100644 --- a/include/sqlpp11/cte.h +++ b/include/sqlpp11/cte.h @@ -167,7 +167,7 @@ namespace sqlpp using _parameters = parameters_of; using _alias_t = typename AliasProvider::_alias_t; - constexpr static bool _is_recursive = detail::is_element_of>::value; + constexpr static bool _is_recursive = required_ctes_of::template count(); using _column_tuple_t = std::tuple>...>; @@ -235,7 +235,7 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - context << name_of::char_ptr() << " AS ("; + context << name_of::template char_ptr() << " AS ("; serialize(t._statement, context); context << ")"; return context; @@ -261,7 +261,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, + 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, @@ -279,7 +279,7 @@ namespace sqlpp static Context& _(const T& /*unused*/, Context& context) { - context << name_of::char_ptr(); + context << name_of::template char_ptr(); return context; } }; diff --git a/include/sqlpp11/detail/type_set.h b/include/sqlpp11/detail/type_set.h index ebbb2293..16fdce03 100644 --- a/include/sqlpp11/detail/type_set.h +++ b/include/sqlpp11/detail/type_set.h @@ -45,29 +45,41 @@ namespace sqlpp template struct is_element_of; + template + struct _base + { + }; + // A type set template struct type_set { + private: + struct _impl : _base... + { + }; + + public: using size = std::integral_constant; using _is_type_set = std::true_type; - static_assert(std::is_same>::value, - "use make_type_set to construct a typeset"); + template + static constexpr bool count() + { + return std::is_base_of<_base, _impl>::value; + } template struct insert { - using type = - typename std::conditional::value, type_set, type_set>::type; + using type = typename std::conditional(), type_set, type_set>::type; }; template