Kea 2.5.8
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 // Set options for the connection:
176 // Make sure auto_reconnect is OFF! Enabling it leaves us with an unusable
177 // connection after a reconnect as among other things, it drops all our
178 // pre-compiled statements.
179 my_bool auto_reconnect = MLM_FALSE;
180 int result = mysql_options(mysql_, MYSQL_OPT_RECONNECT, &auto_reconnect);
181 if (result != 0) {
182 isc_throw(DbOpenError, "unable to set auto-reconnect option: " <<
183 mysql_error(mysql_));
184 }
185
186 // Make sure we have a large idle time window ... say 30 days...
187 const char *wait_time = "SET SESSION wait_timeout = 30 * 86400";
188 result = mysql_options(mysql_, MYSQL_INIT_COMMAND, wait_time);
189 if (result != 0) {
190 isc_throw(DbOpenError, "unable to set wait_timeout " <<
191 mysql_error(mysql_));
192 }
193
194 // Set SQL mode options for the connection: SQL mode governs how what
195 // constitutes insertable data for a given column, and how to handle
196 // invalid data. We want to ensure we get the strictest behavior and
197 // to reject invalid data with an error.
198 const char *sql_mode = "SET SESSION sql_mode ='STRICT_ALL_TABLES'";
199 result = mysql_options(mysql_, MYSQL_INIT_COMMAND, sql_mode);
200 if (result != 0) {
201 isc_throw(DbOpenError, "unable to set SQL mode options: " <<
202 mysql_error(mysql_));
203 }
204
205 // Connection timeout, the amount of time taken for the client to drop
206 // the connection if the server is not responding.
207 result = mysql_options(mysql_, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
208 if (result != 0) {
209 isc_throw(DbOpenError, "unable to set database connection timeout: " <<
210 mysql_error(mysql_));
211 }
212
213 // Set the read timeout if it has been specified. Otherwise, the timeout is
214 // not used.
215 if (read_timeout > 0) {
216 result = mysql_options(mysql_, MYSQL_OPT_READ_TIMEOUT, &read_timeout);
217 if (result != 0) {
218 isc_throw(DbOpenError, "unable to set database read timeout: " <<
219 mysql_error(mysql_));
220 }
221 }
222
223 // Set the write timeout if it has been specified. Otherwise, the timeout
224 // is not used.
225 if (write_timeout > 0) {
226 result = mysql_options(mysql_, MYSQL_OPT_WRITE_TIMEOUT, &write_timeout);
227 if (result != 0) {
228 isc_throw(DbOpenError, "unable to set database write timeout: " <<
229 mysql_error(mysql_));
230 }
231 }
232
233 // If TLS is enabled set it. If something should go wrong it will happen
234 // later at the mysql_real_connect call.
235 if (tls_) {
236 mysql_ssl_set(mysql_, key_file, cert_file, ca_file, ca_dir,
237 cipher_list);
238 }
239
240 // Open the database.
241 //
242 // The option CLIENT_FOUND_ROWS is specified so that in an UPDATE,
243 // the affected rows are the number of rows found that match the
244 // WHERE clause of the SQL statement, not the rows changed. The reason
245 // here is that MySQL apparently does not update a row if data has not
246 // changed and so the "affected rows" (retrievable from MySQL) is zero.
247 // This makes it hard to distinguish whether the UPDATE changed no rows
248 // because no row matching the WHERE clause was found, or because a
249 // row was found but no data was altered.
250 MYSQL* status = mysql_real_connect(mysql_, host, user, password, name,
251 port, NULL, CLIENT_FOUND_ROWS);
252 if (status != mysql_) {
253 std::string error_message = mysql_error(mysql_);
254
255 auto const& rec = reconnectCtl();
256 if (rec && DatabaseConnection::retry_) {
257 // Start the connection recovery.
259
260 std::ostringstream s;
261
262 s << " (scheduling retry " << rec->retryIndex() + 1 << " of " << rec->maxRetries() << " in " << rec->retryInterval() << " milliseconds)";
263
264 error_message += s.str();
265
266 isc_throw(DbOpenErrorWithRetry, error_message);
267 }
268
269 isc_throw(DbOpenError, error_message);
270 }
271
272 // Enable autocommit. In case transaction is explicitly used, this
273 // setting will be overwritten for the transaction. However, there are
274 // cases when lack of autocommit could cause transactions to hang
275 // until commit or rollback is explicitly called. This already
276 // caused issues for some unit tests which were unable to cleanup
277 // the database after the test because of pending transactions.
278 // Use of autocommit will eliminate this problem.
279 my_bool autocommit_result = mysql_autocommit(mysql_, 1);
280 if (autocommit_result != 0) {
281 isc_throw(DbOperationError, mysql_error(mysql_));
282 }
283
284 // To avoid a flush to disk on every commit, the global parameter
285 // innodb_flush_log_at_trx_commit should be set to 2. This will cause the
286 // changes to be written to the log, but flushed to disk in the background
287 // every second. Setting the parameter to that value will speed up the
288 // system, but at the risk of losing data if the system crashes.
289}
290
291// Get schema version.
292
293std::pair<uint32_t, uint32_t>
295 const IOServiceAccessorPtr& ac,
296 const DbCallback& cb,
297 const string& timer_name) {
298 // Get a connection.
299 MySqlConnection conn(parameters, ac, cb);
300
301 if (!timer_name.empty()) {
302 conn.makeReconnectCtl(timer_name);
303 }
304
305 // Open the database.
306 conn.openDatabase();
307
308 // Allocate a new statement.
309 MYSQL_STMT *stmt = mysql_stmt_init(conn.mysql_);
310 if (stmt == NULL) {
311 isc_throw(DbOperationError, "unable to allocate MySQL prepared "
312 "statement structure, reason: " << mysql_error(conn.mysql_));
313 }
314
315 try {
316
317 // Prepare the statement from SQL text.
318 const char* version_sql = "SELECT version, minor FROM schema_version";
319 int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
320 if (status != 0) {
321 isc_throw(DbOperationError, "unable to prepare MySQL statement <"
322 << version_sql << ">, reason: "
323 << mysql_error(conn.mysql_));
324 }
325
326 // Execute the prepared statement.
327 if (MysqlExecuteStatement(stmt) != 0) {
328 isc_throw(DbOperationError, "cannot execute schema version query <"
329 << version_sql << ">, reason: "
330 << mysql_errno(conn.mysql_));
331 }
332
333 // Bind the output of the statement to the appropriate variables.
334 MYSQL_BIND bind[2];
335 memset(bind, 0, sizeof(bind));
336
337 uint32_t version;
338 bind[0].buffer_type = MYSQL_TYPE_LONG;
339 bind[0].is_unsigned = 1;
340 bind[0].buffer = &version;
341 bind[0].buffer_length = sizeof(version);
342
343 uint32_t minor;
344 bind[1].buffer_type = MYSQL_TYPE_LONG;
345 bind[1].is_unsigned = 1;
346 bind[1].buffer = &minor;
347 bind[1].buffer_length = sizeof(minor);
348
349 if (mysql_stmt_bind_result(stmt, bind)) {
350 isc_throw(DbOperationError, "unable to bind result set for <"
351 << version_sql << ">, reason: "
352 << mysql_errno(conn.mysql_));
353 }
354
355 // Fetch the data.
356 if (mysql_stmt_fetch(stmt)) {
357 isc_throw(DbOperationError, "unable to bind result set for <"
358 << version_sql << ">, reason: "
359 << mysql_errno(conn.mysql_));
360 }
361
362 // Discard the statement and its resources
363 mysql_stmt_close(stmt);
364 return (std::make_pair(version, minor));
365
366 } catch (const std::exception&) {
367 // Avoid a memory leak on error.
368 mysql_stmt_close(stmt);
369
370 // Send the exception to the caller.
371 throw;
372 }
373}
374
375void
377 const DbCallback& cb,
378 const string& timer_name) {
379 // retry-on-startup?
380 bool const retry(parameters.count("retry-on-startup") &&
381 parameters.at("retry-on-startup") == "true");
382
384 pair<uint32_t, uint32_t> schema_version;
385 try {
386 schema_version = getVersion(parameters, ac, cb, retry ? timer_name : string());
387 } catch (DbOpenError const& exception) {
388 throw;
389 } catch (DbOpenErrorWithRetry const& exception) {
390 throw;
391 } catch (exception const& exception) {
392 // This failure may occur for a variety of reasons. We are looking at
393 // initializing schema as the only potential mitigation. We could narrow
394 // down on the error that would suggest an uninitialized schema
395 // which would sound something along the lines of
396 // "table schema_version does not exist", but we do not necessarily have
397 // to. If the error had another cause, it will fail again during
398 // initialization or during the subsequent version retrieval and that is
399 // fine, and the error should still be relevant.
400 initializeSchema(parameters);
401
402 // Retrieve again because the initial retrieval failed.
403 schema_version = getVersion(parameters, ac, cb, retry ? timer_name : string());
404 }
405
406 // Check that the versions match.
407 pair<uint32_t, uint32_t> const expected_version(MYSQL_SCHEMA_VERSION_MAJOR,
409 if (schema_version != expected_version) {
410 isc_throw(DbOpenError, "MySQL schema version mismatch: expected version: "
411 << expected_version.first << "." << expected_version.second
412 << ", found version: " << schema_version.first << "."
413 << schema_version.second);
414 }
415}
416
417void
419 if (parameters.count("readonly") && parameters.at("readonly") == "true") {
420 // The readonly flag is historically used for host backends. Still, if
421 // enabled, it is a strong indication that we should not meDDLe with it.
422 return;
423 }
424
426 // It can happen for kea-admin to not exist, especially with
427 // packages that install it in a separate package.
428 return;
429 }
430
431 // Convert parameters.
432 vector<string> kea_admin_parameters(toKeaAdminParameters(parameters));
433 ProcessEnvVars const vars;
434 kea_admin_parameters.insert(kea_admin_parameters.begin(), "db-init");
435
436 // Run.
437 ProcessSpawn kea_admin(ProcessSpawn::SYNC, KEA_ADMIN_, kea_admin_parameters, vars,
438 /* inherit_env = */ true);
440 pid_t const pid(kea_admin.spawn());
441 if (kea_admin.isRunning(pid)) {
442 isc_throw(SchemaInitializationFailed, "kea-admin still running");
443 }
444 int const exit_code(kea_admin.getExitStatus(pid));
445 if (exit_code != 0) {
446 isc_throw(SchemaInitializationFailed, "Expected exit code 0 for kea-admin. Got " << exit_code);
447 }
448}
449
450vector<string>
452 vector<string> result{"mysql"};
453 for (auto const& p : params) {
454 string const& keyword(p.first);
455 string const& value(p.second);
456
457 // These Kea parameters are the same as the kea-admin parameters.
458 if (keyword == "user" ||
459 keyword == "password" ||
460 keyword == "host" ||
461 keyword == "port" ||
462 keyword == "name") {
463 result.push_back("--" + keyword);
464 result.push_back(value);
465 continue;
466 }
467
468 // These Kea parameters do not have a direct kea-admin equivalent.
469 // But they do have a mariadb client flag equivalent.
470 // We pass them to kea-admin using the --extra flag.
471 static unordered_map<string, string> conversions{
472 {"connect-timeout", "connect_timeout"},
473 {"cipher-list", "ssl-cipher"},
474 {"cert-file", "ssl-cert"},
475 {"key-file", "ssl-key"},
476 {"trust-anchor", "ssl-ca"},
477 // {"read-timeout", "--net-read-timeout"}, // available in docs, but client says unknown variable?
478 // {"write-timeout", "--net-write-timeout"}, // available in docs, but client says unknown variable?
479 };
480 if (conversions.count(keyword)) {
481 result.push_back("--extra");
482 result.push_back("--" + conversions.at(keyword) + " " + value);
483 }
484 }
485 return result;
486}
487
488// Prepared statement setup. The textual form of an SQL statement is stored
489// in a vector of strings (text_statements_) and is used in the output of
490// error messages. The SQL statement is also compiled into a "prepared
491// statement" (stored in statements_), which avoids the overhead of compilation
492// during use. As prepared statements have resources allocated to them, the
493// class destructor explicitly destroys them.
494
495void
496MySqlConnection::prepareStatement(uint32_t index, const char* text) {
497 // Validate that there is space for the statement in the statements array
498 // and that nothing has been placed there before.
499 if ((index >= statements_.size()) || (statements_[index] != NULL)) {
500 isc_throw(InvalidParameter, "invalid prepared statement index (" <<
501 static_cast<int>(index) << ") or indexed prepared " <<
502 "statement is not null");
503 }
504
505 // All OK, so prepare the statement
506 text_statements_[index] = std::string(text);
507 statements_[index] = mysql_stmt_init(mysql_);
508 if (statements_[index] == NULL) {
509 isc_throw(DbOperationError, "unable to allocate MySQL prepared "
510 "statement structure, reason: " << mysql_error(mysql_));
511 }
512
513 int status = mysql_stmt_prepare(statements_[index], text, strlen(text));
514 if (status != 0) {
515 isc_throw(DbOperationError, "unable to prepare MySQL statement <" <<
516 text << ">, reason: " << mysql_error(mysql_));
517 }
518}
519
520void
522 const TaggedStatement* end_statement) {
523 // Created the MySQL prepared statements for each DML statement.
524 for (const TaggedStatement* tagged_statement = start_statement;
525 tagged_statement != end_statement; ++tagged_statement) {
526 if (tagged_statement->index >= statements_.size()) {
527 statements_.resize(tagged_statement->index + 1, NULL);
528 text_statements_.resize(tagged_statement->index + 1,
529 std::string(""));
530 }
531 prepareStatement(tagged_statement->index,
532 tagged_statement->text);
533 }
534}
535
538 // Free up the prepared statements, ignoring errors. (What would we do
539 // about them? We're destroying this object and are not really concerned
540 // with errors on a database connection that is about to go away.)
541 for (size_t i = 0; i < statements_.size(); ++i) {
542 if (statements_[i] != NULL) {
543 (void) mysql_stmt_close(statements_[i]);
544 statements_[i] = NULL;
545 }
546 }
547 statements_.clear();
548 text_statements_.clear();
549}
550
551// Time conversion methods.
552//
553// Note that the MySQL TIMESTAMP data type (used for "expire") converts data
554// from the current timezone to UTC for storage, and from UTC to the current
555// timezone for retrieval.
556//
557// This causes no problems providing that:
558// a) cltt is given in local time
559// b) We let the system take care of timezone conversion when converting
560// from a time read from the database into a local time.
561void
563 MYSQL_TIME& output_time) {
564 MySqlBinding::convertToDatabaseTime(input_time, output_time);
565}
566
567void
569 const uint32_t valid_lifetime,
570 MYSQL_TIME& expire) {
571 MySqlBinding::convertToDatabaseTime(cltt, valid_lifetime, expire);
572}
573
574void
576 uint32_t valid_lifetime, time_t& cltt) {
577 MySqlBinding::convertFromDatabaseTime(expire, valid_lifetime, cltt);
578}
579
580void
582 // If it is nested transaction, do nothing.
583 if (++transaction_ref_count_ > 1) {
584 return;
585 }
586
589 // We create prepared statements for all other queries, but MySQL
590 // don't support prepared statements for START TRANSACTION.
591 int status = mysql_query(mysql_, "START TRANSACTION");
592 if (status != 0) {
593 isc_throw(DbOperationError, "unable to start transaction, "
594 "reason: " << mysql_error(mysql_));
595 }
596}
597
598bool
600 return (transaction_ref_count_ > 0);
601}
602
603void
605 if (transaction_ref_count_ <= 0) {
606 isc_throw(Unexpected, "commit called for not started transaction - coding error");
607 }
608
609 // When committing nested transaction, do nothing.
610 if (--transaction_ref_count_ > 0) {
611 return;
612 }
615 if (mysql_commit(mysql_) != 0) {
616 isc_throw(DbOperationError, "commit failed: "
617 << mysql_error(mysql_));
618 }
619}
620
621void
623 if (transaction_ref_count_ <= 0) {
624 isc_throw(Unexpected, "rollback called for not started transaction - coding error");
625 }
626
627 // When rolling back nested transaction, do nothing.
628 if (--transaction_ref_count_ > 0) {
629 return;
630 }
633 if (mysql_rollback(mysql_) != 0) {
634 isc_throw(DbOperationError, "rollback failed: "
635 << mysql_error(mysql_));
636 }
637}
638
639template<typename T>
640void
641MySqlConnection::setIntParameterValue(const std::string& name, int64_t min, int64_t max, T& value) {
642 string svalue;
643 try {
644 svalue = getParameter(name);
645 } catch (...) {
646 // Do nothing if the parameter is not present.
647 }
648 if (svalue.empty()) {
649 return;
650 }
651 try {
652 // Try to convert the value.
653 auto parsed_value = boost::lexical_cast<T>(svalue);
654 // Check if the value is within the specified range.
655 if ((parsed_value < min) || (parsed_value > max)) {
656 isc_throw(BadValue, "bad " << svalue << " value");
657 }
658 // Everything is fine. Return the parsed value.
659 value = parsed_value;
660
661 } catch (...) {
662 // We may end up here when lexical_cast fails or when the
663 // parsed value is not within the desired range. In both
664 // cases let's throw the same general error.
665 isc_throw(BadValue, name << " parameter (" <<
666 svalue << ") must be an integer between "
667 << min << " and " << max);
668 }
669}
670
671} // namespace db
672} // 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.
virtual void makeReconnectCtl(const std::string &timer_name)
Instantiates a ReconnectCtl based on the connection's reconnect parameters.
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:64
bool isDir(string const &path)
Check if there is a directory at the given path.
Definition: filesystem.cc:55
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.