Cleanup the code of the MySQL connector (#509)

* Move the code for sqlpp::mysql::detail::connection_handle_t to include/sqlpp11/mysql/detail/connection_handle.h
* Move the code for sqlpp::mysql::detail::prepared_statement_handle_t to include/sqlpp11/mysql/detail/prepared_statement_handle.h
* Move the code for sqlpp::mysql::detail::result_handle to include/sqlpp11/mysql/detail/result_handle.h
* Rename sqlpp::mysql::detail::connection_handle_t -> sqlpp::mysql::detail::connection_handle
* Rename sqlpp::mysql::serializer_t -> sqlpp::mysql::context_t
* Add const qualifiers to sqlpp::mysql::context_t::escape() and its parameter.
* Rename class/struct types, variables and functions from CamelCase to snake_case.
* Remove a superfluous function that forwards the call to mysql_close().
This commit is contained in:
MeanSquaredError
2023-08-05 10:18:51 +03:00
committed by GitHub
parent 3c598cd0b2
commit 490259ee69
9 changed files with 321 additions and 211 deletions

View File

@@ -26,91 +26,21 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <iostream>
#include <memory>
#include <vector>
#include <sqlpp11/chrono.h>
#include <sqlpp11/exception.h>
#include <sqlpp11/mysql/detail/prepared_statement_handle.h>
#include <sqlpp11/mysql/sqlpp_mysql.h>
#include <iostream>
#ifdef _MSC_VER
#include <iso646.h>
#endif
#include <memory>
namespace sqlpp
{
namespace mysql
{
namespace detail
{
struct result_meta_data_t
{
size_t index;
unsigned long bound_len;
my_bool bound_is_null;
my_bool bound_error;
std::vector<char> bound_text_buffer; // also for blobs
const char** text_buffer;
size_t* len;
bool* is_null;
};
struct prepared_statement_handle_t
{
struct wrapped_bool
{
my_bool value;
wrapped_bool() : value(false)
{
}
wrapped_bool(bool v) : value(v)
{
}
wrapped_bool(const wrapped_bool&) = default;
wrapped_bool(wrapped_bool&&) = default;
wrapped_bool& operator=(const wrapped_bool&) = default;
wrapped_bool& operator=(wrapped_bool&&) = default;
~wrapped_bool() = default;
};
MYSQL_STMT* mysql_stmt;
std::vector<MYSQL_BIND> stmt_params;
std::vector<MYSQL_TIME> stmt_date_time_param_buffer;
std::vector<wrapped_bool> stmt_param_is_null; // my_bool is bool after 8.0, and vector<bool> is bad
std::vector<MYSQL_BIND> result_params;
std::vector<result_meta_data_t> result_param_meta_data;
bool debug;
prepared_statement_handle_t(MYSQL_STMT* stmt, size_t no_of_parameters, size_t no_of_columns, bool debug_)
: mysql_stmt(stmt),
stmt_params(no_of_parameters, MYSQL_BIND{}),
stmt_date_time_param_buffer(no_of_parameters, MYSQL_TIME{}),
stmt_param_is_null(no_of_parameters, false),
result_params(no_of_columns, MYSQL_BIND{}),
result_param_meta_data(no_of_columns, result_meta_data_t{}),
debug(debug_)
{
}
prepared_statement_handle_t(const prepared_statement_handle_t&) = delete;
prepared_statement_handle_t(prepared_statement_handle_t&&) = default;
prepared_statement_handle_t& operator=(const prepared_statement_handle_t&) = delete;
prepared_statement_handle_t& operator=(prepared_statement_handle_t&&) = default;
~prepared_statement_handle_t()
{
if (mysql_stmt)
mysql_stmt_close(mysql_stmt);
}
bool operator!() const
{
return !mysql_stmt;
}
};
} // namespace detail
class bind_result_t
{
std::shared_ptr<detail::prepared_statement_handle_t> _handle;

View File

@@ -32,6 +32,7 @@
#include <memory>
#include <sqlpp11/chrono.h>
#include <sqlpp11/exception.h>
#include <sqlpp11/mysql/detail/result_handle.h>
#include <sqlpp11/mysql/sqlpp_mysql.h>
#include <sqlpp11/mysql/char_result_row.h>
@@ -41,35 +42,9 @@ namespace sqlpp
{
namespace detail
{
struct result_handle
inline auto check_first_digit(const char* text, bool digit_flag) -> bool
{
MYSQL_RES* mysql_res;
bool debug;
result_handle(MYSQL_RES* res, bool debug_) : mysql_res(res), debug(debug_)
{
}
result_handle(const result_handle&) = delete;
result_handle(result_handle&&) = default;
result_handle& operator=(const result_handle&) = delete;
result_handle& operator=(result_handle&&) = default;
~result_handle()
{
if (mysql_res)
mysql_free_result(mysql_res);
}
bool operator!() const
{
return !mysql_res;
}
};
inline auto check_first_digit(const char* text, bool digitFlag) -> bool
{
if (digitFlag)
if (digit_flag)
{
if (not std::isdigit(*text))
{
@@ -88,9 +63,9 @@ namespace sqlpp
inline auto check_date_digits(const char* text) -> bool
{
for (const auto digitFlag : {true, true, true, true, false, true, true, false, true, true}) // YYYY-MM-DD
for (const auto digit_flag : {true, true, true, true, false, true, true, false, true, true}) // YYYY-MM-DD
{
if (not check_first_digit(text, digitFlag))
if (not check_first_digit(text, digit_flag))
return false;
++text;
}
@@ -99,9 +74,9 @@ namespace sqlpp
inline auto check_time_digits(const char* text) -> bool
{
for (const auto digitFlag : {true, true, false, true, true, false, true, true}) // hh:mm:ss
for (const auto digit_flag : {true, true, false, true, true, false, true, true}) // hh:mm:ss
{
if (not check_first_digit(text, digitFlag))
if (not check_first_digit(text, digit_flag))
return false;
++text;
}

View File

@@ -33,11 +33,11 @@
#include <sqlpp11/mysql/bind_result.h>
#include <sqlpp11/mysql/char_result.h>
#include <sqlpp11/mysql/connection_config.h>
#include <sqlpp11/mysql/detail/connection_handle.h>
#include <sqlpp11/mysql/prepared_statement.h>
#include <sqlpp11/mysql/remove.h>
#include <sqlpp11/mysql/update.h>
#include <sqlpp11/serialize.h>
#include <sqlpp11/mysql/sqlpp_mysql.h>
#include <iostream>
#include <sstream>
#include <string>
@@ -48,9 +48,9 @@ namespace sqlpp
{
namespace detail
{
struct MySqlThreadInitializer
struct mysql_thread_initializer
{
MySqlThreadInitializer()
mysql_thread_initializer()
{
if (!mysql_thread_safe())
{
@@ -59,7 +59,7 @@ namespace sqlpp
mysql_thread_init();
}
~MySqlThreadInitializer()
~mysql_thread_initializer()
{
mysql_thread_end();
}
@@ -67,90 +67,10 @@ namespace sqlpp
inline void thread_init()
{
thread_local MySqlThreadInitializer threadInitializer;
thread_local mysql_thread_initializer thread_initializer;
}
inline void connect(MYSQL* mysql, const connection_config& config)
{
if (config.connect_timeout_seconds != 0 &&
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &config.connect_timeout_seconds))
{
throw sqlpp::exception("MySQL: could not set option MYSQL_OPT_CONNECT_TIMEOUT");
}
if (!mysql_real_connect(mysql, config.host.empty() ? nullptr : config.host.c_str(),
config.user.empty() ? nullptr : config.user.c_str(),
config.password.empty() ? nullptr : config.password.c_str(), nullptr, config.port,
config.unix_socket.empty() ? nullptr : config.unix_socket.c_str(), config.client_flag))
{
throw sqlpp::exception("MySQL: could not connect to server: " + std::string(mysql_error(mysql)));
}
if (mysql_set_character_set(mysql, config.charset.c_str()))
{
throw sqlpp::exception("MySQL error: can't set character set " + config.charset);
}
if (not config.database.empty() and mysql_select_db(mysql, config.database.c_str()))
{
throw sqlpp::exception("MySQL error: can't select database '" + config.database + "'");
}
}
inline void handle_cleanup(MYSQL* mysql)
{
mysql_close(mysql);
}
struct connection_handle_t
{
std::shared_ptr<const connection_config> config;
std::unique_ptr<MYSQL, void (*)(MYSQL*)> mysql;
connection_handle_t(const std::shared_ptr<const connection_config>& conf) :
config(conf),
mysql(mysql_init(nullptr), handle_cleanup)
{
if (not mysql)
{
throw sqlpp::exception("MySQL: could not init mysql data structure");
}
if (config->auto_reconnect)
{
my_bool my_true = true;
if (mysql_options(native_handle(), MYSQL_OPT_RECONNECT, &my_true))
{
throw sqlpp::exception("MySQL: could not set option MYSQL_OPT_RECONNECT");
}
}
connect(native_handle(), *config);
}
connection_handle_t(const connection_handle_t&) = delete;
connection_handle_t(connection_handle_t&&) = default;
connection_handle_t& operator=(const connection_handle_t&) = delete;
connection_handle_t& operator=(connection_handle_t&&) = default;
MYSQL* native_handle() const
{
return mysql.get();
}
bool check_connection() const
{
auto nh = native_handle();
return nh && (mysql_ping(nh) == 0);
}
void reconnect()
{
connect(native_handle(), *config);
}
};
inline void execute_statement(std::unique_ptr<connection_handle_t>& handle, const std::string& statement)
inline void execute_statement(std::unique_ptr<connection_handle>& handle, const std::string& statement)
{
thread_init();
@@ -185,7 +105,7 @@ namespace sqlpp
}
}
inline std::shared_ptr<detail::prepared_statement_handle_t> prepare_statement(std::unique_ptr<connection_handle_t>& handle,
inline std::shared_ptr<detail::prepared_statement_handle_t> prepare_statement(std::unique_ptr<connection_handle>& handle,
const std::string& statement,
size_t no_of_parameters,
size_t no_of_columns)
@@ -235,12 +155,12 @@ namespace sqlpp
// Forward declaration
class connection_base;
struct serializer_t
struct context_t
{
serializer_t(const connection_base& db) : _db(db)
context_t(const connection_base& db) : _db(db)
{
}
serializer_t(const connection_base&&) = delete;
context_t(const connection_base&&) = delete;
template <typename T>
std::ostream& operator<<(T t)
@@ -248,7 +168,7 @@ namespace sqlpp
return _os << t;
}
std::string escape(std::string arg);
std::string escape(const std::string& arg) const;
std::string str() const
{
@@ -259,9 +179,9 @@ namespace sqlpp
sqlpp::detail::float_safe_ostringstream _os;
};
std::integral_constant<char, '`'> get_quote_left(const serializer_t&);
std::integral_constant<char, '`'> get_quote_left(const context_t&);
std::integral_constant<char, '`'> get_quote_right(const serializer_t&);
std::integral_constant<char, '`'> get_quote_right(const context_t&);
class connection_base : public sqlpp::connection
{
@@ -336,11 +256,11 @@ namespace sqlpp
using _connection_base_t = connection_base;
using _config_t = connection_config;
using _config_ptr_t = std::shared_ptr<const _config_t>;
using _handle_t = detail::connection_handle_t;
using _handle_t = detail::connection_handle;
using _handle_ptr_t = std::unique_ptr<_handle_t>;
using _prepared_statement_t = ::sqlpp::mysql::prepared_statement_t;
using _context_t = serializer_t;
using _context_t = context_t;
using _serializer_context_t = _context_t;
using _interpreter_context_t = _context_t;
@@ -594,7 +514,7 @@ namespace sqlpp
};
// Method definition moved outside of class because it needs connection_base
inline std::string serializer_t::escape(std::string arg)
inline std::string context_t::escape(const std::string& arg) const
{
return _db.escape(arg);
}

View File

@@ -0,0 +1,117 @@
#pragma once
/*
* Copyright (c) 2013 - 2017, Roland Bock
* Copyright (c) 2023, Vesselin Atanasov
* 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 <sqlpp11/mysql/connection_config.h>
#include <sqlpp11/mysql/sqlpp_mysql.h>
#include <memory>
namespace sqlpp
{
namespace mysql
{
namespace detail
{
inline void connect(MYSQL* mysql, const connection_config& config)
{
if (config.connect_timeout_seconds != 0 &&
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &config.connect_timeout_seconds))
{
throw sqlpp::exception("MySQL: could not set option MYSQL_OPT_CONNECT_TIMEOUT");
}
if (!mysql_real_connect(mysql, config.host.empty() ? nullptr : config.host.c_str(),
config.user.empty() ? nullptr : config.user.c_str(),
config.password.empty() ? nullptr : config.password.c_str(), nullptr, config.port,
config.unix_socket.empty() ? nullptr : config.unix_socket.c_str(), config.client_flag))
{
throw sqlpp::exception("MySQL: could not connect to server: " + std::string(mysql_error(mysql)));
}
if (mysql_set_character_set(mysql, config.charset.c_str()))
{
throw sqlpp::exception("MySQL error: can't set character set " + config.charset);
}
if (not config.database.empty() and mysql_select_db(mysql, config.database.c_str()))
{
throw sqlpp::exception("MySQL error: can't select database '" + config.database + "'");
}
}
struct connection_handle
{
std::shared_ptr<const connection_config> config;
std::unique_ptr<MYSQL, void (*)(MYSQL*)> mysql;
connection_handle(const std::shared_ptr<const connection_config>& conf) :
config(conf),
mysql(mysql_init(nullptr), mysql_close)
{
if (not mysql)
{
throw sqlpp::exception("MySQL: could not init mysql data structure");
}
if (config->auto_reconnect)
{
my_bool my_true = true;
if (mysql_options(native_handle(), MYSQL_OPT_RECONNECT, &my_true))
{
throw sqlpp::exception("MySQL: could not set option MYSQL_OPT_RECONNECT");
}
}
connect(native_handle(), *config);
}
connection_handle(const connection_handle&) = delete;
connection_handle(connection_handle&&) = default;
connection_handle& operator=(const connection_handle&) = delete;
connection_handle& operator=(connection_handle&&) = default;
MYSQL* native_handle() const
{
return mysql.get();
}
bool check_connection() const
{
auto nh = native_handle();
return nh && (mysql_ping(nh) == 0);
}
void reconnect()
{
connect(native_handle(), *config);
}
};
} // namespace detail
} // namespace mysql
} // namespace sqlpp

View File

@@ -0,0 +1,107 @@
#pragma once
/*
* Copyright (c) 2013 - 2015, 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 <sqlpp11/mysql/sqlpp_mysql.h>
#include <vector>
namespace sqlpp
{
namespace mysql
{
namespace detail
{
struct result_meta_data_t
{
size_t index;
unsigned long bound_len;
my_bool bound_is_null;
my_bool bound_error;
std::vector<char> bound_text_buffer; // also for blobs
const char** text_buffer;
size_t* len;
bool* is_null;
};
struct prepared_statement_handle_t
{
struct wrapped_bool
{
my_bool value;
wrapped_bool() : value(false)
{
}
wrapped_bool(bool v) : value(v)
{
}
wrapped_bool(const wrapped_bool&) = default;
wrapped_bool(wrapped_bool&&) = default;
wrapped_bool& operator=(const wrapped_bool&) = default;
wrapped_bool& operator=(wrapped_bool&&) = default;
~wrapped_bool() = default;
};
MYSQL_STMT* mysql_stmt;
std::vector<MYSQL_BIND> stmt_params;
std::vector<MYSQL_TIME> stmt_date_time_param_buffer;
std::vector<wrapped_bool> stmt_param_is_null; // my_bool is bool after 8.0, and vector<bool> is bad
std::vector<MYSQL_BIND> result_params;
std::vector<result_meta_data_t> result_param_meta_data;
bool debug;
prepared_statement_handle_t(MYSQL_STMT* stmt, size_t no_of_parameters, size_t no_of_columns, bool debug_)
: mysql_stmt(stmt),
stmt_params(no_of_parameters, MYSQL_BIND{}),
stmt_date_time_param_buffer(no_of_parameters, MYSQL_TIME{}),
stmt_param_is_null(no_of_parameters, false),
result_params(no_of_columns, MYSQL_BIND{}),
result_param_meta_data(no_of_columns, result_meta_data_t{}),
debug(debug_)
{
}
prepared_statement_handle_t(const prepared_statement_handle_t&) = delete;
prepared_statement_handle_t(prepared_statement_handle_t&&) = default;
prepared_statement_handle_t& operator=(const prepared_statement_handle_t&) = delete;
prepared_statement_handle_t& operator=(prepared_statement_handle_t&&) = default;
~prepared_statement_handle_t()
{
if (mysql_stmt)
mysql_stmt_close(mysql_stmt);
}
bool operator!() const
{
return !mysql_stmt;
}
};
} // namespace detail
} // namespace mysql
} // namespace sqlpp

View File

@@ -0,0 +1,62 @@
#pragma once
/*
* Copyright (c) 2013 - 2015, 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.
*/
namespace sqlpp
{
namespace mysql
{
namespace detail
{
struct result_handle
{
MYSQL_RES* mysql_res;
bool debug;
result_handle(MYSQL_RES* res, bool debug_) : mysql_res(res), debug(debug_)
{
}
result_handle(const result_handle&) = delete;
result_handle(result_handle&&) = default;
result_handle& operator=(const result_handle&) = delete;
result_handle& operator=(result_handle&&) = default;
~result_handle()
{
if (mysql_res)
mysql_free_result(mysql_res);
}
bool operator!() const
{
return !mysql_res;
}
};
} // namespace detail
} // namespace mysql
} // namespace sqlpp

View File

@@ -33,7 +33,6 @@
#include <memory>
#include <iostream>
#include <string>
#include <vector>
#include <sqlpp11/chrono.h>
namespace sqlpp

View File

@@ -32,17 +32,17 @@
namespace sqlpp
{
template <typename First, typename... Args>
mysql::serializer_t& serialize(const concat_t<First, Args...>& t, mysql::serializer_t& context)
mysql::context_t& serialize(const concat_t<First, Args...>& t, mysql::context_t& ctx)
{
context << "CONCAT(";
interpret_tuple(t._args, ',', context);
context << ')';
return context;
ctx << "CONCAT(";
interpret_tuple(t._args, ',', ctx);
ctx << ')';
return ctx;
}
inline mysql::serializer_t& serialize(const insert_default_values_data_t&, mysql::serializer_t& context)
inline mysql::context_t& serialize(const insert_default_values_data_t&, mysql::context_t& ctx)
{
context << " () VALUES()";
return context;
ctx << " () VALUES()";
return ctx;
}
}

View File

@@ -60,7 +60,7 @@ namespace
}
sqlpp::mysql::connection connection{config};
sqlpp::mysql::serializer_t printer{connection};
sqlpp::mysql::context_t printer{connection};
const auto result = serialize(expr, printer).str();