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