Kea  2.3.5-git
mysql_lease_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2022 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 <asiolink/io_address.h>
10 #include <dhcp/duid.h>
11 #include <dhcp/hwaddr.h>
12 #include <dhcpsrv/cfg_db_access.h>
13 #include <dhcpsrv/cfgmgr.h>
14 #include <dhcpsrv/dhcpsrv_log.h>
17 #include <dhcpsrv/timer_mgr.h>
18 #include <mysql/mysql_connection.h>
20 
21 #include <boost/array.hpp>
22 #include <boost/make_shared.hpp>
23 #include <boost/static_assert.hpp>
24 #include <mysqld_error.h>
25 
26 #include <iostream>
27 #include <iomanip>
28 #include <limits>
29 #include <sstream>
30 #include <string>
31 #include <time.h>
32 
33 using namespace isc;
34 using namespace isc::asiolink;
35 using namespace isc::db;
36 using namespace isc::dhcp;
37 using namespace isc::data;
38 using namespace isc::util;
39 using namespace std;
40 
82 
83 namespace {
84 
89 const size_t HOSTNAME_MAX_LEN = 255;
90 
95 const size_t ADDRESS6_TEXT_MAX_LEN = 39;
96 
98 const size_t USER_CONTEXT_MAX_LEN = 8192;
99 
101 const size_t LIMITS_TEXT_MAX_LEN = 512;
102 
103 boost::array<TaggedStatement, MySqlLeaseMgr::NUM_STATEMENTS>
104 tagged_statements = { {
105  {MySqlLeaseMgr::DELETE_LEASE4,
106  "DELETE FROM lease4 WHERE address = ? AND expire = ?"},
107  {MySqlLeaseMgr::DELETE_LEASE4_STATE_EXPIRED,
108  "DELETE FROM lease4 "
109  "WHERE state = ? AND expire < ?"},
110  {MySqlLeaseMgr::DELETE_LEASE6,
111  "DELETE FROM lease6 WHERE address = ? AND expire = ?"},
112  {MySqlLeaseMgr::DELETE_LEASE6_STATE_EXPIRED,
113  "DELETE FROM lease6 "
114  "WHERE state = ? AND expire < ?"},
115  {MySqlLeaseMgr::GET_LEASE4,
116  "SELECT address, hwaddr, client_id, "
117  "valid_lifetime, expire, subnet_id, "
118  "fqdn_fwd, fqdn_rev, hostname, "
119  "state, user_context "
120  "FROM lease4"},
121  {MySqlLeaseMgr::GET_LEASE4_ADDR,
122  "SELECT address, hwaddr, client_id, "
123  "valid_lifetime, expire, subnet_id, "
124  "fqdn_fwd, fqdn_rev, hostname, "
125  "state, user_context "
126  "FROM lease4 "
127  "WHERE address = ?"},
128  {MySqlLeaseMgr::GET_LEASE4_CLIENTID,
129  "SELECT address, hwaddr, client_id, "
130  "valid_lifetime, expire, subnet_id, "
131  "fqdn_fwd, fqdn_rev, hostname, "
132  "state, user_context "
133  "FROM lease4 "
134  "WHERE client_id = ?"},
135  {MySqlLeaseMgr::GET_LEASE4_CLIENTID_SUBID,
136  "SELECT address, hwaddr, client_id, "
137  "valid_lifetime, expire, subnet_id, "
138  "fqdn_fwd, fqdn_rev, hostname, "
139  "state, user_context "
140  "FROM lease4 "
141  "WHERE client_id = ? AND subnet_id = ?"},
142  {MySqlLeaseMgr::GET_LEASE4_HWADDR,
143  "SELECT address, hwaddr, client_id, "
144  "valid_lifetime, expire, subnet_id, "
145  "fqdn_fwd, fqdn_rev, hostname, "
146  "state, user_context "
147  "FROM lease4 "
148  "WHERE hwaddr = ?"},
149  {MySqlLeaseMgr::GET_LEASE4_HWADDR_SUBID,
150  "SELECT address, hwaddr, client_id, "
151  "valid_lifetime, expire, subnet_id, "
152  "fqdn_fwd, fqdn_rev, hostname, "
153  "state, user_context "
154  "FROM lease4 "
155  "WHERE hwaddr = ? AND subnet_id = ?"},
156  {MySqlLeaseMgr::GET_LEASE4_PAGE,
157  "SELECT address, hwaddr, client_id, "
158  "valid_lifetime, expire, subnet_id, "
159  "fqdn_fwd, fqdn_rev, hostname, "
160  "state, user_context "
161  "FROM lease4 "
162  "WHERE address > ? "
163  "ORDER BY address "
164  "LIMIT ?"},
165  {MySqlLeaseMgr::GET_LEASE4_SUBID,
166  "SELECT address, hwaddr, client_id, "
167  "valid_lifetime, expire, subnet_id, "
168  "fqdn_fwd, fqdn_rev, hostname, "
169  "state, user_context "
170  "FROM lease4 "
171  "WHERE subnet_id = ?"},
172  {MySqlLeaseMgr::GET_LEASE4_HOSTNAME,
173  "SELECT address, hwaddr, client_id, "
174  "valid_lifetime, expire, subnet_id, "
175  "fqdn_fwd, fqdn_rev, hostname, "
176  "state, user_context "
177  "FROM lease4 "
178  "WHERE hostname = ?"},
179  {MySqlLeaseMgr::GET_LEASE4_EXPIRE,
180  "SELECT address, hwaddr, client_id, "
181  "valid_lifetime, expire, subnet_id, "
182  "fqdn_fwd, fqdn_rev, hostname, "
183  "state, user_context "
184  "FROM lease4 "
185  "WHERE state != ? "
186  "AND valid_lifetime != 4294967295 "
187  "AND expire < ? "
188  "ORDER BY expire ASC "
189  "LIMIT ?"},
190  {MySqlLeaseMgr::GET_LEASE6,
191  "SELECT address, duid, valid_lifetime, "
192  "expire, subnet_id, pref_lifetime, "
193  "lease_type, iaid, prefix_len, "
194  "fqdn_fwd, fqdn_rev, hostname, "
195  "hwaddr, hwtype, hwaddr_source, "
196  "state, user_context "
197  "FROM lease6"},
198  {MySqlLeaseMgr::GET_LEASE6_ADDR,
199  "SELECT address, duid, valid_lifetime, "
200  "expire, subnet_id, pref_lifetime, "
201  "lease_type, iaid, prefix_len, "
202  "fqdn_fwd, fqdn_rev, hostname, "
203  "hwaddr, hwtype, hwaddr_source, "
204  "state, user_context "
205  "FROM lease6 "
206  "WHERE address = ? AND lease_type = ?"},
207  {MySqlLeaseMgr::GET_LEASE6_DUID_IAID,
208  "SELECT address, duid, valid_lifetime, "
209  "expire, subnet_id, pref_lifetime, "
210  "lease_type, iaid, prefix_len, "
211  "fqdn_fwd, fqdn_rev, hostname, "
212  "hwaddr, hwtype, hwaddr_source, "
213  "state, user_context "
214  "FROM lease6 "
215  "WHERE duid = ? AND iaid = ? AND lease_type = ?"},
216  {MySqlLeaseMgr::GET_LEASE6_DUID_IAID_SUBID,
217  "SELECT address, duid, valid_lifetime, "
218  "expire, subnet_id, pref_lifetime, "
219  "lease_type, iaid, prefix_len, "
220  "fqdn_fwd, fqdn_rev, hostname, "
221  "hwaddr, hwtype, hwaddr_source, "
222  "state, user_context "
223  "FROM lease6 "
224  "WHERE duid = ? AND iaid = ? AND subnet_id = ? "
225  "AND lease_type = ?"},
226  {MySqlLeaseMgr::GET_LEASE6_PAGE,
227  "SELECT address, duid, valid_lifetime, "
228  "expire, subnet_id, pref_lifetime, "
229  "lease_type, iaid, prefix_len, "
230  "fqdn_fwd, fqdn_rev, hostname, "
231  "hwaddr, hwtype, hwaddr_source, "
232  "state, user_context "
233  "FROM lease6 "
234  "WHERE address > ? "
235  "ORDER BY address "
236  "LIMIT ?"},
237  {MySqlLeaseMgr::GET_LEASE6_SUBID,
238  "SELECT address, duid, valid_lifetime, "
239  "expire, subnet_id, pref_lifetime, "
240  "lease_type, iaid, prefix_len, "
241  "fqdn_fwd, fqdn_rev, hostname, "
242  "hwaddr, hwtype, hwaddr_source, "
243  "state, user_context "
244  "FROM lease6 "
245  "WHERE subnet_id = ?"},
246  {MySqlLeaseMgr::GET_LEASE6_DUID,
247  "SELECT address, duid, valid_lifetime, "
248  "expire, subnet_id, pref_lifetime, "
249  "lease_type, iaid, prefix_len, "
250  "fqdn_fwd, fqdn_rev, hostname, "
251  "hwaddr, hwtype, hwaddr_source, "
252  "state, user_context "
253  "FROM lease6 "
254  "WHERE duid = ?"},
255  {MySqlLeaseMgr::GET_LEASE6_HOSTNAME,
256  "SELECT address, duid, valid_lifetime, "
257  "expire, subnet_id, pref_lifetime, "
258  "lease_type, iaid, prefix_len, "
259  "fqdn_fwd, fqdn_rev, hostname, "
260  "hwaddr, hwtype, hwaddr_source, "
261  "state, user_context "
262  "FROM lease6 "
263  "WHERE hostname = ?"},
264  {MySqlLeaseMgr::GET_LEASE6_EXPIRE,
265  "SELECT address, duid, valid_lifetime, "
266  "expire, subnet_id, pref_lifetime, "
267  "lease_type, iaid, prefix_len, "
268  "fqdn_fwd, fqdn_rev, hostname, "
269  "hwaddr, hwtype, hwaddr_source, "
270  "state, user_context "
271  "FROM lease6 "
272  "WHERE state != ? "
273  "AND valid_lifetime != 4294967295 "
274  "AND expire < ? "
275  "ORDER BY expire ASC "
276  "LIMIT ?"},
277  {MySqlLeaseMgr::INSERT_LEASE4,
278  "INSERT INTO lease4(address, hwaddr, client_id, "
279  "valid_lifetime, expire, subnet_id, "
280  "fqdn_fwd, fqdn_rev, hostname, "
281  "state, user_context) "
282  "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
283  {MySqlLeaseMgr::INSERT_LEASE6,
284  "INSERT INTO lease6(address, duid, valid_lifetime, "
285  "expire, subnet_id, pref_lifetime, "
286  "lease_type, iaid, prefix_len, "
287  "fqdn_fwd, fqdn_rev, hostname, "
288  "hwaddr, hwtype, hwaddr_source, "
289  "state, user_context) "
290  "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
291  {MySqlLeaseMgr::UPDATE_LEASE4,
292  "UPDATE lease4 SET address = ?, hwaddr = ?, "
293  "client_id = ?, valid_lifetime = ?, expire = ?, "
294  "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, "
295  "hostname = ?, "
296  "state = ?, user_context = ? "
297  "WHERE address = ? AND expire = ?"},
298  {MySqlLeaseMgr::UPDATE_LEASE6,
299  "UPDATE lease6 SET address = ?, duid = ?, "
300  "valid_lifetime = ?, expire = ?, subnet_id = ?, "
301  "pref_lifetime = ?, lease_type = ?, iaid = ?, "
302  "prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, "
303  "hostname = ?, hwaddr = ?, hwtype = ?, hwaddr_source = ?, "
304  "state = ?, user_context = ? "
305  "WHERE address = ? AND expire = ?"},
306  {MySqlLeaseMgr::ALL_LEASE4_STATS,
307  "SELECT subnet_id, state, leases as state_count "
308  "FROM lease4_stat ORDER BY subnet_id, state"},
309  {MySqlLeaseMgr::SUBNET_LEASE4_STATS,
310  "SELECT subnet_id, state, leases as state_count "
311  "FROM lease4_stat "
312  "WHERE subnet_id = ? "
313  "ORDER BY state"},
314  {MySqlLeaseMgr::SUBNET_RANGE_LEASE4_STATS,
315  "SELECT subnet_id, state, leases as state_count "
316  "FROM lease4_stat "
317  "WHERE subnet_id >= ? and subnet_id <= ? "
318  "ORDER BY subnet_id, state"},
319  {MySqlLeaseMgr::ALL_LEASE6_STATS,
320  "SELECT subnet_id, lease_type, state, leases as state_count "
321  "FROM lease6_stat ORDER BY subnet_id, lease_type, state"},
322  {MySqlLeaseMgr::SUBNET_LEASE6_STATS,
323  "SELECT subnet_id, lease_type, state, leases as state_count "
324  "FROM lease6_stat "
325  "WHERE subnet_id = ? "
326  "ORDER BY lease_type, state"},
327  {MySqlLeaseMgr::SUBNET_RANGE_LEASE6_STATS,
328  "SELECT subnet_id, lease_type, state, leases as state_count "
329  "FROM lease6_stat "
330  "WHERE subnet_id >= ? and subnet_id <= ? "
331  "ORDER BY subnet_id, lease_type, state"},
332  {MySqlLeaseMgr::CHECK_LEASE4_LIMITS, "SELECT checkLease4Limits(?)"},
333  {MySqlLeaseMgr::CHECK_LEASE6_LIMITS, "SELECT checkLease6Limits(?)"},
334  {MySqlLeaseMgr::IS_JSON_SUPPORTED, "SELECT isJsonSupported()"},
335  {MySqlLeaseMgr::GET_LEASE4_COUNT_BY_CLASS,
336  "SELECT leases "
337  "FROM lease4_stat_by_client_class "
338  "WHERE client_class = ?"},
339  {MySqlLeaseMgr::GET_LEASE6_COUNT_BY_CLASS,
340  "SELECT leases "
341  "FROM lease6_stat_by_client_class "
342  "WHERE client_class = ? AND lease_type = ?"},
343 } }; // tagged_statements
344 
345 } // namespace
346 
347 namespace isc {
348 namespace dhcp {
349 
356 
358 public:
359 
371  static void setErrorIndicators(MYSQL_BIND* bind, my_bool* error,
372  size_t count) {
373  for (size_t i = 0; i < count; ++i) {
374  error[i] = MLM_FALSE;
375  bind[i].error = reinterpret_cast<my_bool*>(&error[i]);
376  }
377  }
378 
392  static std::string getColumnsInError(my_bool* error, std::string* names,
393  size_t count) {
394  std::string result = "";
395 
396  // Accumulate list of column names
397  for (size_t i = 0; i < count; ++i) {
398  if (error[i] == MLM_TRUE) {
399  if (!result.empty()) {
400  result += ", ";
401  }
402  result += names[i];
403  }
404  }
405 
406  if (result.empty()) {
407  result = "(None)";
408  }
409 
410  return (result);
411  }
412 };
413 
426 
429  static const size_t LEASE_COLUMNS = 11;
430 
431 public:
432 
437  MySqlLease4Exchange() : addr4_(0), hwaddr_length_(0), hwaddr_null_(MLM_FALSE),
438  client_id_length_(0), client_id_null_(MLM_FALSE),
439  subnet_id_(0), valid_lifetime_(0),
440  fqdn_fwd_(false), fqdn_rev_(false), hostname_length_(0),
441  state_(0), user_context_length_(0),
442  user_context_null_(MLM_FALSE) {
443  memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
444  memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
445  memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
446  memset(user_context_, 0, sizeof(user_context_));
447  std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
448 
449  // Set the column names (for error messages)
450  columns_[0] = "address";
451  columns_[1] = "hwaddr";
452  columns_[2] = "client_id";
453  columns_[3] = "valid_lifetime";
454  columns_[4] = "expire";
455  columns_[5] = "subnet_id";
456  columns_[6] = "fqdn_fwd";
457  columns_[7] = "fqdn_rev";
458  columns_[8] = "hostname";
459  columns_[9] = "state";
460  columns_[10] = "user_context";
461  BOOST_STATIC_ASSERT(10 < LEASE_COLUMNS);
462  }
463 
473  std::vector<MYSQL_BIND> createBindForSend(const Lease4Ptr& lease) {
474 
475  // Store lease object to ensure it remains valid.
476  lease_ = lease;
477 
478  // Initialize prior to constructing the array of MYSQL_BIND structures.
479  // It sets all fields, including is_null, to zero, so we need to set
480  // is_null only if it should be true. This gives up minor performance
481  // benefit while being safe approach. For improved readability, the
482  // code that explicitly sets is_null is there, but is commented out.
483  memset(bind_, 0, sizeof(bind_));
484 
485  // Set up the structures for the various components of the lease4
486  // structure.
487 
488  try {
489  // address: uint32_t
490  // The address in the Lease structure is an IOAddress object. Convert
491  // this to an integer for storage.
492  addr4_ = lease_->addr_.toUint32();
493  bind_[0].buffer_type = MYSQL_TYPE_LONG;
494  bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
495  bind_[0].is_unsigned = MLM_TRUE;
496  // bind_[0].is_null = &MLM_FALSE; // commented out for performance
497  // reasons, see memset() above
498 
499  // hwaddr: varbinary(20) - hardware/MAC address
500  HWAddrPtr hwaddr = lease_->hwaddr_;
501  if (hwaddr) {
502  hwaddr_ = hwaddr->hwaddr_;
503  hwaddr_length_ = hwaddr->hwaddr_.size();
504 
505  // Make sure that the buffer has at least length of 1, even if
506  // empty HW address is passed. This is required by some of the
507  // MySQL connectors that the buffer is set to non-null value.
508  // Otherwise, null value would be inserted into the database,
509  // rather than empty string.
510  if (hwaddr_.empty()) {
511  hwaddr_.resize(1);
512  }
513 
514  bind_[1].buffer_type = MYSQL_TYPE_BLOB;
515  bind_[1].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
516  bind_[1].buffer_length = hwaddr_length_;
517  bind_[1].length = &hwaddr_length_;
518  } else {
519  bind_[1].buffer_type = MYSQL_TYPE_NULL;
520  // According to http://dev.mysql.com/doc/refman/5.5/en/
521  // c-api-prepared-statement-data-structures.html, the other
522  // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
523  // but let's set them to some sane values in case earlier versions
524  // didn't have that assumption.
525  hwaddr_null_ = MLM_TRUE;
526  bind_[1].buffer = NULL;
527  bind_[1].is_null = &hwaddr_null_;
528  }
529 
530  // client_id: varbinary(128)
531  if (lease_->client_id_) {
532  client_id_ = lease_->client_id_->getClientId();
533  client_id_length_ = client_id_.size();
534 
535  // Make sure that the buffer has at least length of 1, even if
536  // empty client id is passed. This is required by some of the
537  // MySQL connectors that the buffer is set to non-null value.
538  // Otherwise, null value would be inserted into the database,
539  // rather than empty string.
540  if (client_id_.empty()) {
541  client_id_.resize(1);
542  }
543 
544  bind_[2].buffer_type = MYSQL_TYPE_BLOB;
545  bind_[2].buffer = reinterpret_cast<char*>(&client_id_[0]);
546  bind_[2].buffer_length = client_id_length_;
547  bind_[2].length = &client_id_length_;
548  // bind_[2].is_null = &MLM_FALSE; // commented out for performance
549  // reasons, see memset() above
550  } else {
551  bind_[2].buffer_type = MYSQL_TYPE_NULL;
552  // According to http://dev.mysql.com/doc/refman/5.5/en/
553  // c-api-prepared-statement-data-structures.html, the other
554  // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
555  // but let's set them to some sane values in case earlier versions
556  // didn't have that assumption.
557  client_id_null_ = MLM_TRUE;
558  bind_[2].buffer = NULL;
559  bind_[2].is_null = &client_id_null_;
560  }
561 
562  // valid lifetime: unsigned int
563  bind_[3].buffer_type = MYSQL_TYPE_LONG;
564  bind_[3].buffer = reinterpret_cast<char*>(&lease_->valid_lft_);
565  bind_[3].is_unsigned = MLM_TRUE;
566  // bind_[3].is_null = &MLM_FALSE; // commented out for performance
567  // reasons, see memset() above
568 
569  // expire: timestamp
570  // The lease structure holds the client last transmission time (cltt_)
571  // For convenience for external tools, this is converted to lease
572  // expiry time (expire). The relationship is given by:
573  //
574  // expire = cltt_ + valid_lft_
575  // Avoid overflow with infinite valid lifetime by using
576  // expire = cltt_ when valid_lft_ = 0xffffffff
577  uint32_t valid_lft = lease_->valid_lft_;
578  if (valid_lft == Lease::INFINITY_LFT) {
579  valid_lft = 0;
580  }
581  MySqlConnection::convertToDatabaseTime(lease_->cltt_, valid_lft,
582  expire_);
583  bind_[4].buffer_type = MYSQL_TYPE_TIMESTAMP;
584  bind_[4].buffer = reinterpret_cast<char*>(&expire_);
585  bind_[4].buffer_length = sizeof(expire_);
586  // bind_[4].is_null = &MLM_FALSE; // commented out for performance
587  // reasons, see memset() above
588 
589  // subnet_id: unsigned int
590  // Can use lease_->subnet_id_ directly as it is of type uint32_t.
591  bind_[5].buffer_type = MYSQL_TYPE_LONG;
592  bind_[5].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
593  bind_[5].is_unsigned = MLM_TRUE;
594  // bind_[5].is_null = &MLM_FALSE; // commented out for performance
595  // reasons, see memset() above
596 
597  // fqdn_fwd: boolean
598  bind_[6].buffer_type = MYSQL_TYPE_TINY;
599  bind_[6].buffer = reinterpret_cast<char*>(&lease_->fqdn_fwd_);
600  bind_[6].is_unsigned = MLM_TRUE;
601  // bind_[6].is_null = &MLM_FALSE; // commented out for performance
602  // reasons, see memset() above
603 
604  // fqdn_rev: boolean
605  bind_[7].buffer_type = MYSQL_TYPE_TINY;
606  bind_[7].buffer = reinterpret_cast<char*>(&lease_->fqdn_rev_);
607  bind_[7].is_unsigned = MLM_TRUE;
608  // bind_[7].is_null = &MLM_FALSE; // commented out for performance
609  // reasons, see memset() above
610 
611  // hostname: varchar(255)
612  // Note that previously we used MYSQL_TYPE_VARCHAR instead of
613  // MYSQL_TYPE_STRING. However, that caused 'buffer type not supported'
614  // errors on some systems running MariaDB.
615  bind_[8].buffer_type = MYSQL_TYPE_STRING;
616  bind_[8].buffer = const_cast<char*>(lease_->hostname_.c_str());
617  bind_[8].buffer_length = lease_->hostname_.length();
618  // bind_[8].is_null = &MLM_FALSE; // commented out for performance
619  // reasons, see memset() above
620 
621  // state: uint32_t
622  bind_[9].buffer_type = MYSQL_TYPE_LONG;
623  bind_[9].buffer = reinterpret_cast<char*>(&lease_->state_);
624  bind_[9].is_unsigned = MLM_TRUE;
625  // bind_[9].is_null = &MLM_FALSE; // commented out for performance
626  // reasons, see memset() above
627 
628  // user_context: text
629  ConstElementPtr ctx = lease->getContext();
630  if (ctx) {
631  bind_[10].buffer_type = MYSQL_TYPE_STRING;
632  std::string ctx_txt = ctx->str();
633  strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
634  bind_[10].buffer = user_context_;
635  bind_[10].buffer_length = ctx_txt.length();
636  // bind_[10].is_null = &MLM_FALSE; // commented out for performance
637  // reasons, see memset() above
638  } else {
639  bind_[10].buffer_type = MYSQL_TYPE_NULL;
640  }
641 
642  // Add the error flags
643  setErrorIndicators(bind_, error_, LEASE_COLUMNS);
644 
645  // .. and check that we have the numbers correct at compile time.
646  BOOST_STATIC_ASSERT(10 < LEASE_COLUMNS);
647 
648  } catch (const std::exception& ex) {
650  "Could not create bind array from Lease4: "
651  << lease_->addr_.toText() << ", reason: " << ex.what());
652  }
653 
654  // Add the data to the vector. Note the end element is one after the
655  // end of the array.
656  return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
657  }
658 
664  std::vector<MYSQL_BIND> createBindForReceive() {
665 
666  // Initialize MYSQL_BIND array.
667  // It sets all fields, including is_null, to zero, so we need to set
668  // is_null only if it should be true. This gives up minor performance
669  // benefit while being safe approach. For improved readability, the
670  // code that explicitly sets is_null is there, but is commented out.
671  memset(bind_, 0, sizeof(bind_));
672 
673  // address: uint32_t
674  bind_[0].buffer_type = MYSQL_TYPE_LONG;
675  bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
676  bind_[0].is_unsigned = MLM_TRUE;
677  // bind_[0].is_null = &MLM_FALSE; // commented out for performance
678  // reasons, see memset() above
679 
680  // hwaddr: varbinary(20)
681  hwaddr_length_ = sizeof(hwaddr_buffer_);
682  bind_[1].buffer_type = MYSQL_TYPE_BLOB;
683  bind_[1].buffer = reinterpret_cast<char*>(hwaddr_buffer_);
684  bind_[1].buffer_length = hwaddr_length_;
685  bind_[1].length = &hwaddr_length_;
686  // bind_[1].is_null = &MLM_FALSE; // commented out for performance
687  // reasons, see memset() above
688 
689  // client_id: varbinary(128)
690  client_id_length_ = sizeof(client_id_buffer_);
691  bind_[2].buffer_type = MYSQL_TYPE_BLOB;
692  bind_[2].buffer = reinterpret_cast<char*>(client_id_buffer_);
693  bind_[2].buffer_length = client_id_length_;
694  bind_[2].length = &client_id_length_;
695  bind_[2].is_null = &client_id_null_;
696  // bind_[2].is_null = &MLM_FALSE; // commented out for performance
697  // reasons, see memset() above
698 
699  // valid lifetime: unsigned int
700  bind_[3].buffer_type = MYSQL_TYPE_LONG;
701  bind_[3].buffer = reinterpret_cast<char*>(&valid_lifetime_);
702  bind_[3].is_unsigned = MLM_TRUE;
703  // bind_[3].is_null = &MLM_FALSE; // commented out for performance
704  // reasons, see memset() above
705 
706  // expire: timestamp
707  bind_[4].buffer_type = MYSQL_TYPE_TIMESTAMP;
708  bind_[4].buffer = reinterpret_cast<char*>(&expire_);
709  bind_[4].buffer_length = sizeof(expire_);
710  // bind_[4].is_null = &MLM_FALSE; // commented out for performance
711  // reasons, see memset() above
712 
713  // subnet_id: unsigned int
714  bind_[5].buffer_type = MYSQL_TYPE_LONG;
715  bind_[5].buffer = reinterpret_cast<char*>(&subnet_id_);
716  bind_[5].is_unsigned = MLM_TRUE;
717  // bind_[5].is_null = &MLM_FALSE; // commented out for performance
718  // reasons, see memset() above
719 
720  // fqdn_fwd: boolean
721  bind_[6].buffer_type = MYSQL_TYPE_TINY;
722  bind_[6].buffer = reinterpret_cast<char*>(&fqdn_fwd_);
723  bind_[6].is_unsigned = MLM_TRUE;
724  // bind_[6].is_null = &MLM_FALSE; // commented out for performance
725  // reasons, see memset() above
726 
727  // fqdn_rev: boolean
728  bind_[7].buffer_type = MYSQL_TYPE_TINY;
729  bind_[7].buffer = reinterpret_cast<char*>(&fqdn_rev_);
730  bind_[7].is_unsigned = MLM_TRUE;
731  // bind_[7].is_null = &MLM_FALSE; // commented out for performance
732  // reasons, see memset() above
733 
734  // hostname: varchar(255)
735  // Note that previously we used MYSQL_TYPE_VARCHAR instead of
736  // MYSQL_TYPE_STRING. However, that caused 'buffer type not supported'
737  // errors on some systems running MariaDB.
738  hostname_length_ = sizeof(hostname_buffer_);
739  bind_[8].buffer_type = MYSQL_TYPE_STRING;
740  bind_[8].buffer = reinterpret_cast<char*>(hostname_buffer_);
741  bind_[8].buffer_length = hostname_length_;
742  bind_[8].length = &hostname_length_;
743  // bind_[8].is_null = &MLM_FALSE; // commented out for performance
744  // reasons, see memset() above
745 
746  // state: uint32_t
747  bind_[9].buffer_type = MYSQL_TYPE_LONG;
748  bind_[9].buffer = reinterpret_cast<char*>(&state_);
749  bind_[9].is_unsigned = MLM_TRUE;
750  // bind_[9].is_null = &MLM_FALSE; // commented out for performance
751  // reasons, see memset() above
752 
753  // user_context: text
754  user_context_null_ = MLM_FALSE;
755  user_context_length_ = sizeof(user_context_);
756  bind_[10].buffer_type = MYSQL_TYPE_STRING;
757  bind_[10].buffer = reinterpret_cast<char*>(user_context_);
758  bind_[10].buffer_length = user_context_length_;
759  bind_[10].length = &user_context_length_;
760  bind_[10].is_null = &user_context_null_;
761 
762  // Add the error flags
763  setErrorIndicators(bind_, error_, LEASE_COLUMNS);
764 
765  // .. and check that we have the numbers correct at compile time.
766  BOOST_STATIC_ASSERT(10 < LEASE_COLUMNS);
767 
768  // Add the data to the vector. Note the end element is one after the
769  // end of the array.
770  return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
771  }
772 
782  // Convert times received from the database to times for the lease
783  // structure. See the expire code of createBindForSend for
784  // the infinite valid lifetime special case.
785  time_t cltt = 0;
786  // Recover from overflow
787  uint32_t valid_lft = valid_lifetime_;
788  if (valid_lft == Lease::INFINITY_LFT) {
789  valid_lft = 0;
790  }
791  MySqlConnection::convertFromDatabaseTime(expire_, valid_lft, cltt);
792 
793  if (client_id_null_ == MLM_TRUE) {
794  // There's no client-id, so we pass client-id_length_ set to 0
795  client_id_length_ = 0;
796  }
797 
798  // Hostname is passed to Lease4 as a string object. We have to create
799  // it from the buffer holding hostname and the buffer length.
800  std::string hostname(hostname_buffer_,
801  hostname_buffer_ + hostname_length_);
802 
803  // Set hardware address if it was set
804  HWAddrPtr hwaddr;
805  if (hwaddr_null_ == MLM_FALSE) {
806  hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_, HTYPE_ETHER));
807  }
808 
809  // Convert user_context to string as well.
810  std::string user_context;
811  if (user_context_null_ == MLM_FALSE) {
812  user_context_[user_context_length_] = '\0';
813  user_context.assign(user_context_);
814  }
815 
816  // Set the user context if there is one.
817  ConstElementPtr ctx;
818  if (!user_context.empty()) {
819  ctx = Element::fromJSON(user_context);
820  if (!ctx || (ctx->getType() != Element::map)) {
821  isc_throw(BadValue, "user context '" << user_context
822  << "' is not a JSON map");
823  }
824  }
825 
826  Lease4Ptr lease(boost::make_shared<Lease4>(addr4_, hwaddr,
827  client_id_buffer_,
828  client_id_length_,
829  valid_lifetime_, cltt,
830  subnet_id_, fqdn_fwd_,
831  fqdn_rev_, hostname));
832 
833  // Set state.
834  lease->state_ = state_;
835 
836  if (ctx) {
837  lease->setContext(ctx);
838  }
839 
840  return (lease);
841  }
842 
853  std::string getErrorColumns() {
854  return (getColumnsInError(error_, columns_, LEASE_COLUMNS));
855  }
856 
857 private:
858 
859  // Note: All array lengths are equal to the corresponding variable in the
860  // schema.
861  // Note: Arrays are declared fixed length for speed of creation
862  uint32_t addr4_;
863  MYSQL_BIND bind_[LEASE_COLUMNS];
864  std::string columns_[LEASE_COLUMNS];
865  my_bool error_[LEASE_COLUMNS];
866  Lease4Ptr lease_;
867  std::vector<uint8_t> hwaddr_;
868  uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
869  unsigned long hwaddr_length_;
870  my_bool hwaddr_null_;
871  std::vector<uint8_t> client_id_;
872  uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
873  unsigned long client_id_length_;
874  my_bool client_id_null_;
875  MYSQL_TIME expire_;
876  uint32_t subnet_id_;
877  uint32_t valid_lifetime_;
878  my_bool fqdn_fwd_;
879  my_bool fqdn_rev_;
880  char hostname_buffer_[HOSTNAME_MAX_LEN];
881  unsigned long hostname_length_;
882  uint32_t state_;
883  char user_context_[USER_CONTEXT_MAX_LEN];
884  unsigned long user_context_length_;
885  my_bool user_context_null_;
886 };
887 
900 
903  static const size_t LEASE_COLUMNS = 17;
904 
905 public:
906 
911  MySqlLease6Exchange() : addr6_length_(0), hwaddr_length_(0),
912  hwaddr_null_(MLM_FALSE), duid_length_(0),
913  iaid_(0), lease_type_(0), prefix_len_(0),
914  pref_lifetime_(0), subnet_id_(0), valid_lifetime_(0),
915  fqdn_fwd_(false), fqdn_rev_(false),
916  hostname_length_(0), hwtype_(0), hwaddr_source_(0),
917  state_(0), user_context_length_(0),
918  user_context_null_(MLM_FALSE) {
919  memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
920  memset(duid_buffer_, 0, sizeof(duid_buffer_));
921  memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
922  memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
923  memset(user_context_, 0, sizeof(user_context_));
924  std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
925 
926  // Set the column names (for error messages)
927  columns_[0] = "address";
928  columns_[1] = "duid";
929  columns_[2] = "valid_lifetime";
930  columns_[3] = "expire";
931  columns_[4] = "subnet_id";
932  columns_[5] = "pref_lifetime";
933  columns_[6] = "lease_type";
934  columns_[7] = "iaid";
935  columns_[8] = "prefix_len";
936  columns_[9] = "fqdn_fwd";
937  columns_[10] = "fqdn_rev";
938  columns_[11] = "hostname";
939  columns_[12] = "hwaddr";
940  columns_[13] = "hwtype";
941  columns_[14] = "hwaddr_source";
942  columns_[15] = "state";
943  columns_[16] = "user_context";
944  BOOST_STATIC_ASSERT(16 < LEASE_COLUMNS);
945  }
946 
955  std::vector<MYSQL_BIND> createBindForSend(const Lease6Ptr& lease) {
956  // Store lease object to ensure it remains valid.
957  lease_ = lease;
958 
959  // Ensure bind_ array clear for constructing the MYSQL_BIND structures
960  // for this lease.
961  // It sets all fields, including is_null, to zero, so we need to set
962  // is_null only if it should be true. This gives up minor performance
963  // benefit while being safe approach. For improved readability, the
964  // code that explicitly sets is_null is there, but is commented out.
965  memset(bind_, 0, sizeof(bind_));
966 
967  try {
968  // address: varchar(39)
969  addr6_ = lease_->addr_.toText();
970  addr6_length_ = addr6_.size();
971 
972  // In the following statement, the string is being read. However, the
973  // MySQL C interface does not use "const", so the "buffer" element
974  // is declared as "char*" instead of "const char*". To resolve this,
975  // the "const" is discarded. (Note that the address of addr6_.c_str()
976  // is guaranteed to be valid until the next non-const operation on
977  // addr6_.)
978  //
979  // The const_cast could be avoided by copying the string to a writable
980  // buffer and storing the address of that in the "buffer" element.
981  // However, this introduces a copy operation (with additional overhead)
982  // purely to get round the structures introduced by design of the
983  // MySQL interface (which uses the area pointed to by "buffer" as input
984  // when specifying query parameters and as output when retrieving data).
985  // For that reason, "const_cast" has been used.
986  bind_[0].buffer_type = MYSQL_TYPE_STRING;
987  bind_[0].buffer = const_cast<char*>(addr6_.c_str());
988  bind_[0].buffer_length = addr6_length_;
989  bind_[0].length = &addr6_length_;
990  // bind_[0].is_null = &MLM_FALSE; // commented out for performance
991  // reasons, see memset() above
992 
993  // duid: varchar(128)
994  if (!lease_->duid_) {
995  isc_throw(DbOperationError, "lease6 for address " << addr6_
996  << " is missing mandatory client-id.");
997  }
998  duid_ = lease_->duid_->getDuid();
999  duid_length_ = duid_.size();
1000 
1001  bind_[1].buffer_type = MYSQL_TYPE_BLOB;
1002  bind_[1].buffer = reinterpret_cast<char*>(&(duid_[0]));
1003  bind_[1].buffer_length = duid_length_;
1004  bind_[1].length = &duid_length_;
1005  // bind_[1].is_null = &MLM_FALSE; // commented out for performance
1006  // reasons, see memset() above
1007 
1008  // valid lifetime: unsigned int
1009  bind_[2].buffer_type = MYSQL_TYPE_LONG;
1010  bind_[2].buffer = reinterpret_cast<char*>(&lease_->valid_lft_);
1011  bind_[2].is_unsigned = MLM_TRUE;
1012  // bind_[2].is_null = &MLM_FALSE; // commented out for performance
1013  // reasons, see memset() above
1014 
1015  // expire: timestamp
1016  // The lease structure holds the client last transmission time (cltt_)
1017  // For convenience for external tools, this is converted to lease
1018  // expiry time (expire). The relationship is given by:
1019  //
1020  // expire = cltt_ + valid_lft_
1021  // Avoid overflow with infinite valid lifetime by using
1022  // expire = cltt_ when valid_lft_ = 0xffffffff
1023  uint32_t valid_lft = lease_->valid_lft_;
1024  if (valid_lft == Lease::INFINITY_LFT) {
1025  valid_lft = 0;
1026  }
1027  MySqlConnection::convertToDatabaseTime(lease_->cltt_, valid_lft,
1028  expire_);
1029  bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
1030  bind_[3].buffer = reinterpret_cast<char*>(&expire_);
1031  bind_[3].buffer_length = sizeof(expire_);
1032  // bind_[3].is_null = &MLM_FALSE; // commented out for performance
1033  // reasons, see memset() above
1034 
1035  // subnet_id: unsigned int
1036  // Can use lease_->subnet_id_ directly as it is of type uint32_t.
1037  bind_[4].buffer_type = MYSQL_TYPE_LONG;
1038  bind_[4].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
1039  bind_[4].is_unsigned = MLM_TRUE;
1040  // bind_[4].is_null = &MLM_FALSE; // commented out for performance
1041  // reasons, see memset() above
1042 
1043  // pref_lifetime: unsigned int
1044  // Can use lease_->preferred_lft_ directly as it is of type uint32_t.
1045  bind_[5].buffer_type = MYSQL_TYPE_LONG;
1046  bind_[5].buffer = reinterpret_cast<char*>(&lease_->preferred_lft_);
1047  bind_[5].is_unsigned = MLM_TRUE;
1048  // bind_[5].is_null = &MLM_FALSE; // commented out for performance
1049  // reasons, see memset() above
1050 
1051  // lease_type: tinyint
1052  // Must convert to uint8_t as lease_->type_ is a LeaseType variable.
1053  lease_type_ = lease_->type_;
1054  bind_[6].buffer_type = MYSQL_TYPE_TINY;
1055  bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
1056  bind_[6].is_unsigned = MLM_TRUE;
1057  // bind_[6].is_null = &MLM_FALSE; // commented out for performance
1058  // reasons, see memset() above
1059 
1060  // iaid: unsigned int
1061  // Can use lease_->iaid_ directly as it is of type uint32_t.
1062  bind_[7].buffer_type = MYSQL_TYPE_LONG;
1063  bind_[7].buffer = reinterpret_cast<char*>(&lease_->iaid_);
1064  bind_[7].is_unsigned = MLM_TRUE;
1065  // bind_[7].is_null = &MLM_FALSE; // commented out for performance
1066  // reasons, see memset() above
1067 
1068  // prefix_len: unsigned tinyint
1069  // Can use lease_->prefixlen_ directly as it is uint32_t.
1070  bind_[8].buffer_type = MYSQL_TYPE_TINY;
1071  bind_[8].buffer = reinterpret_cast<char*>(&lease_->prefixlen_);
1072  bind_[8].is_unsigned = MLM_TRUE;
1073  // bind_[8].is_null = &MLM_FALSE; // commented out for performance
1074  // reasons, see memset() above
1075 
1076  // fqdn_fwd: boolean
1077  bind_[9].buffer_type = MYSQL_TYPE_TINY;
1078  bind_[9].buffer = reinterpret_cast<char*>(&lease_->fqdn_fwd_);
1079  bind_[9].is_unsigned = MLM_TRUE;
1080  // bind_[7].is_null = &MLM_FALSE; // commented out for performance
1081  // reasons, see memset() above
1082 
1083  // fqdn_rev: boolean
1084  bind_[10].buffer_type = MYSQL_TYPE_TINY;
1085  bind_[10].buffer = reinterpret_cast<char*>(&lease_->fqdn_rev_);
1086  bind_[10].is_unsigned = MLM_TRUE;
1087  // bind_[10].is_null = &MLM_FALSE; // commented out for performance
1088  // reasons, see memset() above
1089 
1090  // hostname: varchar(255)
1091  bind_[11].buffer_type = MYSQL_TYPE_STRING;
1092  bind_[11].buffer = const_cast<char*>(lease_->hostname_.c_str());
1093  bind_[11].buffer_length = lease_->hostname_.length();
1094  // bind_[11].is_null = &MLM_FALSE; // commented out for performance
1095  // reasons, see memset() above
1096 
1097  // hwaddr: varbinary(20) - hardware/MAC address
1098  HWAddrPtr hwaddr = lease_->hwaddr_;
1099  if (hwaddr) {
1100  hwaddr_ = hwaddr->hwaddr_;
1101  hwaddr_length_ = hwaddr->hwaddr_.size();
1102 
1103  // Make sure that the buffer has at least length of 1, even if
1104  // empty HW address is passed. This is required by some of the
1105  // MySQL connectors that the buffer is set to non-null value.
1106  // Otherwise, null value would be inserted into the database,
1107  // rather than empty string.
1108  if (hwaddr_.empty()) {
1109  hwaddr_.resize(1);
1110  }
1111 
1112  bind_[12].buffer_type = MYSQL_TYPE_BLOB;
1113  bind_[12].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
1114  bind_[12].buffer_length = hwaddr_length_;
1115  bind_[12].length = &hwaddr_length_;
1116  } else {
1117  bind_[12].buffer_type = MYSQL_TYPE_NULL;
1118  // According to http://dev.mysql.com/doc/refman/5.5/en/
1119  // c-api-prepared-statement-data-structures.html, the other
1120  // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
1121  // but let's set them to some sane values in case earlier versions
1122  // didn't have that assumption.
1123  hwaddr_null_ = MLM_TRUE;
1124  bind_[12].buffer = NULL;
1125  bind_[12].is_null = &hwaddr_null_;
1126  }
1127 
1128  // hardware type: unsigned short int (16 bits)
1129  if (hwaddr) {
1130  hwtype_ = lease->hwaddr_->htype_;
1131  bind_[13].buffer_type = MYSQL_TYPE_SHORT;
1132  bind_[13].buffer = reinterpret_cast<char*>(&hwtype_);
1133  bind_[13].is_unsigned = MLM_TRUE;
1134  } else {
1135  hwtype_ = 0;
1136  bind_[13].buffer_type = MYSQL_TYPE_NULL;
1137  // According to http://dev.mysql.com/doc/refman/5.5/en/
1138  // c-api-prepared-statement-data-structures.html, the other
1139  // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
1140  // but let's set them to some sane values in case earlier versions
1141  // didn't have that assumption.
1142  hwaddr_null_ = MLM_TRUE;
1143  bind_[13].buffer = NULL;
1144  bind_[13].is_null = &hwaddr_null_;
1145  }
1146 
1147  // hardware source: unsigned int (32 bits)
1148  if (hwaddr) {
1149  hwaddr_source_ = lease->hwaddr_->source_;
1150  bind_[14].buffer_type = MYSQL_TYPE_LONG;
1151  bind_[14].buffer = reinterpret_cast<char*>(&hwaddr_source_);
1152  bind_[14].is_unsigned = MLM_TRUE;
1153  } else {
1154  hwaddr_source_ = 0;
1155  bind_[14].buffer_type = MYSQL_TYPE_NULL;
1156  // According to http://dev.mysql.com/doc/refman/5.5/en/
1157  // c-api-prepared-statement-data-structures.html, the other
1158  // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
1159  // but let's set them to some sane values in case earlier versions
1160  // didn't have that assumption.
1161  hwaddr_null_ = MLM_TRUE;
1162  bind_[14].buffer = NULL;
1163  bind_[14].is_null = &hwaddr_null_;
1164  }
1165 
1166  // state: uint32_t
1167  bind_[15].buffer_type = MYSQL_TYPE_LONG;
1168  bind_[15].buffer = reinterpret_cast<char*>(&lease_->state_);
1169  bind_[15].is_unsigned = MLM_TRUE;
1170  // bind_[15].is_null = &MLM_FALSE; // commented out for performance
1171  // reasons, see memset() above
1172 
1173  // user_context: text
1174  ConstElementPtr ctx = lease->getContext();
1175  if (ctx) {
1176  bind_[16].buffer_type = MYSQL_TYPE_STRING;
1177  std::string ctx_txt = ctx->str();
1178  strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
1179  bind_[16].buffer = user_context_;
1180  bind_[16].buffer_length = ctx_txt.length();
1181  // bind_[16].is_null = &MLM_FALSE; // commented out for performance
1182  // reasons, see memset() above
1183  } else {
1184  bind_[16].buffer_type = MYSQL_TYPE_NULL;
1185  }
1186 
1187  // Add the error flags
1188  setErrorIndicators(bind_, error_, LEASE_COLUMNS);
1189 
1190  // .. and check that we have the numbers correct at compile time.
1191  BOOST_STATIC_ASSERT(16 < LEASE_COLUMNS);
1192 
1193  } catch (const std::exception& ex) {
1195  "Could not create bind array from Lease6: "
1196  << lease_->addr_.toText() << ", reason: " << ex.what());
1197  }
1198 
1199  // Add the data to the vector. Note the end element is one after the
1200  // end of the array.
1201  return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
1202  }
1203 
1212  std::vector<MYSQL_BIND> createBindForReceive() {
1213 
1214  // Initialize MYSQL_BIND array.
1215  // It sets all fields, including is_null, to zero, so we need to set
1216  // is_null only if it should be true. This gives up minor performance
1217  // benefit while being safe approach. For improved readability, the
1218  // code that explicitly sets is_null is there, but is commented out.
1219  memset(bind_, 0, sizeof(bind_));
1220 
1221  // address: varchar(39)
1222  // A Lease6_ address has a maximum of 39 characters. The array is
1223  // one byte longer than this to guarantee that we can always null
1224  // terminate it whatever is returned.
1225  addr6_length_ = sizeof(addr6_buffer_) - 1;
1226  bind_[0].buffer_type = MYSQL_TYPE_STRING;
1227  bind_[0].buffer = addr6_buffer_;
1228  bind_[0].buffer_length = addr6_length_;
1229  bind_[0].length = &addr6_length_;
1230  // bind_[0].is_null = &MLM_FALSE; // commented out for performance
1231  // reasons, see memset() above
1232 
1233  // client_id: varbinary(128)
1234  duid_length_ = sizeof(duid_buffer_);
1235  bind_[1].buffer_type = MYSQL_TYPE_BLOB;
1236  bind_[1].buffer = reinterpret_cast<char*>(duid_buffer_);
1237  bind_[1].buffer_length = duid_length_;
1238  bind_[1].length = &duid_length_;
1239  // bind_[1].is_null = &MLM_FALSE; // commented out for performance
1240  // reasons, see memset() above
1241 
1242  // valid lifetime: unsigned int
1243  bind_[2].buffer_type = MYSQL_TYPE_LONG;
1244  bind_[2].buffer = reinterpret_cast<char*>(&valid_lifetime_);
1245  bind_[2].is_unsigned = MLM_TRUE;
1246  // bind_[2].is_null = &MLM_FALSE; // commented out for performance
1247  // reasons, see memset() above
1248 
1249  // expire: timestamp
1250  bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
1251  bind_[3].buffer = reinterpret_cast<char*>(&expire_);
1252  bind_[3].buffer_length = sizeof(expire_);
1253  // bind_[3].is_null = &MLM_FALSE; // commented out for performance
1254  // reasons, see memset() above
1255 
1256  // subnet_id: unsigned int
1257  bind_[4].buffer_type = MYSQL_TYPE_LONG;
1258  bind_[4].buffer = reinterpret_cast<char*>(&subnet_id_);
1259  bind_[4].is_unsigned = MLM_TRUE;
1260  // bind_[4].is_null = &MLM_FALSE; // commented out for performance
1261  // reasons, see memset() above
1262 
1263  // pref_lifetime: unsigned int
1264  bind_[5].buffer_type = MYSQL_TYPE_LONG;
1265  bind_[5].buffer = reinterpret_cast<char*>(&pref_lifetime_);
1266  bind_[5].is_unsigned = MLM_TRUE;
1267  // bind_[5].is_null = &MLM_FALSE; // commented out for performance
1268  // reasons, see memset() above
1269 
1270  // lease_type: tinyint
1271  bind_[6].buffer_type = MYSQL_TYPE_TINY;
1272  bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
1273  bind_[6].is_unsigned = MLM_TRUE;
1274  // bind_[6].is_null = &MLM_FALSE; // commented out for performance
1275  // reasons, see memset() above
1276 
1277  // iaid: unsigned int
1278  bind_[7].buffer_type = MYSQL_TYPE_LONG;
1279  bind_[7].buffer = reinterpret_cast<char*>(&iaid_);
1280  bind_[7].is_unsigned = MLM_TRUE;
1281  // bind_[7].is_null = &MLM_FALSE; // commented out for performance
1282  // reasons, see memset() above
1283 
1284  // prefix_len: unsigned tinyint
1285  bind_[8].buffer_type = MYSQL_TYPE_TINY;
1286  bind_[8].buffer = reinterpret_cast<char*>(&prefix_len_);
1287  bind_[8].is_unsigned = MLM_TRUE;
1288  // bind_[8].is_null = &MLM_FALSE; // commented out for performance
1289  // reasons, see memset() above
1290 
1291  // fqdn_fwd: boolean
1292  bind_[9].buffer_type = MYSQL_TYPE_TINY;
1293  bind_[9].buffer = reinterpret_cast<char*>(&fqdn_fwd_);
1294  bind_[9].is_unsigned = MLM_TRUE;
1295  // bind_[9].is_null = &MLM_FALSE; // commented out for performance
1296  // reasons, see memset() above
1297 
1298  // fqdn_rev: boolean
1299  bind_[10].buffer_type = MYSQL_TYPE_TINY;
1300  bind_[10].buffer = reinterpret_cast<char*>(&fqdn_rev_);
1301  bind_[10].is_unsigned = MLM_TRUE;
1302  // bind_[10].is_null = &MLM_FALSE; // commented out for performance
1303  // reasons, see memset() above
1304 
1305  // hostname: varchar(255)
1306  hostname_length_ = sizeof(hostname_buffer_);
1307  bind_[11].buffer_type = MYSQL_TYPE_STRING;
1308  bind_[11].buffer = reinterpret_cast<char*>(hostname_buffer_);
1309  bind_[11].buffer_length = hostname_length_;
1310  bind_[11].length = &hostname_length_;
1311  // bind_[11].is_null = &MLM_FALSE; // commented out for performance
1312  // reasons, see memset() above
1313 
1314  // hwaddr: varbinary(20)
1315  hwaddr_null_ = MLM_FALSE;
1316  hwaddr_length_ = sizeof(hwaddr_buffer_);
1317  bind_[12].buffer_type = MYSQL_TYPE_BLOB;
1318  bind_[12].buffer = reinterpret_cast<char*>(hwaddr_buffer_);
1319  bind_[12].buffer_length = hwaddr_length_;
1320  bind_[12].length = &hwaddr_length_;
1321  bind_[12].is_null = &hwaddr_null_;
1322 
1323  // hardware type: unsigned short int (16 bits)
1324  bind_[13].buffer_type = MYSQL_TYPE_SHORT;
1325  bind_[13].buffer = reinterpret_cast<char*>(&hwtype_);
1326  bind_[13].is_unsigned = MLM_TRUE;
1327 
1328  // hardware source: unsigned int (32 bits)
1329  bind_[14].buffer_type = MYSQL_TYPE_LONG;
1330  bind_[14].buffer = reinterpret_cast<char*>(&hwaddr_source_);
1331  bind_[14].is_unsigned = MLM_TRUE;
1332 
1333  // state: uint32_t
1334  bind_[15].buffer_type = MYSQL_TYPE_LONG;
1335  bind_[15].buffer = reinterpret_cast<char*>(&state_);
1336  bind_[15].is_unsigned = MLM_TRUE;
1337  // bind_[15].is_null = &MLM_FALSE; // commented out for performance
1338  // reasons, see memset() above
1339 
1340  // user_context: text
1341  user_context_null_ = MLM_FALSE;
1342  user_context_length_ = sizeof(user_context_);
1343  bind_[16].buffer_type = MYSQL_TYPE_STRING;
1344  bind_[16].buffer = reinterpret_cast<char*>(user_context_);
1345  bind_[16].buffer_length = user_context_length_;
1346  bind_[16].length = &user_context_length_;
1347  bind_[16].is_null = &user_context_null_;
1348 
1349  // Add the error flags
1350  setErrorIndicators(bind_, error_, LEASE_COLUMNS);
1351 
1352  // .. and check that we have the numbers correct at compile time.
1353  BOOST_STATIC_ASSERT(16 < LEASE_COLUMNS);
1354 
1355  // Add the data to the vector. Note the end element is one after the
1356  // end of the array.
1357  return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
1358  }
1359 
1371  // The address buffer is declared larger than the buffer size passed
1372  // to the access function so that we can always append a null byte.
1373  // Create the IOAddress object corresponding to the received data.
1374  addr6_buffer_[addr6_length_] = '\0';
1375  std::string address = addr6_buffer_;
1376  IOAddress addr(address);
1377 
1378  // Set the lease type in a variable of the appropriate data type, which
1379  // has been initialized with an arbitrary (but valid) value.
1380  Lease::Type type = Lease::TYPE_NA;
1381  switch (lease_type_) {
1382  case Lease::TYPE_NA:
1383  type = Lease::TYPE_NA;
1384  break;
1385 
1386  case Lease::TYPE_TA:
1387  type = Lease::TYPE_TA;
1388  break;
1389 
1390  case Lease::TYPE_PD:
1391  type = Lease::TYPE_PD;
1392  break;
1393 
1394  default:
1395  isc_throw(BadValue, "invalid lease type returned (" <<
1396  static_cast<int>(lease_type_) << ") for lease with "
1397  << "address " << address << ". Only 0, 1, or 2 are "
1398  << "allowed.");
1399  }
1400 
1401  // Set up DUID,
1402  DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
1403 
1404  // Hostname is passed to Lease6 as a string object, so we have to
1405  // create it from the hostname buffer and length.
1406  std::string hostname(hostname_buffer_,
1407  hostname_buffer_ + hostname_length_);
1408 
1409  // Set hardware address if it was set
1410  HWAddrPtr hwaddr;
1411  if (hwaddr_null_ == MLM_FALSE) {
1412  hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_, hwtype_));
1413  hwaddr->source_ = hwaddr_source_;
1414  }
1415 
1416  // Convert user_context to string as well.
1417  std::string user_context;
1418  if (user_context_null_ == MLM_FALSE) {
1419  user_context_[user_context_length_] = '\0';
1420  user_context.assign(user_context_);
1421  }
1422 
1423  // Set the user context if there is one.
1424  ConstElementPtr ctx;
1425  if (!user_context.empty()) {
1426  ctx = Element::fromJSON(user_context);
1427  if (!ctx || (ctx->getType() != Element::map)) {
1428  isc_throw(BadValue, "user context '" << user_context
1429  << "' is not a JSON map");
1430  }
1431  }
1432 
1433  // Create the lease and set the cltt (after converting from the
1434  // expire time retrieved from the database).
1435  Lease6Ptr result(boost::make_shared<Lease6>(type, addr, duid_ptr, iaid_,
1436  pref_lifetime_,
1437  valid_lifetime_, subnet_id_,
1438  fqdn_fwd_, fqdn_rev_,
1439  hostname, hwaddr,
1440  prefix_len_));
1441  time_t cltt = 0;
1442  // Recover from overflow (see expire code of createBindForSend).
1443  uint32_t valid_lft = valid_lifetime_;
1444  if (valid_lft == Lease::INFINITY_LFT) {
1445  valid_lft = 0;
1446  }
1447  MySqlConnection::convertFromDatabaseTime(expire_, valid_lft, cltt);
1448  // Update cltt_ and current_cltt_ explicitly.
1449  result->cltt_ = cltt;
1450  result->current_cltt_ = cltt;
1451 
1452  // Set state.
1453  result->state_ = state_;
1454 
1455  if (ctx) {
1456  result->setContext(ctx);
1457  }
1458 
1459  return (result);
1460  }
1461 
1472  std::string getErrorColumns() {
1473  return (getColumnsInError(error_, columns_, LEASE_COLUMNS));
1474  }
1475 
1476 private:
1477 
1478  // Note: All array lengths are equal to the corresponding variable in the
1479  // schema.
1480  // Note: arrays are declared fixed length for speed of creation
1481  std::string addr6_;
1482  char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1];
1483  unsigned long addr6_length_;
1484  MYSQL_BIND bind_[LEASE_COLUMNS];
1485  std::string columns_[LEASE_COLUMNS];
1486  my_bool error_[LEASE_COLUMNS];
1487  Lease6Ptr lease_;
1488  std::vector<uint8_t> hwaddr_;
1489  uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
1490  unsigned long hwaddr_length_;
1491  my_bool hwaddr_null_;
1492  std::vector<uint8_t> duid_;
1493  uint8_t duid_buffer_[DUID::MAX_DUID_LEN];
1494  unsigned long duid_length_;
1495  MYSQL_TIME expire_;
1496  uint32_t iaid_;
1497  uint8_t lease_type_;
1498  uint8_t prefix_len_;
1499  uint32_t pref_lifetime_;
1500  uint32_t subnet_id_;
1501  uint32_t valid_lifetime_;
1502  my_bool fqdn_fwd_;
1503  my_bool fqdn_rev_;
1504  char hostname_buffer_[HOSTNAME_MAX_LEN];
1505  unsigned long hostname_length_;
1506  uint16_t hwtype_;
1507  uint32_t hwaddr_source_;
1508  uint32_t state_;
1509  char user_context_[USER_CONTEXT_MAX_LEN];
1510  unsigned long user_context_length_;
1511  my_bool user_context_null_;
1512 };
1513 
1520 
1522 public:
1523 
1532  MySqlLeaseStatsQuery(MySqlConnection& conn, const size_t statement_index,
1533  const bool fetch_type)
1534  : conn_(conn), statement_index_(statement_index), statement_(NULL),
1535  fetch_type_(fetch_type),
1536  // Set the number of columns in the bind array based on fetch_type
1537  // This is the number of columns expected in the result set
1538  bind_(fetch_type_ ? 4 : 3),
1539  subnet_id_(0), lease_type_(0), state_(0), state_count_(0) {
1540  validateStatement();
1541  }
1542 
1552  MySqlLeaseStatsQuery(MySqlConnection& conn, const size_t statement_index,
1553  const bool fetch_type, const SubnetID& subnet_id)
1554  : LeaseStatsQuery(subnet_id), conn_(conn), statement_index_(statement_index),
1555  statement_(NULL), fetch_type_(fetch_type),
1556  // Set the number of columns in the bind array based on fetch_type
1557  // This is the number of columns expected in the result set
1558  bind_(fetch_type_ ? 4 : 3),
1559  subnet_id_(0), lease_type_(0), state_(0), state_count_(0) {
1560  validateStatement();
1561  }
1562 
1575  MySqlLeaseStatsQuery(MySqlConnection& conn, const size_t statement_index,
1576  const bool fetch_type, const SubnetID& first_subnet_id,
1577  const SubnetID& last_subnet_id)
1578  : LeaseStatsQuery(first_subnet_id, last_subnet_id), conn_(conn),
1579  statement_index_(statement_index), statement_(NULL), fetch_type_(fetch_type),
1580  // Set the number of columns in the bind array based on fetch_type
1581  // This is the number of columns expected in the result set
1582  bind_(fetch_type_ ? 4 : 3),
1583  subnet_id_(0), lease_type_(0), state_(0), state_count_(0) {
1584  validateStatement();
1585  }
1586 
1589  (void) mysql_stmt_free_result(statement_);
1590  }
1591 
1599  void start() {
1600  // Set up where clause inputs if needed.
1601  if (getSelectMode() != ALL_SUBNETS) {
1602  MYSQL_BIND inbind[2];
1603  memset(inbind, 0, sizeof(inbind));
1604 
1605  // Add first_subnet_id used by both single and range.
1606  inbind[0].buffer_type = MYSQL_TYPE_LONG;
1607  inbind[0].buffer = reinterpret_cast<char*>(&first_subnet_id_);
1608  inbind[0].is_unsigned = MLM_TRUE;
1609 
1610  // Add last_subnet_id for range.
1611  if (getSelectMode() == SUBNET_RANGE) {
1612  inbind[1].buffer_type = MYSQL_TYPE_LONG;
1613  inbind[1].buffer = reinterpret_cast<char*>(&last_subnet_id_);
1614  inbind[1].is_unsigned = MLM_TRUE;
1615  }
1616 
1617  // Bind the parameters to the statement
1618  int status = mysql_stmt_bind_param(statement_, &inbind[0]);
1619  conn_.checkError(status, statement_index_, "unable to bind parameters");
1620  }
1621 
1622  int col = 0;
1623  // subnet_id: unsigned int
1624  bind_[col].buffer_type = MYSQL_TYPE_LONG;
1625  bind_[col].buffer = reinterpret_cast<char*>(&subnet_id_);
1626  bind_[col].is_unsigned = MLM_TRUE;
1627  ++col;
1628 
1629  // Fetch the lease type if we were told to do so.
1630  if (fetch_type_) {
1631  // lease type: uint32_t
1632  bind_[col].buffer_type = MYSQL_TYPE_LONG;
1633  bind_[col].buffer = reinterpret_cast<char*>(&lease_type_);
1634  bind_[col].is_unsigned = MLM_TRUE;
1635  ++col;
1636  } else {
1637  fetch_type_ = Lease::TYPE_NA;
1638  }
1639 
1640  // state: uint32_t
1641  bind_[col].buffer_type = MYSQL_TYPE_LONG;
1642  bind_[col].buffer = reinterpret_cast<char*>(&state_);
1643  bind_[col].is_unsigned = MLM_TRUE;
1644  ++col;
1645 
1646  // state_count_: int64_t
1647  bind_[col].buffer_type = MYSQL_TYPE_LONGLONG;
1648  bind_[col].buffer = reinterpret_cast<char*>(&state_count_);
1649  //bind_[col].is_unsigned = MLM_FALSE;
1650 
1651  // Set up the MYSQL_BIND array for the data being returned
1652  // and bind it to the statement.
1653  int status = mysql_stmt_bind_result(statement_, &bind_[0]);
1654  conn_.checkError(status, statement_index_, "outbound binding failed");
1655 
1656  // Execute the statement
1657  status = MysqlExecuteStatement(statement_);
1658  conn_.checkError(status, statement_index_, "unable to execute");
1659 
1660  // Ensure that all the lease information is retrieved in one go to avoid
1661  // overhead of going back and forth between client and server.
1662  status = mysql_stmt_store_result(statement_);
1663  conn_.checkError(status, statement_index_, "results storage failed");
1664  }
1665 
1682  bool have_row = false;
1683  int status = mysql_stmt_fetch(statement_);
1684  if (status == MLM_MYSQL_FETCH_SUCCESS) {
1685  row.subnet_id_ = static_cast<SubnetID>(subnet_id_);
1686  row.lease_type_ = static_cast<Lease::Type>(lease_type_);
1687  row.lease_state_ = state_;
1688  if (state_count_ >= 0) {
1689  row.state_count_ = state_count_;
1690  } else {
1691  row.state_count_ = 0;
1692  if (!negative_count_) {
1693  negative_count_ = true;
1695  }
1696  }
1697  have_row = true;
1698  } else if (status != MYSQL_NO_DATA) {
1699  conn_.checkError(status, statement_index_, "getNextRow failed");
1700  }
1701 
1702  return (have_row);
1703  }
1704 
1705 private:
1706 
1710  void validateStatement() {
1711  if (statement_index_ >= MySqlLeaseMgr::NUM_STATEMENTS) {
1712  isc_throw(BadValue, "MySqlLeaseStatsQuery"
1713  " - invalid statement index" << statement_index_);
1714  }
1715 
1716  statement_ = conn_.statements_[statement_index_];
1717  }
1718 
1720  MySqlConnection& conn_;
1721 
1723  size_t statement_index_;
1724 
1726  MYSQL_STMT *statement_;
1727 
1729  bool fetch_type_;
1730 
1732  std::vector<MYSQL_BIND> bind_;
1733 
1735  uint32_t subnet_id_;
1736 
1738  uint32_t lease_type_;
1739 
1741  uint32_t state_;
1742 
1744  int64_t state_count_;
1745 
1747  static bool negative_count_;
1748 };
1749 
1750 // Initialize negative state count flag to false.
1751 bool MySqlLeaseStatsQuery::negative_count_ = false;
1752 
1753 // MySqlLeaseContext Constructor
1754 
1755 MySqlLeaseContext::MySqlLeaseContext(const DatabaseConnection::ParameterMap& parameters,
1756  IOServiceAccessorPtr io_service_accessor,
1757  DbCallback db_reconnect_callback)
1758  : conn_(parameters, io_service_accessor, db_reconnect_callback) {
1759 }
1760 
1761 // MySqlLeaseContextAlloc Constructor and Destructor
1762 
1763 MySqlLeaseMgr::MySqlLeaseContextAlloc::MySqlLeaseContextAlloc(
1764  const MySqlLeaseMgr& mgr) : ctx_(), mgr_(mgr) {
1765 
1766  if (MultiThreadingMgr::instance().getMode()) {
1767  // multi-threaded
1768  {
1769  // we need to protect the whole pool_ operation, hence extra scope {}
1770  lock_guard<mutex> lock(mgr_.pool_->mutex_);
1771  if (!mgr_.pool_->pool_.empty()) {
1772  ctx_ = mgr_.pool_->pool_.back();
1773  mgr_.pool_->pool_.pop_back();
1774  }
1775  }
1776  if (!ctx_) {
1777  ctx_ = mgr_.createContext();
1778  }
1779  } else {
1780  // single-threaded
1781  if (mgr_.pool_->pool_.empty()) {
1782  isc_throw(Unexpected, "No available MySQL lease context?!");
1783  }
1784  ctx_ = mgr_.pool_->pool_.back();
1785  }
1786 }
1787 
1788 MySqlLeaseMgr::MySqlLeaseContextAlloc::~MySqlLeaseContextAlloc() {
1789  if (MultiThreadingMgr::instance().getMode()) {
1790  // multi-threaded
1791  lock_guard<mutex> lock(mgr_.pool_->mutex_);
1792  mgr_.pool_->pool_.push_back(ctx_);
1793  }
1794  // If running in single-threaded mode, there's nothing to do here.
1795 }
1796 
1797 void
1799  isc_throw(isc::NotImplemented, "extended info tables are not yet supported by mysql");
1800 }
1801 
1802 // MySqlLeaseMgr Constructor and Destructor
1803 
1805  : parameters_(parameters), timer_name_("") {
1806 
1807  // Check if the extended info tables are enabled.
1809 
1810  // Create unique timer name per instance.
1811  timer_name_ = "MySqlLeaseMgr[";
1812  timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
1813  timer_name_ += "]DbReconnectTimer";
1814 
1815  // Validate schema version first.
1816  std::pair<uint32_t, uint32_t> code_version(MYSQL_SCHEMA_VERSION_MAJOR,
1818  std::pair<uint32_t, uint32_t> db_version = getVersion();
1819  if (code_version != db_version) {
1821  "MySQL schema version mismatch: need version: "
1822  << code_version.first << "." << code_version.second
1823  << " found version: " << db_version.first << "."
1824  << db_version.second);
1825  }
1826 
1827  // Create an initial context.
1828  pool_.reset(new MySqlLeaseContextPool());
1829  pool_->pool_.push_back(createContext());
1830 }
1831 
1833 }
1834 
1835 bool
1838 
1839  // Invoke application layer connection lost callback.
1840  if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) {
1841  return (false);
1842  }
1843 
1844  bool reopened = false;
1845 
1846  const std::string timer_name = db_reconnect_ctl->timerName();
1847 
1848  // At least one connection was lost.
1849  try {
1850  CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
1852  LeaseMgrFactory::create(cfg_db->getLeaseDbAccessString());
1853  reopened = true;
1854  } catch (const std::exception& ex) {
1856  .arg(ex.what());
1857  }
1858 
1859  if (reopened) {
1860  // Cancel the timer.
1861  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1862  TimerMgr::instance()->unregisterTimer(timer_name);
1863  }
1864 
1865  // Invoke application layer connection recovered callback.
1866  if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) {
1867  return (false);
1868  }
1869  } else {
1870  if (!db_reconnect_ctl->checkRetries()) {
1871  // We're out of retries, log it and initiate shutdown.
1873  .arg(db_reconnect_ctl->maxRetries());
1874 
1875  // Cancel the timer.
1876  if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1877  TimerMgr::instance()->unregisterTimer(timer_name);
1878  }
1879 
1880  // Invoke application layer connection failed callback.
1882  return (false);
1883  }
1884 
1886  .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
1887  .arg(db_reconnect_ctl->maxRetries())
1888  .arg(db_reconnect_ctl->retryInterval());
1889 
1890  // Start the timer.
1891  if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
1892  TimerMgr::instance()->registerTimer(timer_name,
1893  std::bind(&MySqlLeaseMgr::dbReconnect, db_reconnect_ctl),
1894  db_reconnect_ctl->retryInterval(),
1896  }
1897  TimerMgr::instance()->setup(timer_name);
1898  }
1899 
1900  return (true);
1901 }
1902 
1903 // Create context.
1904 
1907  MySqlLeaseContextPtr ctx(new MySqlLeaseContext(parameters_,
1910 
1911  // Open the database.
1912  ctx->conn_.openDatabase();
1913 
1914  // Check if we have TLS when we required it.
1915  if (ctx->conn_.getTls()) {
1916  std::string cipher = ctx->conn_.getTlsCipher();
1917  if (cipher.empty()) {
1919  } else {
1922  .arg(cipher);
1923  }
1924  }
1925 
1926  // Prepare all statements likely to be used.
1927  ctx->conn_.prepareStatements(tagged_statements.begin(),
1928  tagged_statements.end());
1929 
1930  // Create the exchange objects for use in exchanging data between the
1931  // program and the database.
1932  ctx->exchange4_.reset(new MySqlLease4Exchange());
1933  ctx->exchange6_.reset(new MySqlLease6Exchange());
1934 
1935  // Create ReconnectCtl for this connection.
1936  ctx->conn_.makeReconnectCtl(timer_name_);
1937 
1938  return (ctx);
1939 }
1940 
1941 std::string
1943  std::stringstream tmp;
1944  tmp << "MySQL backend " << MYSQL_SCHEMA_VERSION_MAJOR;
1945  tmp << "." << MYSQL_SCHEMA_VERSION_MINOR;
1946  tmp << ", library " << mysql_get_client_info();
1947  return (tmp.str());
1948 }
1949 
1950 // Add leases to the database. The two public methods accept a lease object
1951 // (either V4 of V6), bind the contents to the appropriate prepared
1952 // statement, then call common code to execute the statement.
1953 
1954 bool
1955 MySqlLeaseMgr::addLeaseCommon(MySqlLeaseContextPtr& ctx,
1956  StatementIndex stindex,
1957  std::vector<MYSQL_BIND>& bind) {
1958 
1959  // Bind the parameters to the statement
1960  int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], &bind[0]);
1961  checkError(ctx, status, stindex, "unable to bind parameters");
1962 
1963  // Execute the statement
1964  status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]);
1965  if (status != 0) {
1966 
1967  // Failure: check for the special case of duplicate entry. If this is
1968  // the case, we return false to indicate that the row was not added.
1969  // Otherwise we throw an exception.
1970  if (mysql_errno(ctx->conn_.mysql_) == ER_DUP_ENTRY) {
1971  return (false);
1972  }
1973  checkError(ctx, status, stindex, "unable to execute");
1974  }
1975 
1976  // Insert succeeded
1977  return (true);
1978 }
1979 
1980 bool
1983  .arg(lease->addr_.toText());
1984 
1985  // Get a context
1986  MySqlLeaseContextAlloc get_context(*this);
1987  MySqlLeaseContextPtr ctx = get_context.ctx_;
1988 
1989  // Create the MYSQL_BIND array for the lease
1990  std::vector<MYSQL_BIND> bind = ctx->exchange4_->createBindForSend(lease);
1991 
1992  // ... and drop to common code.
1993  auto result = addLeaseCommon(ctx, INSERT_LEASE4, bind);
1994 
1995  // Update lease current expiration time (allows update between the creation
1996  // of the Lease up to the point of insertion in the database).
1997  lease->updateCurrentExpirationTime();
1998 
1999  return (result);
2000 }
2001 
2002 bool
2005  .arg(lease->addr_.toText())
2006  .arg(lease->type_);
2007 
2008  // Get a context
2009  MySqlLeaseContextAlloc get_context(*this);
2010  MySqlLeaseContextPtr ctx = get_context.ctx_;
2011 
2012  // Create the MYSQL_BIND array for the lease
2013  std::vector<MYSQL_BIND> bind = ctx->exchange6_->createBindForSend(lease);
2014 
2015  // ... and drop to common code.
2016  auto result = addLeaseCommon(ctx, INSERT_LEASE6, bind);
2017 
2018  // Update lease current expiration time (allows update between the creation
2019  // of the Lease up to the point of insertion in the database).
2020  lease->updateCurrentExpirationTime();
2021 
2022  return (result);
2023 }
2024 
2025 // Extraction of leases from the database.
2026 //
2027 // All getLease() methods ultimately call getLeaseCollection(). This
2028 // binds the input parameters passed to it with the appropriate prepared
2029 // statement and executes the statement. It then gets the results from the
2030 // database. getlease() methods that expect a single result back call it
2031 // with the "single" parameter set true: this causes an exception to be
2032 // generated if multiple records can be retrieved from the result set. (Such
2033 // an occurrence either indicates corruption in the database, or that an
2034 // assumption that a query can only return a single record is incorrect.)
2035 // Methods that require a collection of records have "single" set to the
2036 // default value of false. The logic is the same for both Lease4 and Lease6
2037 // objects, so the code is templated.
2038 //
2039 // Methods that require a collection of objects access this method through
2040 // two interface methods (also called getLeaseCollection()). These are
2041 // short enough as to be defined in the header file: all they do is to supply
2042 // the appropriate MySqlLeaseXExchange object depending on the type of the
2043 // LeaseCollection objects passed to them.
2044 //
2045 // Methods that require a single object to be returned access the method
2046 // through two interface methods (called getLease()). As well as supplying
2047 // the appropriate exchange object, they convert between lease collection
2048 // holding zero or one leases into an appropriate Lease object.
2049 
2050 template <typename Exchange, typename LeaseCollection>
2051 void
2052 MySqlLeaseMgr::getLeaseCollection(MySqlLeaseContextPtr& ctx,
2053  StatementIndex stindex,
2054  MYSQL_BIND* bind,
2055  Exchange& exchange,
2056  LeaseCollection& result,
2057  bool single) const {
2058  int status;
2059 
2060  if (bind) {
2061  // Bind the selection parameters to the statement
2062  status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind);
2063  checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
2064  }
2065 
2066  // Set up the MYSQL_BIND array for the data being returned and bind it to
2067  // the statement.
2068  std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
2069  status = mysql_stmt_bind_result(ctx->conn_.statements_[stindex], &outbind[0]);
2070  checkError(ctx, status, stindex, "unable to bind SELECT clause parameters");
2071 
2072  // Execute the statement
2073  status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]);
2074  checkError(ctx, status, stindex, "unable to execute");
2075 
2076  // Ensure that all the lease information is retrieved in one go to avoid
2077  // overhead of going back and forth between client and server.
2078  status = mysql_stmt_store_result(ctx->conn_.statements_[stindex]);
2079  checkError(ctx, status, stindex, "unable to set up for storing all results");
2080 
2081  // Set up the fetch "release" object to release resources associated
2082  // with the call to mysql_stmt_fetch when this method exits, then
2083  // retrieve the data.
2084  MySqlFreeResult fetch_release(ctx->conn_.statements_[stindex]);
2085  int count = 0;
2086  while ((status = mysql_stmt_fetch(ctx->conn_.statements_[stindex])) == 0) {
2087  try {
2088  result.push_back(exchange->getLeaseData());
2089 
2090  } catch (const isc::BadValue& ex) {
2091  // Rethrow the exception with a bit more data.
2092  isc_throw(BadValue, ex.what() << ". Statement is <" <<
2093  ctx->conn_.text_statements_[stindex] << ">");
2094  }
2095 
2096  if (single && (++count > 1)) {
2097  isc_throw(MultipleRecords, "multiple records were found in the "
2098  "database where only one was expected for query "
2099  << ctx->conn_.text_statements_[stindex]);
2100  }
2101  }
2102 
2103  // How did the fetch end?
2104  if (status == 1) {
2105  // Error - unable to fetch results
2106  checkError(ctx, status, stindex, "unable to fetch results");
2107  } else if (status == MYSQL_DATA_TRUNCATED) {
2108  // Data truncated - throw an exception indicating what was at fault
2109  isc_throw(DataTruncated, ctx->conn_.text_statements_[stindex]
2110  << " returned truncated data: columns affected are "
2111  << exchange->getErrorColumns());
2112  }
2113 }
2114 
2115 void
2116 MySqlLeaseMgr::getLease(MySqlLeaseContextPtr& ctx,
2117  StatementIndex stindex, MYSQL_BIND* bind,
2118  Lease4Ptr& result) const {
2119  // Create appropriate collection object and get all leases matching
2120  // the selection criteria. The "single" parameter is true to indicate
2121  // that the called method should throw an exception if multiple
2122  // matching records are found: this particular method is called when only
2123  // one or zero matches is expected.
2124  Lease4Collection collection;
2125  getLeaseCollection(ctx, stindex, bind, ctx->exchange4_, collection, true);
2126 
2127  // Return single record if present, else clear the lease.
2128  if (collection.empty()) {
2129  result.reset();
2130  } else {
2131  result = *collection.begin();
2132  }
2133 }
2134 
2135 void
2136 MySqlLeaseMgr::getLease(MySqlLeaseContextPtr& ctx,
2137  StatementIndex stindex, MYSQL_BIND* bind,
2138  Lease6Ptr& result) const {
2139  // Create appropriate collection object and get all leases matching
2140  // the selection criteria. The "single" parameter is true to indicate
2141  // that the called method should throw an exception if multiple
2142  // matching records are found: this particular method is called when only
2143  // one or zero matches is expected.
2144  Lease6Collection collection;
2145  getLeaseCollection(ctx, stindex, bind, ctx->exchange6_, collection, true);
2146 
2147  // Return single record if present, else clear the lease.
2148  if (collection.empty()) {
2149  result.reset();
2150  } else {
2151  result = *collection.begin();
2152  }
2153 }
2154 
2155 // Basic lease access methods. Obtain leases from the database using various
2156 // criteria.
2157 
2158 Lease4Ptr
2161  .arg(addr.toText());
2162 
2163  // Set up the WHERE clause value
2164  MYSQL_BIND inbind[1];
2165  memset(inbind, 0, sizeof(inbind));
2166 
2167  uint32_t addr4 = addr.toUint32();
2168  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2169  inbind[0].buffer = reinterpret_cast<char*>(&addr4);
2170  inbind[0].is_unsigned = MLM_TRUE;
2171 
2172  // Get the data
2173  Lease4Ptr result;
2174 
2175  // Get a context
2176  MySqlLeaseContextAlloc get_context(*this);
2177  MySqlLeaseContextPtr ctx = get_context.ctx_;
2178 
2179  getLease(ctx, GET_LEASE4_ADDR, inbind, result);
2180 
2181  return (result);
2182 }
2183 
2185 MySqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
2187  .arg(hwaddr.toText());
2188 
2189  // Set up the WHERE clause value
2190  MYSQL_BIND inbind[1];
2191  memset(inbind, 0, sizeof(inbind));
2192 
2193  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2194 
2195  unsigned long hwaddr_length = hwaddr.hwaddr_.size();
2196 
2197  // If the data happens to be empty, we have to create a 1 byte dummy
2198  // buffer and pass it to the binding.
2199  uint8_t single_byte_data = 0;
2200 
2201  // As "buffer" is "char*" - even though the data is being read - we need
2202  // to cast away the "const"ness as well as reinterpreting the data as
2203  // a "char*". (We could avoid the "const_cast" by copying the data to a
2204  // local variable, but as the data is only being read, this introduces
2205  // an unnecessary copy).
2206  uint8_t* data = !hwaddr.hwaddr_.empty() ? const_cast<uint8_t*>(&hwaddr.hwaddr_[0])
2207  : &single_byte_data;
2208 
2209  inbind[0].buffer = reinterpret_cast<char*>(data);
2210  inbind[0].buffer_length = hwaddr_length;
2211  inbind[0].length = &hwaddr_length;
2212 
2213  // Get the data
2214  Lease4Collection result;
2215 
2216  // Get a context
2217  MySqlLeaseContextAlloc get_context(*this);
2218  MySqlLeaseContextPtr ctx = get_context.ctx_;
2219 
2220  getLeaseCollection(ctx, GET_LEASE4_HWADDR, inbind, result);
2221 
2222  return (result);
2223 }
2224 
2225 Lease4Ptr
2226 MySqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
2228  .arg(subnet_id)
2229  .arg(hwaddr.toText());
2230 
2231  // Set up the WHERE clause value
2232  MYSQL_BIND inbind[2];
2233  memset(inbind, 0, sizeof(inbind));
2234 
2235  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2236 
2237  unsigned long hwaddr_length = hwaddr.hwaddr_.size();
2238 
2239  // If the data happens to be empty, we have to create a 1 byte dummy
2240  // buffer and pass it to the binding.
2241  std::vector<uint8_t> single_byte_vec(1);
2242 
2243  // As "buffer" is "char*" - even though the data is being read - we need
2244  // to cast away the "const"ness as well as reinterpreting the data as
2245  // a "char*". (We could avoid the "const_cast" by copying the data to a
2246  // local variable, but as the data is only being read, this introduces
2247  // an unnecessary copy).
2248  uint8_t* data = !hwaddr.hwaddr_.empty() ? const_cast<uint8_t*>(&hwaddr.hwaddr_[0])
2249  : &single_byte_vec[0];
2250 
2251  inbind[0].buffer = reinterpret_cast<char*>(data);
2252  inbind[0].buffer_length = hwaddr_length;
2253  inbind[0].length = &hwaddr_length;
2254 
2255  inbind[1].buffer_type = MYSQL_TYPE_LONG;
2256  inbind[1].buffer = reinterpret_cast<char*>(&subnet_id);
2257  inbind[1].is_unsigned = MLM_TRUE;
2258 
2259  // Get the data
2260  Lease4Ptr result;
2261 
2262  // Get a context
2263  MySqlLeaseContextAlloc get_context(*this);
2264  MySqlLeaseContextPtr ctx = get_context.ctx_;
2265 
2266  getLease(ctx, GET_LEASE4_HWADDR_SUBID, inbind, result);
2267 
2268  return (result);
2269 }
2270 
2272 MySqlLeaseMgr::getLease4(const ClientId& clientid) const {
2274  .arg(clientid.toText());
2275 
2276  // Set up the WHERE clause value
2277  MYSQL_BIND inbind[1];
2278  memset(inbind, 0, sizeof(inbind));
2279 
2280  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2281 
2282  std::vector<uint8_t> client_data = clientid.getClientId();
2283  unsigned long client_data_length = client_data.size();
2284 
2285  // If the data happens to be empty, we have to create a 1 byte dummy
2286  // buffer and pass it to the binding.
2287  if (client_data.empty()) {
2288  client_data.resize(1);
2289  }
2290 
2291  inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
2292  inbind[0].buffer_length = client_data_length;
2293  inbind[0].length = &client_data_length;
2294 
2295  // Get the data
2296  Lease4Collection result;
2297 
2298  // Get a context
2299  MySqlLeaseContextAlloc get_context(*this);
2300  MySqlLeaseContextPtr ctx = get_context.ctx_;
2301 
2302  getLeaseCollection(ctx, GET_LEASE4_CLIENTID, inbind, result);
2303 
2304  return (result);
2305 }
2306 
2307 Lease4Ptr
2308 MySqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
2310  .arg(subnet_id)
2311  .arg(clientid.toText());
2312 
2313  // Set up the WHERE clause value
2314  MYSQL_BIND inbind[2];
2315  memset(inbind, 0, sizeof(inbind));
2316 
2317  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2318 
2319  std::vector<uint8_t> client_data = clientid.getClientId();
2320  unsigned long client_data_length = client_data.size();
2321 
2322  // If the data happens to be empty, we have to create a 1 byte dummy
2323  // buffer and pass it to the binding.
2324  if (client_data.empty()) {
2325  client_data.resize(1);
2326  }
2327 
2328  inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
2329  inbind[0].buffer_length = client_data_length;
2330  inbind[0].length = &client_data_length;
2331 
2332  inbind[1].buffer_type = MYSQL_TYPE_LONG;
2333  inbind[1].buffer = reinterpret_cast<char*>(&subnet_id);
2334  inbind[1].is_unsigned = MLM_TRUE;
2335 
2336  // Get the data
2337  Lease4Ptr result;
2338 
2339  // Get a context
2340  MySqlLeaseContextAlloc get_context(*this);
2341  MySqlLeaseContextPtr ctx = get_context.ctx_;
2342 
2343  getLease(ctx, GET_LEASE4_CLIENTID_SUBID, inbind, result);
2344 
2345  return (result);
2346 }
2347 
2351  .arg(subnet_id);
2352 
2353  // Set up the WHERE clause value
2354  MYSQL_BIND inbind[1];
2355  memset(inbind, 0, sizeof(inbind));
2356 
2357  // Subnet ID
2358  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2359  inbind[0].buffer = reinterpret_cast<char*>(&subnet_id);
2360  inbind[0].is_unsigned = MLM_TRUE;
2361 
2362  // ... and get the data
2363  Lease4Collection result;
2364 
2365  // Get a context
2366  MySqlLeaseContextAlloc get_context(*this);
2367  MySqlLeaseContextPtr ctx = get_context.ctx_;
2368 
2369  getLeaseCollection(ctx, GET_LEASE4_SUBID, inbind, result);
2370 
2371  return (result);
2372 }
2373 
2375 MySqlLeaseMgr::getLeases4(const std::string& hostname) const {
2377  .arg(hostname);
2378 
2379  // Set up the WHERE clause value
2380  MYSQL_BIND inbind[1];
2381  memset(inbind, 0, sizeof(inbind));
2382 
2383  // Hostname
2384  inbind[0].buffer_type = MYSQL_TYPE_STRING;
2385  inbind[0].buffer = const_cast<char*>(hostname.c_str());
2386  inbind[0].buffer_length = hostname.length();
2387 
2388  // ... and get the data
2389  Lease4Collection result;
2390 
2391  // Get a context
2392  MySqlLeaseContextAlloc get_context(*this);
2393  MySqlLeaseContextPtr ctx = get_context.ctx_;
2394 
2395  getLeaseCollection(ctx, GET_LEASE4_HOSTNAME, inbind, result);
2396 
2397  return (result);
2398 }
2399 
2403 
2404  Lease4Collection result;
2405 
2406  // Get a context
2407  MySqlLeaseContextAlloc get_context(*this);
2408  MySqlLeaseContextPtr ctx = get_context.ctx_;
2409 
2410  getLeaseCollection(ctx, GET_LEASE4, 0, result);
2411 
2412  return (result);
2413 }
2414 
2416 MySqlLeaseMgr::getLeases4(const IOAddress& lower_bound_address,
2417  const LeasePageSize& page_size) const {
2418  // Expecting IPv4 address.
2419  if (!lower_bound_address.isV4()) {
2420  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
2421  "retrieving leases from the lease database, got "
2422  << lower_bound_address);
2423  }
2424 
2426  .arg(page_size.page_size_)
2427  .arg(lower_bound_address.toText());
2428 
2429  // Prepare WHERE clause
2430  MYSQL_BIND inbind[2];
2431  memset(inbind, 0, sizeof(inbind));
2432 
2433  // Bind lower bound address
2434  uint32_t lb_address_data = lower_bound_address.toUint32();
2435  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2436  inbind[0].buffer = reinterpret_cast<char*>(&lb_address_data);
2437  inbind[0].is_unsigned = MLM_TRUE;
2438 
2439  // Bind page size value
2440  size_t* ps = const_cast<size_t*>(&page_size.page_size_);
2441  inbind[1].buffer_type = MYSQL_TYPE_LONG;
2442  inbind[1].buffer = reinterpret_cast<char*>(ps);
2443  inbind[1].is_unsigned = MLM_TRUE;
2444 
2445  // Get the leases
2446  Lease4Collection result;
2447 
2448  // Get a context
2449  MySqlLeaseContextAlloc get_context(*this);
2450  MySqlLeaseContextPtr ctx = get_context.ctx_;
2451 
2452  getLeaseCollection(ctx, GET_LEASE4_PAGE, inbind, result);
2453 
2454  return (result);
2455 }
2456 
2457 Lease6Ptr
2459  const IOAddress& addr) const {
2461  .arg(addr.toText())
2462  .arg(lease_type);
2463 
2464  // Set up the WHERE clause value
2465  MYSQL_BIND inbind[2];
2466  memset(inbind, 0, sizeof(inbind));
2467 
2468  std::string addr6 = addr.toText();
2469  unsigned long addr6_length = addr6.size();
2470 
2471  // See the earlier description of the use of "const_cast" when accessing
2472  // the address for an explanation of the reason.
2473  inbind[0].buffer_type = MYSQL_TYPE_STRING;
2474  inbind[0].buffer = const_cast<char*>(addr6.c_str());
2475  inbind[0].buffer_length = addr6_length;
2476  inbind[0].length = &addr6_length;
2477 
2478  // LEASE_TYPE
2479  inbind[1].buffer_type = MYSQL_TYPE_TINY;
2480  inbind[1].buffer = reinterpret_cast<char*>(&lease_type);
2481  inbind[1].is_unsigned = MLM_TRUE;
2482 
2483  Lease6Ptr result;
2484 
2485  // Get a context
2486  MySqlLeaseContextAlloc get_context(*this);
2487  MySqlLeaseContextPtr ctx = get_context.ctx_;
2488 
2489  getLease(ctx, GET_LEASE6_ADDR, inbind, result);
2490 
2491  return (result);
2492 }
2493 
2496  uint32_t iaid) const {
2498  .arg(iaid)
2499  .arg(duid.toText())
2500  .arg(lease_type);
2501 
2502  // Set up the WHERE clause value
2503  MYSQL_BIND inbind[3];
2504  memset(inbind, 0, sizeof(inbind));
2505 
2506  // In the following statement, the DUID is being read. However, the
2507  // MySQL C interface does not use "const", so the "buffer" element
2508  // is declared as "char*" instead of "const char*". To resolve this,
2509  // the "const" is discarded before the uint8_t* is cast to char*.
2510  //
2511  // Note that the const_cast could be avoided by copying the DUID to
2512  // a writable buffer and storing the address of that in the "buffer"
2513  // element. However, this introduces a copy operation (with additional
2514  // overhead) purely to get round the structures introduced by design of
2515  // the MySQL interface (which uses the area pointed to by "buffer" as
2516  // input when specifying query parameters and as output when retrieving
2517  // data). For that reason, "const_cast" has been used.
2518  const vector<uint8_t>& duid_vector = duid.getDuid();
2519  unsigned long duid_length = duid_vector.size();
2520 
2521  // Make sure that the buffer has at least length of 1, even if
2522  // empty client id is passed. This is required by some of the
2523  // MySQL connectors that the buffer is set to non-null value.
2524  // Otherwise, null value would be inserted into the database,
2525  // rather than empty string.
2526  uint8_t single_byte_data = 0;
2527  uint8_t* data = !duid_vector.empty() ? const_cast<uint8_t*>(&duid_vector[0])
2528  : &single_byte_data;
2529 
2530  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2531  inbind[0].buffer = reinterpret_cast<char*>(data);
2532  inbind[0].buffer_length = duid_length;
2533  inbind[0].length = &duid_length;
2534 
2535  // IAID
2536  inbind[1].buffer_type = MYSQL_TYPE_LONG;
2537  inbind[1].buffer = reinterpret_cast<char*>(&iaid);
2538  inbind[1].is_unsigned = MLM_TRUE;
2539 
2540  // LEASE_TYPE
2541  inbind[2].buffer_type = MYSQL_TYPE_TINY;
2542  inbind[2].buffer = reinterpret_cast<char*>(&lease_type);
2543  inbind[2].is_unsigned = MLM_TRUE;
2544 
2545  // ... and get the data
2546  Lease6Collection result;
2547 
2548  // Get a context
2549  MySqlLeaseContextAlloc get_context(*this);
2550  MySqlLeaseContextPtr ctx = get_context.ctx_;
2551 
2552  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID, inbind, result);
2553 
2554  return (result);
2555 }
2556 
2559  uint32_t iaid, SubnetID subnet_id) const {
2561  .arg(iaid)
2562  .arg(subnet_id)
2563  .arg(duid.toText())
2564  .arg(lease_type);
2565 
2566  // Set up the WHERE clause value
2567  MYSQL_BIND inbind[4];
2568  memset(inbind, 0, sizeof(inbind));
2569 
2570  // See the earlier description of the use of "const_cast" when accessing
2571  // the DUID for an explanation of the reason.
2572  const vector<uint8_t>& duid_vector = duid.getDuid();
2573  unsigned long duid_length = duid_vector.size();
2574  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2575  inbind[0].buffer = reinterpret_cast<char*>(
2576  const_cast<uint8_t*>(&duid_vector[0]));
2577  inbind[0].buffer_length = duid_length;
2578  inbind[0].length = &duid_length;
2579 
2580  // IAID
2581  inbind[1].buffer_type = MYSQL_TYPE_LONG;
2582  inbind[1].buffer = reinterpret_cast<char*>(&iaid);
2583  inbind[1].is_unsigned = MLM_TRUE;
2584 
2585  // Subnet ID
2586  inbind[2].buffer_type = MYSQL_TYPE_LONG;
2587  inbind[2].buffer = reinterpret_cast<char*>(&subnet_id);
2588  inbind[2].is_unsigned = MLM_TRUE;
2589 
2590  // LEASE_TYPE
2591  inbind[3].buffer_type = MYSQL_TYPE_TINY;
2592  inbind[3].buffer = reinterpret_cast<char*>(&lease_type);
2593  inbind[3].is_unsigned = MLM_TRUE;
2594 
2595  // ... and get the data
2596  Lease6Collection result;
2597 
2598  // Get a context
2599  MySqlLeaseContextAlloc get_context(*this);
2600  MySqlLeaseContextPtr ctx = get_context.ctx_;
2601 
2602  getLeaseCollection(ctx, GET_LEASE6_DUID_IAID_SUBID, inbind, result);
2603 
2604  return (result);
2605 }
2606 
2610  .arg(subnet_id);
2611 
2612  // Set up the WHERE clause value
2613  MYSQL_BIND inbind[1];
2614  memset(inbind, 0, sizeof(inbind));
2615 
2616  // Subnet ID
2617  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2618  inbind[0].buffer = reinterpret_cast<char*>(&subnet_id);
2619  inbind[0].is_unsigned = MLM_TRUE;
2620 
2621  // ... and get the data
2622  Lease6Collection result;
2623 
2624  // Get a context
2625  MySqlLeaseContextAlloc get_context(*this);
2626  MySqlLeaseContextPtr ctx = get_context.ctx_;
2627 
2628  getLeaseCollection(ctx, GET_LEASE6_SUBID, inbind, result);
2629 
2630  return (result);
2631 }
2632 
2636 
2637  Lease6Collection result;
2638 
2639  // Get a context
2640  MySqlLeaseContextAlloc get_context(*this);
2641  MySqlLeaseContextPtr ctx = get_context.ctx_;
2642 
2643  getLeaseCollection(ctx, GET_LEASE6, 0, result);
2644 
2645  return (result);
2646 }
2647 
2649 MySqlLeaseMgr::getLeases6(const DUID& duid) const {
2651  .arg(duid.toText());
2652 
2653  // Set up the WHERE clause value
2654  MYSQL_BIND inbind[1];
2655  memset(inbind, 0, sizeof(inbind));
2656 
2657  const vector<uint8_t>& duid_vector = duid.getDuid();
2658  unsigned long duid_length = duid_vector.size();
2659 
2660  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2661  inbind[0].buffer = reinterpret_cast<char*>(
2662  const_cast<uint8_t*>(&duid_vector[0]));
2663  inbind[0].buffer_length = duid_length;
2664  inbind[0].length = &duid_length;
2665 
2666  Lease6Collection result;
2667 
2668  // Get a context
2669  MySqlLeaseContextAlloc get_context(*this);
2670  MySqlLeaseContextPtr ctx = get_context.ctx_;
2671 
2672  getLeaseCollection(ctx, GET_LEASE6_DUID, inbind, result);
2673 
2674  return result;
2675 }
2676 
2678 MySqlLeaseMgr::getLeases6(const std::string& hostname) const {
2680  .arg(hostname);
2681 
2682  // Set up the WHERE clause value
2683  MYSQL_BIND inbind[1];
2684  memset(inbind, 0, sizeof(inbind));
2685 
2686  // Hostname
2687  inbind[0].buffer_type = MYSQL_TYPE_STRING;
2688  inbind[0].buffer = const_cast<char*>(hostname.c_str());
2689  inbind[0].buffer_length = hostname.length();
2690 
2691  // ... and get the data
2692  Lease6Collection result;
2693 
2694  // Get a context
2695  MySqlLeaseContextAlloc get_context(*this);
2696  MySqlLeaseContextPtr ctx = get_context.ctx_;
2697 
2698  getLeaseCollection(ctx, GET_LEASE6_HOSTNAME, inbind, result);
2699 
2700  return (result);
2701 }
2702 
2704 MySqlLeaseMgr::getLeases6(const IOAddress& lower_bound_address,
2705  const LeasePageSize& page_size) const {
2706  // Expecting IPv6 address.
2707  if (!lower_bound_address.isV6()) {
2708  isc_throw(InvalidAddressFamily, "expected IPv6 address while "
2709  "retrieving leases from the lease database, got "
2710  << lower_bound_address);
2711  }
2712 
2714  .arg(page_size.page_size_)
2715  .arg(lower_bound_address.toText());
2716 
2717  // Prepare WHERE clause
2718  MYSQL_BIND inbind[2];
2719  memset(inbind, 0, sizeof(inbind));
2720 
2721  // In IPv6 we compare addresses represented as strings. The IPv6 zero address
2722  // is ::, so it is greater than any other address. In this special case, we
2723  // just use 0 for comparison which should be lower than any real IPv6 address.
2724  std::string lb_address_data = "0";
2725  if (!lower_bound_address.isV6Zero()) {
2726  lb_address_data = lower_bound_address.toText();
2727  }
2728 
2729  // Bind lower bound address
2730  unsigned long lb_address_data_size = lb_address_data.size();
2731  inbind[0].buffer_type = MYSQL_TYPE_STRING;
2732  inbind[0].buffer = const_cast<char*>(lb_address_data.c_str());
2733  inbind[0].buffer_length = lb_address_data_size;
2734  inbind[0].length = &lb_address_data_size;
2735 
2736  // Bind page size value
2737  size_t* ps = const_cast<size_t*>(&page_size.page_size_);
2738  inbind[1].buffer_type = MYSQL_TYPE_LONG;
2739  inbind[1].buffer = reinterpret_cast<char*>(ps);
2740  inbind[1].is_unsigned = MLM_TRUE;
2741 
2742  // Get the leases
2743  Lease6Collection result;
2744 
2745  // Get a context
2746  MySqlLeaseContextAlloc get_context(*this);
2747  MySqlLeaseContextPtr ctx = get_context.ctx_;
2748 
2749  getLeaseCollection(ctx, GET_LEASE6_PAGE, inbind, result);
2750 
2751  return (result);
2752 }
2753 
2754 void
2756  const size_t max_leases) const {
2758  .arg(max_leases);
2759  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
2760 }
2761 
2762 void
2764  const size_t max_leases) const {
2766  .arg(max_leases);
2767  getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
2768 }
2769 
2770 template<typename LeaseCollection>
2771 void
2772 MySqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
2773  const size_t max_leases,
2774  StatementIndex statement_index) const {
2775  // Set up the WHERE clause value
2776  MYSQL_BIND inbind[3];
2777  memset(inbind, 0, sizeof(inbind));
2778 
2779  // Exclude reclaimed leases.
2780  uint32_t state = static_cast<uint32_t>(Lease::STATE_EXPIRED_RECLAIMED);
2781  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2782  inbind[0].buffer = reinterpret_cast<char*>(&state);
2783  inbind[0].is_unsigned = MLM_TRUE;
2784 
2785  // Expiration timestamp.
2786  MYSQL_TIME expire_time;
2787  MySqlConnection::convertToDatabaseTime(time(0), expire_time);
2788  inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
2789  inbind[1].buffer = reinterpret_cast<char*>(&expire_time);
2790  inbind[1].buffer_length = sizeof(expire_time);
2791 
2792  // If the number of leases is 0, we will return all leases. This is
2793  // achieved by setting the limit to a very high value.
2794  uint32_t limit = max_leases > 0 ? static_cast<uint32_t>(max_leases) :
2795  std::numeric_limits<uint32_t>::max();
2796  inbind[2].buffer_type = MYSQL_TYPE_LONG;
2797  inbind[2].buffer = reinterpret_cast<char*>(&limit);
2798  inbind[2].is_unsigned = MLM_TRUE;
2799 
2800  // Get a context
2801  MySqlLeaseContextAlloc get_context(*this);
2802  MySqlLeaseContextPtr ctx = get_context.ctx_;
2803 
2804  // Get the data
2805  getLeaseCollection(ctx, statement_index, inbind, expired_leases);
2806 }
2807 
2808 // Update lease methods. These comprise common code that handles the actual
2809 // update, and type-specific methods that set up the parameters for the prepared
2810 // statement depending on the type of lease.
2811 
2812 template <typename LeasePtr>
2813 void
2814 MySqlLeaseMgr::updateLeaseCommon(MySqlLeaseContextPtr& ctx,
2815  StatementIndex stindex,
2816  MYSQL_BIND* bind,
2817  const LeasePtr& lease) {
2818 
2819  // Bind the parameters to the statement
2820  int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind);
2821  checkError(ctx, status, stindex, "unable to bind parameters");
2822 
2823  // Execute
2824  status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]);
2825  checkError(ctx, status, stindex, "unable to execute");
2826 
2827  // See how many rows were affected. The statement should only update a
2828  // single row.
2829  int affected_rows = mysql_stmt_affected_rows(ctx->conn_.statements_[stindex]);
2830 
2831  // Check success case first as it is the most likely outcome.
2832  if (affected_rows == 1) {
2833  return;
2834  }
2835 
2836  // If no rows affected, lease doesn't exist.
2837  if (affected_rows == 0) {
2838  isc_throw(NoSuchLease, "unable to update lease for address " <<
2839  lease->addr_.toText() << " as it does not exist");
2840  }
2841 
2842  // Should not happen - primary key constraint should only have selected
2843  // one row.
2844  isc_throw(DbOperationError, "apparently updated more than one lease "
2845  "that had the address " << lease->addr_.toText());
2846 }
2847 
2848 void
2850  const StatementIndex stindex = UPDATE_LEASE4;
2851 
2853  .arg(lease->addr_.toText());
2854 
2855  // Get a context
2856  MySqlLeaseContextAlloc get_context(*this);
2857  MySqlLeaseContextPtr ctx = get_context.ctx_;
2858 
2859  // Create the MYSQL_BIND array for the data being updated
2860  std::vector<MYSQL_BIND> bind = ctx->exchange4_->createBindForSend(lease);
2861 
2862  // Set up the WHERE clause and append it to the MYSQL_BIND array
2863  MYSQL_BIND inbind[2];
2864  memset(inbind, 0, sizeof(inbind));
2865 
2866  uint32_t addr4 = lease->addr_.toUint32();
2867  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2868  inbind[0].buffer = reinterpret_cast<char*>(&addr4);
2869  inbind[0].is_unsigned = MLM_TRUE;
2870 
2871  bind.push_back(inbind[0]);
2872 
2873  // See the expire code of createBindForSend for the
2874  // infinite valid lifetime special case.
2875  MYSQL_TIME expire;
2876  uint32_t valid_lft = lease->current_valid_lft_;
2877  if (valid_lft == Lease::INFINITY_LFT) {
2878  valid_lft = 0;
2879  }
2880  MySqlConnection::convertToDatabaseTime(lease->current_cltt_, valid_lft,
2881  expire);
2882  inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
2883  inbind[1].buffer = reinterpret_cast<char*>(&expire);
2884  inbind[1].buffer_length = sizeof(expire);
2885 
2886  bind.push_back(inbind[1]);
2887 
2888  // Drop to common update code
2889  updateLeaseCommon(ctx, stindex, &bind[0], lease);
2890 
2891  // Update lease current expiration time.
2892  lease->updateCurrentExpirationTime();
2893 }
2894 
2895 void
2897  const StatementIndex stindex = UPDATE_LEASE6;
2898 
2900  .arg(lease->addr_.toText())
2901  .arg(lease->type_);
2902 
2903  // Get a context
2904  MySqlLeaseContextAlloc get_context(*this);
2905  MySqlLeaseContextPtr ctx = get_context.ctx_;
2906 
2907  // Create the MYSQL_BIND array for the data being updated
2908  std::vector<MYSQL_BIND> bind = ctx->exchange6_->createBindForSend(lease);
2909 
2910  // Set up the WHERE clause and append it to the MYSQL_BIND array
2911  MYSQL_BIND inbind[2];
2912  memset(inbind, 0, sizeof(inbind));
2913 
2914  std::string addr6 = lease->addr_.toText();
2915  unsigned long addr6_length = addr6.size();
2916 
2917  // See the earlier description of the use of "const_cast" when accessing
2918  // the address for an explanation of the reason.
2919  inbind[0].buffer_type = MYSQL_TYPE_STRING;
2920  inbind[0].buffer = const_cast<char*>(addr6.c_str());
2921  inbind[0].buffer_length = addr6_length;
2922  inbind[0].length = &addr6_length;
2923 
2924  bind.push_back(inbind[0]);
2925 
2926  // See the expire code of createBindForSend for the
2927  // infinite valid lifetime special case.
2928  MYSQL_TIME expire;
2929  uint32_t valid_lft = lease->current_valid_lft_;
2930  if (valid_lft == Lease::INFINITY_LFT) {
2931  valid_lft = 0;
2932  }
2933  MySqlConnection::convertToDatabaseTime(lease->current_cltt_, valid_lft,
2934  expire);
2935  inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
2936  inbind[1].buffer = reinterpret_cast<char*>(&expire);
2937  inbind[1].buffer_length = sizeof(expire);
2938 
2939  bind.push_back(inbind[1]);
2940 
2941  // Drop to common update code
2942  updateLeaseCommon(ctx, stindex, &bind[0], lease);
2943 
2944  // Update lease current expiration time.
2945  lease->updateCurrentExpirationTime();
2946 }
2947 
2948 // Delete lease methods. Similar to other groups of methods, these comprise
2949 // a per-type method that sets up the relevant MYSQL_BIND array (in this
2950 // case, a single method for both V4 and V6 addresses) and a common method that
2951 // handles the common processing.
2952 
2953 uint64_t
2954 MySqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex,
2955  MYSQL_BIND* bind) {
2956 
2957  // Get a context
2958  MySqlLeaseContextAlloc get_context(*this);
2959  MySqlLeaseContextPtr ctx = get_context.ctx_;
2960 
2961  // Bind the input parameters to the statement
2962  int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind);
2963  checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
2964 
2965  // Execute
2966  status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]);
2967  checkError(ctx, status, stindex, "unable to execute");
2968 
2969  // See how many rows were affected. Note that the statement may delete
2970  // multiple rows.
2971  return (static_cast<uint64_t>(mysql_stmt_affected_rows(ctx->conn_.statements_[stindex])));
2972 }
2973 
2974 bool
2976  const IOAddress& addr = lease->addr_;
2978  .arg(addr.toText());
2979 
2980  // Set up the WHERE clause value
2981  MYSQL_BIND inbind[2];
2982  memset(inbind, 0, sizeof(inbind));
2983 
2984  uint32_t addr4 = addr.toUint32();
2985 
2986  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2987  inbind[0].buffer = reinterpret_cast<char*>(&addr4);
2988  inbind[0].is_unsigned = MLM_TRUE;
2989 
2990  // See the expire code of createBindForSend for the
2991  // infinite valid lifetime special case.
2992  MYSQL_TIME expire;
2993  uint32_t valid_lft = lease->current_valid_lft_;
2994  if (valid_lft == Lease::INFINITY_LFT) {
2995  valid_lft = 0;
2996  }
2997  MySqlConnection::convertToDatabaseTime(lease->current_cltt_, valid_lft,
2998  expire);
2999  inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
3000  inbind[1].buffer = reinterpret_cast<char*>(&expire);
3001  inbind[1].buffer_length = sizeof(expire);
3002 
3003  auto affected_rows = deleteLeaseCommon(DELETE_LEASE4, inbind);
3004 
3005  // Check success case first as it is the most likely outcome.
3006  if (affected_rows == 1) {
3007  return (true);
3008  }
3009 
3010  // If no rows affected, lease doesn't exist.
3011  if (affected_rows == 0) {
3012  return (false);
3013  }
3014 
3015  // Should not happen - primary key constraint should only have selected
3016  // one row.
3017  isc_throw(DbOperationError, "apparently deleted more than one lease "
3018  "that had the address " << lease->addr_.toText());
3019 }
3020 
3021 bool
3023  const IOAddress& addr = lease->addr_;
3026  .arg(addr.toText());
3027 
3028  // Set up the WHERE clause value
3029  MYSQL_BIND inbind[2];
3030  memset(inbind, 0, sizeof(inbind));
3031 
3032  std::string addr6 = addr.toText();
3033  unsigned long addr6_length = addr6.size();
3034 
3035  // See the earlier description of the use of "const_cast" when accessing
3036  // the address for an explanation of the reason.
3037  inbind[0].buffer_type = MYSQL_TYPE_STRING;
3038  inbind[0].buffer = const_cast<char*>(addr6.c_str());
3039  inbind[0].buffer_length = addr6_length;
3040  inbind[0].length = &addr6_length;
3041 
3042  // See the expire code of createBindForSend for the
3043  // infinite valid lifetime special case.
3044  MYSQL_TIME expire;
3045  uint32_t valid_lft = lease->current_valid_lft_;
3046  if (valid_lft == Lease::INFINITY_LFT) {
3047  valid_lft = 0;
3048  }
3049  MySqlConnection::convertToDatabaseTime(lease->current_cltt_, valid_lft,
3050  expire);
3051  inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
3052  inbind[1].buffer = reinterpret_cast<char*>(&expire);
3053  inbind[1].buffer_length = sizeof(expire);
3054 
3055  auto affected_rows = deleteLeaseCommon(DELETE_LEASE6, inbind);
3056 
3057  // Check success case first as it is the most likely outcome.
3058  if (affected_rows == 1) {
3059  return (true);
3060  }
3061 
3062  // If no rows affected, lease doesn't exist.
3063  if (affected_rows == 0) {
3064  return (false);
3065  }
3066 
3067  // Should not happen - primary key constraint should only have selected
3068  // one row.
3069  isc_throw(DbOperationError, "apparently deleted more than one lease "
3070  "that had the address " << lease->addr_.toText());
3071 }
3072 
3073 uint64_t
3076  .arg(secs);
3077  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
3078 }
3079 
3080 uint64_t
3083  .arg(secs);
3084  return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
3085 }
3086 
3087 uint64_t
3088 MySqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
3089  StatementIndex statement_index) {
3090  // Set up the WHERE clause value
3091  MYSQL_BIND inbind[2];
3092  memset(inbind, 0, sizeof(inbind));
3093 
3094  // State is reclaimed.
3095  uint32_t state = static_cast<uint32_t>(Lease::STATE_EXPIRED_RECLAIMED);
3096  inbind[0].buffer_type = MYSQL_TYPE_LONG;
3097  inbind[0].buffer = reinterpret_cast<char*>(&state);
3098  inbind[0].is_unsigned = MLM_TRUE;
3099 
3100  // Expiration timestamp.
3101  MYSQL_TIME expire_time;
3102  MySqlConnection::convertToDatabaseTime(time(0) - static_cast<time_t>(secs), expire_time);
3103  inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
3104  inbind[1].buffer = reinterpret_cast<char*>(&expire_time);
3105  inbind[1].buffer_length = sizeof(expire_time);
3106 
3107  // Get the number of deleted leases and log it.
3108  uint64_t deleted_leases = deleteLeaseCommon(statement_index, inbind);
3110  .arg(deleted_leases);
3111 
3112  return (deleted_leases);
3113 }
3114 
3115 string
3116 MySqlLeaseMgr::checkLimits(ConstElementPtr const& user_context, StatementIndex const stindex) const {
3117  // No user context means no limits means allocation allowed means empty string.
3118  if (!user_context) {
3119  return string();
3120  }
3121 
3122  // Get a context.
3123  MySqlLeaseContextAlloc get_context(*this);
3124  MySqlLeaseContextPtr ctx = get_context.ctx_;
3125 
3126  // Create bindings.
3127  MySqlBindingCollection in_bindings({
3128  MySqlBinding::createString(user_context->str())
3129  });
3130  MySqlBindingCollection out_bindings({
3131  MySqlBinding::createString(LIMITS_TEXT_MAX_LEN)
3132  });
3133 
3134  // Execute the select.
3135  std::string limit_text;
3136  ctx->conn_.selectQuery(stindex, in_bindings, out_bindings,
3137  [&limit_text] (MySqlBindingCollection const& result) {
3138  limit_text = result[0]->getString();
3139  });
3140 
3141  return limit_text;
3142 }
3143 
3144 string
3145 MySqlLeaseMgr::checkLimits4(ConstElementPtr const& user_context) const {
3146  return checkLimits(user_context, CHECK_LEASE4_LIMITS);
3147 }
3148 
3149 string
3150 MySqlLeaseMgr::checkLimits6(ConstElementPtr const& user_context) const {
3151  return checkLimits(user_context, CHECK_LEASE6_LIMITS);
3152 }
3153 
3154 bool
3155 MySqlLeaseMgr::isJsonSupported() const {
3156  // Get a context.
3157  MySqlLeaseContextAlloc get_context(*this);
3158  MySqlLeaseContextPtr ctx = get_context.ctx_;
3159 
3160  // Create bindings.
3161  MySqlBindingCollection in_bindings;
3162  MySqlBindingCollection out_bindings({
3164  });
3165 
3166  // Execute the select.
3167  bool json_supported(false);
3168  ctx->conn_.selectQuery(IS_JSON_SUPPORTED, in_bindings, out_bindings,
3169  [&json_supported] (MySqlBindingCollection const& result) {
3170  json_supported = result[0]->getBool();
3171  });
3172 
3173  return json_supported;
3174 }
3175 
3176 size_t
3177 MySqlLeaseMgr::getClassLeaseCount(const ClientClass& client_class,
3178  const Lease::Type& ltype /* = Lease::TYPE_V4*/) const {
3179  // Get a context.
3180  MySqlLeaseContextAlloc get_context(*this);
3181  MySqlLeaseContextPtr ctx = get_context.ctx_;
3182 
3183  // Create bindings.
3184  MySqlBindingCollection in_bindings({
3185  MySqlBinding::createString(client_class)
3186  });
3187  if (ltype != Lease::TYPE_V4) {
3188  in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(ltype));
3189  }
3190  MySqlBindingCollection out_bindings({
3191  MySqlBinding::createInteger<int64_t>()
3192  });
3193 
3194  // Execute the select.
3195  StatementIndex const stindex(ltype == Lease::TYPE_V4 ? GET_LEASE4_COUNT_BY_CLASS :
3197  size_t count(0);
3198  ctx->conn_.selectQuery(stindex, in_bindings, out_bindings,
3199  [&count] (MySqlBindingCollection const& result) {
3200  count = result[0]->getInteger<int64_t>();
3201  });
3202 
3203  return count;
3204 }
3205 
3206 void
3207 MySqlLeaseMgr::recountClassLeases4() {
3208  isc_throw(NotImplemented, "MySqlLeaseMgr::recountClassLeases4() not implemented");
3209 }
3210 
3211 void
3212 MySqlLeaseMgr::recountClassLeases6() {
3213  isc_throw(NotImplemented, "MySqlLeaseMgr::recountClassLeases6() not implemented");
3214 }
3215 
3216 void
3217 MySqlLeaseMgr::clearClassLeaseCounts() {
3218  isc_throw(NotImplemented, "MySqlLeaseMgr::clearClassLeaseCounts() not implemented");
3219 }
3220 
3221 void
3222 MySqlLeaseMgr::writeLeases4(const std::string&) {
3223  isc_throw(NotImplemented, "MySqlLeaseMgr::writeLeases4() not implemented");
3224 }
3225 
3226 void
3227 MySqlLeaseMgr::writeLeases6(const std::string&) {
3228  isc_throw(NotImplemented, "MySqlLeaseMgr::writeLeases6() not implemented");
3229 }
3230 
3233  // Get a context
3234  MySqlLeaseContextAlloc get_context(*this);
3235  MySqlLeaseContextPtr ctx = get_context.ctx_;
3236 
3237  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3239  false));
3240  query->start();
3241  return(query);
3242 }
3243 
3246  // Get a context
3247  MySqlLeaseContextAlloc get_context(*this);
3248  MySqlLeaseContextPtr ctx = get_context.ctx_;
3249 
3250  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3252  false,
3253  subnet_id));
3254  query->start();
3255  return(query);
3256 }
3257 
3260  const SubnetID& last_subnet_id) {
3261  // Get a context
3262  MySqlLeaseContextAlloc get_context(*this);
3263  MySqlLeaseContextPtr ctx = get_context.ctx_;
3264 
3265  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3267  false,
3268  first_subnet_id,
3269  last_subnet_id));
3270  query->start();
3271  return(query);
3272 }
3273 
3276  // Get a context
3277  MySqlLeaseContextAlloc get_context(*this);
3278  MySqlLeaseContextPtr ctx = get_context.ctx_;
3279 
3280  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3282  true));
3283  query->start();
3284  return(query);
3285 }
3286 
3289  // Get a context
3290  MySqlLeaseContextAlloc get_context(*this);
3291  MySqlLeaseContextPtr ctx = get_context.ctx_;
3292 
3293  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3295  true,
3296  subnet_id));
3297  query->start();
3298  return(query);
3299 }
3300 
3303  const SubnetID& last_subnet_id) {
3304  // Get a context
3305  MySqlLeaseContextAlloc get_context(*this);
3306  MySqlLeaseContextPtr ctx = get_context.ctx_;
3307 
3308  LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3310  true,
3311  first_subnet_id,
3312  last_subnet_id));
3313  query->start();
3314  return(query);
3315 }
3316 
3317 size_t
3318 MySqlLeaseMgr::wipeLeases4(const SubnetID& /*subnet_id*/) {
3319  isc_throw(NotImplemented, "wipeLeases4 is not implemented for MySQL backend");
3320 }
3321 
3322 size_t
3323 MySqlLeaseMgr::wipeLeases6(const SubnetID& /*subnet_id*/) {
3324  isc_throw(NotImplemented, "wipeLeases6 is not implemented for MySQL backend");
3325 }
3326 
3327 // Miscellaneous database methods.
3328 
3329 std::string
3331  // Get a context
3332  MySqlLeaseContextAlloc get_context(*this);
3333  MySqlLeaseContextPtr ctx = get_context.ctx_;
3334 
3335  std::string name = "";
3336  try {
3337  name = ctx->conn_.getParameter("name");
3338  } catch (...) {
3339  // Return an empty name
3340  }
3341  return (name);
3342 }
3343 
3344 std::string
3346  return (std::string("MySQL Database"));
3347 }
3348 
3349 std::pair<uint32_t, uint32_t>
3352 
3353  return (MySqlConnection::getVersion(parameters_));
3354 }
3355 
3356 void
3359 }
3360 
3361 void
3364 }
3365 
3366 void
3367 MySqlLeaseMgr::checkError(MySqlLeaseContextPtr& ctx,
3368  int status, StatementIndex index,
3369  const char* what) const {
3370  ctx->conn_.checkError(status, index, what);
3371 }
3372 
3373 void
3375  isc_throw(NotImplemented, "MySqlLeaseMgr::deleteExtendedInfo6 not implemented");
3376 }
3377 
3378 void
3379 MySqlLeaseMgr::addRelayId6(const IOAddress& /* lease_addr */,
3380  const vector<uint8_t>& /* relay_id */) {
3381  isc_throw(NotImplemented, "MySqlLeaseMgr::addRelayId6 not implemented");
3382 }
3383 
3384 void
3385 MySqlLeaseMgr::addRemoteId6(const IOAddress& /* lease_addr */,
3386  const vector<uint8_t>& /* remote_id */) {
3387  isc_throw(NotImplemented, "MySqlLeaseMgr::addRemoteId6 not implemented");
3388 }
3389 
3391 MySqlLeaseMgr::getLeases4ByRelayId(const OptionBuffer& /* relay_id */,
3392  const IOAddress& /* lower_bound_address */,
3393  const LeasePageSize& /* page_size */,
3394  const time_t& /* qry_start_time = 0 */,
3395  const time_t& /* qry_end_time = 0 */) {
3396  isc_throw(NotImplemented, "MySqlLeaseMgr::getLeases4ByRelayId not implemented");
3397 }
3398 
3400 MySqlLeaseMgr::getLeases4ByRemoteId(const OptionBuffer& /* remote_id */,
3401  const IOAddress& /* lower_bound_address */,
3402  const LeasePageSize& /* page_size */,
3403  const time_t& /* qry_start_time = 0 */,
3404  const time_t& /* qry_end_time = 0 */) {
3405  isc_throw(NotImplemented, "MySqlLeaseMgr::getLeases4ByRemoteId not implemented");
3406 }
3407 
3409 MySqlLeaseMgr::getLeases6ByRelayId(const DUID& /* relay_id */,
3410  const IOAddress& /* link_addr */,
3411  uint8_t /* link_len */,
3412  const IOAddress& /* lower_bound_address */,
3413  const LeasePageSize& /* page_size */) {
3414  isc_throw(NotImplemented, "MySqlLeaseMgr::getLeases6ByRelayId not implemented");
3415 }
3416 
3418 MySqlLeaseMgr::getLeases6ByRemoteId(const OptionBuffer& /* remote_id */,
3419  const IOAddress& /* link_addr */,
3420  uint8_t /* link_len */,
3421  const IOAddress& /* lower_bound_address */,
3422  const LeasePageSize& /* page_size*/) {
3423  isc_throw(NotImplemented, "MySqlLeaseMgr::getLeases6ByRemoteId not implemented");
3424 }
3425 
3427 MySqlLeaseMgr::getLeases6ByLink(const IOAddress& /* link_addr */,
3428  uint8_t /* link_len */,
3429  const IOAddress& /* lower_bound_address */,
3430  const LeasePageSize& /* page_size */) {
3431  isc_throw(NotImplemented, "MySqlLeaseMgr::getLeases6ByLink not implemented");
3432 }
3433 
3434 size_t
3435 MySqlLeaseMgr::buildExtendedInfoTables6(bool /* update */, bool /* current */) {
3437  "MySqlLeaseMgr::buildExtendedInfoTables6 not implemented");
3438 }
3439 
3440 } // namespace dhcp
3441 } // namespace isc
RAII class creating a critical section.
const isc::log::MessageID DHCPSRV_MYSQL_GET_EXPIRED4
const isc::log::MessageID DHCPSRV_MYSQL_ADD_ADDR4
void start()
Creates the IPv4 lease statistical data result set.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
std::function< bool(util::ReconnectCtlPtr db_reconnect_ctl)> DbCallback
Defines a callback prototype for propagating events upward.
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:20
const size_t ADDRESS6_TEXT_MAX_LEN
Maximum size of an IPv6 address represented as a text string.
Definition: host.h:32
bool my_bool
my_bool type in MySQL 8.x.
static bool dbReconnect(util::ReconnectCtlPtr db_reconnect_ctl)
Attempts to reconnect the server to the lease DB backend manager.
boost::shared_ptr< LeaseStatsQuery > LeaseStatsQueryPtr
Defines a pointer to a LeaseStatsQuery.
Definition: lease_mgr.h:210
const isc::log::MessageID DHCPSRV_MYSQL_GET_IAID_SUBID_DUID
Fetch and Release MySQL Results.
A generic exception that is thrown when a function is not implemented.
const size_t USER_CONTEXT_MAX_LEN
Maximum length of user context.
Definition: host.h:54
static const uint32_t STATE_EXPIRED_RECLAIMED
Expired and reclaimed lease.
Definition: lease.h:75
const std::vector< uint8_t > & getClientId() const
Returns reference to the client-id data.
Definition: duid.cc:117
virtual void setExtendedInfoTablesEnabled(const bool enabled)
Extended information / Bulk Lease Query shared interface.
Definition: lease_mgr.h:983
static std::string getDBVersion()
Local version of getDBVersion() class method.
const isc::log::MessageID DHCPSRV_MYSQL_DELETE_ADDR
static void convertToDatabaseTime(const time_t input_time, MYSQL_TIME &output_time)
Convert time_t value to database time.
const isc::log::MessageID DHCPSRV_MYSQL_GET_HOSTNAME6
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs) override
Deletes all expired-reclaimed DHCPv6 leases.
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
const isc::log::MessageID DHCPSRV_MYSQL_GET4
Data is truncated.
Definition: db_exceptions.h:23
static std::pair< uint32_t, uint32_t > getVersion(const ParameterMap &parameters)
Get the schema version.
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery4(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id) override
Creates and runs the IPv4 lease stats query for a single subnet.
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
static void setErrorIndicators(MYSQL_BIND *bind, my_bool *error, size_t count)
Set error indicators.
MySQL Lease Context Pool.
const isc::log::MessageID DHCPSRV_MYSQL_GET_PAGE6
static void destroy()
Destroy lease manager.
const isc::log::MessageID DHCPSRV_MYSQL_NEGATIVE_LEASES_STAT
MySqlLeaseStatsQuery(MySqlConnection &conn, const size_t statement_index, const bool fetch_type, const SubnetID &subnet_id)
Constructor to query for a single subnet&#39;s stats.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
std::string getErrorColumns()
Return columns in error.
Attempt to update lease that was not there.
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition: lease.h:514
const uint32_t MYSQL_SCHEMA_VERSION_MAJOR
const isc::log::MessageID DHCPSRV_MYSQL_DELETED_EXPIRED_RECLAIMED
virtual LeaseStatsQueryPtr startLeaseStatsQuery6() override
Creates and runs the IPv6 lease stats query.
const isc::log::MessageID DHCPSRV_MYSQL_GET_SUBID4
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
std::vector< uint8_t > hwaddr_
Definition: hwaddr.h:98
STL namespace.
Base class for fulfilling a statistical lease data query.
Definition: lease_mgr.h:131
const uint32_t MYSQL_SCHEMA_VERSION_MINOR
const isc::log::MessageID DHCPSRV_MYSQL_GET_HWADDR
const isc::log::MessageID DHCPSRV_MYSQL_UPDATE_ADDR4
const isc::log::MessageID DHCPSRV_MYSQL_GET_DUID
boost::shared_ptr< Lease > LeasePtr
Pointer to the lease object.
Definition: lease.h:22
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
static MySqlBindingPtr createBool()
Creates binding having a bool type for receiving data.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id) override
Creates and runs the IPv6 lease stats query for a single subnet.
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
static MySqlBindingPtr createString(const unsigned long length)
Creates binding of text type for receiving data.
Exception thrown on failure to open database.
const isc::log::MessageID DHCPSRV_MYSQL_GET_PAGE4
const isc::log::MessageID DHCPSRV_MYSQL_GET_HOSTNAME4
static isc::asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service.
Definition: lease_mgr.h:793
const size_t HOSTNAME_MAX_LEN
Maximum length of the hostname stored in DNS.
Definition: host.h:42
const isc::log::MessageID DHCPSRV_MYSQL_DELETE_EXPIRED_RECLAIMED4
std::vector< MYSQL_BIND > createBindForReceive()
Create BIND array to receive data.
int MysqlExecuteStatement(MYSQL_STMT *stmt)
Execute a prepared statement.
Multiple lease records found where one expected.
Definition: db_exceptions.h:16
#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...
MySQL Lease Context.
Definition: edns.h:19
const my_bool MLM_FALSE
MySQL false value.
std::vector< MYSQL_BIND > createBindForSend(const Lease4Ptr &lease)
Create MYSQL_BIND objects for Lease4 Pointer.
const size_t page_size_
Holds page size.
Definition: lease_mgr.h:56
StatementIndex
Statement Tags.
boost::shared_ptr< MySqlLeaseContext > MySqlLeaseContextPtr
Type of pointers to contexts.
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:294
bool getNextRow(LeaseStatsRow &row)
Fetches the next row in the result set.
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const override
Returns an IPv4 lease for specified IPv4 address.
SubnetID subnet_id_
The subnet ID to which this data applies.
Definition: lease_mgr.h:117
virtual void setExtendedInfoTablesEnabled(const bool enabled) override
Extended information / Bulk Lease Query shared interface.
const isc::log::MessageID DHCPSRV_MYSQL_GET_ADDR6
A generic exception that is thrown when an unexpected error condition occurs.
IPv4 lease.
Definition: lease.h:50
virtual ~MySqlLeaseMgr()
Destructor (closes database)
virtual void updateLease4(const Lease4Ptr &lease4) override
Updates IPv4 lease.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
virtual void addRemoteId6(const isc::asiolink::IOAddress &lease_addr, const std::vector< uint8_t > &remote_id) override
Add lease6 extended info into by-remote-id table.
std::vector< MYSQL_BIND > createBindForSend(const Lease6Ptr &lease)
Create MYSQL_BIND objects for Lease6 Pointer.
const isc::log::MessageID DHCPSRV_MYSQL_GET_ADDR4
virtual size_t wipeLeases4(const SubnetID &subnet_id) override
Removes specified IPv4 leases.
static bool invokeDbRecoveredCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection&#39;s restored connectivity callback.
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:677
virtual Lease4Collection getLeases4() const override
Returns all IPv4 leases.
virtual std::pair< uint32_t, uint32_t > getVersion() const override
Returns backend version.
MySql derivation of the statistical lease data query.
const isc::log::MessageID DHCPSRV_MYSQL_ROLLBACK
MySQL Lease Manager.
const isc::log::MessageID DHCPSRV_MYSQL_ADD_ADDR6
const isc::log::MessageID DHCPSRV_MYSQL_GET_VERSION
const isc::log::MessageID DHCPSRV_MYSQL_GET_SUBID_CLIENTID
const std::vector< uint8_t > & getDuid() const
Returns a const reference to the actual DUID value.
Definition: duid.cc:46
const int MLM_MYSQL_FETCH_SUCCESS
check for bool size
virtual void getExpiredLeases6(Lease6Collection &expired_leases, const size_t max_leases) const override
Returns a collection of expired DHCPv6 leases.
Ethernet 10Mbps.
Definition: dhcp4.h:56
Lease6Ptr getLeaseData()
Copy Received Data into Lease6 Object.
MySqlLeaseStatsQuery(MySqlConnection &conn, const size_t statement_index, const bool fetch_type)
Constructor to query for all subnets&#39; stats.
virtual void deleteExtendedInfo6(const isc::asiolink::IOAddress &addr) override
Delete lease6 extended info from tables.
const isc::log::MessageID DHCPSRV_MYSQL_NO_TLS
Invalid address family used as input to Lease Manager.
Definition: db_exceptions.h:59
const isc::log::MessageID DHCPSRV_MYSQL_COMMIT
const isc::log::MessageID DHCPSRV_MYSQL_DELETE_EXPIRED_RECLAIMED6
virtual size_t wipeLeases6(const SubnetID &subnet_id) override
Removed specified IPv6 leases.
Defines the logger used by the top-level component of kea-lfc.
const isc::log::MessageID DHCPSRV_MYSQL_LEASE_DB_RECONNECT_ATTEMPT_FAILED
virtual bool addLease(const Lease4Ptr &lease) override
Adds an IPv4 lease.
virtual std::string getName() const override
Returns backend name.
static bool invokeDbFailedCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection&#39;s restore failed connectivity callback.
Common MySQL and Lease Data Methods.
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery6(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id) override
Creates and runs the IPv6 lease stats query for a single subnet.
Lease4Ptr getLeaseData()
Copy Received Data into Lease4 Object.
Exchange MySQL and Lease6 Data.
Exchange MySQL and Lease4 Data.
static const uint32_t INFINITY_LFT
Infinity (means static, i.e. never expire)
Definition: lease.h:34
uint32_t lease_state_
The lease_state to which the count applies.
Definition: lease_mgr.h:121
Type
Type of lease or pool.
Definition: lease.h:46
Holds Client identifier or client IPv4 address.
Definition: duid.h:111
static void create(const std::string &dbaccess)
Create an instance of a lease manager.
const isc::log::MessageID DHCPSRV_MYSQL_LEASE_DB_RECONNECT_FAILED
const isc::log::MessageID DHCPSRV_MYSQL_GET_SUBID6
MySqlLeaseStatsQuery(MySqlConnection &conn, const size_t statement_index, const bool fetch_type, const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Constructor to query for the stats for a range of subnets.
const isc::log::MessageID DHCPSRV_MYSQL_GET_IAID_DUID
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
const isc::log::MessageID DHCPSRV_MYSQL_GET_CLIENTID
std::vector< MySqlBindingPtr > MySqlBindingCollection
Collection of bindings.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID &subnet_id) override
Creates and runs the IPv4 lease stats query for a single subnet.
std::vector< MYSQL_BIND > createBindForReceive()
Create BIND array to receive data.
int64_t state_count_
state_count The count of leases in the lease state
Definition: lease_mgr.h:123
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t secs) override
Deletes all expired-reclaimed DHCPv4 leases.
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
Contains a single row of lease statistical data.
Definition: lease_mgr.h:64
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:75
Wraps value holding size of the page with leases.
Definition: lease_mgr.h:46
const isc::log::MessageID DHCPSRV_MYSQL_GET_EXPIRED6
const isc::log::MessageID DHCPSRV_MYSQL_TLS_CIPHER
Lease::Type lease_type_
The lease_type to which the count applies.
Definition: lease_mgr.h:119
std::string ClientClass
Defines a single class name.
Definition: classify.h:42
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const override
Returns existing IPv6 lease for a given IPv6 address.
std::function< isc::asiolink::IOServicePtr()> IOServiceAccessor
Function which returns the IOService that can be used to recover the connection.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:449
static bool invokeDbLostCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection&#39;s lost connectivity callback.
virtual LeaseStatsQueryPtr startLeaseStatsQuery4() override
Creates and runs the IPv4 lease stats query.
virtual void getExpiredLeases4(Lease4Collection &expired_leases, const size_t max_leases) const override
Returns a collection of expired DHCPv4 leases.
const isc::log::MessageID DHCPSRV_MYSQL_LEASE_DB_RECONNECT_ATTEMPT_SCHEDULE
virtual ~MySqlLeaseStatsQuery()
Destructor.
const isc::log::MessageID DHCPSRV_MYSQL_UPDATE_ADDR6
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:519
virtual void updateLease6(const Lease6Ptr &lease6) override
Updates IPv6 lease.
virtual std::string getDescription() const override
Returns description of the backend.
virtual void commit() override
Commit Transactions.
MySqlLeaseContextPtr createContext() const
Create a new context.
MySqlLeaseMgr(const db::DatabaseConnection::ParameterMap &parameters)
Constructor.
static std::string getColumnsInError(my_bool *error, std::string *names, size_t count)
Return columns in error.
const isc::log::MessageID DHCPSRV_MYSQL_GET_SUBID_HWADDR
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:122
virtual void rollback() override
Rollback Transactions.
Exception thrown on failure to execute a database function.
const isc::log::MessageID DHCPSRV_MYSQL_GET6
const my_bool MLM_TRUE
MySQL true value.
boost::shared_ptr< IOServiceAccessor > IOServiceAccessorPtr
Pointer to an instance of IOServiceAccessor.
virtual Lease6Collection getLeases6() const override
Returns all IPv6 leases.
std::string toText(bool include_htype=true) const
Returns textual representation of a hardware address (e.g.
Definition: hwaddr.cc:51
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:25
Common MySQL Connector Pool.
virtual bool deleteLease(const Lease4Ptr &lease) override
Deletes an IPv4 lease.
virtual void addRelayId6(const isc::asiolink::IOAddress &lease_addr, const std::vector< uint8_t > &relay_id) override
Add lease6 extended info into by-relay-id table.
std::string getErrorColumns()
Return columns in error.