17#include <boost/lexical_cast.hpp>
23#include <unordered_map>
34int MySqlHolder::atexit_ = [] {
35 return atexit([] { mysql_library_end(); });
42 : conn_(conn), committed_(false) {
65 const char* host =
"localhost";
74 unsigned int port = 0;
76 setIntParameterValue(
"port", 0, numeric_limits<uint16_t>::max(), port);
78 }
catch (
const std::exception& ex) {
82 const char* user = NULL;
91 const char* password = NULL;
95 password = spassword.c_str();
100 const char* name = NULL;
104 name = sname.c_str();
111 unsigned int read_timeout = 0;
112 unsigned int write_timeout = 0;
117 setIntParameterValue(
"connect-timeout", 1, numeric_limits<int>::max(), connect_timeout);
121 setIntParameterValue(
"read-timeout", 0, numeric_limits<int>::max(), read_timeout);
122 setIntParameterValue(
"write-timeout", 0, numeric_limits<int>::max(), write_timeout);
124 }
catch (
const std::exception& ex) {
128 const char* ca_file(0);
129 const char* ca_dir(0);
135 ca_dir = sca.c_str();
137 ca_file = sca.c_str();
143 const char* cert_file(0);
148 cert_file = scert.c_str();
153 const char* key_file(0);
158 key_file = skey.c_str();
163 const char* cipher_list(0);
168 cipher_list = scipher.c_str();
176#ifdef HAS_MYSQL_OPT_RECONNECT
183 result = mysql_options(
mysql_, MYSQL_OPT_RECONNECT, &auto_reconnect);
191 const char *wait_time =
"SET SESSION wait_timeout = 30 * 86400";
192 result = mysql_options(
mysql_, MYSQL_INIT_COMMAND, wait_time);
202 const char *sql_mode =
"SET SESSION sql_mode ='STRICT_ALL_TABLES'";
203 result = mysql_options(
mysql_, MYSQL_INIT_COMMAND, sql_mode);
211 result = mysql_options(
mysql_, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
219 if (read_timeout > 0) {
220 result = mysql_options(
mysql_, MYSQL_OPT_READ_TIMEOUT, &read_timeout);
229 if (write_timeout > 0) {
230 result = mysql_options(
mysql_, MYSQL_OPT_WRITE_TIMEOUT, &write_timeout);
240 result = mysql_options(
mysql_, MYSQL_OPT_SSL_KEY, key_file);
245 result = mysql_options(
mysql_, MYSQL_OPT_SSL_CERT, cert_file);
250 result = mysql_options(
mysql_, MYSQL_OPT_SSL_CA, ca_file);
255 result = mysql_options(
mysql_, MYSQL_OPT_SSL_CAPATH, ca_dir);
260 result = mysql_options(
mysql_, MYSQL_OPT_SSL_CIPHER, cipher_list);
276 MYSQL* status = mysql_real_connect(
mysql_, host, user, password, name,
277 port, NULL, CLIENT_FOUND_ROWS);
279 std::string error_message = mysql_error(
mysql_);
286 std::ostringstream s;
288 s <<
" (scheduling retry " << rec->retryIndex() + 1 <<
" of " << rec->maxRetries() <<
" in " << rec->retryInterval() <<
" milliseconds)";
290 error_message += s.str();
306 if (autocommit_result != 0) {
319std::pair<uint32_t, uint32_t>
323 const string& timer_name) {
327 if (!timer_name.empty()) {
328 conn.makeReconnectCtl(timer_name);
335 MYSQL_STMT *stmt = mysql_stmt_init(conn.mysql_);
338 "statement structure, reason: " << mysql_error(conn.mysql_));
344 const char* version_sql =
"SELECT version, minor FROM schema_version";
345 int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
348 << version_sql <<
">, reason: "
349 << mysql_error(conn.mysql_));
355 << version_sql <<
">, reason: "
356 << mysql_errno(conn.mysql_));
361 memset(bind, 0,
sizeof(bind));
364 bind[0].buffer_type = MYSQL_TYPE_LONG;
365 bind[0].is_unsigned = 1;
367 bind[0].buffer_length =
sizeof(
version);
370 bind[1].buffer_type = MYSQL_TYPE_LONG;
371 bind[1].is_unsigned = 1;
372 bind[1].buffer = &minor;
373 bind[1].buffer_length =
sizeof(minor);
375 if (mysql_stmt_bind_result(stmt, bind)) {
377 << version_sql <<
">, reason: "
378 << mysql_errno(conn.mysql_));
382 if (mysql_stmt_fetch(stmt)) {
384 << version_sql <<
">, reason: "
385 << mysql_errno(conn.mysql_));
389 mysql_stmt_close(stmt);
390 return (std::make_pair(
version, minor));
392 }
catch (
const std::exception&) {
394 mysql_stmt_close(stmt);
404 const string& timer_name) {
406 bool const retry(parameters.count(
"retry-on-startup") &&
407 parameters.at(
"retry-on-startup") ==
"true");
410 pair<uint32_t, uint32_t> schema_version;
412 schema_version =
getVersion(parameters, ac, cb, retry ? timer_name : string());
417 }
catch (exception
const& exception) {
429 schema_version =
getVersion(parameters, ac, cb, retry ? timer_name : string());
435 if (schema_version != expected_version) {
437 << expected_version.first <<
"." << expected_version.second
438 <<
", found version: " << schema_version.first <<
"."
439 << schema_version.second);
445 if (parameters.count(
"readonly") && parameters.at(
"readonly") ==
"true") {
460 kea_admin_parameters.insert(kea_admin_parameters.begin(),
"db-init");
466 pid_t
const pid(kea_admin.spawn());
467 if (kea_admin.isRunning(pid)) {
470 int const exit_code(kea_admin.getExitStatus(pid));
471 if (exit_code != 0) {
478 vector<string> result{
"mysql"};
479 for (
auto const& p : params) {
480 string const& keyword(p.first);
481 string const& value(p.second);
484 if (keyword ==
"user" ||
485 keyword ==
"password" ||
489 result.push_back(
"--" + keyword);
490 result.push_back(value);
497 static unordered_map<string, string> conversions{
498 {
"connect-timeout",
"connect_timeout"},
499 {
"cipher-list",
"ssl-cipher"},
500 {
"cert-file",
"ssl-cert"},
501 {
"key-file",
"ssl-key"},
502 {
"trust-anchor",
"ssl-ca"},
506 if (conversions.count(keyword)) {
507 result.push_back(
"--extra");
508 result.push_back(
"--" + conversions.at(keyword) +
" " + value);
525 if ((index >= statements_.size()) || (statements_[index] != NULL)) {
527 static_cast<int>(index) <<
") or indexed prepared " <<
528 "statement is not null");
533 statements_[index] = mysql_stmt_init(
mysql_);
534 if (statements_[index] == NULL) {
536 "statement structure, reason: " << mysql_error(
mysql_));
539 int status = mysql_stmt_prepare(statements_[index], text, strlen(text));
542 text <<
">, reason: " << mysql_error(
mysql_));
551 tagged_statement != end_statement; ++tagged_statement) {
552 if (tagged_statement->index >= statements_.size()) {
553 statements_.resize(tagged_statement->index + 1, NULL);
558 tagged_statement->text);
567 for (
size_t i = 0; i < statements_.size(); ++i) {
568 if (statements_[i] != NULL) {
569 (void) mysql_stmt_close(statements_[i]);
570 statements_[i] = NULL;
589 MYSQL_TIME& output_time) {
595 const uint32_t valid_lifetime,
596 MYSQL_TIME& expire) {
602 uint32_t valid_lifetime, time_t& cltt) {
617 int status = mysql_query(
mysql_,
"START TRANSACTION");
620 "reason: " << mysql_error(
mysql_));
641 if (mysql_commit(
mysql_) != 0) {
659 if (mysql_rollback(
mysql_) != 0) {
667MySqlConnection::setIntParameterValue(
const std::string& name, int64_t min, int64_t max, T& value) {
674 if (svalue.empty()) {
679 auto parsed_value = boost::lexical_cast<T>(svalue);
681 if ((parsed_value < min) || (parsed_value > max)) {
685 value = parsed_value;
692 svalue <<
") must be an integer between "
693 << min <<
" and " << max);
int version()
returns Kea hooks version.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
A generic exception that is thrown when an unexpected error condition occurs.
Utility class for spawning new processes.
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
util::ReconnectCtlPtr reconnectCtl()
The reconnect settings.
static bool retry_
Flag which indicates if the database connection should be retried on fail.
void checkUnusable()
Throws an exception if the connection is not usable.
static isc::asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Exception thrown on failure to open database but permit retries.
Exception thrown on failure to open database.
Exception thrown on failure to execute a database function.
static void convertFromDatabaseTime(const MYSQL_TIME &expire, uint32_t valid_lifetime, time_t &cltt)
Converts Database Time to Lease Times.
static void convertToDatabaseTime(const time_t input_time, MYSQL_TIME &output_time)
Converts time_t value to database time.
Common MySQL Connector Pool.
static std::string KEA_ADMIN_
Holds location to kea-admin.
MySqlHolder mysql_
MySQL connection handle.
void prepareStatement(uint32_t index, const char *text)
Prepare Single Statement.
bool isTransactionStarted() const
Checks if there is a transaction in progress.
std::vector< std::string > text_statements_
Raw text of statements.
bool tls_
TLS flag (true when TLS was required, false otherwise).
static void convertToDatabaseTime(const time_t input_time, MYSQL_TIME &output_time)
Convert time_t value to database time.
static std::pair< uint32_t, uint32_t > getVersion(const ParameterMap ¶meters, const IOServiceAccessorPtr &ac=IOServiceAccessorPtr(), const DbCallback &cb=DbCallback(), const std::string &timer_name=std::string())
Get the schema version.
static void convertFromDatabaseTime(const MYSQL_TIME &expire, uint32_t valid_lifetime, time_t &cltt)
Convert Database Time to Lease Times.
void commit()
Commits current transaction.
void startRecoverDbConnection()
The recover connection.
static void initializeSchema(const ParameterMap ¶meters)
Initialize schema.
static std::vector< std::string > toKeaAdminParameters(ParameterMap const ¶ms)
Convert MySQL library parameters to kea-admin parameters.
void openDatabase()
Open Database.
void prepareStatements(const TaggedStatement *start_statement, const TaggedStatement *end_statement)
Prepare statements.
int transaction_ref_count_
Reference counter for transactions.
void startTransaction()
Starts new transaction.
virtual ~MySqlConnection()
Destructor.
void rollback()
Rollbacks current transaction.
static void ensureSchemaVersion(const ParameterMap ¶meters, const DbCallback &cb=DbCallback(), const std::string &timer_name=std::string())
Retrieve schema version, validate it against the hardcoded version, and attempt to initialize the sch...
~MySqlTransaction()
Destructor.
void commit()
Commits transaction.
MySqlTransaction(MySqlConnection &conn)
Constructor.
Exception thrown if name of database is not specified.
Thrown when an initialization of the schema failed.
We want to reuse the database backend connection and exchange code for other uses,...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
std::vector< std::string > ProcessEnvVars
Type of the container holding environment variables of the executable being run as a background proce...
const int DB_DBG_TRACE_DETAIL
Database logging levels.
const my_bool MLM_FALSE
MySQL false value.
const int MYSQL_DEFAULT_CONNECTION_TIMEOUT
@ MYSQL_START_TRANSACTION
@ MYSQL_INITIALIZE_SCHEMA
const uint32_t MYSQL_SCHEMA_VERSION_MAJOR
boost::shared_ptr< IOServiceAccessor > IOServiceAccessorPtr
Pointer to an instance of IOServiceAccessor.
const uint32_t MYSQL_SCHEMA_VERSION_MINOR
bool my_bool
my_bool type in MySQL 8.x.
std::function< bool(util::ReconnectCtlPtr db_reconnect_ctl)> DbCallback
Defines a callback prototype for propagating events upward.
std::function< isc::asiolink::IOServicePtr()> IOServiceAccessor
Function which returns the IOService that can be used to recover the connection.
int MysqlExecuteStatement(MYSQL_STMT *stmt)
Execute a prepared statement.
bool isFile(string const &path)
Check if there is a file at the given path.
bool isDir(string const &path)
Check if there is a directory at the given path.
Defines the logger used by the top-level component of kea-lfc.
DB_LOG & arg(T first, Args... args)
Pass parameters to replace logger placeholders.
MySQL Selection Statements.