Kea  1.5.0
mysql_binding.cc
Go to the documentation of this file.
1 // Copyright (C) 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 #include <config.h>
8 
9 #include <mysql/mysql_binding.h>
10 
11 using namespace isc::data;
12 
13 namespace isc {
14 namespace db {
15 
16 std::string
17 MySqlBinding::getString() const {
18  // Make sure the binding type is text.
19  validateAccess<std::string>();
20  if (length_ == 0) {
21  return (std::string());
22  }
23  return (std::string(buffer_.begin(), buffer_.begin() + length_));
24 }
25 
26 std::string
27 MySqlBinding::getStringOrDefault(const std::string& default_value) const {
28  if (amNull()) {
29  return (default_value);
30  }
31  return (getString());
32 }
33 
35 MySqlBinding::getJSON() const {
36  if (amNull()) {
37  return (ElementPtr());
38  }
39  std::string s = getString();
40  return (Element::fromJSON(s));
41 }
42 
43 std::vector<uint8_t>
44 MySqlBinding::getBlob() const {
45  // Make sure the binding type is blob.
46  validateAccess<std::vector<uint8_t> >();
47  if (length_ == 0) {
48  return (std::vector<uint8_t>());
49  }
50  return (std::vector<uint8_t>(buffer_.begin(), buffer_.begin() + length_));
51 }
52 
53 std::vector<uint8_t>
54 MySqlBinding::getBlobOrDefault(const std::vector<uint8_t>& default_value) const {
55  if (amNull()) {
56  return (default_value);
57  }
58  return (getBlob());
59 }
60 
61 boost::posix_time::ptime
62 MySqlBinding::getTimestamp() const {
63  // Make sure the binding type is timestamp.
64  validateAccess<boost::posix_time::ptime>();
65  // Copy the buffer contents into native timestamp structure and
66  // then convert it to posix time.
67  const MYSQL_TIME* database_time = reinterpret_cast<const MYSQL_TIME*>(&buffer_[0]);
68  return (convertFromDatabaseTime(*database_time));
69 }
70 
71 boost::posix_time::ptime
72 MySqlBinding::getTimestampOrDefault(const boost::posix_time::ptime& default_value) const {
73  if (amNull()) {
74  return (default_value);
75  }
76  return (getTimestamp());
77 }
78 
80 MySqlBinding::createString(const unsigned long length) {
82  length));
83  return (binding);
84 }
85 
87 MySqlBinding::createString(const std::string& value) {
89  value.size()));
90  binding->setBufferValue(value.begin(), value.end());
91  return (binding);
92 }
93 
95 MySqlBinding::condCreateString(const std::string& value) {
96  return (value.empty() ? MySqlBinding::createNull() : createString(value));
97 }
98 
100 MySqlBinding::createBlob(const unsigned long length) {
101  MySqlBindingPtr binding(new MySqlBinding(MySqlBindingTraits<std::vector<uint8_t> >::column_type,
102  length));
103  return (binding);
104 }
105 
107 MySqlBinding::createTimestamp(const boost::posix_time::ptime& timestamp) {
110  binding->setTimestampValue(timestamp);
111  return (binding);
112 }
113 
115 MySqlBinding::createTimestamp() {
118  return (binding);
119 }
120 
122 MySqlBinding::createNull() {
123  MySqlBindingPtr binding(new MySqlBinding(MYSQL_TYPE_NULL, 0));
124  return (binding);
125 }
126 
127 void
128 MySqlBinding::convertToDatabaseTime(const time_t input_time,
129  MYSQL_TIME& output_time) {
130 
131  // Convert to broken-out time
132  struct tm time_tm;
133  (void) localtime_r(&input_time, &time_tm);
134 
135  // Place in output expire structure.
136  output_time.year = time_tm.tm_year + 1900;
137  output_time.month = time_tm.tm_mon + 1; // Note different base
138  output_time.day = time_tm.tm_mday;
139  output_time.hour = time_tm.tm_hour;
140  output_time.minute = time_tm.tm_min;
141  output_time.second = time_tm.tm_sec;
142  output_time.second_part = 0; // No fractional seconds
143  output_time.neg = my_bool(0); // Not negative
144 }
145 
146 void
147 MySqlBinding::convertToDatabaseTime(const time_t cltt,
148  const uint32_t valid_lifetime,
149  MYSQL_TIME& expire) {
150 
151  // Calculate expiry time. Store it in the 64-bit value so as we can detect
152  // overflows.
153  int64_t expire_time_64 = static_cast<int64_t>(cltt) +
154  static_cast<int64_t>(valid_lifetime);
155 
156  // Even on 64-bit systems MySQL doesn't seem to accept the timestamps
157  // beyond the max value of int32_t.
158  if (expire_time_64 > DatabaseConnection::MAX_DB_TIME) {
159  isc_throw(BadValue, "Time value is too large: " << expire_time_64);
160  }
161 
162  const time_t expire_time = static_cast<const time_t>(expire_time_64);
163 
164  // Convert to broken-out time
165  struct tm expire_tm;
166  (void) localtime_r(&expire_time, &expire_tm);
167 
168  // Place in output expire structure.
169  expire.year = expire_tm.tm_year + 1900;
170  expire.month = expire_tm.tm_mon + 1; // Note different base
171  expire.day = expire_tm.tm_mday;
172  expire.hour = expire_tm.tm_hour;
173  expire.minute = expire_tm.tm_min;
174  expire.second = expire_tm.tm_sec;
175  expire.second_part = 0; // No fractional seconds
176  expire.neg = my_bool(0); // Not negative
177 }
178 
179 void
180 MySqlBinding::convertFromDatabaseTime(const MYSQL_TIME& expire,
181  uint32_t valid_lifetime,
182  time_t& cltt) {
183  // Copy across fields from MYSQL_TIME structure.
184  struct tm expire_tm;
185  memset(&expire_tm, 0, sizeof(expire_tm));
186 
187  expire_tm.tm_year = expire.year - 1900;
188  expire_tm.tm_mon = expire.month - 1;
189  expire_tm.tm_mday = expire.day;
190  expire_tm.tm_hour = expire.hour;
191  expire_tm.tm_min = expire.minute;
192  expire_tm.tm_sec = expire.second;
193  expire_tm.tm_isdst = -1; // Let the system work out about DST
194 
195  // Convert to local time
196  cltt = mktime(&expire_tm) - valid_lifetime;
197 }
198 
199 boost::posix_time::ptime
200 MySqlBinding::convertFromDatabaseTime(const MYSQL_TIME& database_time) {
201  // Copy across fields from MYSQL_TIME structure.
202  struct tm converted_tm;
203  memset(&converted_tm, 0, sizeof(converted_tm));
204 
205  converted_tm.tm_year = database_time.year - 1900;
206  converted_tm.tm_mon = database_time.month - 1;
207  converted_tm.tm_mday = database_time.day;
208  converted_tm.tm_hour = database_time.hour;
209  converted_tm.tm_min = database_time.minute;
210  converted_tm.tm_sec = database_time.second;
211  converted_tm.tm_isdst = -1; // Let the system work out about DST
212 
213  // Convert to local time
214  return (boost::posix_time::ptime_from_tm(converted_tm));
215 }
216 
217 MySqlBinding::MySqlBinding(enum_field_types buffer_type,
218  const size_t length)
219  : buffer_(length), length_(length),
220  null_value_(buffer_type == MYSQL_TYPE_NULL) {
221  memset(&bind_, 0, sizeof(MYSQL_BIND));
222  bind_.buffer_type = buffer_type;
223 
224  if (buffer_type != MYSQL_TYPE_NULL) {
225  bind_.buffer = &buffer_[0];
226  bind_.buffer_length = length_;
227  bind_.length = &length_;
228  bind_.is_null = &null_value_;
229  }
230 }
231 
232 void
233 MySqlBinding::setBufferLength(const unsigned long length) {
234  length_ = length;
235  // It appears that the MySQL connectors sometimes require that the
236  // buffer is specified (set to a non-zero value), even if the buffer
237  // length is 0. We have found that setting the buffer to 0 value would
238  // cause the value inserted to the database be NULL. In order to avoid
239  // it, we simply make sure that the buffer length is at least 1 byte and
240  // provide the pointer to this byte within the binding.
241  buffer_.resize(length_ > 0 ? length_ : 1);
242  bind_.buffer = &buffer_[0];
243  bind_.buffer_length = length_;
244 }
245 
246 void
247 MySqlBinding::setTimestampValue(const boost::posix_time::ptime& timestamp) {
248  // Convert timestamp to tm structure.
249  tm td_tm = to_tm(timestamp);
250  // Convert tm value to time_t.
251  time_t tt = mktime(&td_tm);
252  // Convert time_t to database time.
253  MYSQL_TIME database_time;
254  convertToDatabaseTime(tt, database_time);
255  // Copy database time into the buffer.
256  memcpy(static_cast<void*>(&buffer_[0]), reinterpret_cast<char*>(&database_time),
257  sizeof(MYSQL_TIME));
258  bind_.buffer = &buffer_[0];
259 }
260 
261 } // end of namespace isc::db
262 } // end of namespace isc
static void convertToDatabaseTime(const time_t input_time, MYSQL_TIME &output_time)
Converts time_t value to database time.
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
static ElementPtr fromJSON(const std::string &in, bool preproc=false)
These functions will parse the given string (JSON) representation of a compound element.
Definition: data.cc:750
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Trait class for column types supported in MySQL.
Definition: mysql_binding.h:34
Defines the logger used by the top-level component of kea-dhcp-ddns.
boost::shared_ptr< MySqlBinding > MySqlBindingPtr
Shared pointer to the Binding class.
MySQL binding used in prepared statements.