Kea 2.7.6
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) {
79 isc_throw(DbInvalidPort, ex.what());
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) {
125 isc_throw(DbInvalidTimeout, ex.what());
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 // Disable the recovery mechanism in test mode.
420 throw;
421 }
422 // This failure may occur for a variety of reasons. We are looking at
423 // initializing schema as the only potential mitigation. We could narrow
424 // down on the error that would suggest an uninitialized schema
425 // which would sound something along the lines of
426 // "table schema_version does not exist", but we do not necessarily have
427 // to. If the error had another cause, it will fail again during
428 // initialization or during the subsequent version retrieval and that is
429 // fine, and the error should still be relevant.
430 initializeSchema(parameters);
431
432 // Retrieve again because the initial retrieval failed.
433 schema_version = getVersion(parameters, ac, cb, retry ? timer_name : string());
434 }
435
436 // Check that the versions match.
437 pair<uint32_t, uint32_t> const expected_version(MYSQL_SCHEMA_VERSION_MAJOR,
439 if (schema_version != expected_version) {
440 isc_throw(DbOpenError, "MySQL schema version mismatch: expected version: "
441 << expected_version.first << "." << expected_version.second
442 << ", found version: " << schema_version.first << "."
443 << schema_version.second);
444 }
445}
446
447void
449 if (parameters.count("readonly") && parameters.at("readonly") == "true") {
450 // The readonly flag is historically used for host backends. Still, if
451 // enabled, it is a strong indication that we should not meDDLe with it.
452 return;
453 }
454
456 // It can happen for kea-admin to not exist, especially with
457 // packages that install it in a separate package.
458 return;
459 }
460
461 // Convert parameters.
462 vector<string> kea_admin_parameters(toKeaAdminParameters(parameters));
463 ProcessEnvVars const vars;
464 kea_admin_parameters.insert(kea_admin_parameters.begin(), "db-init");
465
466 // Run.
467 ProcessSpawn kea_admin(ProcessSpawn::SYNC, KEA_ADMIN_, kea_admin_parameters, vars,
468 /* inherit_env = */ true);
470 pid_t const pid(kea_admin.spawn());
471 if (kea_admin.isRunning(pid)) {
472 isc_throw(SchemaInitializationFailed, "kea-admin still running");
473 }
474 int const exit_code(kea_admin.getExitStatus(pid));
475 if (exit_code != 0) {
476 isc_throw(SchemaInitializationFailed, "Expected exit code 0 for kea-admin. Got " << exit_code);
477 }
478}
479
480vector<string>
482 vector<string> result{"mysql"};
483 for (auto const& p : params) {
484 string const& keyword(p.first);
485 string const& value(p.second);
486
487 // These Kea parameters are the same as the kea-admin parameters.
488 if (keyword == "user" ||
489 keyword == "password" ||
490 keyword == "host" ||
491 keyword == "port" ||
492 keyword == "name") {
493 result.push_back("--" + keyword);
494 result.push_back(value);
495 continue;
496 }
497
498 // These Kea parameters do not have a direct kea-admin equivalent.
499 // But they do have a mariadb client flag equivalent.
500 // We pass them to kea-admin using the --extra flag.
501 static unordered_map<string, string> conversions{
502 {"connect-timeout", "connect_timeout"},
503 {"cipher-list", "ssl-cipher"},
504 {"cert-file", "ssl-cert"},
505 {"key-file", "ssl-key"},
506 {"trust-anchor", "ssl-ca"},
507 // {"read-timeout", "--net-read-timeout"}, // available in docs, but client says unknown variable?
508 // {"write-timeout", "--net-write-timeout"}, // available in docs, but client says unknown variable?
509 };
510 if (conversions.count(keyword)) {
511 result.push_back("--extra");
512 result.push_back("--" + conversions.at(keyword) + " " + value);
513 }
514 }
515 return result;
516}
517
518// Prepared statement setup. The textual form of an SQL statement is stored
519// in a vector of strings (text_statements_) and is used in the output of
520// error messages. The SQL statement is also compiled into a "prepared
521// statement" (stored in statements_), which avoids the overhead of compilation
522// during use. As prepared statements have resources allocated to them, the
523// class destructor explicitly destroys them.
524
525void
526MySqlConnection::prepareStatement(uint32_t index, const char* text) {
527 // Validate that there is space for the statement in the statements array
528 // and that nothing has been placed there before.
529 if ((index >= statements_.size()) || (statements_[index] != NULL)) {
530 isc_throw(InvalidParameter, "invalid prepared statement index (" <<
531 static_cast<int>(index) << ") or indexed prepared " <<
532 "statement is not null");
533 }
534
535 // All OK, so prepare the statement
536 text_statements_[index] = std::string(text);
537 statements_[index] = mysql_stmt_init(mysql_);
538 if (statements_[index] == NULL) {
539 isc_throw(DbOperationError, "unable to allocate MySQL prepared "
540 "statement structure, reason: " << mysql_error(mysql_));
541 }
542
543 int status = mysql_stmt_prepare(statements_[index], text, strlen(text));
544 if (status != 0) {
545 isc_throw(DbOperationError, "unable to prepare MySQL statement <" <<
546 text << ">, reason: " << mysql_error(mysql_));
547 }
548}
549
550void
552 const TaggedStatement* end_statement) {
553 // Created the MySQL prepared statements for each DML statement.
554 for (const TaggedStatement* tagged_statement = start_statement;
555 tagged_statement != end_statement; ++tagged_statement) {
556 if (tagged_statement->index >= statements_.size()) {
557 statements_.resize(tagged_statement->index + 1, NULL);
558 text_statements_.resize(tagged_statement->index + 1,
559 std::string(""));
560 }
561 prepareStatement(tagged_statement->index,
562 tagged_statement->text);
563 }
564}
565
568 // Free up the prepared statements, ignoring errors. (What would we do
569 // about them? We're destroying this object and are not really concerned
570 // with errors on a database connection that is about to go away.)
571 for (size_t i = 0; i < statements_.size(); ++i) {
572 if (statements_[i] != NULL) {
573 (void) mysql_stmt_close(statements_[i]);
574 statements_[i] = NULL;
575 }
576 }
577 statements_.clear();
578 text_statements_.clear();
579}
580
581// Time conversion methods.
582//
583// Note that the MySQL TIMESTAMP data type (used for "expire") converts data
584// from the current timezone to UTC for storage, and from UTC to the current
585// timezone for retrieval.
586//
587// This causes no problems providing that:
588// a) cltt is given in local time
589// b) We let the system take care of timezone conversion when converting
590// from a time read from the database into a local time.
591void
593 MYSQL_TIME& output_time) {
594 MySqlBinding::convertToDatabaseTime(input_time, output_time);
595}
596
597void
599 const uint32_t valid_lifetime,
600 MYSQL_TIME& expire) {
601 MySqlBinding::convertToDatabaseTime(cltt, valid_lifetime, expire);
602}
603
604void
606 uint32_t valid_lifetime, time_t& cltt) {
607 MySqlBinding::convertFromDatabaseTime(expire, valid_lifetime, cltt);
608}
609
610void
612 // If it is nested transaction, do nothing.
613 if (++transaction_ref_count_ > 1) {
614 return;
615 }
616
619 // We create prepared statements for all other queries, but MySQL
620 // don't support prepared statements for START TRANSACTION.
621 int status = mysql_query(mysql_, "START TRANSACTION");
622 if (status != 0) {
623 isc_throw(DbOperationError, "unable to start transaction, "
624 "reason: " << mysql_error(mysql_));
625 }
626}
627
628bool
632
633void
635 if (transaction_ref_count_ <= 0) {
636 isc_throw(Unexpected, "commit called for not started transaction - coding error");
637 }
638
639 // When committing nested transaction, do nothing.
640 if (--transaction_ref_count_ > 0) {
641 return;
642 }
645 if (mysql_commit(mysql_) != 0) {
646 isc_throw(DbOperationError, "commit failed: "
647 << mysql_error(mysql_));
648 }
649}
650
651void
653 if (transaction_ref_count_ <= 0) {
654 isc_throw(Unexpected, "rollback called for not started transaction - coding error");
655 }
656
657 // When rolling back nested transaction, do nothing.
658 if (--transaction_ref_count_ > 0) {
659 return;
660 }
663 if (mysql_rollback(mysql_) != 0) {
664 isc_throw(DbOperationError, "rollback failed: "
665 << mysql_error(mysql_));
666 }
667}
668
669template<typename T>
670void
671MySqlConnection::setIntParameterValue(const std::string& name, int64_t min, int64_t max, T& value) {
672 string svalue;
673 try {
674 svalue = getParameter(name);
675 } catch (...) {
676 // Do nothing if the parameter is not present.
677 }
678 if (svalue.empty()) {
679 return;
680 }
681 try {
682 // Try to convert the value.
683 auto parsed_value = boost::lexical_cast<T>(svalue);
684 // Check if the value is within the specified range.
685 if ((parsed_value < min) || (parsed_value > max)) {
686 isc_throw(BadValue, "bad " << svalue << " value");
687 }
688 // Everything is fine. Return the parsed value.
689 value = parsed_value;
690
691 } catch (...) {
692 // We may end up here when lexical_cast fails or when the
693 // parsed value is not within the desired range. In both
694 // cases let's throw the same general error.
695 isc_throw(BadValue, name << " parameter (" <<
696 svalue << ") must be an integer between "
697 << min << " and " << max);
698 }
699}
700
701} // namespace db
702} // 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...
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.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
virtual void makeReconnectCtl(const std::string &timer_name)
Instantiates a ReconnectCtl based on the connection's reconnect parameters.
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.
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:61
bool isDir(string const &path)
Check if there is a directory at the given path.
Definition filesystem.cc:52
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.