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();
180 int result = mysql_options(
mysql_, MYSQL_OPT_RECONNECT, &auto_reconnect);
187 const char *wait_time =
"SET SESSION wait_timeout = 30 * 86400";
188 result = mysql_options(
mysql_, MYSQL_INIT_COMMAND, wait_time);
198 const char *sql_mode =
"SET SESSION sql_mode ='STRICT_ALL_TABLES'";
199 result = mysql_options(
mysql_, MYSQL_INIT_COMMAND, sql_mode);
207 result = mysql_options(
mysql_, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
215 if (read_timeout > 0) {
216 result = mysql_options(
mysql_, MYSQL_OPT_READ_TIMEOUT, &read_timeout);
225 if (write_timeout > 0) {
226 result = mysql_options(
mysql_, MYSQL_OPT_WRITE_TIMEOUT, &write_timeout);
236 mysql_ssl_set(
mysql_, key_file, cert_file, ca_file, ca_dir,
250 MYSQL* status = mysql_real_connect(
mysql_, host, user, password, name,
251 port, NULL, CLIENT_FOUND_ROWS);
253 std::string error_message = mysql_error(
mysql_);
260 std::ostringstream s;
262 s <<
" (scheduling retry " << rec->retryIndex() + 1 <<
" of " << rec->maxRetries() <<
" in " << rec->retryInterval() <<
" milliseconds)";
264 error_message += s.str();
280 if (autocommit_result != 0) {
293std::pair<uint32_t, uint32_t>
297 const string& timer_name) {
301 if (!timer_name.empty()) {
309 MYSQL_STMT *stmt = mysql_stmt_init(conn.
mysql_);
312 "statement structure, reason: " << mysql_error(conn.
mysql_));
318 const char* version_sql =
"SELECT version, minor FROM schema_version";
319 int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
322 << version_sql <<
">, reason: "
323 << mysql_error(conn.
mysql_));
329 << version_sql <<
">, reason: "
330 << mysql_errno(conn.
mysql_));
335 memset(bind, 0,
sizeof(bind));
338 bind[0].buffer_type = MYSQL_TYPE_LONG;
339 bind[0].is_unsigned = 1;
341 bind[0].buffer_length =
sizeof(
version);
344 bind[1].buffer_type = MYSQL_TYPE_LONG;
345 bind[1].is_unsigned = 1;
346 bind[1].buffer = &minor;
347 bind[1].buffer_length =
sizeof(minor);
349 if (mysql_stmt_bind_result(stmt, bind)) {
351 << version_sql <<
">, reason: "
352 << mysql_errno(conn.
mysql_));
356 if (mysql_stmt_fetch(stmt)) {
358 << version_sql <<
">, reason: "
359 << mysql_errno(conn.
mysql_));
363 mysql_stmt_close(stmt);
364 return (std::make_pair(
version, minor));
366 }
catch (
const std::exception&) {
368 mysql_stmt_close(stmt);
378 const string& timer_name) {
380 bool const retry(parameters.count(
"retry-on-startup") &&
381 parameters.at(
"retry-on-startup") ==
"true");
384 pair<uint32_t, uint32_t> schema_version;
386 schema_version =
getVersion(parameters, ac, cb, retry ? timer_name :
string());
391 }
catch (exception
const& exception) {
403 schema_version =
getVersion(parameters, ac, cb, retry ? timer_name :
string());
409 if (schema_version != expected_version) {
411 << expected_version.first <<
"." << expected_version.second
412 <<
", found version: " << schema_version.first <<
"."
413 << schema_version.second);
419 if (parameters.count(
"readonly") && parameters.at(
"readonly") ==
"true") {
434 kea_admin_parameters.insert(kea_admin_parameters.begin(),
"db-init");
440 pid_t
const pid(kea_admin.
spawn());
445 if (exit_code != 0) {
452 vector<string> result{
"mysql"};
453 for (
auto const& p : params) {
454 string const& keyword(p.first);
455 string const& value(p.second);
458 if (keyword ==
"user" ||
459 keyword ==
"password" ||
463 result.push_back(
"--" + keyword);
464 result.push_back(value);
471 static unordered_map<string, string> conversions{
472 {
"connect-timeout",
"connect_timeout"},
473 {
"cipher-list",
"ssl-cipher"},
474 {
"cert-file",
"ssl-cert"},
475 {
"key-file",
"ssl-key"},
476 {
"trust-anchor",
"ssl-ca"},
480 if (conversions.count(keyword)) {
481 result.push_back(
"--extra");
482 result.push_back(
"--" + conversions.at(keyword) +
" " + value);
499 if ((index >= statements_.size()) || (statements_[index] != NULL)) {
501 static_cast<int>(index) <<
") or indexed prepared " <<
502 "statement is not null");
507 statements_[index] = mysql_stmt_init(
mysql_);
508 if (statements_[index] == NULL) {
510 "statement structure, reason: " << mysql_error(
mysql_));
513 int status = mysql_stmt_prepare(statements_[index], text, strlen(text));
516 text <<
">, reason: " << mysql_error(
mysql_));
525 tagged_statement != end_statement; ++tagged_statement) {
526 if (tagged_statement->index >= statements_.size()) {
527 statements_.resize(tagged_statement->index + 1, NULL);
532 tagged_statement->text);
541 for (
size_t i = 0; i < statements_.size(); ++i) {
542 if (statements_[i] != NULL) {
543 (void) mysql_stmt_close(statements_[i]);
544 statements_[i] = NULL;
563 MYSQL_TIME& output_time) {
569 const uint32_t valid_lifetime,
570 MYSQL_TIME& expire) {
576 uint32_t valid_lifetime, time_t& cltt) {
591 int status = mysql_query(
mysql_,
"START TRANSACTION");
594 "reason: " << mysql_error(
mysql_));
615 if (mysql_commit(
mysql_) != 0) {
633 if (mysql_rollback(
mysql_) != 0) {
641MySqlConnection::setIntParameterValue(
const std::string& name, int64_t min, int64_t max, T& value) {
648 if (svalue.empty()) {
653 auto parsed_value = boost::lexical_cast<T>(svalue);
655 if ((parsed_value < min) || (parsed_value > max)) {
659 value = parsed_value;
666 svalue <<
") must be an integer between "
667 << 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.
int getExitStatus(const pid_t pid) const
Returns exit status of the process.
bool isRunning(const pid_t pid) const
Checks if the process is still running.
std::string getCommandLine() const
Returns full command line, including arguments, for the process.
pid_t spawn(bool dismiss=false)
Spawn the new process.
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
util::ReconnectCtlPtr reconnectCtl()
The reconnect settings.
virtual void makeReconnectCtl(const std::string &timer_name)
Instantiates a ReconnectCtl based on the connection's reconnect parameters.
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.