Kea  2.1.7-git
mysql_binding.h
Go to the documentation of this file.
1 // Copyright (C) 2018-2019,2021 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_BINDING_H
8 #define MYSQL_BINDING_H
9 
10 #include <asiolink/io_address.h>
11 #include <cc/data.h>
13 #include <exceptions/exceptions.h>
14 #include <util/optional.h>
15 #include <boost/date_time/posix_time/conversion.hpp>
16 #include <boost/date_time/posix_time/posix_time.hpp>
17 #include <boost/shared_ptr.hpp>
18 #include <mysql/mysql_constants.h>
19 #include <mysql.h>
20 #include <mysqld_error.h>
21 #include <cstdint>
22 #include <iterator>
23 #include <string>
24 #include <vector>
25 
26 namespace isc {
27 namespace db {
28 
35 template<typename T>
38  static const enum_field_types column_type = MYSQL_TYPE_BLOB;
42  static const size_t length = 0;
45  static const bool am_unsigned = false;
46 };
47 
49 template<>
50 struct MySqlBindingTraits<std::string> {
51  static const enum_field_types column_type = MYSQL_TYPE_STRING;
52  static const size_t length = 0;
53  static const bool am_unsigned = false;
54 };
55 
57 template<>
58 struct MySqlBindingTraits<boost::posix_time::ptime> {
59  static const enum_field_types column_type = MYSQL_TYPE_TIMESTAMP;
60  static const size_t length = sizeof(MYSQL_TIME);
61  static const bool am_unsignged = false;
62 };
63 
65 template<>
66 struct MySqlBindingTraits<int8_t> {
67  static const enum_field_types column_type = MYSQL_TYPE_TINY;
68  static const size_t length = 1;
69  static const bool am_unsigned = false;
70 };
71 
73 template<>
74 struct MySqlBindingTraits<uint8_t> {
75  static const enum_field_types column_type = MYSQL_TYPE_TINY;
76  static const size_t length = 1;
77  static const bool am_unsigned = true;
78 };
79 
81 template<>
82 struct MySqlBindingTraits<int16_t> {
83  static const enum_field_types column_type = MYSQL_TYPE_SHORT;
84  static const size_t length = 2;
85  static const bool am_unsigned = false;
86 };
87 
89 template<>
90 struct MySqlBindingTraits<uint16_t> {
91  static const enum_field_types column_type = MYSQL_TYPE_SHORT;
92  static const size_t length = 2;
93  static const bool am_unsigned = true;
94 };
95 
97 template<>
98 struct MySqlBindingTraits<int32_t> {
99  static const enum_field_types column_type = MYSQL_TYPE_LONG;
100  static const size_t length = 4;
101  static const bool am_unsigned = false;
102 };
103 
105 template<>
106 struct MySqlBindingTraits<uint32_t> {
107  static const enum_field_types column_type = MYSQL_TYPE_LONG;
108  static const size_t length = 4;
109  static const bool am_unsigned = true;
110 };
111 
113 template<>
114 struct MySqlBindingTraits<int64_t> {
115  static const enum_field_types column_type = MYSQL_TYPE_LONGLONG;
116  static const size_t length = 8;
117  static const bool am_unsigned = false;
118 };
119 
121 template<>
122 struct MySqlBindingTraits<uint64_t> {
123  static const enum_field_types column_type = MYSQL_TYPE_LONGLONG;
124  static const size_t length = 8;
125  static const bool am_unsigned = true;
126 };
127 
128 template<>
129 struct MySqlBindingTraits<float> {
130  static const enum_field_types column_type = MYSQL_TYPE_FLOAT;
131  static const size_t length = 4;
132  static const bool am_unsigned = false;
133 };
134 
137 
139 typedef boost::shared_ptr<MySqlBinding> MySqlBindingPtr;
140 
163 public:
164 
168  enum_field_types getType() const {
169  return (bind_.buffer_type);
170  }
171 
180  MYSQL_BIND& getMySqlBinding() {
181  return (bind_);
182  }
183 
193  std::string getString() const;
194 
204  std::string getStringOrDefault(const std::string& default_value) const;
205 
215  data::ElementPtr getJSON() const;
216 
226  std::vector<uint8_t> getBlob() const;
227 
237  std::vector<uint8_t>
238  getBlobOrDefault(const std::vector<uint8_t>& default_value) const;
239 
252  template<typename T>
253  T getInteger() const {
254  // Make sure that the binding type is numeric.
255  validateAccess<T>();
256 
257  // Convert the buffer to a numeric type and then return a copy.
258  const T* value = reinterpret_cast<const T*>(&buffer_[0]);
259  return (*value);
260  }
261 
274  template<typename T>
275  T getIntegerOrDefault(T default_value) const {
276  if (amNull()) {
277  return (default_value);
278  }
279  return (getInteger<T>());
280  }
281 
291  float getFloat() const;
292 
302  bool getBool() const {
303  return (static_cast<bool>(getInteger<uint8_t>()));
304  }
305 
315  boost::posix_time::ptime getTimestamp() const;
316 
326  boost::posix_time::ptime
327  getTimestampOrDefault(const boost::posix_time::ptime& default_value) const;
328 
332  bool amNull() const {
333  return (null_value_ == MLM_TRUE);
334  }
335 
342  static MySqlBindingPtr createString(const unsigned long length);
343 
349  static MySqlBindingPtr createString(const std::string& value);
350 
357  static MySqlBindingPtr condCreateString(const util::Optional<std::string>& value);
358 
365  static MySqlBindingPtr createBlob(const unsigned long length);
366 
377  template<typename Iterator>
378  static MySqlBindingPtr createBlob(Iterator begin, Iterator end) {
379  MySqlBindingPtr binding(new MySqlBinding(MYSQL_TYPE_BLOB,
380  std::distance(begin, end)));
381  binding->setBufferValue(begin, end);
382  return (binding);
383  }
384 
391  template<typename T>
392  static MySqlBindingPtr createInteger() {
393  MySqlBindingPtr binding(new MySqlBinding(MySqlBindingTraits<T>::column_type,
395  binding->setValue<T>(0);
396  return (binding);
397  }
398 
407  template<typename T>
408  static MySqlBindingPtr createInteger(T value) {
409  MySqlBindingPtr binding(new MySqlBinding(MySqlBindingTraits<T>::column_type,
411  binding->setValue(value);
412  return (binding);
413  }
414 
424  template<typename T>
425  static MySqlBindingPtr condCreateInteger(const util::Optional<T>& value) {
426  return (value.unspecified() ? createNull() : createInteger<T>(value.get()));
427  }
428 
434  static MySqlBindingPtr createFloat(const float value);
435 
444  template<typename T>
445  static MySqlBindingPtr condCreateFloat(const util::Optional<T>& value) {
446  return (value.unspecified() ? createNull() :
447  createInteger<float> (static_cast<float>(value.get())));
448  }
449 
454  static MySqlBindingPtr createBool();
455 
462  static MySqlBindingPtr createBool(const bool value);
463 
470  static MySqlBindingPtr condCreateBool(const util::Optional<bool>& value);
471 
478  static MySqlBindingPtr
479  condCreateIPv4Address(const util::Optional<asiolink::IOAddress>& value);
480 
484  static MySqlBindingPtr createTimestamp();
485 
491  static MySqlBindingPtr createTimestamp(const boost::posix_time::ptime& timestamp);
492 
499  static MySqlBindingPtr createNull();
500 
506  static void convertToDatabaseTime(const time_t input_time,
507  MYSQL_TIME& output_time);
508 
514  static void convertToDatabaseTime(const boost::posix_time::ptime& input_time,
515  MYSQL_TIME& output_time);
516 
536  static void convertToDatabaseTime(const time_t cltt,
537  const uint32_t valid_lifetime,
538  MYSQL_TIME& expire);
539 
557  static void convertFromDatabaseTime(const MYSQL_TIME& expire,
558  uint32_t valid_lifetime,
559  time_t& cltt);
560 
567  static boost::posix_time::ptime
568  convertFromDatabaseTime(const MYSQL_TIME& database_time);
569 
570 private:
571 
579  MySqlBinding(enum_field_types buffer_type, const size_t length);
580 
589  template<typename Iterator>
590  void setBufferValue(Iterator begin, Iterator end) {
591  length_ = std::distance(begin, end);
592  buffer_.assign(begin, end);
593  // It appears that the MySQL connectors sometimes require that the
594  // buffer is specified (set to a non-zero value), even if the buffer
595  // length is 0. We have found that setting the buffer to 0 value would
596  // cause the value inserted to the database be NULL. In order to avoid
597  // it, we simply make sure that the buffer length is at least 1 byte and
598  // provide the pointer to this byte within the binding.
599  if (buffer_.empty()) {
600  buffer_.resize(1);
601  }
602  bind_.buffer = &buffer_[0];
603  bind_.buffer_length = length_;
604  }
605 
609  void setBufferLength(const unsigned long length);
610 
617  template<typename T>
618  void setValue(T value) {
619  memcpy(static_cast<void*>(&buffer_[0]), reinterpret_cast<char*>(&value),
620  sizeof(value));
621  bind_.buffer = &buffer_[0];
622  bind_.is_unsigned = (MySqlBindingTraits<T>::am_unsigned ? MLM_TRUE : MLM_FALSE);
623  }
624 
629  void setTimestampValue(const boost::posix_time::ptime& timestamp);
630 
639  template<typename T>
640  void validateAccess() const {
641  // Can't retrieve null value.
642  if (amNull()) {
643  isc_throw(InvalidOperation, "retrieved value is null");
644  }
645  // The type of the accessor must match the stored data type.
646  if (MySqlBindingTraits<T>::column_type != getType()) {
647  isc_throw(InvalidOperation, "mismatched column type");
648  }
649  }
650 
652  std::vector<uint8_t> buffer_;
653 
655  unsigned long length_;
656 
658  my_bool null_value_;
659 
661  MYSQL_BIND bind_;
662 };
663 
665 typedef std::vector<MySqlBindingPtr> MySqlBindingCollection;
666 
667 
668 } // end of namespace isc::db
669 } // end of namespace isc
670 
671 #endif
static MySqlBindingPtr createInteger(T value)
Creates binding of numeric type for sending data.
bool my_bool
my_bool type in MySQL 8.x.
void unspecified(bool unspecified)
Modifies the flag that indicates whether the value is specified or unspecified.
Definition: optional.h:136
static const enum_field_types column_type
Column type represented in MySQL C API.
Definition: mysql_binding.h:38
enum_field_types getType() const
Returns MySQL column type for the binding.
static MySqlBindingPtr createBlob(Iterator begin, Iterator end)
Creates binding of blob type for sending data.
T get() const
Retrieves the encapsulated value.
Definition: optional.h:114
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
STL namespace.
MYSQL_BIND & getMySqlBinding()
Returns reference to the native binding.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
const my_bool MLM_FALSE
MySQL false value.
static const size_t length
Length of data in this column.
Definition: mysql_binding.h:42
static MySqlBindingPtr condCreateInteger(const util::Optional< T > &value)
Conditionally creates binding of numeric type for sending data if provided value is specified...
Trait class for column types supported in MySQL.
Definition: mysql_binding.h:36
T getInteger() const
Returns numeric value held in the binding.
static MySqlBindingPtr condCreateFloat(const util::Optional< T > &value)
Conditionally creates binding of float type for sending data if provided value is specified...
Defines the logger used by the top-level component of kea-lfc.
static const bool am_unsigned
Boolean value indicating if the numeric value is unsigned.
Definition: mysql_binding.h:45
A generic exception that is thrown if a function is called in a prohibited way.
std::vector< MySqlBindingPtr > MySqlBindingCollection
Collection of bindings.
boost::shared_ptr< MySqlBinding > MySqlBindingPtr
Shared pointer to the Binding class.
T getIntegerOrDefault(T default_value) const
Returns numeric value held in the binding.
bool amNull() const
Checks if the bound value is NULL.
static MySqlBindingPtr createInteger()
Creates binding of numeric type for receiving data.
bool getBool() const
Returns boolean value held in the binding.
MySQL binding used in prepared statements.
const my_bool MLM_TRUE
MySQL true value.