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) {
91 const char* password = 0;
95 password = spassword.c_str();
99 string spassword_file;
106 if (!spassword_file.empty()) {
109 password = spassword.c_str();
116 const char* name = 0;
120 name = sname.c_str();
127 unsigned int read_timeout = 0;
128 unsigned int write_timeout = 0;
133 setIntParameterValue(
"connect-timeout", 1, numeric_limits<int>::max(), connect_timeout);
137 setIntParameterValue(
"read-timeout", 0, numeric_limits<int>::max(), read_timeout);
138 setIntParameterValue(
"write-timeout", 0, numeric_limits<int>::max(), write_timeout);
140 }
catch (
const std::exception& ex) {
144 const char* ca_file(0);
145 const char* ca_dir(0);
151 ca_dir = sca.c_str();
153 ca_file = sca.c_str();
159 const char* cert_file(0);
164 cert_file = scert.c_str();
169 const char* key_file(0);
174 key_file = skey.c_str();
179 const char* cipher_list(0);
184 cipher_list = scipher.c_str();
192#ifdef HAS_MYSQL_OPT_RECONNECT
199 result = mysql_options(
mysql_, MYSQL_OPT_RECONNECT, &auto_reconnect);
207 const char *wait_time =
"SET SESSION wait_timeout = 30 * 86400";
208 result = mysql_options(
mysql_, MYSQL_INIT_COMMAND, wait_time);
218 const char *sql_mode =
"SET SESSION sql_mode ='STRICT_ALL_TABLES'";
219 result = mysql_options(
mysql_, MYSQL_INIT_COMMAND, sql_mode);
227 result = mysql_options(
mysql_, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
235 if (read_timeout > 0) {
236 result = mysql_options(
mysql_, MYSQL_OPT_READ_TIMEOUT, &read_timeout);
245 if (write_timeout > 0) {
246 result = mysql_options(
mysql_, MYSQL_OPT_WRITE_TIMEOUT, &write_timeout);
256 result = mysql_options(
mysql_, MYSQL_OPT_SSL_KEY, key_file);
261 result = mysql_options(
mysql_, MYSQL_OPT_SSL_CERT, cert_file);
266 result = mysql_options(
mysql_, MYSQL_OPT_SSL_CA, ca_file);
271 result = mysql_options(
mysql_, MYSQL_OPT_SSL_CAPATH, ca_dir);
276 result = mysql_options(
mysql_, MYSQL_OPT_SSL_CIPHER, cipher_list);
292 MYSQL* status = mysql_real_connect(
mysql_, host, user, password, name,
293 port, 0, CLIENT_FOUND_ROWS);
298 std::string error_message = mysql_error(
mysql_);
306 std::ostringstream s;
308 s <<
" (scheduling retry " << rec->retryIndex() + 1 <<
" of " << rec->maxRetries() <<
" in " << rec->retryInterval() <<
" milliseconds)";
310 error_message += s.str();
326 if (autocommit_result != 0) {
339std::pair<uint32_t, uint32_t>
343 const string& timer_name,
348 if (!timer_name.empty()) {
356 MYSQL_STMT *stmt = mysql_stmt_init(conn.
mysql_);
359 "statement structure, reason: " << mysql_error(conn.
mysql_));
365 const char* version_sql =
"SELECT version, minor FROM schema_version";
366 int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
369 << version_sql <<
">, reason: "
370 << mysql_error(conn.
mysql_));
376 << version_sql <<
">, reason: "
377 << mysql_errno(conn.
mysql_));
382 memset(bind, 0,
sizeof(bind));
385 bind[0].buffer_type = MYSQL_TYPE_LONG;
386 bind[0].is_unsigned = 1;
388 bind[0].buffer_length =
sizeof(
version);
391 bind[1].buffer_type = MYSQL_TYPE_LONG;
392 bind[1].is_unsigned = 1;
393 bind[1].buffer = &minor;
394 bind[1].buffer_length =
sizeof(minor);
396 if (mysql_stmt_bind_result(stmt, bind)) {
398 << version_sql <<
">, reason: "
399 << mysql_errno(conn.
mysql_));
403 if (mysql_stmt_fetch(stmt)) {
405 << version_sql <<
">, reason: "
406 << mysql_errno(conn.
mysql_));
410 mysql_stmt_close(stmt);
411 return (std::make_pair(
version, minor));
413 }
catch (
const std::exception&) {
415 mysql_stmt_close(stmt);
425 const string& timer_name) {
427 bool const retry(parameters.count(
"retry-on-startup") &&
428 parameters.at(
"retry-on-startup") ==
"true");
431 pair<uint32_t, uint32_t> schema_version;
433 schema_version =
getVersion(parameters, ac,
cb, retry ? timer_name :
string());
446 }
catch (exception
const& exception) {
464 schema_version =
getVersion(parameters, ac,
cb, retry ? timer_name :
string());
470 if (schema_version != expected_version) {
472 << expected_version.first <<
"." << expected_version.second
473 <<
", found version: " << schema_version.first <<
"."
474 << schema_version.second);
480 if (parameters.count(
"readonly") && parameters.at(
"readonly") ==
"true") {
487 if (parameters.count(
"password-file")) {
503 kea_admin_parameters.insert(kea_admin_parameters.begin(),
"db-init");
510 pid_t
const pid(kea_admin.
spawn());
515 if (exit_code != 0) {
522 vector<string> result{
"mysql"};
523 for (
auto const& p : params) {
524 string const& keyword(p.first);
525 string const& value(p.second);
528 if (keyword ==
"user" ||
529 keyword ==
"password" ||
533 result.push_back(
"--" + keyword);
534 result.push_back(value);
541 static unordered_map<string, string> conversions{
542 {
"connect-timeout",
"connect_timeout"},
543 {
"cipher-list",
"ssl-cipher"},
544 {
"cert-file",
"ssl-cert"},
545 {
"key-file",
"ssl-key"},
546 {
"trust-anchor",
"ssl-ca"},
550 if (conversions.count(keyword)) {
551 result.push_back(
"--extra");
552 result.push_back(
"--" + conversions.at(keyword) +
" " + value);
569 if ((index >= statements_.size()) || (statements_[index] != 0)) {
571 static_cast<int>(index) <<
") or indexed prepared " <<
572 "statement is not null");
577 statements_[index] = mysql_stmt_init(
mysql_);
578 if (statements_[index] == 0) {
580 "statement structure, reason: " << mysql_error(
mysql_));
583 int status = mysql_stmt_prepare(statements_[index], text, strlen(text));
586 text <<
">, reason: " << mysql_error(
mysql_));
595 tagged_statement != end_statement; ++tagged_statement) {
596 if (tagged_statement->index >= statements_.size()) {
597 statements_.resize(tagged_statement->index + 1, 0);
602 tagged_statement->text);
611 for (
size_t i = 0; i < statements_.size(); ++i) {
612 if (statements_[i] != 0) {
613 (void) mysql_stmt_close(statements_[i]);
633 MYSQL_TIME& output_time) {
639 const uint32_t valid_lifetime,
640 MYSQL_TIME& expire) {
646 uint32_t valid_lifetime, time_t& cltt) {
661 int status = mysql_query(
mysql_,
"START TRANSACTION");
664 "reason: " << mysql_error(
mysql_));
685 if (mysql_commit(
mysql_) != 0) {
703 if (mysql_rollback(
mysql_) != 0) {
711MySqlConnection::setIntParameterValue(
const std::string& name, int64_t min, int64_t max, T& value) {
718 if (svalue.empty()) {
723 auto parsed_value = boost::lexical_cast<T>(svalue);
725 if ((parsed_value < min) || (parsed_value > max)) {
726 isc_throw(BadValue,
"bad " << svalue <<
" value");
729 value = parsed_value;
735 isc_throw(BadValue, name <<
" parameter (" <<
736 svalue <<
") must be an integer between "
737 << 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_NO_INIT_NO_PASSWORD
@ 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.
string getContent(string const &file_name)
Get the content of a regular file.
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.