Kea 2.7.1
mysql_connection.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2024 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
12#include <database/db_log.h>
15#include <util/filesystem.h>
16
17#include <boost/lexical_cast.hpp>
18
19#include <cstdint>
20#include <exception>
21#include <limits>
22#include <string>
23#include <unordered_map>
24
25using namespace isc;
26using namespace isc::asiolink;
27using namespace std;
28
29namespace isc {
30namespace db {
31
32std::string MySqlConnection::KEA_ADMIN_ = KEA_ADMIN;
33
34int MySqlHolder::atexit_ = [] {
35 return atexit([] { mysql_library_end(); });
36}();
37
39const int MYSQL_DEFAULT_CONNECTION_TIMEOUT = 5; // seconds
40
42 : conn_(conn), committed_(false) {
43 conn_.startTransaction();
44}
45
47 // Rollback if the MySqlTransaction::commit wasn't explicitly
48 // called.
49 if (!committed_) {
50 conn_.rollback();
51 }
52}
53
54void
56 conn_.commit();
57 committed_ = true;
58}
59
60// Open the database using the parameters passed to the constructor.
61
62void
64 // Set up the values of the parameters
65 const char* host = "localhost";
66 string shost;
67 try {
68 shost = getParameter("host");
69 host = shost.c_str();
70 } catch (...) {
71 // No host. Fine, we'll use "localhost"
72 }
73
74 unsigned int port = 0;
75 try {
76 setIntParameterValue("port", 0, numeric_limits<uint16_t>::max(), port);
77
78 } catch (const std::exception& ex) {
80 }
81
82 const char* user = NULL;
83 string suser;
84 try {
85 suser = getParameter("user");
86 user = suser.c_str();
87 } catch (...) {
88 // No user. Fine, we'll use NULL
89 }
90
91 const char* password = NULL;
92 string spassword;
93 try {
94 spassword = getParameter("password");
95 password = spassword.c_str();
96 } catch (...) {
97 // No password. Fine, we'll use NULL
98 }
99
100 const char* name = NULL;
101 string sname;
102 try {
103 sname = getParameter("name");
104 name = sname.c_str();
105 } catch (...) {
106 // No database name. Throw a "NoName" exception
107 isc_throw(NoDatabaseName, "must specify a name for the database");
108 }
109
110 unsigned int connect_timeout = MYSQL_DEFAULT_CONNECTION_TIMEOUT;
111 unsigned int read_timeout = 0;
112 unsigned int write_timeout = 0;
113 try {
114 // The timeout is only valid if greater than zero, as depending on the
115 // database, a zero timeout might signify something like "wait
116 // indefinitely".
117 setIntParameterValue("connect-timeout", 1, numeric_limits<int>::max(), connect_timeout);
118 // Other timeouts can be 0, meaning that the database client will follow a default
119 // behavior. Earlier MySQL versions didn't have these parameters, so we allow 0
120 // to skip setting them.
121 setIntParameterValue("read-timeout", 0, numeric_limits<int>::max(), read_timeout);
122 setIntParameterValue("write-timeout", 0, numeric_limits<int>::max(), write_timeout);
123
124 } catch (const std::exception& ex) {
126 }
127
128 const char* ca_file(0);
129 const char* ca_dir(0);
130 string sca;
131 try {
132 sca = getParameter("trust-anchor");
133 tls_ = true;
134 if (util::file::isDir(sca)) {
135 ca_dir = sca.c_str();
136 } else {
137 ca_file = sca.c_str();
138 }
139 } catch (...) {
140 // No trust anchor
141 }
142
143 const char* cert_file(0);
144 string scert;
145 try {
146 scert = getParameter("cert-file");
147 tls_ = true;
148 cert_file = scert.c_str();
149 } catch (...) {
150 // No client certificate file
151 }
152
153 const char* key_file(0);
154 string skey;
155 try {
156 skey = getParameter("key-file");
157 tls_ = true;
158 key_file = skey.c_str();
159 } catch (...) {
160 // No private key file
161 }
162
163 const char* cipher_list(0);
164 string scipher;
165 try {
166 scipher = getParameter("cipher-list");
167 tls_ = true;
168 cipher_list = scipher.c_str();
169 } catch (...) {
170 // No cipher list
171 }
172
173 // Set options for the connection:
174 //
175 int result;
176#ifdef HAS_MYSQL_OPT_RECONNECT
177 // Though still supported by Mariadb (as of 11.5.0), MYSQL_OPT_RECONNECT is
178 // deprecated as of MySQL 8.0.34. Where it is still supported we should
179 // continue to ensure it is off. Enabling it leaves us with an unusable
180 // connection after a reconnect as among other things, it drops all our
181 // pre-compiled statements.
182 my_bool auto_reconnect = MLM_FALSE;
183 result = mysql_options(mysql_, MYSQL_OPT_RECONNECT, &auto_reconnect);
184 if (result != 0) {
185 isc_throw(DbOpenError, "unable to set auto-reconnect option: " <<
186 mysql_error(mysql_));
187 }
188#endif
189
190 // Make sure we have a large idle time window ... say 30 days...
191 const char *wait_time = "SET SESSION wait_timeout = 30 * 86400";
192 result = mysql_options(mysql_, MYSQL_INIT_COMMAND, wait_time);
193 if (result != 0) {
194 isc_throw(DbOpenError, "unable to set wait_timeout " <<
195 mysql_error(mysql_));
196 }
197
198 // Set SQL mode options for the connection: SQL mode governs how what
199 // constitutes insertable data for a given column, and how to handle
200 // invalid data. We want to ensure we get the strictest behavior and
201 // to reject invalid data with an error.
202 const char *sql_mode = "SET SESSION sql_mode ='STRICT_ALL_TABLES'";
203 result = mysql_options(mysql_, MYSQL_INIT_COMMAND, sql_mode);
204 if (result != 0) {
205 isc_throw(DbOpenError, "unable to set SQL mode options: " <<
206 mysql_error(mysql_));
207 }
208
209 // Connection timeout, the amount of time taken for the client to drop
210 // the connection if the server is not responding.
211 result = mysql_options(mysql_, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
212 if (result != 0) {
213 isc_throw(DbOpenError, "unable to set database connection timeout: " <<
214 mysql_error(mysql_));
215 }
216
217 // Set the read timeout if it has been specified. Otherwise, the timeout is
218 // not used.
219 if (read_timeout > 0) {
220 result = mysql_options(mysql_, MYSQL_OPT_READ_TIMEOUT, &read_timeout);
221 if (result != 0) {
222 isc_throw(DbOpenError, "unable to set database read timeout: " <<
223 mysql_error(mysql_));
224 }
225 }
226
227 // Set the write timeout if it has been specified. Otherwise, the timeout
228 // is not used.
229 if (write_timeout > 0) {
230 result = mysql_options(mysql_, MYSQL_OPT_WRITE_TIMEOUT, &write_timeout);
231 if (result != 0) {
232 isc_throw(DbOpenError, "unable to set database write timeout: " <<
233 mysql_error(mysql_));
234 }
235 }
236
237 // If TLS is enabled set it. If something should go wrong it will happen
238 // later at the mysql_real_connect call.
239 if (tls_) {
240 result = mysql_options(mysql_, MYSQL_OPT_SSL_KEY, key_file);
241 if (result != 0) {
242 isc_throw(DbOpenError, "unable to set key: " << mysql_error(mysql_));
243 }
244
245 result = mysql_options(mysql_, MYSQL_OPT_SSL_CERT, cert_file);
246 if (result != 0) {
247 isc_throw(DbOpenError, "unable to set certificate: " << mysql_error(mysql_));
248 }
249
250 result = mysql_options(mysql_, MYSQL_OPT_SSL_CA, ca_file);
251 if (result != 0) {
252 isc_throw(DbOpenError, "unable to set CA: " << mysql_error(mysql_));
253 }
254
255 result = mysql_options(mysql_, MYSQL_OPT_SSL_CAPATH, ca_dir);
256 if (result != 0) {
257 isc_throw(DbOpenError, "unable to set CA path: " << mysql_error(mysql_));
258 }
259
260 result = mysql_options(mysql_, MYSQL_OPT_SSL_CIPHER, cipher_list);
261 if (result != 0) {
262 isc_throw(DbOpenError, "unable to set cipher: " << mysql_error(mysql_));
263 }
264 }
265
266 // Open the database.
267 //
268 // The option CLIENT_FOUND_ROWS is specified so that in an UPDATE,
269 // the affected rows are the number of rows found that match the
270 // WHERE clause of the SQL statement, not the rows changed. The reason
271 // here is that MySQL apparently does not update a row if data has not
272 // changed and so the "affected rows" (retrievable from MySQL) is zero.
273 // This makes it hard to distinguish whether the UPDATE changed no rows
274 // because no row matching the WHERE clause was found, or because a
275 // row was found but no data was altered.
276 MYSQL* status = mysql_real_connect(mysql_, host, user, password, name,
277 port, NULL, CLIENT_FOUND_ROWS);
278 if (status != mysql_) {
279 std::string error_message = mysql_error(mysql_);
280
281 auto const& rec = reconnectCtl();
282 if (rec && DatabaseConnection::retry_) {
283 // Start the connection recovery.
285
286 std::ostringstream s;
287
288 s << " (scheduling retry " << rec->retryIndex() + 1 << " of " << rec->maxRetries() << " in " << rec->retryInterval() << " milliseconds)";
289
290 error_message += s.str();
291
292 isc_throw(DbOpenErrorWithRetry, error_message);
293 }
294
295 isc_throw(DbOpenError, error_message);
296 }
297
298 // Enable autocommit. In case transaction is explicitly used, this
299 // setting will be overwritten for the transaction. However, there are
300 // cases when lack of autocommit could cause transactions to hang
301 // until commit or rollback is explicitly called. This already
302 // caused issues for some unit tests which were unable to cleanup
303 // the database after the test because of pending transactions.
304 // Use of autocommit will eliminate this problem.
305 my_bool autocommit_result = mysql_autocommit(mysql_, 1);
306 if (autocommit_result != 0) {
307 isc_throw(DbOperationError, mysql_error(mysql_));
308 }
309
310 // To avoid a flush to disk on every commit, the global parameter
311 // innodb_flush_log_at_trx_commit should be set to 2. This will cause the
312 // changes to be written to the log, but flushed to disk in the background
313 // every second. Setting the parameter to that value will speed up the
314 // system, but at the risk of losing data if the system crashes.
315}
316
317// Get schema version.
318
319std::pair<uint32_t, uint32_t>
321 const IOServiceAccessorPtr& ac,
322 const DbCallback& cb,
323 const string& timer_name) {
324 // Get a connection.
325 MySqlConnection conn(parameters, ac, cb);
326
327 if (!timer_name.empty()) {
328 conn.makeReconnectCtl(timer_name);
329 }
330
331 // Open the database.
332 conn.openDatabase();
333
334 // Allocate a new statement.
335 MYSQL_STMT *stmt = mysql_stmt_init(conn.mysql_);
336 if (stmt == NULL) {
337 isc_throw(DbOperationError, "unable to allocate MySQL prepared "
338 "statement structure, reason: " << mysql_error(conn.mysql_));
339 }
340
341 try {
342
343 // Prepare the statement from SQL text.
344 const char* version_sql = "SELECT version, minor FROM schema_version";
345 int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
346 if (status != 0) {
347 isc_throw(DbOperationError, "unable to prepare MySQL statement <"
348 << version_sql << ">, reason: "
349 << mysql_error(conn.mysql_));
350 }
351
352 // Execute the prepared statement.
353 if (MysqlExecuteStatement(stmt) != 0) {
354 isc_throw(DbOperationError, "cannot execute schema version query <"
355 << version_sql << ">, reason: "
356 << mysql_errno(conn.mysql_));
357 }
358
359 // Bind the output of the statement to the appropriate variables.
360 MYSQL_BIND bind[2];
361 memset(bind, 0, sizeof(bind));
362
363 uint32_t version;
364 bind[0].buffer_type = MYSQL_TYPE_LONG;
365 bind[0].is_unsigned = 1;
366 bind[0].buffer = &version;
367 bind[0].buffer_length = sizeof(version);
368
369 uint32_t minor;
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);
374
375 if (mysql_stmt_bind_result(stmt, bind)) {
376 isc_throw(DbOperationError, "unable to bind result set for <"
377 << version_sql << ">, reason: "
378 << mysql_errno(conn.mysql_));
379 }
380
381 // Fetch the data.
382 if (mysql_stmt_fetch(stmt)) {
383 isc_throw(DbOperationError, "unable to bind result set for <"
384 << version_sql << ">, reason: "
385 << mysql_errno(conn.mysql_));
386 }
387
388 // Discard the statement and its resources
389 mysql_stmt_close(stmt);
390 return (std::make_pair(version, minor));
391
392 } catch (const std::exception&) {
393 // Avoid a memory leak on error.
394 mysql_stmt_close(stmt);
395
396 // Send the exception to the caller.
397 throw;
398 }
399}
400
401void
403 const DbCallback& cb,
404 const string& timer_name) {
405 // retry-on-startup?
406 bool const retry(parameters.count("retry-on-startup") &&
407 parameters.at("retry-on-startup") == "true");
408
410 pair<uint32_t, uint32_t> schema_version;
411 try {
412 schema_version = getVersion(parameters, ac, cb, retry ? timer_name : string());
413 } catch (DbOpenError const& exception) {
414 throw;
415 } catch (DbOpenErrorWithRetry const& exception) {
416 throw;
417 } catch (exception const& exception) {
418 // This failure may occur for a variety of reasons. We are looking at
419 // initializing schema as the only potential mitigation. We could narrow
420 // down on the error that would suggest an uninitialized schema
421 // which would sound something along the lines of
422 // "table schema_version does not exist", but we do not necessarily have
423 // to. If the error had another cause, it will fail again during
424 // initialization or during the subsequent version retrieval and that is
425 // fine, and the error should still be relevant.
426 initializeSchema(parameters);
427
428 // Retrieve again because the initial retrieval failed.
429 schema_version = getVersion(parameters, ac, cb, retry ? timer_name : string());
430 }
431
432 // Check that the versions match.
433 pair<uint32_t, uint32_t> const expected_version(MYSQL_SCHEMA_VERSION_MAJOR,
435 if (schema_version != expected_version) {
436 isc_throw(DbOpenError, "MySQL schema version mismatch: expected version: "
437 << expected_version.first << "." << expected_version.second
438 << ", found version: " << schema_version.first << "."
439 << schema_version.second);
440 }
441}
442
443void
445 if (parameters.count("readonly") && parameters.at("readonly") == "true") {
446 // The readonly flag is historically used for host backends. Still, if
447 // enabled, it is a strong indication that we should not meDDLe with it.
448 return;
449 }
450
452 // It can happen for kea-admin to not exist, especially with
453 // packages that install it in a separate package.
454 return;
455 }
456
457 // Convert parameters.
458 vector<string> kea_admin_parameters(toKeaAdminParameters(parameters));
459 ProcessEnvVars const vars;
460 kea_admin_parameters.insert(kea_admin_parameters.begin(), "db-init");
461
462 // Run.
463 ProcessSpawn kea_admin(ProcessSpawn::SYNC, KEA_ADMIN_, kea_admin_parameters, vars,
464 /* inherit_env = */ true);
465 DB_LOG_INFO(MYSQL_INITIALIZE_SCHEMA).arg(kea_admin.getCommandLine());
466 pid_t const pid(kea_admin.spawn());
467 if (kea_admin.isRunning(pid)) {
468 isc_throw(SchemaInitializationFailed, "kea-admin still running");
469 }
470 int const exit_code(kea_admin.getExitStatus(pid));
471 if (exit_code != 0) {
472 isc_throw(SchemaInitializationFailed, "Expected exit code 0 for kea-admin. Got " << exit_code);
473 }
474}
475
476vector<string>
478 vector<string> result{"mysql"};
479 for (auto const& p : params) {
480 string const& keyword(p.first);
481 string const& value(p.second);
482
483 // These Kea parameters are the same as the kea-admin parameters.
484 if (keyword == "user" ||
485 keyword == "password" ||
486 keyword == "host" ||
487 keyword == "port" ||
488 keyword == "name") {
489 result.push_back("--" + keyword);
490 result.push_back(value);
491 continue;
492 }
493
494 // These Kea parameters do not have a direct kea-admin equivalent.
495 // But they do have a mariadb client flag equivalent.
496 // We pass them to kea-admin using the --extra flag.
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"},
503 // {"read-timeout", "--net-read-timeout"}, // available in docs, but client says unknown variable?
504 // {"write-timeout", "--net-write-timeout"}, // available in docs, but client says unknown variable?
505 };
506 if (conversions.count(keyword)) {
507 result.push_back("--extra");
508 result.push_back("--" + conversions.at(keyword) + " " + value);
509 }
510 }
511 return result;
512}
513
514// Prepared statement setup. The textual form of an SQL statement is stored
515// in a vector of strings (text_statements_) and is used in the output of
516// error messages. The SQL statement is also compiled into a "prepared
517// statement" (stored in statements_), which avoids the overhead of compilation
518// during use. As prepared statements have resources allocated to them, the
519// class destructor explicitly destroys them.
520
521void
522MySqlConnection::prepareStatement(uint32_t index, const char* text) {
523 // Validate that there is space for the statement in the statements array
524 // and that nothing has been placed there before.
525 if ((index >= statements_.size()) || (statements_[index] != NULL)) {
526 isc_throw(InvalidParameter, "invalid prepared statement index (" <<
527 static_cast<int>(index) << ") or indexed prepared " <<
528 "statement is not null");
529 }
530
531 // All OK, so prepare the statement
532 text_statements_[index] = std::string(text);
533 statements_[index] = mysql_stmt_init(mysql_);
534 if (statements_[index] == NULL) {
535 isc_throw(DbOperationError, "unable to allocate MySQL prepared "
536 "statement structure, reason: " << mysql_error(mysql_));
537 }
538
539 int status = mysql_stmt_prepare(statements_[index], text, strlen(text));
540 if (status != 0) {
541 isc_throw(DbOperationError, "unable to prepare MySQL statement <" <<
542 text << ">, reason: " << mysql_error(mysql_));
543 }
544}
545
546void
548 const TaggedStatement* end_statement) {
549 // Created the MySQL prepared statements for each DML statement.
550 for (const TaggedStatement* tagged_statement = start_statement;
551 tagged_statement != end_statement; ++tagged_statement) {
552 if (tagged_statement->index >= statements_.size()) {
553 statements_.resize(tagged_statement->index + 1, NULL);
554 text_statements_.resize(tagged_statement->index + 1,
555 std::string(""));
556 }
557 prepareStatement(tagged_statement->index,
558 tagged_statement->text);
559 }
560}
561
564 // Free up the prepared statements, ignoring errors. (What would we do
565 // about them? We're destroying this object and are not really concerned
566 // with errors on a database connection that is about to go away.)
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;
571 }
572 }
573 statements_.clear();
574 text_statements_.clear();
575}
576
577// Time conversion methods.
578//
579// Note that the MySQL TIMESTAMP data type (used for "expire") converts data
580// from the current timezone to UTC for storage, and from UTC to the current
581// timezone for retrieval.
582//
583// This causes no problems providing that:
584// a) cltt is given in local time
585// b) We let the system take care of timezone conversion when converting
586// from a time read from the database into a local time.
587void
589 MYSQL_TIME& output_time) {
590 MySqlBinding::convertToDatabaseTime(input_time, output_time);
591}
592
593void
595 const uint32_t valid_lifetime,
596 MYSQL_TIME& expire) {
597 MySqlBinding::convertToDatabaseTime(cltt, valid_lifetime, expire);
598}
599
600void
602 uint32_t valid_lifetime, time_t& cltt) {
603 MySqlBinding::convertFromDatabaseTime(expire, valid_lifetime, cltt);
604}
605
606void
608 // If it is nested transaction, do nothing.
609 if (++transaction_ref_count_ > 1) {
610 return;
611 }
612
615 // We create prepared statements for all other queries, but MySQL
616 // don't support prepared statements for START TRANSACTION.
617 int status = mysql_query(mysql_, "START TRANSACTION");
618 if (status != 0) {
619 isc_throw(DbOperationError, "unable to start transaction, "
620 "reason: " << mysql_error(mysql_));
621 }
622}
623
624bool
628
629void
631 if (transaction_ref_count_ <= 0) {
632 isc_throw(Unexpected, "commit called for not started transaction - coding error");
633 }
634
635 // When committing nested transaction, do nothing.
636 if (--transaction_ref_count_ > 0) {
637 return;
638 }
641 if (mysql_commit(mysql_) != 0) {
642 isc_throw(DbOperationError, "commit failed: "
643 << mysql_error(mysql_));
644 }
645}
646
647void
649 if (transaction_ref_count_ <= 0) {
650 isc_throw(Unexpected, "rollback called for not started transaction - coding error");
651 }
652
653 // When rolling back nested transaction, do nothing.
654 if (--transaction_ref_count_ > 0) {
655 return;
656 }
659 if (mysql_rollback(mysql_) != 0) {
660 isc_throw(DbOperationError, "rollback failed: "
661 << mysql_error(mysql_));
662 }
663}
664
665template<typename T>
666void
667MySqlConnection::setIntParameterValue(const std::string& name, int64_t min, int64_t max, T& value) {
668 string svalue;
669 try {
670 svalue = getParameter(name);
671 } catch (...) {
672 // Do nothing if the parameter is not present.
673 }
674 if (svalue.empty()) {
675 return;
676 }
677 try {
678 // Try to convert the value.
679 auto parsed_value = boost::lexical_cast<T>(svalue);
680 // Check if the value is within the specified range.
681 if ((parsed_value < min) || (parsed_value > max)) {
682 isc_throw(BadValue, "bad " << svalue << " value");
683 }
684 // Everything is fine. Return the parsed value.
685 value = parsed_value;
686
687 } catch (...) {
688 // We may end up here when lexical_cast fails or when the
689 // parsed value is not within the desired range. In both
690 // cases let's throw the same general error.
691 isc_throw(BadValue, name << " parameter (" <<
692 svalue << ") must be an integer between "
693 << min << " and " << max);
694 }
695}
696
697} // namespace db
698} // namespace isc
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.
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.
Invalid port number.
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 &parameters, 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 &parameters)
Initialize schema.
static std::vector< std::string > toKeaAdminParameters(ParameterMap const &params)
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 &parameters, 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...
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.
const int DB_DBG_TRACE_DETAIL
Database logging levels.
Definition db_log.cc:21
const my_bool MLM_FALSE
MySQL false value.
const int MYSQL_DEFAULT_CONNECTION_TIMEOUT
@ MYSQL_START_TRANSACTION
Definition db_log.h:66
@ MYSQL_INITIALIZE_SCHEMA
Definition db_log.h:64
@ MYSQL_ROLLBACK
Definition db_log.h:68
@ MYSQL_COMMIT
Definition db_log.h:67
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.
Definition filesystem.cc:63
bool isDir(string const &path)
Check if there is a directory at the given path.
Definition filesystem.cc:54
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.
Definition db_log.h:144
MySQL Selection Statements.