ClickHouse/base/mysqlxx/Connection.cpp
Alexander Kazakov 4bcaed98d8
Added "opt_reconnect" parameter to config for controlling MYSQL_OPT_RECONNECT option (#19998)
* Support for MYSQL_OPT_RECONNECT option

It can now be controlled by .opt_reconnect = {true|false} parameter in
the mysql replica config section
2021-02-26 09:49:49 +03:00

161 lines
4.2 KiB
C++

#if __has_include(<mysql.h>)
#include <mysql.h>
#else
#include <mysql/mysql.h>
#endif
#include <mysqlxx/Connection.h>
#include <mysqlxx/Exception.h>
static inline const char* ifNotEmpty(const char* s)
{
return s && *s ? s : nullptr;
}
namespace mysqlxx
{
LibrarySingleton::LibrarySingleton()
{
if (mysql_library_init(0, nullptr, nullptr))
throw Exception("Cannot initialize MySQL library.");
}
LibrarySingleton::~LibrarySingleton()
{
mysql_library_end();
}
auto & LibrarySingleton::instance()
{
static LibrarySingleton instance;
return instance;
}
Connection::Connection()
: driver(std::make_unique<MYSQL>())
{
/// MySQL library initialization.
LibrarySingleton::instance();
}
Connection::Connection(
const char* db,
const char* server,
const char* user,
const char* password,
unsigned port,
const char * socket,
const char* ssl_ca,
const char* ssl_cert,
const char* ssl_key,
unsigned timeout,
unsigned rw_timeout,
bool enable_local_infile,
bool opt_reconnect)
: Connection()
{
connect(db, server, user, password, port, socket, ssl_ca, ssl_cert, ssl_key, timeout, rw_timeout, enable_local_infile, opt_reconnect);
}
Connection::Connection(const std::string & config_name)
: Connection()
{
connect(config_name);
}
Connection::~Connection()
{
disconnect();
mysql_thread_end();
}
void Connection::connect(const char* db,
const char * server,
const char * user,
const char * password,
unsigned port,
const char * socket,
const char * ssl_ca,
const char * ssl_cert,
const char * ssl_key,
unsigned timeout,
unsigned rw_timeout,
bool enable_local_infile,
bool opt_reconnect)
{
if (is_connected)
disconnect();
if (!mysql_init(driver.get()))
throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
is_initialized = true;
/// Set timeouts.
if (mysql_options(driver.get(), MYSQL_OPT_CONNECT_TIMEOUT, &timeout))
throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
if (mysql_options(driver.get(), MYSQL_OPT_READ_TIMEOUT, &rw_timeout))
throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
if (mysql_options(driver.get(), MYSQL_OPT_WRITE_TIMEOUT, &rw_timeout))
throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
/// Disable LOAD DATA LOCAL INFILE because it is insecure if necessary.
unsigned enable_local_infile_arg = static_cast<unsigned>(enable_local_infile);
if (mysql_options(driver.get(), MYSQL_OPT_LOCAL_INFILE, &enable_local_infile_arg))
throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
/// See C API Developer Guide: Automatic Reconnection Control
if (mysql_options(driver.get(), MYSQL_OPT_RECONNECT, reinterpret_cast<const char *>(&opt_reconnect)))
throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
/// Specifies particular ssl key and certificate if it needs
if (mysql_ssl_set(driver.get(), ifNotEmpty(ssl_key), ifNotEmpty(ssl_cert), ifNotEmpty(ssl_ca), nullptr, nullptr))
throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
if (!mysql_real_connect(driver.get(), server, user, password, db, port, ifNotEmpty(socket), driver->client_flag))
throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
/// Sets UTF-8 as default encoding. See https://mariadb.com/kb/en/mysql_set_character_set/
if (mysql_set_character_set(driver.get(), "utf8mb4"))
throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
is_connected = true;
}
bool Connection::connected() const
{
return is_connected;
}
void Connection::disconnect()
{
if (!is_initialized)
return;
mysql_close(driver.get());
memset(driver.get(), 0, sizeof(*driver));
is_initialized = false;
is_connected = false;
}
bool Connection::ping()
{
return is_connected && !mysql_ping(driver.get());
}
Query Connection::query(const std::string & str)
{
return Query(this, str);
}
MYSQL * Connection::getDriver()
{
return driver.get();
}
}