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());
426 }
catch (exception
const& exception) {
442 schema_version =
getVersion(parameters, ac,
cb, retry ? timer_name :
string());
448 if (schema_version != expected_version) {
450 << expected_version.first <<
"." << expected_version.second
451 <<
", found version: " << schema_version.first <<
"."
452 << schema_version.second);
458 if (parameters.count(
"readonly") && parameters.at(
"readonly") ==
"true") {
473 kea_admin_parameters.insert(kea_admin_parameters.begin(),
"db-init");
480 pid_t
const pid(kea_admin.
spawn());
485 if (exit_code != 0) {
492 vector<string> result{
"mysql"};
493 for (
auto const& p : params) {
494 string const& keyword(p.first);
495 string const& value(p.second);
498 if (keyword ==
"user" ||
499 keyword ==
"password" ||
503 result.push_back(
"--" + keyword);
504 result.push_back(value);
511 static unordered_map<string, string> conversions{
512 {
"connect-timeout",
"connect_timeout"},
513 {
"cipher-list",
"ssl-cipher"},
514 {
"cert-file",
"ssl-cert"},
515 {
"key-file",
"ssl-key"},
516 {
"trust-anchor",
"ssl-ca"},
520 if (conversions.count(keyword)) {
521 result.push_back(
"--extra");
522 result.push_back(
"--" + conversions.at(keyword) +
" " + value);
539 if ((index >= statements_.size()) || (statements_[index] != NULL)) {
541 static_cast<int>(index) <<
") or indexed prepared " <<
542 "statement is not null");
547 statements_[index] = mysql_stmt_init(
mysql_);
548 if (statements_[index] == NULL) {
550 "statement structure, reason: " << mysql_error(
mysql_));
553 int status = mysql_stmt_prepare(statements_[index], text, strlen(text));
556 text <<
">, reason: " << mysql_error(
mysql_));
565 tagged_statement != end_statement; ++tagged_statement) {
566 if (tagged_statement->index >= statements_.size()) {
567 statements_.resize(tagged_statement->index + 1, NULL);
572 tagged_statement->text);
581 for (
size_t i = 0; i < statements_.size(); ++i) {
582 if (statements_[i] != NULL) {
583 (void) mysql_stmt_close(statements_[i]);
584 statements_[i] = NULL;
603 MYSQL_TIME& output_time) {
609 const uint32_t valid_lifetime,
610 MYSQL_TIME& expire) {
616 uint32_t valid_lifetime, time_t& cltt) {
631 int status = mysql_query(
mysql_,
"START TRANSACTION");
634 "reason: " << mysql_error(
mysql_));
655 if (mysql_commit(
mysql_) != 0) {
673 if (mysql_rollback(
mysql_) != 0) {
681MySqlConnection::setIntParameterValue(
const std::string& name, int64_t min, int64_t max, T& value) {
688 if (svalue.empty()) {
693 auto parsed_value = boost::lexical_cast<T>(svalue);
695 if ((parsed_value < min) || (parsed_value > max)) {
696 isc_throw(BadValue,
"bad " << svalue <<
" value");
699 value = parsed_value;
705 isc_throw(BadValue, name <<
" parameter (" <<
706 svalue <<
") must be an integer between "
707 << 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.
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
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.