Kea 1.5.0
mysql_connection.h
Go to the documentation of this file.
1// Copyright (C) 2012-2018 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#ifndef MYSQL_CONNECTION_H
8#define MYSQL_CONNECTION_H
9
12#include <database/db_log.h>
14#include <mysql/mysql_binding.h>
16#include <boost/scoped_ptr.hpp>
17#include <mysql.h>
18#include <mysqld_error.h>
19#include <errmsg.h>
20#include <functional>
21#include <vector>
22#include <stdint.h>
23
24namespace isc {
25namespace db {
26
27
41
43public:
44
55 MySqlFreeResult(MYSQL_STMT* statement) : statement_(statement)
56 {}
57
62 (void) mysql_stmt_free_result(statement_);
63 }
64
65private:
66 MYSQL_STMT* statement_;
67};
68
73
75 uint32_t index;
76 const char* text;
77};
78
90class MySqlHolder : public boost::noncopyable {
91public:
92
98 MySqlHolder() : mysql_(mysql_init(NULL)) {
99 if (mysql_ == NULL) {
100 isc_throw(db::DbOpenError, "unable to initialize MySQL");
101 }
102 }
103
108 if (mysql_ != NULL) {
109 mysql_close(mysql_);
110 }
111 // The library itself shouldn't be needed anymore
112 mysql_library_end();
113 }
114
119 operator MYSQL*() const {
120 return (mysql_);
121 }
122
123private:
124 MYSQL* mysql_;
125};
126
128class MySqlConnection;
129
150class MySqlTransaction : public boost::noncopyable {
151public:
152
162
167
169 void commit();
170
171private:
172
174 MySqlConnection& conn_;
175
180 bool committed_;
181};
182
183
192public:
193
195 typedef std::function<void(MySqlBindingCollection&)> ConsumeResultFun;
196
200 MySqlConnection(const ParameterMap& parameters)
201 : DatabaseConnection(parameters) {
202 }
203
205 virtual ~MySqlConnection();
206
220 void prepareStatement(uint32_t index, const char* text);
221
236 void prepareStatements(const TaggedStatement* start_statement,
237 const TaggedStatement* end_statement);
238
240 void clearStatements();
241
249 void openDatabase();
250
258
264 static
265 void convertToDatabaseTime(const time_t input_time, MYSQL_TIME& output_time);
266
286 static
287 void convertToDatabaseTime(const time_t cltt, const uint32_t valid_lifetime,
288 MYSQL_TIME& expire);
289
307 static
308 void convertFromDatabaseTime(const MYSQL_TIME& expire,
309 uint32_t valid_lifetime, time_t& cltt);
311
313 void startTransaction();
314
342 template<typename StatementIndex>
343 void selectQuery(const StatementIndex& index,
344 const MySqlBindingCollection& in_bindings,
345 MySqlBindingCollection& out_bindings,
346 ConsumeResultFun process_result) {
347 // Extract native input bindings.
348 std::vector<MYSQL_BIND> in_bind_vec;
349 for (MySqlBindingPtr in_binding : in_bindings) {
350 in_bind_vec.push_back(in_binding->getMySqlBinding());
351 }
352
353 int status = 0;
354 if (!in_bind_vec.empty()) {
355 // Bind parameters to the prepared statement.
356 status = mysql_stmt_bind_param(statements_[index], &in_bind_vec[0]);
357 checkError(status, index, "unable to bind parameters for select");
358 }
359
360 // Bind variables that will receive results as well.
361 std::vector<MYSQL_BIND> out_bind_vec;
362 for (MySqlBindingPtr out_binding : out_bindings) {
363 out_bind_vec.push_back(out_binding->getMySqlBinding());
364 }
365 if (!out_bind_vec.empty()) {
366 status = mysql_stmt_bind_result(statements_[index], &out_bind_vec[0]);
367 checkError(status, index, "unable to bind result parameters for select");
368 }
369
370 // Execute query.
371 status = mysql_stmt_execute(statements_[index]);
372 checkError(status, index, "unable to execute");
373
374 status = mysql_stmt_store_result(statements_[index]);
375 checkError(status, index, "unable to set up for storing all results");
376
377 // Fetch results.
378 MySqlFreeResult fetch_release(statements_[index]);
379 while ((status = mysql_stmt_fetch(statements_[index])) ==
381 try {
382 // For each returned row call user function which should
383 // consume the row and copy the data to a safe place.
384 process_result(out_bindings);
385
386 } catch (const std::exception& ex) {
387 // Rethrow the exception with a bit more data.
388 isc_throw(BadValue, ex.what() << ". Statement is <" <<
389 text_statements_[index] << ">");
390 }
391 }
392
393 // How did the fetch end?
394 // If mysql_stmt_fetch return value is equal to 1 an error occurred.
395 if (status == MLM_MYSQL_FETCH_FAILURE) {
396 // Error - unable to fetch results
397 checkError(status, index, "unable to fetch results");
398
399 } else if (status == MYSQL_DATA_TRUNCATED) {
400 // Data truncated - throw an exception indicating what was at fault
402 << " returned truncated data");
403 }
404 }
405
420 template<typename StatementIndex>
421 void insertQuery(const StatementIndex& index,
422 const MySqlBindingCollection& in_bindings) {
423 std::vector<MYSQL_BIND> in_bind_vec;
424 for (MySqlBindingPtr in_binding : in_bindings) {
425 in_bind_vec.push_back(in_binding->getMySqlBinding());
426 }
427
428 // Bind the parameters to the statement
429 int status = mysql_stmt_bind_param(statements_[index], &in_bind_vec[0]);
430 checkError(status, index, "unable to bind parameters");
431
432 // Execute the statement
433 status = mysql_stmt_execute(statements_[index]);
434
435 if (status != 0) {
436 // Failure: check for the special case of duplicate entry.
437 if (mysql_errno(mysql_) == ER_DUP_ENTRY) {
438 isc_throw(DuplicateEntry, "Database duplicate entry error");
439 }
440 checkError(status, index, "unable to execute");
441 }
442 }
443
458 template<typename StatementIndex>
459 uint64_t updateDeleteQuery(const StatementIndex& index,
460 const MySqlBindingCollection& in_bindings) {
461 std::vector<MYSQL_BIND> in_bind_vec;
462 for (MySqlBindingPtr in_binding : in_bindings) {
463 in_bind_vec.push_back(in_binding->getMySqlBinding());
464 }
465
466 // Bind the parameters to the statement
467 int status = mysql_stmt_bind_param(statements_[index], &in_bind_vec[0]);
468 checkError(status, index, "unable to bind parameters");
469
470 // Execute the statement
471 status = mysql_stmt_execute(statements_[index]);
472
473 if (status != 0) {
474 checkError(status, index, "unable to execute");
475 }
476
477 // Let's return how many rows were affected.
478 return (static_cast<uint64_t>(mysql_stmt_affected_rows(statements_[index])));
479 }
480
481
488 void commit();
489
496 void rollback();
497
528 template<typename StatementIndex>
529 void checkError(const int status, const StatementIndex& index,
530 const char* what) const {
531 if (status != 0) {
532 switch(mysql_errno(mysql_)) {
533 // These are the ones we consider fatal. Remember this method is
534 // used to check errors of API calls made subsequent to successfully
535 // connecting. Errors occurring while attempting to connect are
536 // checked in the connection code. An alternative would be to call
537 // mysql_ping() - assuming autoreconnect is off. If that fails
538 // then we know connection is toast.
539 case CR_SERVER_GONE_ERROR:
540 case CR_SERVER_LOST:
541 case CR_OUT_OF_MEMORY:
542 case CR_CONNECTION_ERROR:
544 .arg(what)
545 .arg(text_statements_[static_cast<int>(index)])
546 .arg(mysql_error(mysql_))
547 .arg(mysql_errno(mysql_));
548
549 // If there's no lost db callback or it returns false,
550 // then we're not attempting to recover so we're done
551 if (!invokeDbLostCallback()) {
552 exit (-1);
553 }
554
555 // We still need to throw so caller can error out of the current
556 // processing.
558 "fatal database errror or connectivity lost");
559 default:
560 // Connection is ok, so it must be an SQL error
561 isc_throw(db::DbOperationError, what << " for <"
562 << text_statements_[static_cast<int>(index)]
563 << ">, reason: "
564 << mysql_error(mysql_) << " (error code "
565 << mysql_errno(mysql_) << ")");
566 }
567 }
568 }
569
574 std::vector<MYSQL_STMT*> statements_;
575
580 std::vector<std::string> text_statements_;
581
587};
588
589}; // end of isc::db namespace
590}; // end of isc namespace
591
592#endif // MYSQL_CONNECTION_H
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.
Data is truncated.
Definition: db_exceptions.h:35
Common database connection class.
bool invokeDbLostCallback() const
Invokes the connection's lost connectivity callback.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Exception thrown on failure to open database.
Exception thrown on failure to execute a database function.
Database duplicate entry error.
Definition: db_exceptions.h:42
Common MySQL Connector Pool.
MySqlHolder mysql_
MySQL connection handle.
void prepareStatement(uint32_t index, const char *text)
Prepare Single Statement.
std::vector< MYSQL_STMT * > statements_
Prepared statements.
std::vector< std::string > text_statements_
Raw text of statements.
void insertQuery(const StatementIndex &index, const MySqlBindingCollection &in_bindings)
Executes INSERT prepared statement.
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()
Commit Transactions.
MySqlConnection(const ParameterMap &parameters)
Constructor.
uint64_t updateDeleteQuery(const StatementIndex &index, const MySqlBindingCollection &in_bindings)
Executes UPDATE or DELETE prepared statement and returns the number of affected rows.
void openDatabase()
Open Database.
void prepareStatements(const TaggedStatement *start_statement, const TaggedStatement *end_statement)
Prepare statements.
void checkError(const int status, const StatementIndex &index, const char *what) const
Check Error and Throw Exception.
void startTransaction()
Starts Transaction.
virtual ~MySqlConnection()
Destructor.
std::function< void(MySqlBindingCollection &)> ConsumeResultFun
Function invoked to process fetched row.
void selectQuery(const StatementIndex &index, const MySqlBindingCollection &in_bindings, MySqlBindingCollection &out_bindings, ConsumeResultFun process_result)
Executes SELECT query using prepared statement.
void clearStatements()
Clears prepared statements and text statements.
void rollback()
Rollback Transactions.
Fetch and Release MySQL Results.
MySqlFreeResult(MYSQL_STMT *statement)
Constructor.
MySQL Handle Holder.
MySqlHolder()
Constructor.
RAII object representing MySQL transaction.
void commit()
Commits transaction.
We want to reuse the database backend connection and exchange code for other uses,...
#define DB_LOG_ERROR(MESSAGE)
Definition: db_log.h:137
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< MySqlBinding > MySqlBindingPtr
Shared pointer to the Binding class.
@ MYSQL_FATAL_ERROR
Definition: db_log.h:60
const int MLM_MYSQL_FETCH_FAILURE
MySQL fetch failure code.
std::vector< MySqlBindingPtr > MySqlBindingCollection
Collection of bindings.
const int MLM_MYSQL_FETCH_SUCCESS
MySQL fetch success code.
Defines the logger used by the top-level component of kea-dhcp-ddns.
MySQL Selection Statements.