Kea 2.6.2
mysql_connection.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2025 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 unsigned int id) {
325 // Get a connection.
326 MySqlConnection conn(parameters, ac, cb);
327
328 if (!timer_name.empty()) {
329 conn.makeReconnectCtl(timer_name, id);
330 }
331
332 // Open the database.
333 conn.openDatabase();
334
335 // Allocate a new statement.
336 MYSQL_STMT *stmt = mysql_stmt_init(conn.mysql_);
337 if (stmt == NULL) {
338 isc_throw(DbOperationError, "unable to allocate MySQL prepared "
339 "statement structure, reason: " << mysql_error(conn.mysql_));
340 }
341
342 try {
343
344 // Prepare the statement from SQL text.
345 const char* version_sql = "SELECT version, minor FROM schema_version";
346 int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
347 if (status != 0) {
348 isc_throw(DbOperationError, "unable to prepare MySQL statement <"
349 << version_sql << ">, reason: "
350 << mysql_error(conn.mysql_));
351 }
352
353 // Execute the prepared statement.
354 if (MysqlExecuteStatement(stmt) != 0) {
355 isc_throw(DbOperationError, "cannot execute schema version query <"
356 << version_sql << ">, reason: "
357 << mysql_errno(conn.mysql_));
358 }
359
360 // Bind the output of the statement to the appropriate variables.
361 MYSQL_BIND bind[2];
362 memset(bind, 0, sizeof(bind));
363
364 uint32_t version;
365 bind[0].buffer_type = MYSQL_TYPE_LONG;
366 bind[0].is_unsigned = 1;
367 bind[0].buffer = &version;
368 bind[0].buffer_length = sizeof(version);
369
370 uint32_t minor;
371 bind[1].buffer_type = MYSQL_TYPE_LONG;
372 bind[1].is_unsigned = 1;
373 bind[1].buffer = &minor;
374 bind[1].buffer_length = sizeof(minor);
375
376 if (mysql_stmt_bind_result(stmt, bind)) {
377 isc_throw(DbOperationError, "unable to bind result set for <"
378 << version_sql << ">, reason: "
379 << mysql_errno(conn.mysql_));
380 }
381
382 // Fetch the data.
383 if (mysql_stmt_fetch(stmt)) {
384 isc_throw(DbOperationError, "unable to bind result set for <"
385 << version_sql << ">, reason: "
386 << mysql_errno(conn.mysql_));
387 }
388
389 // Discard the statement and its resources
390 mysql_stmt_close(stmt);
391 return (std::make_pair(version, minor));
392
393 } catch (const std::exception&) {
394 // Avoid a memory leak on error.
395 mysql_stmt_close(stmt);
396
397 // Send the exception to the caller.
398 throw;
399 }
400}
401
402void
404 const DbCallback& cb,
405 const string& timer_name) {
406 // retry-on-startup?
407 bool const retry(parameters.count("retry-on-startup") &&
408 parameters.at("retry-on-startup") == "true");
409
411 pair<uint32_t, uint32_t> schema_version;
412 try {
413 schema_version = getVersion(parameters, ac, cb, retry ? timer_name : string());
414 } catch (DbOpenError const& exception) {
415 throw;
416 } catch (DbOpenErrorWithRetry const& exception) {
417 throw;
418 } catch (exception const& exception) {
419 // This failure may occur for a variety of reasons. We are looking at
420 // initializing schema as the only potential mitigation. We could narrow
421 // down on the error that would suggest an uninitialized schema
422 // which would sound something along the lines of
423 // "table schema_version does not exist", but we do not necessarily have
424 // to. If the error had another cause, it will fail again during
425 // initialization or during the subsequent version retrieval and that is
426 // fine, and the error should still be relevant.
427 initializeSchema(parameters);
428
429 // Retrieve again because the initial retrieval failed.
430 schema_version = getVersion(parameters, ac, cb, retry ? timer_name : string());
431 }
432
433 // Check that the versions match.
434 pair<uint32_t, uint32_t> const expected_version(MYSQL_SCHEMA_VERSION_MAJOR,
436 if (schema_version != expected_version) {
437 isc_throw(DbOpenError, "MySQL schema version mismatch: expected version: "
438 << expected_version.first << "." << expected_version.second
439 << ", found version: " << schema_version.first << "."
440 << schema_version.second);
441 }
442}
443
444void
446 if (parameters.count("readonly") && parameters.at("readonly") == "true") {
447 // The readonly flag is historically used for host backends. Still, if
448 // enabled, it is a strong indication that we should not meDDLe with it.
449 return;
450 }
451
453 // It can happen for kea-admin to not exist, especially with
454 // packages that install it in a separate package.
455 return;
456 }
457
458 // Convert parameters.
459 vector<string> kea_admin_parameters(toKeaAdminParameters(parameters));
460 ProcessEnvVars const vars;
461 kea_admin_parameters.insert(kea_admin_parameters.begin(), "db-init");
462
463 // Run.
464 ProcessSpawn kea_admin(ProcessSpawn::SYNC, KEA_ADMIN_, kea_admin_parameters, vars,
465 /* inherit_env = */ true);
467 pid_t const pid(kea_admin.spawn());
468 if (kea_admin.isRunning(pid)) {
469 isc_throw(SchemaInitializationFailed, "kea-admin still running");
470 }
471 int const exit_code(kea_admin.getExitStatus(pid));
472 if (exit_code != 0) {
473 isc_throw(SchemaInitializationFailed, "Expected exit code 0 for kea-admin. Got " << exit_code);
474 }
475}
476
477vector<string>
479 vector<string> result{"mysql"};
480 for (auto const& p : params) {
481 string const& keyword(p.first);
482 string const& value(p.second);
483
484 // These Kea parameters are the same as the kea-admin parameters.
485 if (keyword == "user" ||
486 keyword == "password" ||
487 keyword == "host" ||
488 keyword == "port" ||
489 keyword == "name") {
490 result.push_back("--" + keyword);
491 result.push_back(value);
492 continue;
493 }
494
495 // These Kea parameters do not have a direct kea-admin equivalent.
496 // But they do have a mariadb client flag equivalent.
497 // We pass them to kea-admin using the --extra flag.
498 static unordered_map<string, string> conversions{
499 {"connect-timeout", "connect_timeout"},
500 {"cipher-list", "ssl-cipher"},
501 {"cert-file", "ssl-cert"},
502 {"key-file", "ssl-key"},
503 {"trust-anchor", "ssl-ca"},
504 // {"read-timeout", "--net-read-timeout"}, // available in docs, but client says unknown variable?
505 // {"write-timeout", "--net-write-timeout"}, // available in docs, but client says unknown variable?
506 };
507 if (conversions.count(keyword)) {
508 result.push_back("--extra");
509 result.push_back("--" + conversions.at(keyword) + " " + value);
510 }
511 }
512 return result;
513}
514
515// Prepared statement setup. The textual form of an SQL statement is stored
516// in a vector of strings (text_statements_) and is used in the output of
517// error messages. The SQL statement is also compiled into a "prepared
518// statement" (stored in statements_), which avoids the overhead of compilation
519// during use. As prepared statements have resources allocated to them, the
520// class destructor explicitly destroys them.
521
522void
523MySqlConnection::prepareStatement(uint32_t index, const char* text) {
524 // Validate that there is space for the statement in the statements array
525 // and that nothing has been placed there before.
526 if ((index >= statements_.size()) || (statements_[index] != NULL)) {
527 isc_throw(InvalidParameter, "invalid prepared statement index (" <<
528 static_cast<int>(index) << ") or indexed prepared " <<
529 "statement is not null");
530 }
531
532 // All OK, so prepare the statement
533 text_statements_[index] = std::string(text);
534 statements_[index] = mysql_stmt_init(mysql_);
535 if (statements_[index] == NULL) {
536 isc_throw(DbOperationError, "unable to allocate MySQL prepared "
537 "statement structure, reason: " << mysql_error(mysql_));
538 }
539
540 int status = mysql_stmt_prepare(statements_[index], text, strlen(text));
541 if (status != 0) {
542 isc_throw(DbOperationError, "unable to prepare MySQL statement <" <<
543 text << ">, reason: " << mysql_error(mysql_));
544 }
545}
546
547void
549 const TaggedStatement* end_statement) {
550 // Created the MySQL prepared statements for each DML statement.
551 for (const TaggedStatement* tagged_statement = start_statement;
552 tagged_statement != end_statement; ++tagged_statement) {
553 if (tagged_statement->index >= statements_.size()) {
554 statements_.resize(tagged_statement->index + 1, NULL);
555 text_statements_.resize(tagged_statement->index + 1,
556 std::string(""));
557 }
558 prepareStatement(tagged_statement->index,
559 tagged_statement->text);
560 }
561}
562
565 // Free up the prepared statements, ignoring errors. (What would we do
566 // about them? We're destroying this object and are not really concerned
567 // with errors on a database connection that is about to go away.)
568 for (size_t i = 0; i < statements_.size(); ++i) {
569 if (statements_[i] != NULL) {
570 (void) mysql_stmt_close(statements_[i]);
571 statements_[i] = NULL;
572 }
573 }
574 statements_.clear();
575 text_statements_.clear();
576}
577
578// Time conversion methods.
579//
580// Note that the MySQL TIMESTAMP data type (used for "expire") converts data
581// from the current timezone to UTC for storage, and from UTC to the current
582// timezone for retrieval.
583//
584// This causes no problems providing that:
585// a) cltt is given in local time
586// b) We let the system take care of timezone conversion when converting
587// from a time read from the database into a local time.
588void
590 MYSQL_TIME& output_time) {
591 MySqlBinding::convertToDatabaseTime(input_time, output_time);
592}
593
594void
596 const uint32_t valid_lifetime,
597 MYSQL_TIME& expire) {
598 MySqlBinding::convertToDatabaseTime(cltt, valid_lifetime, expire);
599}
600
601void
603 uint32_t valid_lifetime, time_t& cltt) {
604 MySqlBinding::convertFromDatabaseTime(expire, valid_lifetime, cltt);
605}
606
607void
609 // If it is nested transaction, do nothing.
610 if (++transaction_ref_count_ > 1) {
611 return;
612 }
613
616 // We create prepared statements for all other queries, but MySQL
617 // don't support prepared statements for START TRANSACTION.
618 int status = mysql_query(mysql_, "START TRANSACTION");
619 if (status != 0) {
620 isc_throw(DbOperationError, "unable to start transaction, "
621 "reason: " << mysql_error(mysql_));
622 }
623}
624
625bool
629
630void
632 if (transaction_ref_count_ <= 0) {
633 isc_throw(Unexpected, "commit called for not started transaction - coding error");
634 }
635
636 // When committing nested transaction, do nothing.
637 if (--transaction_ref_count_ > 0) {
638 return;
639 }
642 if (mysql_commit(mysql_) != 0) {
643 isc_throw(DbOperationError, "commit failed: "
644 << mysql_error(mysql_));
645 }
646}
647
648void
650 if (transaction_ref_count_ <= 0) {
651 isc_throw(Unexpected, "rollback called for not started transaction - coding error");
652 }
653
654 // When rolling back nested transaction, do nothing.
655 if (--transaction_ref_count_ > 0) {
656 return;
657 }
660 if (mysql_rollback(mysql_) != 0) {
661 isc_throw(DbOperationError, "rollback failed: "
662 << mysql_error(mysql_));
663 }
664}
665
666template<typename T>
667void
668MySqlConnection::setIntParameterValue(const std::string& name, int64_t min, int64_t max, T& value) {
669 string svalue;
670 try {
671 svalue = getParameter(name);
672 } catch (...) {
673 // Do nothing if the parameter is not present.
674 }
675 if (svalue.empty()) {
676 return;
677 }
678 try {
679 // Try to convert the value.
680 auto parsed_value = boost::lexical_cast<T>(svalue);
681 // Check if the value is within the specified range.
682 if ((parsed_value < min) || (parsed_value > max)) {
683 isc_throw(BadValue, "bad " << svalue << " value");
684 }
685 // Everything is fine. Return the parsed value.
686 value = parsed_value;
687
688 } catch (...) {
689 // We may end up here when lexical_cast fails or when the
690 // parsed value is not within the desired range. In both
691 // cases let's throw the same general error.
692 isc_throw(BadValue, name << " parameter (" <<
693 svalue << ") must be an integer between "
694 << min << " and " << max);
695 }
696}
697
698} // namespace db
699} // namespace isc
when the call the UDPServer carries on at the same position As a result
Definition asiodns.dox:16
int version()
returns Kea hooks version.
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, unsigned int id)
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.
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(), 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 &parameters, IOServiceAccessorPtr io_accessor=IOServiceAccessorPtr(), DbCallback callback=DbCallback())
Constructor.
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.