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 
11 #include <database/db_exceptions.h>
12 #include <database/db_log.h>
13 #include <exceptions/exceptions.h>
14 #include <mysql/mysql_binding.h>
15 #include <mysql/mysql_constants.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 
24 namespace isc {
25 namespace db {
26 
27 
41 
43 public:
44 
55  MySqlFreeResult(MYSQL_STMT* statement) : statement_(statement)
56  {}
57 
62  (void) mysql_stmt_free_result(statement_);
63  }
64 
65 private:
66  MYSQL_STMT* statement_;
67 };
68 
73 
75  uint32_t index;
76  const char* text;
77 };
78 
90 class MySqlHolder : public boost::noncopyable {
91 public:
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 
123 private:
124  MYSQL* mysql_;
125 };
126 
128 class MySqlConnection;
129 
150 class MySqlTransaction : public boost::noncopyable {
151 public:
152 
162 
167 
169  void commit();
170 
171 private:
172 
174  MySqlConnection& conn_;
175 
180  bool committed_;
181 };
182 
183 
192 public:
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
db_log.h
isc::db::MySqlConnection::checkError
void checkError(const int status, const StatementIndex &index, const char *what) const
Check Error and Throw Exception.
Definition: mysql_connection.h:529
isc::db::MySqlConnection::convertToDatabaseTime
static void convertToDatabaseTime(const time_t input_time, MYSQL_TIME &output_time)
Convert time_t value to database time.
Definition: mysql_connection.cc:293
isc::db::MySqlConnection::startTransaction
void startTransaction()
Starts Transaction.
Definition: mysql_connection.cc:312
isc::db::MySqlConnection::updateDeleteQuery
uint64_t updateDeleteQuery(const StatementIndex &index, const MySqlBindingCollection &in_bindings)
Executes UPDATE or DELETE prepared statement and returns the number of affected rows.
Definition: mysql_connection.h:459
isc::db::MySqlConnection::clearStatements
void clearStatements()
Clears prepared statements and text statements.
Definition: mysql_connection.cc:262
isc::db::MySqlBindingPtr
boost::shared_ptr< MySqlBinding > MySqlBindingPtr
Shared pointer to the Binding class.
Definition: mysql_binding.h:127
db_exceptions.h
isc::db::MySqlFreeResult
Fetch and Release MySQL Results.
Definition: mysql_connection.h:42
isc::db::MySqlConnection::MySqlConnection
MySqlConnection(const ParameterMap &parameters)
Constructor.
Definition: mysql_connection.h:200
isc::db::MySqlConnection::statements_
std::vector< MYSQL_STMT * > statements_
Prepared statements.
Definition: mysql_connection.h:574
isc::db::MySqlHolder
MySQL Handle Holder.
Definition: mysql_connection.h:90
isc::db::MySqlFreeResult::~MySqlFreeResult
~MySqlFreeResult()
Destructor.
Definition: mysql_connection.h:61
isc::db::MySqlConnection::~MySqlConnection
virtual ~MySqlConnection()
Destructor.
Definition: mysql_connection.cc:268
isc::db::TaggedStatement
MySQL Selection Statements.
Definition: mysql_connection.h:74
isc::db::MySqlConnection::convertFromDatabaseTime
static void convertFromDatabaseTime(const MYSQL_TIME &expire, uint32_t valid_lifetime, time_t &cltt)
Convert Database Time to Lease Times.
Definition: mysql_connection.cc:306
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc::Exception::what
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Definition: exceptions/exceptions.cc:32
isc::db::DbOperationError
Exception thrown on failure to execute a database function.
Definition: database_connection.h:36
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::db::MySqlConnection::text_statements_
std::vector< std::string > text_statements_
Raw text of statements.
Definition: mysql_connection.h:580
isc::db::MySqlTransaction
RAII object representing MySQL transaction.
Definition: mysql_connection.h:150
isc::db::MySqlTransaction::MySqlTransaction
MySqlTransaction(MySqlConnection &conn)
Constructor.
Definition: mysql_connection.cc:29
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: exceptions/exceptions.h:132
isc::db::MySqlFreeResult::MySqlFreeResult
MySqlFreeResult(MYSQL_STMT *statement)
Constructor.
Definition: mysql_connection.h:55
isc::db::MySqlConnection::insertQuery
void insertQuery(const StatementIndex &index, const MySqlBindingCollection &in_bindings)
Executes INSERT prepared statement.
Definition: mysql_connection.h:421
isc::db::MySqlBindingCollection
std::vector< MySqlBindingPtr > MySqlBindingCollection
Collection of bindings.
Definition: mysql_binding.h:572
isc::db::MySqlConnection::rollback
void rollback()
Rollback Transactions.
Definition: mysql_connection.cc:333
isc::db::MySqlConnection::commit
void commit()
Commit Transactions.
Definition: mysql_connection.cc:324
isc::db::MySqlConnection
Common MySQL Connector Pool.
Definition: mysql_connection.h:191
isc::db::MySqlHolder::MySqlHolder
MySqlHolder()
Constructor.
Definition: mysql_connection.h:98
mysql_constants.h
database_connection.h
isc::db::DatabaseConnection::invokeDbLostCallback
bool invokeDbLostCallback() const
Invokes the connection's lost connectivity callback.
Definition: database_connection.cc:147
isc::db::MLM_MYSQL_FETCH_SUCCESS
const int MLM_MYSQL_FETCH_SUCCESS
MySQL fetch success code.
Definition: mysql_constants.h:26
isc::db::MySqlTransaction::commit
void commit()
Commits transaction.
Definition: mysql_connection.cc:43
DB_LOG_ERROR
#define DB_LOG_ERROR(MESSAGE)
Definition: db_log.h:137
isc::db::DuplicateEntry
Database duplicate entry error.
Definition: db_exceptions.h:42
exceptions.h
isc::db::DatabaseConnection
Common database connection class.
Definition: database_connection.h:140
isc::db::MySqlHolder::~MySqlHolder
~MySqlHolder()
Destructor.
Definition: mysql_connection.h:107
isc::db::DataTruncated
Data is truncated.
Definition: db_exceptions.h:35
isc::db::MySqlConnection::ConsumeResultFun
std::function< void(MySqlBindingCollection &)> ConsumeResultFun
Function invoked to process fetched row.
Definition: mysql_connection.h:195
isc::db::MySqlTransaction::~MySqlTransaction
~MySqlTransaction()
Destructor.
Definition: mysql_connection.cc:34
isc::db::DbOpenError
Exception thrown on failure to open database.
Definition: database_connection.h:29
isc::db::MySqlConnection::prepareStatement
void prepareStatement(uint32_t index, const char *text)
Prepare Single Statement.
Definition: mysql_connection.cc:222
mysql_binding.h
isc::db::MLM_MYSQL_FETCH_FAILURE
const int MLM_MYSQL_FETCH_FAILURE
MySQL fetch failure code.
Definition: mysql_constants.h:29
isc::db::DatabaseConnection::ParameterMap
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Definition: database_connection.h:152
isc::db::MySqlConnection::mysql_
MySqlHolder mysql_
MySQL connection handle.
Definition: mysql_connection.h:586
isc::db::TaggedStatement::text
const char * text
Definition: mysql_connection.h:76
isc::db::MySqlConnection::openDatabase
void openDatabase()
Open Database.
Definition: mysql_connection.cc:52
isc::db::MySqlConnection::prepareStatements
void prepareStatements(const TaggedStatement *start_statement, const TaggedStatement *end_statement)
Prepare statements.
Definition: mysql_connection.cc:247
isc::db::MySqlConnection::selectQuery
void selectQuery(const StatementIndex &index, const MySqlBindingCollection &in_bindings, MySqlBindingCollection &out_bindings, ConsumeResultFun process_result)
Executes SELECT query using prepared statement.
Definition: mysql_connection.h:343
isc::db::TaggedStatement::index
uint32_t index
Definition: mysql_connection.h:75
isc::db::MYSQL_FATAL_ERROR
@ MYSQL_FATAL_ERROR
Definition: db_log.h:60