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