18#include <boost/lexical_cast.hpp>
24#include <unordered_map>
42 : conn_(conn), committed_(false) {
43 conn_.startTransaction();
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();
104 const char* name = NULL;
108 name = sname.c_str();
115 unsigned int read_timeout = 0;
116 unsigned int write_timeout = 0;
121 setIntParameterValue(
"connect-timeout", 1, numeric_limits<int>::max(), connect_timeout);
125 setIntParameterValue(
"read-timeout", 0, numeric_limits<int>::max(), read_timeout);
126 setIntParameterValue(
"write-timeout", 0, numeric_limits<int>::max(), write_timeout);
128 }
catch (
const std::exception& ex) {
132 const char* ca_file(0);
133 const char* ca_dir(0);
139 ca_dir = sca.c_str();
141 ca_file = sca.c_str();
147 const char* cert_file(0);
152 cert_file = scert.c_str();
157 const char* key_file(0);
162 key_file = skey.c_str();
167 const char* cipher_list(0);
172 cipher_list = scipher.c_str();
180#ifdef HAS_MYSQL_OPT_RECONNECT
187 result = mysql_options(
mysql_, MYSQL_OPT_RECONNECT, &auto_reconnect);
195 const char *wait_time =
"SET SESSION wait_timeout = 30 * 86400";
196 result = mysql_options(
mysql_, MYSQL_INIT_COMMAND, wait_time);
206 const char *sql_mode =
"SET SESSION sql_mode ='STRICT_ALL_TABLES'";
207 result = mysql_options(
mysql_, MYSQL_INIT_COMMAND, sql_mode);
215 result = mysql_options(
mysql_, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
223 if (read_timeout > 0) {
224 result = mysql_options(
mysql_, MYSQL_OPT_READ_TIMEOUT, &read_timeout);
233 if (write_timeout > 0) {
234 result = mysql_options(
mysql_, MYSQL_OPT_WRITE_TIMEOUT, &write_timeout);
244 result = mysql_options(
mysql_, MYSQL_OPT_SSL_KEY, key_file);
249 result = mysql_options(
mysql_, MYSQL_OPT_SSL_CERT, cert_file);
254 result = mysql_options(
mysql_, MYSQL_OPT_SSL_CA, ca_file);
259 result = mysql_options(
mysql_, MYSQL_OPT_SSL_CAPATH, ca_dir);
264 result = mysql_options(
mysql_, MYSQL_OPT_SSL_CIPHER, cipher_list);
280 MYSQL* status = mysql_real_connect(
mysql_, host, user, password, name,
281 port, NULL, CLIENT_FOUND_ROWS);
286 std::string error_message = mysql_error(
mysql_);
294 std::ostringstream s;
296 s <<
" (scheduling retry " << rec->retryIndex() + 1 <<
" of " << rec->maxRetries() <<
" in " << rec->retryInterval() <<
" milliseconds)";
298 error_message += s.str();
314 if (autocommit_result != 0) {
327std::pair<uint32_t, uint32_t>
331 const string& timer_name,
336 if (!timer_name.empty()) {
344 MYSQL_STMT *stmt = mysql_stmt_init(conn.
mysql_);
347 "statement structure, reason: " << mysql_error(conn.
mysql_));
353 const char* version_sql =
"SELECT version, minor FROM schema_version";
354 int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
357 << version_sql <<
">, reason: "
358 << mysql_error(conn.
mysql_));
364 << version_sql <<
">, reason: "
365 << mysql_errno(conn.
mysql_));
370 memset(bind, 0,
sizeof(bind));
373 bind[0].buffer_type = MYSQL_TYPE_LONG;
374 bind[0].is_unsigned = 1;
376 bind[0].buffer_length =
sizeof(
version);
379 bind[1].buffer_type = MYSQL_TYPE_LONG;
380 bind[1].is_unsigned = 1;
381 bind[1].buffer = &minor;
382 bind[1].buffer_length =
sizeof(minor);
384 if (mysql_stmt_bind_result(stmt, bind)) {
386 << version_sql <<
">, reason: "
387 << mysql_errno(conn.
mysql_));
391 if (mysql_stmt_fetch(stmt)) {
393 << version_sql <<
">, reason: "
394 << mysql_errno(conn.
mysql_));
398 mysql_stmt_close(stmt);
399 return (std::make_pair(
version, minor));
401 }
catch (
const std::exception&) {
403 mysql_stmt_close(stmt);
413 const string& timer_name) {
415 bool const retry(parameters.count(
"retry-on-startup") &&
416 parameters.at(
"retry-on-startup") ==
"true");
419 pair<uint32_t, uint32_t> schema_version;
421 schema_version =
getVersion(parameters, ac,
cb, retry ? timer_name :
string());
434 }
catch (exception
const& exception) {
452 schema_version =
getVersion(parameters, ac,
cb, retry ? timer_name :
string());
458 if (schema_version != expected_version) {
460 << expected_version.first <<
"." << expected_version.second
461 <<
", found version: " << schema_version.first <<
"."
462 << schema_version.second);
468 if (parameters.count(
"readonly") && parameters.at(
"readonly") ==
"true") {
485 kea_admin_parameters.insert(kea_admin_parameters.begin(),
"db-init");
492 pid_t
const pid(kea_admin.
spawn());
497 if (exit_code != 0) {
504 vector<string> result{
"mysql"};
505 for (
auto const& p : params) {
506 string const& keyword(p.first);
507 string const& value(p.second);
510 if (keyword ==
"user" ||
511 keyword ==
"password" ||
515 result.push_back(
"--" + keyword);
516 result.push_back(value);
523 static unordered_map<string, string> conversions{
524 {
"connect-timeout",
"connect_timeout"},
525 {
"cipher-list",
"ssl-cipher"},
526 {
"cert-file",
"ssl-cert"},
527 {
"key-file",
"ssl-key"},
528 {
"trust-anchor",
"ssl-ca"},
532 if (conversions.count(keyword)) {
533 result.push_back(
"--extra");
534 result.push_back(
"--" + conversions.at(keyword) +
" " + value);
551 if ((index >= statements_.size()) || (statements_[index] != NULL)) {
553 static_cast<int>(index) <<
") or indexed prepared " <<
554 "statement is not null");
559 statements_[index] = mysql_stmt_init(
mysql_);
560 if (statements_[index] == NULL) {
562 "statement structure, reason: " << mysql_error(
mysql_));
565 int status = mysql_stmt_prepare(statements_[index], text, strlen(text));
568 text <<
">, reason: " << mysql_error(
mysql_));
577 tagged_statement != end_statement; ++tagged_statement) {
578 if (tagged_statement->index >= statements_.size()) {
579 statements_.resize(tagged_statement->index + 1, NULL);
584 tagged_statement->text);
593 for (
size_t i = 0; i < statements_.size(); ++i) {
594 if (statements_[i] != NULL) {
595 (void) mysql_stmt_close(statements_[i]);
596 statements_[i] = NULL;
615 MYSQL_TIME& output_time) {
621 const uint32_t valid_lifetime,
622 MYSQL_TIME& expire) {
628 uint32_t valid_lifetime, time_t& cltt) {
643 int status = mysql_query(
mysql_,
"START TRANSACTION");
646 "reason: " << mysql_error(
mysql_));
667 if (mysql_commit(
mysql_) != 0) {
685 if (mysql_rollback(
mysql_) != 0) {
693MySqlConnection::setIntParameterValue(
const std::string& name, int64_t min, int64_t max, T& value) {
700 if (svalue.empty()) {
705 auto parsed_value = boost::lexical_cast<T>(svalue);
707 if ((parsed_value < min) || (parsed_value > max)) {
708 isc_throw(BadValue,
"bad " << svalue <<
" value");
711 value = parsed_value;
717 isc_throw(BadValue, name <<
" parameter (" <<
718 svalue <<
") must be an integer between "
719 << min <<
" and " << max);
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.
std::string getCommandLine(std::unordered_set< std::string > redact_args={}) const
Returns full command line, including arguments, for the process.
bool isRunning(const pid_t pid) const
Checks if the process is still running.
pid_t spawn(bool dismiss=false)
Spawn the new process.
Exception thrown on attempt to use a default credential.
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, unsigned int id)
Instantiates a ReconnectCtl based on the connection's reconnect parameters.
void markUnusable()
Sets the unusable flag to true.
static bool test_mode_
Test mode flag (default false).
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.
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(), unsigned int id=0)
Get the schema version.
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 void convertFromDatabaseTime(const MYSQL_TIME &expire, uint32_t valid_lifetime, time_t &cltt)
Convert Database Time to Lease Times.
void commit()
Commits current transaction.
MySqlConnection(const ParameterMap ¶meters, IOServiceAccessorPtr io_accessor=IOServiceAccessorPtr(), DbCallback callback=DbCallback())
Constructor.
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.
int version()
returns Kea hooks version.
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
@ MYSQL_INITIAL_CONNECTION_FAIL
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.
static void check(const std::string &value)
Check if the value is a default credential.
DB_LOG & arg(T first, Args... args)
Pass parameters to replace logger placeholders.
Structure used to initialize and clean up after MySQL library.
MySQL Selection Statements.