Kea  1.5.0
mysql_host_data_source.cc
Go to the documentation of this file.
1 // Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
10 #include <dhcp/libdhcp++.h>
11 #include <dhcp/option.h>
12 #include <dhcp/option_definition.h>
13 #include <dhcp/option_space.h>
14 #include <dhcpsrv/cfg_option.h>
15 #include <dhcpsrv/dhcpsrv_log.h>
17 #include <util/buffer.h>
18 #include <util/optional_value.h>
19 
20 #include <boost/algorithm/string/split.hpp>
21 #include <boost/algorithm/string/classification.hpp>
22 #include <boost/array.hpp>
23 #include <boost/pointer_cast.hpp>
24 #include <boost/static_assert.hpp>
25 
26 #include <mysql.h>
27 #include <mysqld_error.h>
28 
29 #include <stdint.h>
30 #include <string>
31 
32 using namespace isc;
33 using namespace isc::asiolink;
34 using namespace isc::db;
35 using namespace isc::dhcp;
36 using namespace isc::util;
37 using namespace isc::data;
38 using namespace std;
39 
40 namespace {
41 
46 const size_t ADDRESS6_TEXT_MAX_LEN = 39;
47 
50 const size_t CLIENT_CLASSES_MAX_LEN = 255;
51 
56 const size_t HOSTNAME_MAX_LEN = 255;
57 
59 const size_t OPTION_VALUE_MAX_LEN = 4096;
60 
62 const size_t OPTION_FORMATTED_VALUE_MAX_LEN = 8192;
63 
65 const size_t OPTION_SPACE_MAX_LEN = 128;
66 
68 const size_t USER_CONTEXT_MAX_LEN = 8192;
69 
71 const size_t SERVER_HOSTNAME_MAX_LEN = 64;
72 
74 const size_t BOOT_FILE_NAME_MAX_LEN = 128;
75 
77 const size_t KEY_LEN = 16;
78 
83 const uint8_t MAX_IDENTIFIER_TYPE = static_cast<uint8_t>(Host::LAST_IDENTIFIER_TYPE);
84 
113 class MySqlHostExchange {
114 private:
115 
117  static const size_t HOST_COLUMNS = 14;
118 
119 public:
120 
127  MySqlHostExchange(const size_t additional_columns_num = 0)
128  : columns_num_(HOST_COLUMNS + additional_columns_num),
129  bind_(columns_num_), columns_(columns_num_),
130  error_(columns_num_, MLM_FALSE), host_id_(0),
131  dhcp_identifier_length_(0), dhcp_identifier_type_(0),
132  dhcp4_subnet_id_(SUBNET_ID_UNUSED),
133  dhcp6_subnet_id_(SUBNET_ID_UNUSED), ipv4_address_(0),
134  hostname_length_(0), dhcp4_client_classes_length_(0),
135  dhcp6_client_classes_length_(0),
136  user_context_length_(0),
137  dhcp4_next_server_(0),
138  dhcp4_server_hostname_length_(0),
139  dhcp4_boot_file_name_length_(0),
140  dhcp4_subnet_id_null_(MLM_FALSE),
141  dhcp6_subnet_id_null_(MLM_FALSE),
142  ipv4_address_null_(MLM_FALSE), hostname_null_(MLM_FALSE),
143  dhcp4_client_classes_null_(MLM_FALSE),
144  dhcp6_client_classes_null_(MLM_FALSE),
145  user_context_null_(MLM_FALSE),
146  dhcp4_next_server_null_(MLM_FALSE),
147  dhcp4_server_hostname_null_(MLM_FALSE),
148  dhcp4_boot_file_name_null_(MLM_FALSE),
149  auth_key_null_(MLM_FALSE) {
150 
151  // Fill arrays with 0 so as they don't include any garbage.
152  memset(dhcp_identifier_buffer_, 0, sizeof(dhcp_identifier_buffer_));
153  memset(hostname_, 0, sizeof(hostname_));
154  memset(dhcp4_client_classes_, 0, sizeof(dhcp4_client_classes_));
155  memset(dhcp6_client_classes_, 0, sizeof(dhcp6_client_classes_));
156  memset(user_context_, 0, sizeof(user_context_));
157  memset(dhcp4_server_hostname_, 0, sizeof(dhcp4_server_hostname_));
158  memset(dhcp4_boot_file_name_, 0, sizeof(dhcp4_boot_file_name_));
159 
160  // Set the column names for use by this class. This only comprises
161  // names used by the MySqlHostExchange class. Derived classes will
162  // need to set names for the columns they use.
163  columns_[0] = "host_id";
164  columns_[1] = "dhcp_identifier";
165  columns_[2] = "dhcp_identifier_type";
166  columns_[3] = "dhcp4_subnet_id";
167  columns_[4] = "dhcp6_subnet_id";
168  columns_[5] = "ipv4_address";
169  columns_[6] = "hostname";
170  columns_[7] = "dhcp4_client_classes";
171  columns_[8] = "dhcp6_client_classes";
172  columns_[9] = "user_context";
173  columns_[10] = "dhcp4_next_server";
174  columns_[11] = "dhcp4_server_hostname";
175  columns_[12] = "dhcp4_boot_file_name";
176  columns_[13] = "auth_key";
177 
178  BOOST_STATIC_ASSERT(13 < HOST_COLUMNS);
179  };
180 
182  virtual ~MySqlHostExchange() {
183  }
184 
199  size_t findAvailColumn() const {
200  std::vector<std::string>::const_iterator empty_column =
201  std::find(columns_.begin(), columns_.end(), std::string());
202  return (std::distance(columns_.begin(), empty_column));
203  }
204 
208  uint64_t getHostId() const {
209  return (host_id_);
210  };
211 
222  static void setErrorIndicators(std::vector<MYSQL_BIND>& bind,
223  std::vector<my_bool>& error) {
224  for (size_t i = 0; i < error.size(); ++i) {
225  error[i] = MLM_FALSE;
226  bind[i].error = reinterpret_cast<char*>(&error[i]);
227  }
228  };
229 
243  static std::string getColumnsInError(std::vector<my_bool>& error,
244  const std::vector<std::string>& names) {
245  std::string result = "";
246 
247  // Accumulate list of column names
248  for (size_t i = 0; i < names.size(); ++i) {
249  if (error[i] == MLM_TRUE) {
250  if (!result.empty()) {
251  result += ", ";
252  }
253  result += names[i];
254  }
255  }
256 
257  if (result.empty()) {
258  result = "(None)";
259  }
260 
261  return (result);
262  };
263 
274  std::vector<MYSQL_BIND> createBindForSend(const HostPtr& host) {
275  // Store host object to ensure it remains valid.
276  host_ = host;
277 
278  // Initialize prior to constructing the array of MYSQL_BIND structures.
279  // It sets all fields, including is_null, to zero, so we need to set
280  // is_null only if it should be true. This gives up minor performance
281  // benefit while being safe approach.
282  memset(&bind_[0], 0, sizeof(MYSQL_BIND) * bind_.size());
283 
284  // Set up the structures for the various components of the host structure.
285 
286  try {
287  // host_id : INT UNSIGNED NOT NULL
288  // The host_id is auto_incremented by MySQL database,
289  // so we need to pass the NULL value
290  host_id_ = 0;
291  bind_[0].buffer_type = MYSQL_TYPE_LONG;
292  bind_[0].buffer = reinterpret_cast<char*>(&host_id_);
293  bind_[0].is_unsigned = MLM_TRUE;
294 
295  // dhcp_identifier : VARBINARY(128) NOT NULL
296  dhcp_identifier_length_ = host->getIdentifier().size();
297  memcpy(static_cast<void*>(dhcp_identifier_buffer_),
298  &(host->getIdentifier())[0],
299  host->getIdentifier().size());
300 
301  bind_[1].buffer_type = MYSQL_TYPE_BLOB;
302  bind_[1].buffer = dhcp_identifier_buffer_;
303  bind_[1].buffer_length = dhcp_identifier_length_;
304  bind_[1].length = &dhcp_identifier_length_;
305 
306  // dhcp_identifier_type : TINYINT NOT NULL
307  dhcp_identifier_type_ = static_cast<uint8_t>(host->getIdentifierType());
308  bind_[2].buffer_type = MYSQL_TYPE_TINY;
309  bind_[2].buffer = reinterpret_cast<char*>(&dhcp_identifier_type_);
310  bind_[2].is_unsigned = MLM_TRUE;
311 
312  // dhcp4_subnet_id : INT UNSIGNED NULL
313  // Can't take an address of intermediate object, so let's store it
314  // in dhcp4_subnet_id_
315  dhcp4_subnet_id_ = host->getIPv4SubnetID();
316  dhcp4_subnet_id_null_ = host->getIPv4SubnetID() == SUBNET_ID_UNUSED ? MLM_TRUE : MLM_FALSE;
317  bind_[3].buffer_type = MYSQL_TYPE_LONG;
318  bind_[3].buffer = reinterpret_cast<char*>(&dhcp4_subnet_id_);
319  bind_[3].is_unsigned = MLM_TRUE;
320  bind_[3].is_null = &dhcp4_subnet_id_null_;
321 
322  // dhcp6_subnet_id : INT UNSIGNED NULL
323  // Can't take an address of intermediate object, so let's store it
324  // in dhcp6_subnet_id_
325  dhcp6_subnet_id_ = host->getIPv6SubnetID();
326  dhcp6_subnet_id_null_ = host->getIPv6SubnetID() == SUBNET_ID_UNUSED ? MLM_TRUE : MLM_FALSE;
327  bind_[4].buffer_type = MYSQL_TYPE_LONG;
328  bind_[4].buffer = reinterpret_cast<char*>(&dhcp6_subnet_id_);
329  bind_[4].is_unsigned = MLM_TRUE;
330  bind_[4].is_null = &dhcp6_subnet_id_null_;
331 
332  // ipv4_address : INT UNSIGNED NULL
333  // The address in the Host structure is an IOAddress object. Convert
334  // this to an integer for storage.
335  ipv4_address_ = host->getIPv4Reservation().toUint32();
336  ipv4_address_null_ = ipv4_address_ == 0 ? MLM_TRUE : MLM_FALSE;
337  bind_[5].buffer_type = MYSQL_TYPE_LONG;
338  bind_[5].buffer = reinterpret_cast<char*>(&ipv4_address_);
339  bind_[5].is_unsigned = MLM_TRUE;
340  bind_[5].is_null = &ipv4_address_null_;
341 
342  // hostname : VARCHAR(255) NULL
343  strncpy(hostname_, host->getHostname().c_str(), HOSTNAME_MAX_LEN - 1);
344  hostname_length_ = host->getHostname().length();
345  bind_[6].buffer_type = MYSQL_TYPE_STRING;
346  bind_[6].buffer = reinterpret_cast<char*>(hostname_);
347  bind_[6].buffer_length = hostname_length_;
348 
349  // dhcp4_client_classes : VARCHAR(255) NULL
350  bind_[7].buffer_type = MYSQL_TYPE_STRING;
351  // Override default separator to not include space after comma.
352  string classes4_txt = host->getClientClasses4().toText(",");
353  strncpy(dhcp4_client_classes_, classes4_txt.c_str(), CLIENT_CLASSES_MAX_LEN - 1);
354  bind_[7].buffer = dhcp4_client_classes_;
355  bind_[7].buffer_length = classes4_txt.length();
356 
357  // dhcp6_client_classes : VARCHAR(255) NULL
358  bind_[8].buffer_type = MYSQL_TYPE_STRING;
359  // Override default separator to not include space after comma.
360  string classes6_txt = host->getClientClasses6().toText(",");
361  strncpy(dhcp6_client_classes_, classes6_txt.c_str(), CLIENT_CLASSES_MAX_LEN - 1);
362  bind_[8].buffer = dhcp6_client_classes_;
363  bind_[8].buffer_length = classes6_txt.length();
364 
365  // user_context : TEXT NULL
366  ConstElementPtr ctx = host->getContext();
367  if (ctx) {
368  bind_[9].buffer_type = MYSQL_TYPE_STRING;
369  string ctx_txt = ctx->str();
370  strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
371  bind_[9].buffer = user_context_;
372  bind_[9].buffer_length = ctx_txt.length();
373  } else {
374  bind_[9].buffer_type = MYSQL_TYPE_NULL;
375  }
376 
377  // ipv4_address : INT UNSIGNED NULL
378  // The address in the Host structure is an IOAddress object. Convert
379  // this to an integer for storage.
380  dhcp4_next_server_ = host->getNextServer().toUint32();
381  bind_[10].buffer_type = MYSQL_TYPE_LONG;
382  bind_[10].buffer = reinterpret_cast<char*>(&dhcp4_next_server_);
383  bind_[10].is_unsigned = MLM_TRUE;
384  // bind_[10].is_null = &MLM_FALSE; // commented out for performance
385  // reasons, see memset() above
386 
387  // dhcp4_server_hostname
388  bind_[11].buffer_type = MYSQL_TYPE_STRING;
389  std::string server_hostname = host->getServerHostname();
390  strncpy(dhcp4_server_hostname_, server_hostname.c_str(),
391  SERVER_HOSTNAME_MAX_LEN - 1);
392  bind_[11].buffer = dhcp4_server_hostname_;
393  bind_[11].buffer_length = server_hostname.length();
394 
395  // dhcp4_boot_file_name
396  bind_[12].buffer_type = MYSQL_TYPE_STRING;
397  std::string boot_file_name = host->getBootFileName();
398  strncpy(dhcp4_boot_file_name_, boot_file_name.c_str(),
399  BOOT_FILE_NAME_MAX_LEN - 1);
400  bind_[12].buffer = dhcp4_boot_file_name_;
401  bind_[12].buffer_length = boot_file_name.length();
402 
403  // auth key
404  bind_[13].buffer_type = MYSQL_TYPE_STRING;
405  std::string auth_key = host->getKey().ToText();
406  std::strncpy(auth_key_, auth_key.c_str(), KEY_LEN);
407  auth_key_null_ = auth_key.empty() ? MLM_TRUE : MLM_FALSE;
408  bind_[13].buffer = auth_key_;
409  bind_[13].buffer_length = auth_key.length();
410 
411  } catch (const std::exception& ex) {
413  "Could not create bind array from Host: "
414  << host->getHostname() << ", reason: " << ex.what());
415  }
416 
417  // Add the data to the vector. Note the end element is one after the
418  // end of the array.
419  return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[columns_num_]));
420  };
421 
429  virtual std::vector<MYSQL_BIND> createBindForReceive() {
430  // Initialize MYSQL_BIND array.
431  // It sets all fields, including is_null, to zero, so we need to set
432  // is_null only if it should be true. This gives up minor performance
433  // benefit while being safe approach. For improved readability, the
434  // code that explicitly sets is_null is there, but is commented out.
435  // This also takes care of setting bind_[X].is_null to MLM_FALSE.
436  memset(&bind_[0], 0, sizeof(MYSQL_BIND) * bind_.size());
437 
438  // host_id : INT UNSIGNED NOT NULL
439  bind_[0].buffer_type = MYSQL_TYPE_LONG;
440  bind_[0].buffer = reinterpret_cast<char*>(&host_id_);
441  bind_[0].is_unsigned = MLM_TRUE;
442 
443  // dhcp_identifier : VARBINARY(128) NOT NULL
444  dhcp_identifier_length_ = sizeof(dhcp_identifier_buffer_);
445  bind_[1].buffer_type = MYSQL_TYPE_BLOB;
446  bind_[1].buffer = reinterpret_cast<char*>(dhcp_identifier_buffer_);
447  bind_[1].buffer_length = dhcp_identifier_length_;
448  bind_[1].length = &dhcp_identifier_length_;
449 
450  // dhcp_identifier_type : TINYINT NOT NULL
451  bind_[2].buffer_type = MYSQL_TYPE_TINY;
452  bind_[2].buffer = reinterpret_cast<char*>(&dhcp_identifier_type_);
453  bind_[2].is_unsigned = MLM_TRUE;
454 
455  // dhcp4_subnet_id : INT UNSIGNED NULL
456  dhcp4_subnet_id_null_ = MLM_FALSE;
457  bind_[3].buffer_type = MYSQL_TYPE_LONG;
458  bind_[3].buffer = reinterpret_cast<char*>(&dhcp4_subnet_id_);
459  bind_[3].is_unsigned = MLM_TRUE;
460  bind_[3].is_null = &dhcp4_subnet_id_null_;
461 
462  // dhcp6_subnet_id : INT UNSIGNED NULL
463  dhcp6_subnet_id_null_ = MLM_FALSE;
464  bind_[4].buffer_type = MYSQL_TYPE_LONG;
465  bind_[4].buffer = reinterpret_cast<char*>(&dhcp6_subnet_id_);
466  bind_[4].is_unsigned = MLM_TRUE;
467  bind_[4].is_null = &dhcp6_subnet_id_null_;
468 
469  // ipv4_address : INT UNSIGNED NULL
470  ipv4_address_null_ = MLM_FALSE;
471  bind_[5].buffer_type = MYSQL_TYPE_LONG;
472  bind_[5].buffer = reinterpret_cast<char*>(&ipv4_address_);
473  bind_[5].is_unsigned = MLM_TRUE;
474  bind_[5].is_null = &ipv4_address_null_;
475 
476  // hostname : VARCHAR(255) NULL
477  hostname_null_ = MLM_FALSE;
478  hostname_length_ = sizeof(hostname_);
479  bind_[6].buffer_type = MYSQL_TYPE_STRING;
480  bind_[6].buffer = reinterpret_cast<char*>(hostname_);
481  bind_[6].buffer_length = hostname_length_;
482  bind_[6].length = &hostname_length_;
483  bind_[6].is_null = &hostname_null_;
484 
485  // dhcp4_client_classes : VARCHAR(255) NULL
486  dhcp4_client_classes_null_ = MLM_FALSE;
487  dhcp4_client_classes_length_ = sizeof(dhcp4_client_classes_);
488  bind_[7].buffer_type = MYSQL_TYPE_STRING;
489  bind_[7].buffer = reinterpret_cast<char*>(dhcp4_client_classes_);
490  bind_[7].buffer_length = dhcp4_client_classes_length_;
491  bind_[7].length = &dhcp4_client_classes_length_;
492  bind_[7].is_null = &dhcp4_client_classes_null_;
493 
494  // dhcp6_client_classes : VARCHAR(255) NULL
495  dhcp6_client_classes_null_ = MLM_FALSE;
496  dhcp6_client_classes_length_ = sizeof(dhcp6_client_classes_);
497  bind_[8].buffer_type = MYSQL_TYPE_STRING;
498  bind_[8].buffer = reinterpret_cast<char*>(dhcp6_client_classes_);
499  bind_[8].buffer_length = dhcp6_client_classes_length_;
500  bind_[8].length = &dhcp6_client_classes_length_;
501  bind_[8].is_null = &dhcp6_client_classes_null_;
502 
503  // user_context : TEXT NULL
504  user_context_null_ = MLM_FALSE;
505  user_context_length_ = sizeof(user_context_);
506  bind_[9].buffer_type = MYSQL_TYPE_STRING;
507  bind_[9].buffer = reinterpret_cast<char*>(user_context_);
508  bind_[9].buffer_length = user_context_length_;
509  bind_[9].length = &user_context_length_;
510  bind_[9].is_null = &user_context_null_;
511 
512  // dhcp4_next_server
513  dhcp4_next_server_null_ = MLM_FALSE;
514  bind_[10].buffer_type = MYSQL_TYPE_LONG;
515  bind_[10].buffer = reinterpret_cast<char*>(&dhcp4_next_server_);
516  bind_[10].is_unsigned = MLM_TRUE;
517  bind_[10].is_null = &dhcp4_next_server_null_;
518 
519  // dhcp4_server_hostname
520  dhcp4_server_hostname_null_ = MLM_FALSE;
521  dhcp4_server_hostname_length_ = sizeof(dhcp4_server_hostname_);
522  bind_[11].buffer_type = MYSQL_TYPE_STRING;
523  bind_[11].buffer = reinterpret_cast<char*>(dhcp4_server_hostname_);
524  bind_[11].buffer_length = dhcp4_server_hostname_length_;
525  bind_[11].length = &dhcp4_server_hostname_length_;
526  bind_[11].is_null = &dhcp4_server_hostname_null_;
527 
528  // dhcp4_boot_file_name
529  dhcp4_boot_file_name_null_ = MLM_FALSE;
530  dhcp4_boot_file_name_length_ = sizeof(dhcp4_boot_file_name_);
531  bind_[12].buffer_type = MYSQL_TYPE_STRING;
532  bind_[12].buffer = reinterpret_cast<char*>(dhcp4_boot_file_name_);
533  bind_[12].buffer_length = dhcp4_boot_file_name_length_;
534  bind_[12].length = &dhcp4_boot_file_name_length_;
535  bind_[12].is_null = &dhcp4_boot_file_name_null_;
536 
537  // auth_key_
538  auth_key_null_ = MLM_FALSE;
539  auth_key_length_ = sizeof(auth_key_);
540  bind_[13].buffer_type = MYSQL_TYPE_STRING;
541  bind_[13].buffer = reinterpret_cast<char*>(auth_key_);
542  bind_[13].buffer_length = auth_key_length_;
543  bind_[13].length = &auth_key_length_;
544  bind_[13].is_null = &auth_key_null_;
545 
546  // Add the error flags
547  setErrorIndicators(bind_, error_);
548 
549  // Add the data to the vector. Note the end element is one after the
550  // end of the array.
551  return (bind_);
552  };
553 
562  HostPtr retrieveHost() {
563  // Check if the identifier stored in the database is correct.
564  if (dhcp_identifier_type_ > MAX_IDENTIFIER_TYPE) {
565  isc_throw(BadValue, "invalid dhcp identifier type returned: "
566  << static_cast<int>(dhcp_identifier_type_));
567  }
568  // Set the dhcp identifier type in a variable of the appropriate
569  // data type.
570  Host::IdentifierType type =
571  static_cast<Host::IdentifierType>(dhcp_identifier_type_);
572 
573  // Set DHCPv4 subnet ID to the value returned. If NULL returned,
574  // set to 0.
575  SubnetID ipv4_subnet_id(SUBNET_ID_UNUSED);
576  if (dhcp4_subnet_id_null_ == MLM_FALSE) {
577  ipv4_subnet_id = static_cast<SubnetID>(dhcp4_subnet_id_);
578  }
579 
580  // Set DHCPv6 subnet ID to the value returned. If NULL returned,
581  // set to 0.
582  SubnetID ipv6_subnet_id(SUBNET_ID_UNUSED);
583  if (dhcp6_subnet_id_null_ == MLM_FALSE) {
584  ipv6_subnet_id = static_cast<SubnetID>(dhcp6_subnet_id_);
585  }
586 
587  // Set IPv4 address reservation if it was given, if not, set IPv4 zero
588  // address
589  asiolink::IOAddress ipv4_reservation = asiolink::IOAddress::IPV4_ZERO_ADDRESS();
590  if (ipv4_address_null_ == MLM_FALSE) {
591  ipv4_reservation = asiolink::IOAddress(ipv4_address_);
592  }
593 
594  // Set hostname if non NULL value returned. Otherwise, leave an
595  // empty string.
596  std::string hostname;
597  if (hostname_null_ == MLM_FALSE) {
598  hostname = std::string(hostname_, hostname_length_);
599  }
600 
601  // Set DHCPv4 client classes if non NULL value returned.
602  std::string dhcp4_client_classes;
603  if (dhcp4_client_classes_null_ == MLM_FALSE) {
604  dhcp4_client_classes = std::string(dhcp4_client_classes_,
605  dhcp4_client_classes_length_);
606  }
607 
608  // Set DHCPv6 client classes if non NULL value returned.
609  std::string dhcp6_client_classes;
610  if (dhcp6_client_classes_null_ == MLM_FALSE) {
611  dhcp6_client_classes = std::string(dhcp6_client_classes_,
612  dhcp6_client_classes_length_);
613  }
614 
615  // Convert user_context to string as well.
616  std::string user_context;
617  if (user_context_null_ == MLM_FALSE) {
618  user_context_[user_context_length_] = '\0';
619  user_context.assign(user_context_);
620  }
621 
622  // Set next server value (siaddr) if non NULL value returned.
623  asiolink::IOAddress next_server = asiolink::IOAddress::IPV4_ZERO_ADDRESS();
624  if (dhcp4_next_server_null_ == MLM_FALSE) {
625  next_server = asiolink::IOAddress(dhcp4_next_server_);
626  }
627 
628  // Set server hostname (sname) if non NULL value returned.
629  std::string dhcp4_server_hostname;
630  if (dhcp4_server_hostname_null_ == MLM_FALSE) {
631  dhcp4_server_hostname = std::string(dhcp4_server_hostname_,
632  dhcp4_server_hostname_length_);
633  }
634 
635  // Set boot file name (file) if non NULL value returned.
636  std::string dhcp4_boot_file_name;
637  if (dhcp4_boot_file_name_null_ == MLM_FALSE) {
638  dhcp4_boot_file_name = std::string(dhcp4_boot_file_name_,
639  dhcp4_boot_file_name_length_);
640  }
641 
642  // Set the auth key if a non empty array is retrieved
643  std::string auth_key;
644  if (auth_key_null_ == MLM_FALSE) {
645  auth_key = std::string(auth_key_, auth_key_length_);
646  }
647 
648  // Create and return Host object from the data gathered.
649  HostPtr h(new Host(dhcp_identifier_buffer_, dhcp_identifier_length_,
650  type, ipv4_subnet_id, ipv6_subnet_id, ipv4_reservation,
651  hostname, dhcp4_client_classes, dhcp6_client_classes,
652  next_server, dhcp4_server_hostname,
653  dhcp4_boot_file_name, AuthKey(auth_key)));
654  h->setHostId(host_id_);
655 
656  // Set the user context if there is one.
657  if (!user_context.empty()) {
658  try {
659  ConstElementPtr ctx = Element::fromJSON(user_context);
660  if (!ctx || (ctx->getType() != Element::map)) {
661  isc_throw(BadValue, "user context '" << user_context
662  << "' is not a JSON map");
663  }
664  h->setContext(ctx);
665  } catch (const isc::data::JSONError& ex) {
666  isc_throw(BadValue, "user context '" << user_context
667  << "' is invalid JSON: " << ex.what());
668  }
669  }
670 
671  return (h);
672  };
673 
687  virtual void processFetchedData(ConstHostCollection& hosts) {
688  HostPtr host;
689  // Add new host only if there are no hosts yet or the host id of the
690  // most recently added host is different than the host id of the
691  // currently processed host.
692  if (hosts.empty() || (hosts.back()->getHostId() != getHostId())) {
693  // Create Host object from the fetched data and append it to the
694  // collection.
695  host = retrieveHost();
696  hosts.push_back(host);
697  }
698  }
699 
710  std::string getErrorColumns() {
711  return (getColumnsInError(error_, columns_));
712  };
713 
714 protected:
715 
717  size_t columns_num_;
718 
720  std::vector<MYSQL_BIND> bind_;
721 
723  std::vector<std::string> columns_;
724 
726  std::vector<my_bool> error_;
727 
730  HostPtr host_;
731 
732 private:
733 
735  uint64_t host_id_;
736 
739  uint8_t dhcp_identifier_buffer_[DUID::MAX_DUID_LEN];
740 
742  unsigned long dhcp_identifier_length_;
743 
746  uint8_t dhcp_identifier_type_;
747 
749  uint32_t dhcp4_subnet_id_;
750 
752  uint32_t dhcp6_subnet_id_;
753 
755  uint32_t ipv4_address_;
756 
758  char hostname_[HOSTNAME_MAX_LEN];
759 
761  unsigned long hostname_length_;
762 
764  char dhcp4_client_classes_[CLIENT_CLASSES_MAX_LEN];
765 
768  unsigned long dhcp4_client_classes_length_;
769 
771  char dhcp6_client_classes_[CLIENT_CLASSES_MAX_LEN];
772 
775  unsigned long dhcp6_client_classes_length_;
776 
778  char user_context_[USER_CONTEXT_MAX_LEN];
779 
781  unsigned long user_context_length_;
782 
784  uint32_t dhcp4_next_server_;
785 
787  char dhcp4_server_hostname_[SERVER_HOSTNAME_MAX_LEN];
788 
790  unsigned long dhcp4_server_hostname_length_;
791 
793  char dhcp4_boot_file_name_[BOOT_FILE_NAME_MAX_LEN];
794 
796  unsigned long dhcp4_boot_file_name_length_;
797 
799  char auth_key_[KEY_LEN];
800 
802  unsigned long auth_key_length_;
803 
806 
807  my_bool dhcp4_subnet_id_null_;
809 
811  my_bool dhcp6_subnet_id_null_;
812 
814  my_bool ipv4_address_null_;
815 
817  my_bool hostname_null_;
818 
821  my_bool dhcp4_client_classes_null_;
822 
825  my_bool dhcp6_client_classes_null_;
826 
828  my_bool user_context_null_;
829 
831  my_bool dhcp4_next_server_null_;
832 
834  my_bool dhcp4_server_hostname_null_;
835 
837  my_bool dhcp4_boot_file_name_null_;
838 
840  my_bool auth_key_null_;
841 
843 };
844 
854 class MySqlHostWithOptionsExchange : public MySqlHostExchange {
855 private:
856 
858  static const size_t OPTION_COLUMNS = 7;
859 
874  class OptionProcessor {
875  public:
876 
883  OptionProcessor(const Option::Universe& universe,
884  const size_t start_column)
885  : universe_(universe), start_column_(start_column), option_id_(0),
886  code_(0), value_length_(0), formatted_value_length_(0),
887  space_length_(0), persistent_(false), user_context_length_(0),
888  option_id_null_(MLM_FALSE), code_null_(MLM_FALSE),
889  value_null_(MLM_FALSE), formatted_value_null_(MLM_FALSE),
890  space_null_(MLM_FALSE), user_context_null_(MLM_FALSE),
891  option_id_index_(start_column), code_index_(start_column_ + 1),
892  value_index_(start_column_ + 2),
893  formatted_value_index_(start_column_ + 3),
894  space_index_(start_column_ + 4),
895  persistent_index_(start_column_ + 5),
896  user_context_index_(start_column_ + 6),
897  most_recent_option_id_(0) {
898 
899  memset(value_, 0, sizeof(value_));
900  memset(formatted_value_, 0, sizeof(formatted_value_));
901  memset(space_, 0, sizeof(space_));
902  memset(user_context_, 0, sizeof(user_context_));
903  }
904 
906  uint64_t getOptionId() const {
907  if (option_id_null_ == MLM_FALSE) {
908  return (option_id_);
909  }
910  return (0);
911  }
912 
925  void retrieveOption(const CfgOptionPtr& cfg) {
926  // option_id may be NULL if dhcp4_options or dhcp6_options table
927  // doesn't contain any options for the particular host. Also, the
928  // current option id must be greater than id if the most recent
929  // option because options are ordered by option id. Otherwise
930  // we assume that this is already processed option.
931  if ((option_id_null_ == MLM_TRUE) ||
932  (most_recent_option_id_ >= option_id_)) {
933  return;
934  }
935 
936  // Remember current option id as the most recent processed one. We
937  // will be comparing it with option ids in subsequent rows.
938  most_recent_option_id_ = option_id_;
939 
940  // Convert it to string object for easier comparison.
941  std::string space;
942  if (space_null_ == MLM_FALSE) {
943  // Typically, the string values returned by the database are not
944  // NULL terminated.
945  space_[space_length_] = '\0';
946  space.assign(space_);
947  }
948 
949  // If empty or null space provided, use a default top level space.
950  if (space.empty()) {
951  space = (universe_ == Option::V4 ? "dhcp4" : "dhcp6");
952  }
953 
954  // Convert formatted_value to string as well.
955  std::string formatted_value;
956  if (formatted_value_null_ == MLM_FALSE) {
957  formatted_value_[formatted_value_length_] = '\0';
958  formatted_value.assign(formatted_value_);
959  }
960 
961  // Convert user_context to string as well.
962  std::string user_context;
963  if (user_context_null_ == MLM_FALSE) {
964  user_context_[user_context_length_] = '\0';
965  user_context.assign(user_context_);
966  }
967 
968  // Options are held in a binary or textual format in the database.
969  // This is similar to having an option specified in a server
970  // configuration file. Such option is converted to appropriate C++
971  // class, using option definition. Thus, we need to find the
972  // option definition for this option code and option space.
973 
974  // Check if this is a standard option.
975  OptionDefinitionPtr def = LibDHCP::getOptionDef(space, code_);
976 
977  // Otherwise, we may check if this an option encapsulated within the
978  // vendor space.
979  if (!def && (space != DHCP4_OPTION_SPACE) &&
980  (space != DHCP6_OPTION_SPACE)) {
981  uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(space);
982  if (vendor_id > 0) {
983  def = LibDHCP::getVendorOptionDef(universe_, vendor_id, code_);
984  }
985  }
986 
987  // In all other cases, we use runtime option definitions, which
988  // should be also registered within the libdhcp++.
989  if (!def) {
990  def = LibDHCP::getRuntimeOptionDef(space, code_);
991  }
992 
993  OptionPtr option;
994 
995  if (!def) {
996  // If no definition found, we use generic option type.
997  OptionBuffer buf(value_, value_ + value_length_);
998  option.reset(new Option(universe_, code_, buf.begin(),
999  buf.end()));
1000  } else {
1001  // The option value may be specified in textual or binary format
1002  // in the database. If formatted_value is empty, the binary
1003  // format is used. Depending on the format we use a different
1004  // variant of the optionFactory function.
1005  if (formatted_value.empty()) {
1006  OptionBuffer buf(value_, value_ + value_length_);
1007  option = def->optionFactory(universe_, code_, buf.begin(),
1008  buf.end());
1009  } else {
1010  // Spit the value specified in comma separated values
1011  // format.
1012  std::vector<std::string> split_vec;
1013  boost::split(split_vec, formatted_value, boost::is_any_of(","));
1014  option = def->optionFactory(universe_, code_, split_vec);
1015  }
1016  }
1017 
1018  OptionDescriptor desc(option, persistent_, formatted_value);
1019 
1020  // Set the user context if there is one into the option descriptor.
1021  if (!user_context.empty()) {
1022  try {
1023  ConstElementPtr ctx = Element::fromJSON(user_context);
1024  if (!ctx || (ctx->getType() != Element::map)) {
1025  isc_throw(BadValue, "user context '" << user_context
1026  << "' is no a JSON map");
1027  }
1028  desc.setContext(ctx);
1029  } catch (const isc::data::JSONError& ex) {
1030  isc_throw(BadValue, "user context '" << user_context
1031  << "' is invalid JSON: " << ex.what());
1032  }
1033  }
1034 
1035  cfg->add(desc, space);
1036  }
1037 
1042  void setColumnNames(std::vector<std::string>& columns) {
1043  columns[option_id_index_] = "option_id";
1044  columns[code_index_] = "code";
1045  columns[value_index_] = "value";
1046  columns[formatted_value_index_] = "formatted_value";
1047  columns[space_index_] = "space";
1048  columns[persistent_index_] = "persistent";
1049  columns[user_context_index_] = "user_context";
1050  }
1051 
1057  void setBindFields(std::vector<MYSQL_BIND>& bind) {
1058  // This method is called just before making a new query, so we
1059  // reset the most_recent_option_id_ to start over with options
1060  // processing.
1061  most_recent_option_id_ = 0;
1062 
1063  // option_id : INT UNSIGNED NOT NULL AUTO_INCREMENT,
1064  bind[option_id_index_].buffer_type = MYSQL_TYPE_LONG;
1065  bind[option_id_index_].buffer = reinterpret_cast<char*>(&option_id_);
1066  bind[option_id_index_].is_unsigned = MLM_TRUE;
1067 
1068  // code : TINYINT OR SHORT UNSIGNED NOT NULL
1069  bind[code_index_].buffer_type = MYSQL_TYPE_SHORT;
1070  bind[code_index_].buffer = reinterpret_cast<char*>(&code_);
1071  bind[code_index_].is_unsigned = MLM_TRUE;
1072  bind[code_index_].is_null = &code_null_;
1073 
1074  // value : BLOB NULL
1075  value_length_ = sizeof(value_);
1076  bind[value_index_].buffer_type = MYSQL_TYPE_BLOB;
1077  bind[value_index_].buffer = reinterpret_cast<char*>(value_);
1078  bind[value_index_].buffer_length = value_length_;
1079  bind[value_index_].length = &value_length_;
1080  bind[value_index_].is_null = &value_null_;
1081 
1082  // formatted_value : TEXT NULL
1083  formatted_value_length_ = sizeof(formatted_value_);
1084  bind[formatted_value_index_].buffer_type = MYSQL_TYPE_STRING;
1085  bind[formatted_value_index_].buffer = reinterpret_cast<char*>(formatted_value_);
1086  bind[formatted_value_index_].buffer_length = formatted_value_length_;
1087  bind[formatted_value_index_].length = &formatted_value_length_;
1088  bind[formatted_value_index_].is_null = &formatted_value_null_;
1089 
1090  // space : VARCHAR(128) NULL
1091  space_length_ = sizeof(space_);
1092  bind[space_index_].buffer_type = MYSQL_TYPE_STRING;
1093  bind[space_index_].buffer = reinterpret_cast<char*>(space_);
1094  bind[space_index_].buffer_length = space_length_;
1095  bind[space_index_].length = &space_length_;
1096  bind[space_index_].is_null = &space_null_;
1097 
1098  // persistent : TINYINT(1) NOT NULL DEFAULT 0
1099  bind[persistent_index_].buffer_type = MYSQL_TYPE_TINY;
1100  bind[persistent_index_].buffer = reinterpret_cast<char*>(&persistent_);
1101  bind[persistent_index_].is_unsigned = MLM_TRUE;
1102 
1103  // user_context : TEXT NULL
1104  user_context_length_ = sizeof(user_context_);
1105  bind[user_context_index_].buffer_type = MYSQL_TYPE_STRING;
1106  bind[user_context_index_].buffer = reinterpret_cast<char*>(user_context_);
1107  bind[user_context_index_].buffer_length = user_context_length_;
1108  bind[user_context_index_].length = &user_context_length_;
1109  bind[user_context_index_].is_null = &user_context_null_;
1110  }
1111 
1112  private:
1113 
1115  Option::Universe universe_;
1116 
1118  size_t start_column_;
1119 
1121  uint32_t option_id_;
1122 
1124  uint16_t code_;
1125 
1127  uint8_t value_[OPTION_VALUE_MAX_LEN];
1128 
1130  unsigned long value_length_;
1131 
1133  char formatted_value_[OPTION_FORMATTED_VALUE_MAX_LEN];
1134 
1136  unsigned long formatted_value_length_;
1137 
1139  char space_[OPTION_SPACE_MAX_LEN];
1140 
1142  unsigned long space_length_;
1143 
1146  bool persistent_;
1147 
1149  char user_context_[USER_CONTEXT_MAX_LEN];
1150 
1152  unsigned long user_context_length_;
1153 
1156 
1157  my_bool option_id_null_;
1159 
1161  my_bool code_null_;
1162 
1164  my_bool value_null_;
1165 
1168  my_bool formatted_value_null_;
1169 
1171  my_bool space_null_;
1172 
1174  my_bool user_context_null_;
1176 
1178 
1179  size_t option_id_index_;
1181 
1183  size_t code_index_;
1184 
1186  size_t value_index_;
1187 
1189  size_t formatted_value_index_;
1190 
1192  size_t space_index_;
1193 
1195  size_t persistent_index_;
1197 
1199  size_t user_context_index_;
1200 
1202  uint32_t most_recent_option_id_;
1203  };
1204 
1206  typedef boost::shared_ptr<OptionProcessor> OptionProcessorPtr;
1207 
1208 public:
1209 
1216  enum FetchedOptions {
1217  DHCP4_ONLY,
1218  DHCP6_ONLY,
1219  DHCP4_AND_DHCP6
1220  };
1221 
1230  MySqlHostWithOptionsExchange(const FetchedOptions& fetched_options,
1231  const size_t additional_columns_num = 0)
1232  : MySqlHostExchange(getRequiredColumnsNum(fetched_options)
1233  + additional_columns_num),
1234  opt_proc4_(), opt_proc6_() {
1235 
1236  // Create option processor for DHCPv4 options, if required.
1237  if ((fetched_options == DHCP4_ONLY) ||
1238  (fetched_options == DHCP4_AND_DHCP6)) {
1239  opt_proc4_.reset(new OptionProcessor(Option::V4,
1240  findAvailColumn()));
1241  opt_proc4_->setColumnNames(columns_);
1242  }
1243 
1244  // Create option processor for DHCPv6 options, if required.
1245  if ((fetched_options == DHCP6_ONLY) ||
1246  (fetched_options == DHCP4_AND_DHCP6)) {
1247  opt_proc6_.reset(new OptionProcessor(Option::V6,
1248  findAvailColumn()));
1249  opt_proc6_->setColumnNames(columns_);
1250  }
1251  }
1252 
1261  virtual void processFetchedData(ConstHostCollection& hosts) {
1262  // Holds pointer to the previously parsed host.
1263  HostPtr most_recent_host;
1264  if (!hosts.empty()) {
1265  // Const cast is not very elegant way to deal with it, but
1266  // there is a good reason to use it here. This method is called
1267  // to build a collection of const hosts to be returned to the
1268  // caller. If we wanted to use non-const collection we'd need
1269  // to copy the whole collection before returning it, which has
1270  // performance implications. Alternatively, we could store the
1271  // most recently added host in a class member but this would
1272  // make the code less readable.
1273  most_recent_host = boost::const_pointer_cast<Host>(hosts.back());
1274  }
1275 
1276  // If no host has been parsed yet or we're at the row holding next
1277  // host, we create a new host object and put it at the end of the
1278  // list.
1279  if (!most_recent_host || (most_recent_host->getHostId() < getHostId())) {
1280  HostPtr host = retrieveHost();
1281  hosts.push_back(host);
1282  most_recent_host = host;
1283  }
1284 
1285  // Parse DHCPv4 options if required to do so.
1286  if (opt_proc4_) {
1287  CfgOptionPtr cfg = most_recent_host->getCfgOption4();
1288  opt_proc4_->retrieveOption(cfg);
1289  }
1290 
1291  // Parse DHCPv6 options if required to do so.
1292  if (opt_proc6_) {
1293  CfgOptionPtr cfg = most_recent_host->getCfgOption6();
1294  opt_proc6_->retrieveOption(cfg);
1295  }
1296  }
1297 
1301  virtual std::vector<MYSQL_BIND> createBindForReceive() {
1302  // The following call sets bind_ values between 0 and 8.
1303  static_cast<void>(MySqlHostExchange::createBindForReceive());
1304 
1305  // Bind variables for DHCPv4 options.
1306  if (opt_proc4_) {
1307  opt_proc4_->setBindFields(bind_);
1308  }
1309 
1310  // Bind variables for DHCPv6 options.
1311  if (opt_proc6_) {
1312  opt_proc6_->setBindFields(bind_);
1313  }
1314 
1315  // Add the error flags
1316  setErrorIndicators(bind_, error_);
1317 
1318  return (bind_);
1319  };
1320 
1321 private:
1322 
1334  static size_t getRequiredColumnsNum(const FetchedOptions& fetched_options) {
1335  return (fetched_options == DHCP4_AND_DHCP6 ? 2 * OPTION_COLUMNS :
1336  OPTION_COLUMNS);
1337  }
1338 
1342  OptionProcessorPtr opt_proc4_;
1343 
1347  OptionProcessorPtr opt_proc6_;
1348 };
1349 
1362 class MySqlHostIPv6Exchange : public MySqlHostWithOptionsExchange {
1363 private:
1364 
1366  static const size_t RESERVATION_COLUMNS = 5;
1367 
1368 public:
1369 
1374  MySqlHostIPv6Exchange(const FetchedOptions& fetched_options)
1375  : MySqlHostWithOptionsExchange(fetched_options, RESERVATION_COLUMNS),
1376  reservation_id_(0),
1377  reserv_type_(0), reserv_type_null_(MLM_FALSE),
1378  ipv6_address_buffer_len_(0), prefix_len_(0), iaid_(0),
1379  reservation_id_index_(findAvailColumn()),
1380  address_index_(reservation_id_index_ + 1),
1381  prefix_len_index_(reservation_id_index_ + 2),
1382  type_index_(reservation_id_index_ + 3),
1383  iaid_index_(reservation_id_index_ + 4),
1384  most_recent_reservation_id_(0) {
1385 
1386  memset(ipv6_address_buffer_, 0, sizeof(ipv6_address_buffer_));
1387 
1388  // Provide names of additional columns returned by the queries.
1389  columns_[reservation_id_index_] = "reservation_id";
1390  columns_[address_index_] = "address";
1391  columns_[prefix_len_index_] = "prefix_len";
1392  columns_[type_index_] = "type";
1393  columns_[iaid_index_] = "dhcp6_iaid";
1394  }
1395 
1399  uint32_t getReservationId() const {
1400  if (reserv_type_null_ == MLM_FALSE) {
1401  return (reservation_id_);
1402  }
1403  return (0);
1404  };
1405 
1412  IPv6Resrv retrieveReservation() {
1413  // Set the IPv6 Reservation type (0 = IA_NA, 2 = IA_PD)
1414  IPv6Resrv::Type type = IPv6Resrv::TYPE_NA;
1415 
1416  switch (reserv_type_) {
1417  case 0:
1418  type = IPv6Resrv::TYPE_NA;
1419  break;
1420 
1421  case 2:
1422  type = IPv6Resrv::TYPE_PD;
1423  break;
1424 
1425  default:
1427  "invalid IPv6 reservation type returned: "
1428  << static_cast<int>(reserv_type_)
1429  << ". Only 0 or 2 are allowed.");
1430  }
1431 
1432  ipv6_address_buffer_[ipv6_address_buffer_len_] = '\0';
1433  std::string address = ipv6_address_buffer_;
1434  IPv6Resrv r(type, IOAddress(address), prefix_len_);
1435  return (r);
1436  };
1437 
1457  virtual void processFetchedData(ConstHostCollection& hosts) {
1458 
1459  // Call parent class to fetch host information and options.
1460  MySqlHostWithOptionsExchange::processFetchedData(hosts);
1461 
1462  if (getReservationId() == 0) {
1463  return;
1464  }
1465 
1466  if (hosts.empty()) {
1467  isc_throw(Unexpected, "no host information while retrieving"
1468  " IPv6 reservation");
1469  }
1470  HostPtr host = boost::const_pointer_cast<Host>(hosts.back());
1471 
1472  // If we're dealing with a new reservation, let's add it to the
1473  // host.
1474  if (getReservationId() > most_recent_reservation_id_) {
1475  most_recent_reservation_id_ = getReservationId();
1476 
1477  if (most_recent_reservation_id_ > 0) {
1478  host->addReservation(retrieveReservation());
1479  }
1480  }
1481  }
1482 
1491  virtual std::vector<MYSQL_BIND> createBindForReceive() {
1492  // Reset most recent reservation id value because we're now making
1493  // a new SELECT query.
1494  most_recent_reservation_id_ = 0;
1495 
1496  // Bind values supported by parent classes.
1497  static_cast<void>(MySqlHostWithOptionsExchange::createBindForReceive());
1498 
1499  // reservation_id : INT UNSIGNED NOT NULL AUTO_INCREMENT
1500  bind_[reservation_id_index_].buffer_type = MYSQL_TYPE_LONG;
1501  bind_[reservation_id_index_].buffer = reinterpret_cast<char*>(&reservation_id_);
1502  bind_[reservation_id_index_].is_unsigned = MLM_TRUE;
1503 
1504  // IPv6 address/prefix VARCHAR(39)
1505  ipv6_address_buffer_len_ = sizeof(ipv6_address_buffer_) - 1;
1506  bind_[address_index_].buffer_type = MYSQL_TYPE_STRING;
1507  bind_[address_index_].buffer = ipv6_address_buffer_;
1508  bind_[address_index_].buffer_length = ipv6_address_buffer_len_;
1509  bind_[address_index_].length = &ipv6_address_buffer_len_;
1510 
1511  // prefix_len : TINYINT
1512  bind_[prefix_len_index_].buffer_type = MYSQL_TYPE_TINY;
1513  bind_[prefix_len_index_].buffer = reinterpret_cast<char*>(&prefix_len_);
1514  bind_[prefix_len_index_].is_unsigned = MLM_TRUE;
1515 
1516  // (reservation) type : TINYINT
1517  reserv_type_null_ = MLM_FALSE;
1518  bind_[type_index_].buffer_type = MYSQL_TYPE_TINY;
1519  bind_[type_index_].buffer = reinterpret_cast<char*>(&reserv_type_);
1520  bind_[type_index_].is_unsigned = MLM_TRUE;
1521  bind_[type_index_].is_null = &reserv_type_null_;
1522 
1523  // dhcp6_iaid INT UNSIGNED
1524  bind_[iaid_index_].buffer_type = MYSQL_TYPE_LONG;
1525  bind_[iaid_index_].buffer = reinterpret_cast<char*>(&iaid_);
1526  bind_[iaid_index_].is_unsigned = MLM_TRUE;
1527 
1528  // Add the error flags
1529  setErrorIndicators(bind_, error_);
1530 
1531  return (bind_);
1532  };
1533 
1534 private:
1535 
1537  uint32_t reservation_id_;
1538 
1540  uint8_t reserv_type_;
1541 
1546  my_bool reserv_type_null_;
1547 
1549  char ipv6_address_buffer_[ADDRESS6_TEXT_MAX_LEN + 1];
1550 
1552  unsigned long ipv6_address_buffer_len_;
1553 
1555  uint8_t prefix_len_;
1556 
1558  uint32_t iaid_;
1559 
1561 
1562  size_t reservation_id_index_;
1564 
1566  size_t address_index_;
1567 
1569  size_t prefix_len_index_;
1570 
1572  size_t type_index_;
1573 
1575  size_t iaid_index_;
1576 
1578 
1580  uint32_t most_recent_reservation_id_;
1581 };
1582 
1593 class MySqlIPv6ReservationExchange {
1594 private:
1595 
1597  static const size_t RESRV_COLUMNS = 6;
1598 
1599 public:
1600 
1604  MySqlIPv6ReservationExchange()
1605  : host_id_(0), address_("::"), address_len_(0), prefix_len_(0), type_(0),
1606  iaid_(0), resv_(IPv6Resrv::TYPE_NA, asiolink::IOAddress("::"), 128) {
1607 
1608  // Reset error table.
1609  std::fill(&error_[0], &error_[RESRV_COLUMNS], MLM_FALSE);
1610 
1611  // Set the column names (for error messages)
1612  columns_[0] = "host_id";
1613  columns_[1] = "address";
1614  columns_[2] = "prefix_len";
1615  columns_[3] = "type";
1616  columns_[4] = "dhcp6_iaid";
1617  BOOST_STATIC_ASSERT(4 < RESRV_COLUMNS);
1618  }
1619 
1632  std::vector<MYSQL_BIND> createBindForSend(const IPv6Resrv& resv,
1633  const HostID& id) {
1634 
1635  // Store the values to ensure they remain valid.
1636  resv_ = resv;
1637  host_id_ = id;
1638 
1639  // Initialize prior to constructing the array of MYSQL_BIND structures.
1640  // It sets all fields, including is_null, to zero, so we need to set
1641  // is_null only if it should be true. This gives up minor performance
1642  // benefit while being safe approach. For improved readability, the
1643  // code that explicitly sets is_null is there, but is commented out.
1644  memset(bind_, 0, sizeof(bind_));
1645 
1646  // Set up the structures for the various components of the host structure.
1647 
1648  try {
1649  // address VARCHAR(39)
1650  address_ = resv.getPrefix().toText();
1651  address_len_ = address_.length();
1652  bind_[0].buffer_type = MYSQL_TYPE_BLOB;
1653  bind_[0].buffer = reinterpret_cast<char*>
1654  (const_cast<char*>(address_.c_str()));
1655  bind_[0].buffer_length = address_len_;
1656  bind_[0].length = &address_len_;
1657 
1658  // prefix_len tinyint
1659  prefix_len_ = resv.getPrefixLen();
1660  bind_[1].buffer_type = MYSQL_TYPE_TINY;
1661  bind_[1].buffer = reinterpret_cast<char*>(&prefix_len_);
1662  bind_[1].is_unsigned = MLM_TRUE;
1663 
1664  // type tinyint
1665  // See lease6_types for values (0 = IA_NA, 1 = IA_TA, 2 = IA_PD)
1666  type_ = resv.getType() == IPv6Resrv::TYPE_NA ? 0 : 2;
1667  bind_[2].buffer_type = MYSQL_TYPE_TINY;
1668  bind_[2].buffer = reinterpret_cast<char*>(&type_);
1669  bind_[2].is_unsigned = MLM_TRUE;
1670 
1671  // dhcp6_iaid INT UNSIGNED
1673  iaid_ = 0;
1674  bind_[3].buffer_type = MYSQL_TYPE_LONG;
1675  bind_[3].buffer = reinterpret_cast<char*>(&iaid_);
1676  bind_[3].is_unsigned = MLM_TRUE;
1677 
1678  // host_id INT UNSIGNED NOT NULL
1679  bind_[4].buffer_type = MYSQL_TYPE_LONG;
1680  bind_[4].buffer = reinterpret_cast<char*>(&host_id_);
1681  bind_[4].is_unsigned = MLM_TRUE;
1682 
1683  } catch (const std::exception& ex) {
1685  "Could not create bind array from IPv6 Reservation: "
1686  << resv_.toText() << ", reason: " << ex.what());
1687  }
1688 
1689  // Add the data to the vector. Note the end element is one after the
1690  // end of the array.
1691  // RESRV_COLUMNS -1 as we do not set reservation_id.
1692  return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[RESRV_COLUMNS-1]));
1693  }
1694 
1695 private:
1696 
1698  uint64_t host_id_;
1699 
1701  std::string address_;
1702 
1704  unsigned long address_len_;
1705 
1707  uint8_t prefix_len_;
1708 
1710  uint8_t type_;
1711 
1713  uint8_t iaid_;
1714 
1716  IPv6Resrv resv_;
1717 
1719  MYSQL_BIND bind_[RESRV_COLUMNS];
1720 
1722  std::string columns_[RESRV_COLUMNS];
1723 
1726  my_bool error_[RESRV_COLUMNS];
1727 };
1728 
1732 class MySqlOptionExchange {
1733 private:
1734 
1736  static const size_t OPTION_COLUMNS = 10;
1737 
1738 public:
1739 
1741  MySqlOptionExchange()
1742 
1743  : type_(0), value_len_(0), formatted_value_len_(0), space_(),
1744  space_len_(0), persistent_(false), user_context_(),
1745  user_context_len_(0), client_class_(), client_class_len_(0),
1746  subnet_id_(SUBNET_ID_UNUSED), host_id_(0), option_() {
1747 
1748  BOOST_STATIC_ASSERT(9 < OPTION_COLUMNS);
1749  }
1750 
1754  std::vector<MYSQL_BIND>
1755  createBindForSend(const OptionDescriptor& opt_desc,
1756  const std::string& opt_space,
1757  const OptionalValue<SubnetID>& subnet_id,
1758  const HostID& host_id) {
1759 
1760  // Hold pointer to the option to make sure it remains valid until
1761  // we complete a query.
1762  option_ = opt_desc.option_;
1763 
1764  memset(bind_, 0, sizeof(bind_));
1765 
1766  try {
1767  // option_id: INT UNSIGNED NOT NULL
1768  // The option_id is auto_incremented, so we need to pass the NULL
1769  // value.
1770  bind_[0].buffer_type = MYSQL_TYPE_NULL;
1771 
1772  // code: SMALLINT UNSIGNED NOT NULL
1773  type_ = option_->getType();
1774  bind_[1].buffer_type = MYSQL_TYPE_SHORT;
1775  bind_[1].buffer = reinterpret_cast<char*>(&type_);
1776  bind_[1].is_unsigned = MLM_TRUE;
1777 
1778  // value: BLOB NULL
1779  if (opt_desc.formatted_value_.empty() &&
1780  (opt_desc.option_->len() > opt_desc.option_->getHeaderLen())) {
1781  // The formatted_value is empty and the option value is
1782  // non-empty so we need to prepare on-wire format for the
1783  // option and store it in the database as a blob.
1784  OutputBuffer buf(opt_desc.option_->len());
1785  opt_desc.option_->pack(buf);
1786  const char* buf_ptr = static_cast<const char*>(buf.getData());
1787  value_.assign(buf_ptr + opt_desc.option_->getHeaderLen(),
1788  buf_ptr + buf.getLength());
1789  value_len_ = value_.size();
1790  bind_[2].buffer_type = MYSQL_TYPE_BLOB;
1791  bind_[2].buffer = &value_[0];
1792  bind_[2].buffer_length = value_len_;
1793  bind_[2].length = &value_len_;
1794 
1795  } else {
1796  // No value or formatted_value specified. In this case, the
1797  // value blob is NULL.
1798  value_.clear();
1799  bind_[2].buffer_type = MYSQL_TYPE_NULL;
1800  }
1801 
1802  // formatted_value: TEXT NULL,
1803  if (!opt_desc.formatted_value_.empty()) {
1804  formatted_value_len_ = opt_desc.formatted_value_.size();
1805  bind_[3].buffer_type = MYSQL_TYPE_STRING;
1806  bind_[3].buffer = const_cast<char*>(opt_desc.formatted_value_.c_str());
1807  bind_[3].buffer_length = formatted_value_len_;
1808  bind_[3].length = &formatted_value_len_;
1809 
1810  } else {
1811  bind_[3].buffer_type = MYSQL_TYPE_NULL;
1812  }
1813 
1814  // space: VARCHAR(128) NULL
1815  space_ = opt_space;
1816  space_len_ = space_.size();
1817  bind_[4].buffer_type = MYSQL_TYPE_STRING;
1818  bind_[4].buffer = const_cast<char*>(space_.c_str());
1819  bind_[4].buffer_length = space_len_;
1820  bind_[4].length = &space_len_;
1821 
1822  // persistent: TINYINT(1) NOT NULL DEFAULT 0
1823  persistent_ = opt_desc.persistent_;
1824  bind_[5].buffer_type = MYSQL_TYPE_TINY;
1825  bind_[5].buffer = reinterpret_cast<char*>(&persistent_);
1826  bind_[5].is_unsigned = MLM_TRUE;
1827 
1828  // user_context: TEST NULL,
1829  ConstElementPtr ctx = opt_desc.getContext();
1830  if (ctx) {
1831  user_context_ = ctx->str();
1832  user_context_len_ = user_context_.size();
1833  bind_[6].buffer_type = MYSQL_TYPE_STRING;
1834  bind_[6].buffer = const_cast<char*>(user_context_.c_str());
1835  bind_[6].buffer_length = user_context_len_;
1836  bind_[6].length = &user_context_len_;
1837  } else {
1838  bind_[6].buffer_type = MYSQL_TYPE_NULL;
1839  }
1840 
1841  // dhcp_client_class: VARCHAR(128) NULL
1842  client_class_len_ = client_class_.size();
1843  bind_[7].buffer_type = MYSQL_TYPE_STRING;
1844  bind_[7].buffer = const_cast<char*>(client_class_.c_str());
1845  bind_[7].buffer_length = client_class_len_;
1846  bind_[7].length = &client_class_len_;
1847 
1848  // dhcp4_subnet_id: INT UNSIGNED NULL
1849  if (subnet_id.isSpecified()) {
1850  subnet_id_ = subnet_id;
1851  bind_[8].buffer_type = MYSQL_TYPE_LONG;
1852  bind_[8].buffer = reinterpret_cast<char*>(subnet_id_);
1853  bind_[8].is_unsigned = MLM_TRUE;
1854 
1855  } else {
1856  bind_[8].buffer_type = MYSQL_TYPE_NULL;
1857  }
1858 
1859  // host_id: INT UNSIGNED NOT NULL
1860  host_id_ = host_id;
1861  bind_[9].buffer_type = MYSQL_TYPE_LONG;
1862  bind_[9].buffer = reinterpret_cast<char*>(&host_id_);
1863  bind_[9].is_unsigned = MLM_TRUE;
1864 
1865  } catch (const std::exception& ex) {
1867  "Could not create bind array for inserting DHCP "
1868  "option: " << option_->toText() << ", reason: "
1869  << ex.what());
1870  }
1871 
1872  return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[OPTION_COLUMNS]));
1873  }
1874 
1875 private:
1876 
1878  uint16_t type_;
1879 
1881  std::vector<uint8_t> value_;
1882 
1884  unsigned long value_len_;
1885 
1887  unsigned long formatted_value_len_;
1888 
1890  std::string space_;
1891 
1893  unsigned long space_len_;
1894 
1897  bool persistent_;
1898 
1900  std::string user_context_;
1901 
1903  unsigned long user_context_len_;
1904 
1906  std::string client_class_;
1907 
1909  unsigned long client_class_len_;
1910 
1912  uint32_t subnet_id_;
1913 
1915  uint32_t host_id_;
1916 
1918  OptionPtr option_;
1919 
1921  MYSQL_BIND bind_[OPTION_COLUMNS];
1922 };
1923 
1924 } // end of anonymous namespace
1925 
1926 namespace isc {
1927 namespace dhcp {
1928 
1931 public:
1932 
1940  GET_HOST_DHCPID, // Gets hosts by host identifier
1941  GET_HOST_ADDR, // Gets hosts by IPv4 address
1942  GET_HOST_SUBID4_DHCPID, // Gets host by IPv4 SubnetID, HW address/DUID
1943  GET_HOST_SUBID6_DHCPID, // Gets host by IPv6 SubnetID, HW address/DUID
1944  GET_HOST_SUBID_ADDR, // Gets host by IPv4 SubnetID and IPv4 address
1945  GET_HOST_PREFIX, // Gets host by IPv6 prefix
1946  GET_HOST_SUBID6_ADDR, // Gets host by IPv6 SubnetID and IPv6 prefix
1947  INSERT_HOST, // Insert new host to collection
1948  INSERT_V6_RESRV, // Insert v6 reservation
1949  INSERT_V4_OPTION, // Insert DHCPv4 option
1950  INSERT_V6_OPTION, // Insert DHCPv6 option
1951  DEL_HOST_ADDR4, // Delete v4 host (subnet-id, addr4)
1952  DEL_HOST_SUBID4_ID, // Delete v4 host (subnet-id, ident.type, identifier)
1953  DEL_HOST_SUBID6_ID, // Delete v6 host (subnet-id, ident.type, identifier)
1954  NUM_STATEMENTS // Number of statements
1955  };
1956 
1962  static const StatementIndex WRITE_STMTS_BEGIN = INSERT_HOST;
1963 
1968  MySqlHostDataSourceImpl(const MySqlConnection::ParameterMap& parameters);
1969 
1972 
1979  //
1986  std::pair<uint32_t, uint32_t> getVersion() const;
1987 
1995  void addStatement(MySqlHostDataSourceImpl::StatementIndex stindex,
1996  std::vector<MYSQL_BIND>& bind);
1997 
2004  bool
2005  delStatement(StatementIndex stindex, MYSQL_BIND* bind);
2006 
2011  void addResv(const IPv6Resrv& resv, const HostID& id);
2012 
2021  void addOption(const MySqlHostDataSourceImpl::StatementIndex& stindex,
2022  const OptionDescriptor& opt_desc,
2023  const std::string& opt_space,
2024  const OptionalValue<SubnetID>& subnet_id,
2025  const HostID& host_id);
2026 
2033  void addOptions(const StatementIndex& stindex, const ConstCfgOptionPtr& options_cfg,
2034  const uint64_t host_id);
2035 
2046  void checkError(const int status, const StatementIndex index,
2047  const char* what) const;
2048 
2066  void getHostCollection(StatementIndex stindex, MYSQL_BIND* bind,
2067  boost::shared_ptr<MySqlHostExchange> exchange,
2068  ConstHostCollection& result, bool single) const;
2069 
2086  ConstHostPtr getHost(const SubnetID& subnet_id,
2087  const Host::IdentifierType& identifier_type,
2088  const uint8_t* identifier_begin,
2089  const size_t identifier_len,
2090  StatementIndex stindex,
2091  boost::shared_ptr<MySqlHostExchange> exchange) const;
2092 
2100  void checkReadOnly() const;
2101 
2104  boost::shared_ptr<MySqlHostWithOptionsExchange> host_exchange_;
2105 
2108  boost::shared_ptr<MySqlHostIPv6Exchange> host_ipv6_exchange_;
2109 
2113  boost::shared_ptr<MySqlHostIPv6Exchange> host_ipv46_exchange_;
2114 
2117  boost::shared_ptr<MySqlIPv6ReservationExchange> host_ipv6_reservation_exchange_;
2118 
2122  boost::shared_ptr<MySqlOptionExchange> host_option_exchange_;
2123 
2126 
2129 };
2130 
2132 typedef boost::array<TaggedStatement, MySqlHostDataSourceImpl::NUM_STATEMENTS>
2134 
2138  // Retrieves host information, IPv6 reservations and both DHCPv4 and
2139  // DHCPv6 options associated with the host. The LEFT JOIN clause is used
2140  // to retrieve information from 4 different tables using a single query.
2141  // Hence, this query returns multiple rows for a single host.
2142  {MySqlHostDataSourceImpl::GET_HOST_DHCPID,
2143  "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2144  "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
2145  "h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
2146  "h.user_context, "
2147  "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2148  "h.dhcp4_boot_file_name, h.auth_key, "
2149  "o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
2150  "o4.persistent, o4.user_context, "
2151  "o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
2152  "o6.persistent, o6.user_context, "
2153  "r.reservation_id, r.address, r.prefix_len, r.type, "
2154  "r.dhcp6_iaid "
2155  "FROM hosts AS h "
2156  "LEFT JOIN dhcp4_options AS o4 "
2157  "ON h.host_id = o4.host_id "
2158  "LEFT JOIN dhcp6_options AS o6 "
2159  "ON h.host_id = o6.host_id "
2160  "LEFT JOIN ipv6_reservations AS r "
2161  "ON h.host_id = r.host_id "
2162  "WHERE dhcp_identifier = ? AND dhcp_identifier_type = ? "
2163  "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id"},
2164 
2165  // Retrieves host information along with the DHCPv4 options associated with
2166  // it. Left joining the dhcp4_options table results in multiple rows being
2167  // returned for the same host. The host is retrieved by IPv4 address.
2168  {MySqlHostDataSourceImpl::GET_HOST_ADDR,
2169  "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2170  "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2171  "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2172  "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2173  "h.dhcp4_boot_file_name, h.auth_key, "
2174  "o.option_id, o.code, o.value, o.formatted_value, o.space, "
2175  "o.persistent, o.user_context "
2176  "FROM hosts AS h "
2177  "LEFT JOIN dhcp4_options AS o "
2178  "ON h.host_id = o.host_id "
2179  "WHERE ipv4_address = ? "
2180  "ORDER BY h.host_id, o.option_id"},
2181 
2182  // Retrieves host information and DHCPv4 options using subnet identifier
2183  // and client's identifier. Left joining the dhcp4_options table results in
2184  // multiple rows being returned for the same host.
2185  {MySqlHostDataSourceImpl::GET_HOST_SUBID4_DHCPID,
2186  "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2187  "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2188  "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2189  "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2190  "h.dhcp4_boot_file_name, h.auth_key, "
2191  ""
2192  "o.option_id, o.code, o.value, o.formatted_value, o.space, "
2193  "o.persistent, o.user_context "
2194  "FROM hosts AS h "
2195  "LEFT JOIN dhcp4_options AS o "
2196  "ON h.host_id = o.host_id "
2197  "WHERE h.dhcp4_subnet_id = ? AND h.dhcp_identifier_type = ? "
2198  " AND h.dhcp_identifier = ? "
2199  "ORDER BY h.host_id, o.option_id"},
2200 
2201  // Retrieves host information, IPv6 reservations and DHCPv6 options
2202  // associated with a host. The number of rows returned is a multiplication
2203  // of number of IPv6 reservations and DHCPv6 options.
2204  {MySqlHostDataSourceImpl::GET_HOST_SUBID6_DHCPID,
2205  "SELECT h.host_id, h.dhcp_identifier, "
2206  "h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2207  "h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2208  "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2209  "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2210  "h.dhcp4_boot_file_name, h.auth_key, "
2211  "o.option_id, o.code, o.value, o.formatted_value, o.space, "
2212  "o.persistent, o.user_context, "
2213  "r.reservation_id, r.address, r.prefix_len, r.type, "
2214  "r.dhcp6_iaid "
2215  "FROM hosts AS h "
2216  "LEFT JOIN dhcp6_options AS o "
2217  "ON h.host_id = o.host_id "
2218  "LEFT JOIN ipv6_reservations AS r "
2219  "ON h.host_id = r.host_id "
2220  "WHERE h.dhcp6_subnet_id = ? AND h.dhcp_identifier_type = ? "
2221  "AND h.dhcp_identifier = ? "
2222  "ORDER BY h.host_id, o.option_id, r.reservation_id"},
2223 
2224  // Retrieves host information and DHCPv4 options for the host using subnet
2225  // identifier and IPv4 reservation. Left joining the dhcp4_options table
2226  // results in multiple rows being returned for the host. The number of
2227  // rows depends on the number of options defined for the host.
2228  {MySqlHostDataSourceImpl::GET_HOST_SUBID_ADDR,
2229  "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2230  "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2231  "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2232  "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2233  "h.dhcp4_boot_file_name, h.auth_key, "
2234  "o.option_id, o.code, o.value, o.formatted_value, o.space, "
2235  "o.persistent, o.user_context "
2236  "FROM hosts AS h "
2237  "LEFT JOIN dhcp4_options AS o "
2238  "ON h.host_id = o.host_id "
2239  "WHERE h.dhcp4_subnet_id = ? AND h.ipv4_address = ? "
2240  "ORDER BY h.host_id, o.option_id"},
2241 
2242  // Retrieves host information, IPv6 reservations and DHCPv6 options
2243  // associated with a host using prefix and prefix length. This query
2244  // returns host information for a single host. However, multiple rows
2245  // are returned due to left joining IPv6 reservations and DHCPv6 options.
2246  // The number of rows returned is multiplication of number of existing
2247  // IPv6 reservations and DHCPv6 options.
2248  {MySqlHostDataSourceImpl::GET_HOST_PREFIX,
2249  "SELECT h.host_id, h.dhcp_identifier, "
2250  "h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2251  "h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2252  "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2253  "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2254  "h.dhcp4_boot_file_name, h.auth_key, "
2255  "o.option_id, o.code, o.value, o.formatted_value, o.space, "
2256  "o.persistent, o.user_context,"
2257  "r.reservation_id, r.address, r.prefix_len, r.type, "
2258  "r.dhcp6_iaid "
2259  "FROM hosts AS h "
2260  "LEFT JOIN dhcp6_options AS o "
2261  "ON h.host_id = o.host_id "
2262  "LEFT JOIN ipv6_reservations AS r "
2263  "ON h.host_id = r.host_id "
2264  "WHERE h.host_id = "
2265  "(SELECT host_id FROM ipv6_reservations "
2266  "WHERE address = ? AND prefix_len = ?) "
2267  "ORDER BY h.host_id, o.option_id, r.reservation_id"},
2268 
2269  // Retrieves host information, IPv6 reservations and DHCPv6 options
2270  // associated with a host using subnet id and prefix. This query
2271  // returns host information for a single host. However, multiple rows
2272  // are returned due to left joining IPv6 reservations and DHCPv6 options.
2273  // The number of rows returned is multiplication of number of existing
2274  // IPv6 reservations and DHCPv6 options.
2275  {MySqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR,
2276  "SELECT h.host_id, h.dhcp_identifier, "
2277  "h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2278  "h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2279  "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2280 
2281  "h.dhcp4_next_server, h.dhcp4_server_hostname, "
2282  "h.dhcp4_boot_file_name, h.auth_key, "
2283  "o.option_id, o.code, o.value, o.formatted_value, o.space, "
2284  "o.persistent, o.user_context, "
2285  "r.reservation_id, r.address, r.prefix_len, r.type, "
2286  "r.dhcp6_iaid "
2287  "FROM hosts AS h "
2288  "LEFT JOIN dhcp6_options AS o "
2289  "ON h.host_id = o.host_id "
2290  "LEFT JOIN ipv6_reservations AS r "
2291  "ON h.host_id = r.host_id "
2292  "WHERE h.dhcp6_subnet_id = ? AND r.address = ? "
2293  "ORDER BY h.host_id, o.option_id, r.reservation_id"},
2294 
2295  // Inserts a host into the 'hosts' table.
2296  {MySqlHostDataSourceImpl::INSERT_HOST,
2297  "INSERT INTO hosts(host_id, dhcp_identifier, dhcp_identifier_type, "
2298  "dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
2299  "dhcp4_client_classes, dhcp6_client_classes, "
2300  "user_context, dhcp4_next_server, "
2301  "dhcp4_server_hostname, dhcp4_boot_file_name, auth_key) "
2302  "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
2303 
2304  // Inserts a single IPv6 reservation into 'reservations' table.
2305  {MySqlHostDataSourceImpl::INSERT_V6_RESRV,
2306  "INSERT INTO ipv6_reservations(address, prefix_len, type, "
2307  "dhcp6_iaid, host_id) "
2308  "VALUES (?,?,?,?,?)"},
2309 
2310  // Inserts a single DHCPv4 option into 'dhcp4_options' table.
2311  // Using fixed scope_id = 3, which associates an option with host.
2312  {MySqlHostDataSourceImpl::INSERT_V4_OPTION,
2313  "INSERT INTO dhcp4_options(option_id, code, value, formatted_value, space, "
2314  "persistent, user_context, dhcp_client_class, dhcp4_subnet_id, host_id, scope_id) "
2315  " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"},
2316 
2317  // Inserts a single DHCPv6 option into 'dhcp6_options' table.
2318  // Using fixed scope_id = 3, which associates an option with host.
2319  {MySqlHostDataSourceImpl::INSERT_V6_OPTION,
2320  "INSERT INTO dhcp6_options(option_id, code, value, formatted_value, space, "
2321  "persistent, user_context, dhcp_client_class, dhcp6_subnet_id, host_id, scope_id) "
2322  " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 3)"},
2323 
2324  {MySqlHostDataSourceImpl::DEL_HOST_ADDR4,
2325  "DELETE FROM hosts WHERE dhcp4_subnet_id = ? AND ipv4_address = ?"},
2326 
2327  {MySqlHostDataSourceImpl::DEL_HOST_SUBID4_ID,
2328  "DELETE FROM hosts WHERE dhcp4_subnet_id = ? AND dhcp_identifier_type=? "
2329  "AND dhcp_identifier = ?"},
2330 
2331  {MySqlHostDataSourceImpl::DEL_HOST_SUBID6_ID,
2332  "DELETE FROM hosts WHERE dhcp6_subnet_id = ? AND dhcp_identifier_type=? "
2333  "AND dhcp_identifier = ?"}
2334 
2335  }
2336 };
2337 
2338 MySqlHostDataSourceImpl::
2339 MySqlHostDataSourceImpl(const MySqlConnection::ParameterMap& parameters)
2340  : host_exchange_(new MySqlHostWithOptionsExchange(MySqlHostWithOptionsExchange::DHCP4_ONLY)),
2341  host_ipv6_exchange_(new MySqlHostIPv6Exchange(MySqlHostWithOptionsExchange::DHCP6_ONLY)),
2342  host_ipv46_exchange_(new MySqlHostIPv6Exchange(MySqlHostWithOptionsExchange::
2343  DHCP4_AND_DHCP6)),
2344  host_ipv6_reservation_exchange_(new MySqlIPv6ReservationExchange()),
2345  host_option_exchange_(new MySqlOptionExchange()),
2346  conn_(parameters),
2347  is_readonly_(false) {
2348 
2349  // Open the database.
2350  conn_.openDatabase();
2351 
2352  // Test schema version before we try to prepare statements.
2353  std::pair<uint32_t, uint32_t> code_version(MYSQL_SCHEMA_VERSION_MAJOR,
2355  std::pair<uint32_t, uint32_t> db_version = getVersion();
2356  if (code_version != db_version) {
2357  isc_throw(DbOpenError, "MySQL schema version mismatch: need version: "
2358  << code_version.first << "." << code_version.second
2359  << " found version: " << db_version.first << "."
2360  << db_version.second);
2361  }
2362 
2363  // Enable autocommit. In case transaction is explicitly used, this
2364  // setting will be overwritten for the transaction. However, there are
2365  // cases when lack of autocommit could cause transactions to hang
2366  // until commit or rollback is explicitly called. This already
2367  // caused issues for some unit tests which were unable to cleanup
2368  // the database after the test because of pending transactions.
2369  // Use of autocommit will eliminate this problem.
2370  my_bool result = mysql_autocommit(conn_.mysql_, 1);
2371  if (result != 0) {
2372  isc_throw(DbOperationError, mysql_error(conn_.mysql_));
2373  }
2374 
2375  // Prepare query statements. Those are will be only used to retrieve
2376  // information from the database, so they can be used even if the
2377  // database is read only for the current user.
2380 
2381  // Check if the backend is explicitly configured to operate with
2382  // read only access to the database.
2384 
2385  // If we are using read-write mode for the database we also prepare
2386  // statements for INSERTS etc.
2387  if (!is_readonly_) {
2388  // Prepare statements for writing to the database, e.g. INSERT.
2390  tagged_statements.end());
2391  } else {
2392  LOG_INFO(dhcpsrv_logger, DHCPSRV_MYSQL_HOST_DB_READONLY);
2393  }
2394 }
2395 
2397  // Free up the prepared statements, ignoring errors. (What would we do
2398  // about them? We're destroying this object and are not really concerned
2399  // with errors on a database connection that is about to go away.)
2400  for (int i = 0; i < conn_.statements_.size(); ++i) {
2401  if (conn_.statements_[i] != NULL) {
2402  (void) mysql_stmt_close(conn_.statements_[i]);
2403  conn_.statements_[i] = NULL;
2404  }
2405  }
2406 
2407  // There is no need to close the database in this destructor: it is
2408  // closed in the destructor of the mysql_ member variable.
2409 }
2410 
2411 std::pair<uint32_t, uint32_t>
2414  DHCPSRV_MYSQL_HOST_DB_GET_VERSION);
2415 
2416  // Allocate a new statement.
2417  MYSQL_STMT *stmt = mysql_stmt_init(conn_.mysql_);
2418  if (stmt == NULL) {
2419  isc_throw(DbOperationError, "unable to allocate MySQL prepared "
2420  "statement structure, reason: " << mysql_error(conn_.mysql_));
2421  }
2422 
2423  // Prepare the statement from SQL text.
2424  const char* version_sql = "SELECT version, minor FROM schema_version";
2425  int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
2426  if (status != 0) {
2427  isc_throw(DbOperationError, "unable to prepare MySQL statement <"
2428  << version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
2429  }
2430 
2431  // Execute the prepared statement.
2432  if (mysql_stmt_execute(stmt) != 0) {
2433  isc_throw(DbOperationError, "cannot execute schema version query <"
2434  << version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
2435  }
2436 
2437  // Bind the output of the statement to the appropriate variables.
2438  MYSQL_BIND bind[2];
2439  memset(bind, 0, sizeof(bind));
2440 
2441  uint32_t major;
2442  bind[0].buffer_type = MYSQL_TYPE_LONG;
2443  bind[0].is_unsigned = 1;
2444  bind[0].buffer = &major;
2445  bind[0].buffer_length = sizeof(major);
2446 
2447  uint32_t minor;
2448  bind[1].buffer_type = MYSQL_TYPE_LONG;
2449  bind[1].is_unsigned = 1;
2450  bind[1].buffer = &minor;
2451  bind[1].buffer_length = sizeof(minor);
2452 
2453  if (mysql_stmt_bind_result(stmt, bind)) {
2454  isc_throw(DbOperationError, "unable to bind result set for <"
2455  << version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
2456  }
2457 
2458  // Fetch the data.
2459  if (mysql_stmt_fetch(stmt)) {
2460  mysql_stmt_close(stmt);
2461  isc_throw(DbOperationError, "unable to bind result set for <"
2462  << version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
2463  }
2464 
2465  // Discard the statement and its resources
2466  mysql_stmt_close(stmt);
2467 
2468  return (std::make_pair(major, minor));
2469 }
2470 
2471 
2472 void
2474  std::vector<MYSQL_BIND>& bind) {
2475 
2476  // Bind the parameters to the statement
2477  int status = mysql_stmt_bind_param(conn_.statements_[stindex], &bind[0]);
2478  checkError(status, stindex, "unable to bind parameters");
2479 
2480  // Execute the statement
2481  status = mysql_stmt_execute(conn_.statements_[stindex]);
2482 
2483  if (status != 0) {
2484  // Failure: check for the special case of duplicate entry.
2485  if (mysql_errno(conn_.mysql_) == ER_DUP_ENTRY) {
2486  isc_throw(DuplicateEntry, "Database duplicate entry error");
2487  }
2488  checkError(status, stindex, "unable to execute");
2489  }
2490 }
2491 
2492 bool
2494  MYSQL_BIND* bind) {
2495  // Bind the parameters to the statement
2496  int status = mysql_stmt_bind_param(conn_.statements_[stindex], &bind[0]);
2497  checkError(status, stindex, "unable to bind parameters");
2498 
2499  // Execute the statement
2500  status = mysql_stmt_execute(conn_.statements_[stindex]);
2501 
2502  if (status != 0) {
2503  checkError(status, stindex, "unable to execute");
2504  }
2505 
2506  // Let's check how many hosts were deleted.
2507  my_ulonglong numrows = mysql_stmt_affected_rows(conn_.statements_[stindex]);
2508  return (numrows != 0);
2509 }
2510 
2511 void
2513  const HostID& id) {
2514  std::vector<MYSQL_BIND> bind =
2515  host_ipv6_reservation_exchange_->createBindForSend(resv, id);
2516 
2518 }
2519 
2520 void
2522  const OptionDescriptor& opt_desc,
2523  const std::string& opt_space,
2524  const OptionalValue<SubnetID>& subnet_id,
2525  const HostID& id) {
2526  std::vector<MYSQL_BIND> bind =
2527  host_option_exchange_->createBindForSend(opt_desc, opt_space,
2528  subnet_id, id);
2529 
2530  addStatement(stindex, bind);
2531 }
2532 
2533 void
2535  const ConstCfgOptionPtr& options_cfg,
2536  const uint64_t host_id) {
2537  // Get option space names and vendor space names and combine them within a
2538  // single list.
2539  std::list<std::string> option_spaces = options_cfg->getOptionSpaceNames();
2540  std::list<std::string> vendor_spaces = options_cfg->getVendorIdsSpaceNames();
2541  option_spaces.insert(option_spaces.end(), vendor_spaces.begin(),
2542  vendor_spaces.end());
2543 
2544  // For each option space retrieve all options and insert them into the
2545  // database.
2546  for (std::list<std::string>::const_iterator space = option_spaces.begin();
2547  space != option_spaces.end(); ++space) {
2548  OptionContainerPtr options = options_cfg->getAll(*space);
2549  if (options && !options->empty()) {
2550  for (OptionContainer::const_iterator opt = options->begin();
2551  opt != options->end(); ++opt) {
2552  addOption(stindex, *opt, *space, OptionalValue<SubnetID>(),
2553  host_id);
2554  }
2555  }
2556  }
2557 }
2558 
2559 void
2561 checkError(const int status, const StatementIndex index,
2562  const char* what) const {
2563  conn_.checkError(status, index, what);
2564 }
2565 
2566 void
2568 getHostCollection(StatementIndex stindex, MYSQL_BIND* bind,
2569  boost::shared_ptr<MySqlHostExchange> exchange,
2570  ConstHostCollection& result, bool single) const {
2571 
2572  // Bind the selection parameters to the statement
2573  int status = mysql_stmt_bind_param(conn_.statements_[stindex], bind);
2574  checkError(status, stindex, "unable to bind WHERE clause parameter");
2575 
2576  // Set up the MYSQL_BIND array for the data being returned and bind it to
2577  // the statement.
2578  std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
2579  status = mysql_stmt_bind_result(conn_.statements_[stindex], &outbind[0]);
2580  checkError(status, stindex, "unable to bind SELECT clause parameters");
2581 
2582  // Execute the statement
2583  status = mysql_stmt_execute(conn_.statements_[stindex]);
2584  checkError(status, stindex, "unable to execute");
2585 
2586  // Ensure that all the lease information is retrieved in one go to avoid
2587  // overhead of going back and forth between client and server.
2588  status = mysql_stmt_store_result(conn_.statements_[stindex]);
2589  checkError(status, stindex, "unable to set up for storing all results");
2590 
2591  // Set up the fetch "release" object to release resources associated
2592  // with the call to mysql_stmt_fetch when this method exits, then
2593  // retrieve the data. mysql_stmt_fetch return value equal to 0 represents
2594  // successful data fetch.
2595  MySqlFreeResult fetch_release(conn_.statements_[stindex]);
2596  while ((status = mysql_stmt_fetch(conn_.statements_[stindex])) ==
2598  try {
2599  exchange->processFetchedData(result);
2600 
2601  } catch (const isc::BadValue& ex) {
2602  // Rethrow the exception with a bit more data.
2603  isc_throw(BadValue, ex.what() << ". Statement is <" <<
2604  conn_.text_statements_[stindex] << ">");
2605  }
2606 
2607  if (single && (result.size() > 1)) {
2608  isc_throw(MultipleRecords, "multiple records were found in the "
2609  "database where only one was expected for query "
2610  << conn_.text_statements_[stindex]);
2611  }
2612  }
2613 
2614  // How did the fetch end?
2615  // If mysql_stmt_fetch return value is equal to 1 an error occurred.
2616  if (status == MLM_MYSQL_FETCH_FAILURE) {
2617  // Error - unable to fetch results
2618  checkError(status, stindex, "unable to fetch results");
2619 
2620  } else if (status == MYSQL_DATA_TRUNCATED) {
2621  // Data truncated - throw an exception indicating what was at fault
2623  << " returned truncated data: columns affected are "
2624  << exchange->getErrorColumns());
2625  }
2626 }
2627 
2630 getHost(const SubnetID& subnet_id,
2631  const Host::IdentifierType& identifier_type,
2632  const uint8_t* identifier_begin,
2633  const size_t identifier_len,
2634  StatementIndex stindex,
2635  boost::shared_ptr<MySqlHostExchange> exchange) const {
2636 
2637  // Set up the WHERE clause value
2638  MYSQL_BIND inbind[3];
2639  memset(inbind, 0, sizeof(inbind));
2640 
2641  uint32_t subnet_buffer = static_cast<uint32_t>(subnet_id);
2642  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2643  inbind[0].buffer = reinterpret_cast<char*>(&subnet_buffer);
2644  inbind[0].is_unsigned = MLM_TRUE;
2645 
2646  // Identifier value.
2647  std::vector<char> identifier_vec(identifier_begin,
2648  identifier_begin + identifier_len);
2649  unsigned long length = identifier_vec.size();
2650  inbind[2].buffer_type = MYSQL_TYPE_BLOB;
2651  inbind[2].buffer = &identifier_vec[0];
2652  inbind[2].buffer_length = length;
2653  inbind[2].length = &length;
2654 
2655  // Identifier type.
2656  char identifier_type_copy = static_cast<char>(identifier_type);
2657  inbind[1].buffer_type = MYSQL_TYPE_TINY;
2658  inbind[1].buffer = reinterpret_cast<char*>(&identifier_type_copy);
2659  inbind[1].is_unsigned = MLM_TRUE;
2660 
2661  ConstHostCollection collection;
2662  getHostCollection(stindex, inbind, exchange, collection, true);
2663 
2664  // Return single record if present, else clear the host.
2665  ConstHostPtr result;
2666  if (!collection.empty())
2667  result = *collection.begin();
2668 
2669  return (result);
2670 }
2671 
2672 void
2674  if (is_readonly_) {
2675  isc_throw(ReadOnlyDb, "MySQL host database backend is configured to"
2676  " operate in read only mode");
2677  }
2678 }
2679 
2681 MySqlHostDataSource(const MySqlConnection::ParameterMap& parameters)
2682  : impl_(new MySqlHostDataSourceImpl(parameters)) {
2683 }
2684 
2686  delete impl_;
2687 }
2688 
2689 void
2691  // If operating in read-only mode, throw exception.
2692  impl_->checkReadOnly();
2693 
2694  // Initiate MySQL transaction as we will have to make multiple queries
2695  // to insert host information into multiple tables. If that fails on
2696  // any stage, the transaction will be rolled back by the destructor of
2697  // the MySqlTransaction class.
2698  MySqlTransaction transaction(impl_->conn_);
2699 
2700  // Create the MYSQL_BIND array for the host
2701  std::vector<MYSQL_BIND> bind = impl_->host_exchange_->createBindForSend(host);
2702 
2703  // ... and insert the host.
2705 
2706  // Gets the last inserted hosts id
2707  uint64_t host_id = mysql_insert_id(impl_->conn_.mysql_);
2708 
2709  // Insert DHCPv4 options.
2710  ConstCfgOptionPtr cfg_option4 = host->getCfgOption4();
2711  if (cfg_option4) {
2713  cfg_option4, host_id);
2714  }
2715 
2716  // Insert DHCPv6 options.
2717  ConstCfgOptionPtr cfg_option6 = host->getCfgOption6();
2718  if (cfg_option6) {
2720  cfg_option6, host_id);
2721  }
2722 
2723  // Insert IPv6 reservations.
2724  IPv6ResrvRange v6resv = host->getIPv6Reservations();
2725  if (std::distance(v6resv.first, v6resv.second) > 0) {
2726  for (IPv6ResrvIterator resv = v6resv.first; resv != v6resv.second;
2727  ++resv) {
2728  impl_->addResv(resv->second, host_id);
2729  }
2730  }
2731 
2732  // Everything went fine, so explicitly commit the transaction.
2733  transaction.commit();
2734 }
2735 
2736 bool
2738  // If operating in read-only mode, throw exception.
2739  impl_->checkReadOnly();
2740 
2741  if (addr.isV4()) {
2742  // Set up the WHERE clause value
2743  MYSQL_BIND inbind[2];
2744 
2745  uint32_t subnet = subnet_id;
2746  memset(inbind, 0, sizeof(inbind));
2747  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2748  inbind[0].buffer = reinterpret_cast<char*>(&subnet);
2749  inbind[0].is_unsigned = MLM_TRUE;
2750 
2751  uint32_t addr4 = addr.toUint32();
2752  inbind[1].buffer_type = MYSQL_TYPE_LONG;
2753  inbind[1].buffer = reinterpret_cast<char*>(&addr4);
2754  inbind[1].is_unsigned = MLM_TRUE;
2755 
2756  ConstHostCollection collection;
2757  return (impl_->delStatement(MySqlHostDataSourceImpl::DEL_HOST_ADDR4, inbind));
2758  }
2759 
2760  // v6
2761  ConstHostPtr host = get6(subnet_id, addr);
2762  if (!host) {
2763  return (false);
2764  }
2765 
2766  // Ok, there is a host. Let's delete it.
2767  return del6(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0],
2768  host->getIdentifier().size());
2769 }
2770 
2771 bool
2773  const Host::IdentifierType& identifier_type,
2774  const uint8_t* identifier_begin, const size_t identifier_len) {
2775  // If operating in read-only mode, throw exception.
2776  impl_->checkReadOnly();
2777 
2778  // Set up the WHERE clause value
2779  MYSQL_BIND inbind[3];
2780 
2781  // subnet-id
2782  memset(inbind, 0, sizeof(inbind));
2783  uint32_t subnet = static_cast<uint32_t>(subnet_id);
2784  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2785  inbind[0].buffer = reinterpret_cast<char*>(&subnet);
2786  inbind[0].is_unsigned = MLM_TRUE;
2787 
2788  // identifier type
2789  char identifier_type_copy = static_cast<char>(identifier_type);
2790  inbind[1].buffer_type = MYSQL_TYPE_TINY;
2791  inbind[1].buffer = reinterpret_cast<char*>(&identifier_type_copy);
2792  inbind[1].is_unsigned = MLM_TRUE;
2793 
2794  // identifier value
2795  std::vector<char> identifier_vec(identifier_begin,
2796  identifier_begin + identifier_len);
2797  unsigned long length = identifier_vec.size();
2798  inbind[2].buffer_type = MYSQL_TYPE_BLOB;
2799  inbind[2].buffer = &identifier_vec[0];
2800  inbind[2].buffer_length = length;
2801  inbind[2].length = &length;
2802 
2803  ConstHostCollection collection;
2805 }
2806 
2807 bool
2809  const Host::IdentifierType& identifier_type,
2810  const uint8_t* identifier_begin, const size_t identifier_len) {
2811  // If operating in read-only mode, throw exception.
2812  impl_->checkReadOnly();
2813 
2814  // Set up the WHERE clause value
2815  MYSQL_BIND inbind[3];
2816 
2817  // subnet-id
2818  memset(inbind, 0, sizeof(inbind));
2819  uint32_t subnet = static_cast<uint32_t>(subnet_id);
2820  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2821  inbind[0].buffer = reinterpret_cast<char*>(&subnet);
2822  inbind[0].is_unsigned = MLM_TRUE;
2823 
2824  // identifier type
2825  char identifier_type_copy = static_cast<char>(identifier_type);
2826  inbind[1].buffer_type = MYSQL_TYPE_TINY;
2827  inbind[1].buffer = reinterpret_cast<char*>(&identifier_type_copy);
2828  inbind[1].is_unsigned = MLM_TRUE;
2829 
2830  // identifier value
2831  std::vector<char> identifier_vec(identifier_begin,
2832  identifier_begin + identifier_len);
2833  unsigned long length = identifier_vec.size();
2834  inbind[2].buffer_type = MYSQL_TYPE_BLOB;
2835  inbind[2].buffer = &identifier_vec[0];
2836  inbind[2].buffer_length = length;
2837  inbind[2].length = &length;
2838 
2839  ConstHostCollection collection;
2841 }
2842 
2845  const uint8_t* identifier_begin,
2846  const size_t identifier_len) const {
2847  // Set up the WHERE clause value
2848  MYSQL_BIND inbind[2];
2849  memset(inbind, 0, sizeof(inbind));
2850 
2851  // Identifier type.
2852  char identifier_type_copy = static_cast<char>(identifier_type);
2853  inbind[1].buffer = &identifier_type_copy;
2854  inbind[1].buffer_type = MYSQL_TYPE_TINY;
2855  inbind[1].is_unsigned = MLM_TRUE;
2856 
2857  // Identifier value.
2858  std::vector<char> identifier_vec(identifier_begin,
2859  identifier_begin + identifier_len);
2860  unsigned long int length = identifier_vec.size();
2861  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2862  inbind[0].buffer = &identifier_vec[0];
2863  inbind[0].buffer_length = length;
2864  inbind[0].length = &length;
2865 
2866  ConstHostCollection result;
2868  impl_->host_ipv46_exchange_,
2869  result, false);
2870  return (result);
2871 }
2872 
2875 
2876  // Set up the WHERE clause value
2877  MYSQL_BIND inbind[1];
2878  memset(inbind, 0, sizeof(inbind));
2879 
2880  uint32_t addr4 = address.toUint32();
2881  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2882  inbind[0].buffer = reinterpret_cast<char*>(&addr4);
2883  inbind[0].is_unsigned = MLM_TRUE;
2884 
2885  ConstHostCollection result;
2887  impl_->host_exchange_, result, false);
2888 
2889  return (result);
2890 }
2891 
2894  const Host::IdentifierType& identifier_type,
2895  const uint8_t* identifier_begin,
2896  const size_t identifier_len) const {
2897 
2898  return (impl_->getHost(subnet_id, identifier_type, identifier_begin,
2900  impl_->host_exchange_));
2901 }
2902 
2905  const asiolink::IOAddress& address) const {
2906  // Check that address is IPv4, not IPv6.
2907  if (!address.isV4()) {
2908  isc_throw(BadValue, "MySqlHostDataSource::get4(2): wrong address type, "
2909  "address supplied is not an IPv4 address");
2910  }
2911 
2912  // Set up the WHERE clause value
2913  MYSQL_BIND inbind[2];
2914  uint32_t subnet = subnet_id;
2915  memset(inbind, 0, sizeof(inbind));
2916  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2917  inbind[0].buffer = reinterpret_cast<char*>(&subnet);
2918  inbind[0].is_unsigned = MLM_TRUE;
2919 
2920  uint32_t addr4 = address.toUint32();
2921  inbind[1].buffer_type = MYSQL_TYPE_LONG;
2922  inbind[1].buffer = reinterpret_cast<char*>(&addr4);
2923  inbind[1].is_unsigned = MLM_TRUE;
2924 
2925  ConstHostCollection collection;
2927  inbind, impl_->host_exchange_, collection, true);
2928 
2929  // Return single record if present, else clear the host.
2930  ConstHostPtr result;
2931  if (!collection.empty())
2932  result = *collection.begin();
2933 
2934  return (result);
2935 }
2936 
2939  const Host::IdentifierType& identifier_type,
2940  const uint8_t* identifier_begin,
2941  const size_t identifier_len) const {
2942 
2943  return (impl_->getHost(subnet_id, identifier_type, identifier_begin,
2945  impl_->host_ipv6_exchange_));
2946 }
2947 
2950  const uint8_t prefix_len) const {
2952 
2953  // Set up the WHERE clause value
2954  MYSQL_BIND inbind[2];
2955  memset(inbind, 0, sizeof(inbind));
2956 
2957  std::string addr6 = prefix.toText();
2958  unsigned long addr6_length = addr6.size();
2959 
2960  inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2961  inbind[0].buffer = reinterpret_cast<char*>
2962  (const_cast<char*>(addr6.c_str()));
2963  inbind[0].length = &addr6_length;
2964  inbind[0].buffer_length = addr6_length;
2965 
2966  uint8_t tmp = prefix_len;
2967  inbind[1].buffer_type = MYSQL_TYPE_TINY;
2968  inbind[1].buffer = reinterpret_cast<char*>(&tmp);
2969  inbind[1].is_unsigned = MLM_TRUE;
2970 
2971  ConstHostCollection collection;
2973  inbind, impl_->host_ipv6_exchange_,
2974  collection, true);
2975 
2976  // Return single record if present, else clear the host.
2977  ConstHostPtr result;
2978  if (!collection.empty()) {
2979  result = *collection.begin();
2980  }
2981 
2982  return (result);
2983 }
2984 
2987  const asiolink::IOAddress& address) const {
2988  // Set up the WHERE clause value
2989  MYSQL_BIND inbind[2];
2990  memset(inbind, 0, sizeof(inbind));
2991 
2992  uint32_t subnet_buffer = static_cast<uint32_t>(subnet_id);
2993  inbind[0].buffer_type = MYSQL_TYPE_LONG;
2994  inbind[0].buffer = reinterpret_cast<char*>(&subnet_buffer);
2995  inbind[0].is_unsigned = MLM_TRUE;
2996 
2997  std::string addr6 = address.toText();
2998  unsigned long addr6_length = addr6.size();
2999 
3000  inbind[1].buffer_type = MYSQL_TYPE_BLOB;
3001  inbind[1].buffer = reinterpret_cast<char*>
3002  (const_cast<char*>(addr6.c_str()));
3003  inbind[1].length = &addr6_length;
3004  inbind[1].buffer_length = addr6_length;
3005 
3006  ConstHostCollection collection;
3008  inbind, impl_->host_ipv6_exchange_,
3009  collection, true);
3010 
3011  // Return single record if present, else clear the host.
3012  ConstHostPtr result;
3013  if (!collection.empty()) {
3014  result = *collection.begin();
3015  }
3016 
3017  return (result);
3018 }
3019 
3020 // Miscellaneous database methods.
3021 
3022 std::string MySqlHostDataSource::getName() const {
3023  std::string name = "";
3024  try {
3025  name = impl_->conn_.getParameter("name");
3026  } catch (...) {
3027  // Return an empty name
3028  }
3029  return (name);
3030 }
3031 
3033  return (std::string("Host data source that stores host information"
3034  "in MySQL database"));
3035 }
3036 
3037 std::pair<uint32_t, uint32_t> MySqlHostDataSource::getVersion() const {
3038  return(impl_->getVersion());
3039 }
3040 
3041 void
3043  // If operating in read-only mode, throw exception.
3044  impl_->checkReadOnly();
3045  impl_->conn_.commit();
3046 }
3047 
3048 void
3050  // If operating in read-only mode, throw exception.
3051  impl_->checkReadOnly();
3052  impl_->conn_.rollback();
3053 }
3054 
3055 }; // end of isc::dhcp namespace
3056 }; // end of isc namespace
code_
uint16_t code_
Definition: rrparamregistry.cc:71
isc::dhcp::MySqlHostDataSourceImpl::host_ipv46_exchange_
boost::shared_ptr< MySqlHostIPv6Exchange > host_ipv46_exchange_
Pointer to an object representing an exchange which can be used to retrieve hosts,...
Definition: mysql_host_data_source.cc:2113
isc::dhcp::OptionContainerPtr
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
Definition: cfg_option.h:206
isc::dhcp::IPv6Resrv::getType
Type getType() const
Returns reservation type.
Definition: host.h:149
isc::dhcp::OptionBuffer
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:25
optional_value.h
isc::util::OptionalValue
Simple class representing an optional value.
Definition: optional_value.h:55
isc::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition: exceptions/exceptions.h:153
option_space.h
isc::dhcp::AuthKey
Authentication keys.
Definition: host.h:34
isc::dhcp::ConstCfgOptionPtr
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
Definition: cfg_option.h:500
isc::dhcp::MySqlHostDataSourceImpl::host_ipv6_exchange_
boost::shared_ptr< MySqlHostIPv6Exchange > host_ipv6_exchange_
Pointer to an object representing an exchange which can be used to retrieve hosts,...
Definition: mysql_host_data_source.cc:2108
isc::dhcp::MySqlHostDataSourceImpl::getHost
ConstHostPtr getHost(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len, StatementIndex stindex, boost::shared_ptr< MySqlHostExchange > exchange) const
Retrieves a host by subnet and client's unique identifier.
Definition: mysql_host_data_source.cc:2630
isc::dhcp::MySqlHostDataSourceImpl::GET_HOST_ADDR
@ GET_HOST_ADDR
Definition: mysql_host_data_source.cc:1941
isc::dhcp::OptionDefinitionPtr
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
Definition: option_definition.h:51
isc::dhcp::Host::IdentifierType
IdentifierType
Type of the host identifier.
Definition: host.h:252
isc::dhcp::TaggedStatementArray
boost::array< TaggedStatement, MySqlHostDataSourceImpl::NUM_STATEMENTS > TaggedStatementArray
Array of tagged statements.
Definition: mysql_host_data_source.cc:2133
isc::dhcp::MySqlHostDataSource::getAll
virtual ConstHostCollection getAll(const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Return all hosts connected to any subnet for which reservations have been made using a specified iden...
Definition: mysql_host_data_source.cc:2844
isc::dhcp::MySqlHostDataSource::commit
virtual void commit()
Commit Transactions.
Definition: mysql_host_data_source.cc:3042
isc::dhcp::MySqlHostDataSourceImpl::host_exchange_
boost::shared_ptr< MySqlHostWithOptionsExchange > host_exchange_
Pointer to the object representing an exchange which can be used to retrieve hosts and DHCPv4 options...
Definition: mysql_host_data_source.cc:2104
isc::dhcp::MySqlHostDataSourceImpl::addStatement
void addStatement(MySqlHostDataSourceImpl::StatementIndex stindex, std::vector< MYSQL_BIND > &bind)
Executes statements which inserts a row into one of the tables.
Definition: mysql_host_data_source.cc:2473
isc::db
Definition: cql_connection.cc:29
isc::dhcp::MySqlHostDataSource::getName
virtual std::string getName() const
Returns backend name.
Definition: mysql_host_data_source.cc:3022
libdhcp++.h
isc::dhcp::MySqlHostDataSource::get6
virtual ConstHostPtr get6(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Returns a host connected to the IPv6 subnet.
Definition: mysql_host_data_source.cc:2938
isc::dhcp::MySqlHostDataSourceImpl::host_option_exchange_
boost::shared_ptr< MySqlOptionExchange > host_option_exchange_
Pointer to an object representing an exchange which can be used to insert DHCPv4 or DHCPv6 option int...
Definition: mysql_host_data_source.cc:2122
isc::dhcp::MySqlHostDataSourceImpl::checkError
void checkError(const int status, const StatementIndex index, const char *what) const
Check Error and Throw Exception.
Definition: mysql_host_data_source.cc:2561
isc::util::OptionalValue::isSpecified
bool isSpecified() const
Checks if the value is specified or unspecified.
Definition: optional_value.h:110
isc::dhcp::DHCPSRV_DBG_TRACE_DETAIL
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
isc::db::MySqlConnection::checkError
void checkError(const int status, const StatementIndex &index, const char *what) const
Check Error and Throw Exception.
Definition: mysql_connection.h:529
isc::db::DatabaseConnection::configuredReadOnly
bool configuredReadOnly() const
Convenience method checking if database should be opened with read only access.
Definition: database_connection.cc:95
DHCP6_OPTION_SPACE
#define DHCP6_OPTION_SPACE
Definition: option_space.h:17
isc::dhcp::Host
Represents a device with IPv4 and/or IPv6 reservations.
Definition: host.h:242
db_exceptions.h
isc::db::ReadOnlyDb
Attempt to modify data in read-only database.
Definition: db_exceptions.h:49
isc::dhcp::MySqlHostDataSourceImpl::GET_HOST_SUBID6_DHCPID
@ GET_HOST_SUBID6_DHCPID
Definition: mysql_host_data_source.cc:1943
isc::db::MySqlFreeResult
Fetch and Release MySQL Results.
Definition: mysql_connection.h:42
isc::db::MySqlConnection::statements_
std::vector< MYSQL_STMT * > statements_
Prepared statements.
Definition: mysql_connection.h:574
isc::dhcp::MySqlHostDataSourceImpl::checkReadOnly
void checkReadOnly() const
Throws exception if database is read only.
Definition: mysql_host_data_source.cc:2673
isc::dhcp::HostPtr
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
Definition: host.h:725
isc::data
Definition: cfg_to_element.h:25
isc::dhcp::MySqlHostDataSourceImpl
Implementation of the MySqlHostDataSource.
Definition: mysql_host_data_source.cc:1930
isc::dhcp::MySqlHostDataSourceImpl::addOptions
void addOptions(const StatementIndex &stindex, const ConstCfgOptionPtr &options_cfg, const uint64_t host_id)
Inserts multiple options into the database.
Definition: mysql_host_data_source.cc:2534
isc::dhcp::OptionDescriptor::persistent_
bool persistent_
Persistence flag.
Definition: cfg_option.h:44
isc::dhcp::MySqlHostDataSourceImpl::getHostCollection
void getHostCollection(StatementIndex stindex, MYSQL_BIND *bind, boost::shared_ptr< MySqlHostExchange > exchange, ConstHostCollection &result, bool single) const
Creates collection of Host objects with associated information such as IPv6 reservations and/or DHCP ...
Definition: mysql_host_data_source.cc:2568
isc::dhcp::MySqlHostDataSourceImpl::is_readonly_
bool is_readonly_
Indicates if the database is opened in read only mode.
Definition: mysql_host_data_source.cc:2128
isc::dhcp::MySqlHostDataSourceImpl::GET_HOST_SUBID_ADDR
@ GET_HOST_SUBID_ADDR
Definition: mysql_host_data_source.cc:1944
isc::data::UserContext::getContext
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
Definition: user_context.h:24
isc::dhcp::IPv6Resrv::getPrefix
const asiolink::IOAddress & getPrefix() const
Returns prefix for the reservation.
Definition: host.h:135
isc::dhcp::MySqlHostDataSourceImpl::WRITE_STMTS_BEGIN
static const StatementIndex WRITE_STMTS_BEGIN
Index of first statement performing write to the database.
Definition: mysql_host_data_source.cc:1962
isc::util
Definition: edns.h:19
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc::dhcp::MySqlHostDataSource::del
virtual bool del(const SubnetID &subnet_id, const asiolink::IOAddress &addr)
Attempts to delete a host by (subnet-id, address)
Definition: mysql_host_data_source.cc:2737
isc::dhcp::MySqlHostDataSourceImpl::addResv
void addResv(const IPv6Resrv &resv, const HostID &id)
Inserts IPv6 Reservation into ipv6_reservation table.
Definition: mysql_host_data_source.cc:2512
isc::db::DatabaseConnection::getParameter
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
Definition: database_connection.cc:28
isc::Exception::what
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Definition: exceptions/exceptions.cc:32
isc::dhcp::MySqlHostDataSource::getDescription
virtual std::string getDescription() const
Returns description of the backend.
Definition: mysql_host_data_source.cc:3032
isc::dhcp::MySqlHostDataSourceImpl::~MySqlHostDataSourceImpl
~MySqlHostDataSourceImpl()
Destructor.
Definition: mysql_host_data_source.cc:2396
isc::dhcp::IPv6Resrv::Type
Type
Type of the reservation.
Definition: host.h:112
isc::db::DbOperationError
Exception thrown on failure to execute a database function.
Definition: database_connection.h:36
isc::dhcp::MySqlHostDataSource::getVersion
virtual std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
Definition: mysql_host_data_source.cc:3037
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::dhcp::MySqlHostDataSourceImpl::StatementIndex
StatementIndex
Statement Tags.
Definition: mysql_host_data_source.cc:1939
LOG_DEBUG
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
isc::db::MySqlConnection::text_statements_
std::vector< std::string > text_statements_
Raw text of statements.
Definition: mysql_connection.h:580
isc::db::MLM_FALSE
const my_bool MLM_FALSE
MySQL false value.
Definition: mysql_constants.h:20
isc::db::MySqlTransaction
RAII object representing MySQL transaction.
Definition: mysql_connection.h:150
dhcpsrv_log.h
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: exceptions/exceptions.h:132
isc::dhcp::MySqlHostDataSource::MySqlHostDataSource
MySqlHostDataSource(const db::DatabaseConnection::ParameterMap &parameters)
Constructor.
Definition: mysql_host_data_source.cc:2681
isc::dhcp::MySqlHostDataSourceImpl::INSERT_V6_RESRV
@ INSERT_V6_RESRV
Definition: mysql_host_data_source.cc:1948
isc::dhcp::MySqlHostDataSource::getAll4
virtual ConstHostCollection getAll4(const asiolink::IOAddress &address) const
Returns a collection of hosts using the specified IPv4 address.
Definition: mysql_host_data_source.cc:2874
isc::dhcp::MySqlHostDataSourceImpl::host_ipv6_reservation_exchange_
boost::shared_ptr< MySqlIPv6ReservationExchange > host_ipv6_reservation_exchange_
Pointer to an object representing an exchange which can be used to insert new IPv6 reservation.
Definition: mysql_host_data_source.cc:2117
isc::dhcp::IPv6Resrv
IPv6 reservation for a host.
Definition: host.h:106
isc::dhcp::MySqlHostDataSourceImpl::GET_HOST_PREFIX
@ GET_HOST_PREFIX
Definition: mysql_host_data_source.cc:1945
isc::dhcp
Definition: ctrl_dhcp4_srv.cc:75
cfg_option.h
isc::dhcp::MySqlHostDataSource::add
virtual void add(const HostPtr &host)
Adds a new host to the collection.
Definition: mysql_host_data_source.cc:2690
DHCP4_OPTION_SPACE
#define DHCP4_OPTION_SPACE
Definition: option_space.h:16
isc::data::JSONError
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
Definition: data.h:43
isc::util::OutputBuffer
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
isc::dhcp::MySqlHostDataSource::del4
virtual bool del4(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len)
Attempts to delete a host by (subnet4-id, identifier type, identifier)
Definition: mysql_host_data_source.cc:2772
mysql_host_data_source.h
isc::db::MySqlConnection::rollback
void rollback()
Rollback Transactions.
Definition: mysql_connection.cc:333
isc::db::MLM_TRUE
const my_bool MLM_TRUE
MySQL true value.
Definition: mysql_constants.h:23
isc::dhcp::MySqlHostDataSource::del6
virtual bool del6(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len)
Attempts to delete a host by (subnet6-id, identifier type, identifier)
Definition: mysql_host_data_source.cc:2808
isc::dhcp::MySqlHostDataSourceImpl::DEL_HOST_SUBID6_ID
@ DEL_HOST_SUBID6_ID
Definition: mysql_host_data_source.cc:1953
option_definition.h
isc::db::MySqlConnection::commit
void commit()
Commit Transactions.
Definition: mysql_connection.cc:324
isc::dhcp::MySqlHostDataSource::get4
virtual ConstHostPtr get4(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Returns a host connected to the IPv4 subnet.
Definition: mysql_host_data_source.cc:2893
isc::dhcp::MySqlHostDataSourceImpl::GET_HOST_DHCPID
@ GET_HOST_DHCPID
Definition: mysql_host_data_source.cc:1940
isc::db::MySqlConnection
Common MySQL Connector Pool.
Definition: mysql_connection.h:191
isc::db::MultipleRecords
Multiple lease records found where one expected.
Definition: db_exceptions.h:28
isc::dhcp::HostID
uint64_t HostID
HostID (used only when storing in MySQL, PostgreSQL or Cassandra)
Definition: host.h:28
isc::dhcp::MySqlHostDataSourceImpl::delStatement
bool delStatement(StatementIndex stindex, MYSQL_BIND *bind)
Executes statements that delete records.
Definition: mysql_host_data_source.cc:2493
isc::dhcp::MySqlHostDataSourceImpl::DEL_HOST_SUBID4_ID
@ DEL_HOST_SUBID4_ID
Definition: mysql_host_data_source.cc:1952
buffer.h
isc::dhcp::OptionDescriptor::option_
OptionPtr option_
Option instance.
Definition: cfg_option.h:38
isc::dhcp::MySqlHostDataSourceImpl::GET_HOST_SUBID4_DHCPID
@ GET_HOST_SUBID4_DHCPID
Definition: mysql_host_data_source.cc:1942
isc::dhcp::MySqlHostDataSourceImpl::INSERT_V6_OPTION
@ INSERT_V6_OPTION
Definition: mysql_host_data_source.cc:1950
isc::db::MLM_MYSQL_FETCH_SUCCESS
const int MLM_MYSQL_FETCH_SUCCESS
MySQL fetch success code.
Definition: mysql_constants.h:26
isc::db::MySqlTransaction::commit
void commit()
Commits transaction.
Definition: mysql_connection.cc:43
isc::dhcp::ConstHostCollection
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
Definition: host.h:731
isc::dhcp::MySqlHostDataSourceImpl::getVersion
std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
Definition: mysql_host_data_source.cc:2412
isc::db::DuplicateEntry
Database duplicate entry error.
Definition: db_exceptions.h:42
isc::dhcp::OptionPtr
boost::shared_ptr< Option > OptionPtr
Definition: option.h:37
isc::db::MYSQL_SCHEMA_VERSION_MINOR
const uint32_t MYSQL_SCHEMA_VERSION_MINOR
Definition: mysql_constants.h:36
isc::dhcp::ConstHostPtr
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Definition: host.h:728
isc::dhcp::OptionDescriptor
Option descriptor.
Definition: cfg_option.h:35
isc::dhcp::MySqlHostDataSourceImpl::DEL_HOST_ADDR4
@ DEL_HOST_ADDR4
Definition: mysql_host_data_source.cc:1951
isc::dhcp::IPv6Resrv::getPrefixLen
uint8_t getPrefixLen() const
Returns prefix length.
Definition: host.h:140
isc::db::DataTruncated
Data is truncated.
Definition: db_exceptions.h:35
isc::dhcp::CfgOptionPtr
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Definition: cfg_option.h:497
isc::dhcp::Option::Universe
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:67
isc::dhcp::tagged_statements
TaggedStatementArray tagged_statements
Prepared MySQL statements used by the backend to insert and retrieve hosts from the database.
Definition: mysql_host_data_source.cc:2137
isc::data::ConstElementPtr
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
isc::db::DbOpenError
Exception thrown on failure to open database.
Definition: database_connection.h:29
isc::dhcp::MySqlHostDataSource::rollback
virtual void rollback()
Rollback Transactions.
Definition: mysql_host_data_source.cc:3049
isc::dhcp::SubnetID
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
option.h
isc::dhcp::MySqlHostDataSourceImpl::INSERT_V4_OPTION
@ INSERT_V4_OPTION
Definition: mysql_host_data_source.cc:1949
isc::db::MLM_MYSQL_FETCH_FAILURE
const int MLM_MYSQL_FETCH_FAILURE
MySQL fetch failure code.
Definition: mysql_constants.h:29
isc::db::MySqlConnection::mysql_
MySqlHolder mysql_
MySQL connection handle.
Definition: mysql_connection.h:586
isc::dhcp::MySqlHostDataSourceImpl::INSERT_HOST
@ INSERT_HOST
Definition: mysql_host_data_source.cc:1947
isc::db::MYSQL_SCHEMA_VERSION_MAJOR
const uint32_t MYSQL_SCHEMA_VERSION_MAJOR
Definition: mysql_constants.h:35
isc::dhcp::MySqlHostDataSourceImpl::addOption
void addOption(const MySqlHostDataSourceImpl::StatementIndex &stindex, const OptionDescriptor &opt_desc, const std::string &opt_space, const OptionalValue< SubnetID > &subnet_id, const HostID &host_id)
Inserts a single DHCP option into the database.
Definition: mysql_host_data_source.cc:2521
isc::dhcp::MySqlHostDataSource::~MySqlHostDataSource
virtual ~MySqlHostDataSource()
Virtual destructor.
Definition: mysql_host_data_source.cc:2685
isc::dhcp::MySqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR
@ GET_HOST_SUBID6_ADDR
Definition: mysql_host_data_source.cc:1946
isc::dhcp::IPv6ResrvIterator
IPv6ResrvCollection::const_iterator IPv6ResrvIterator
Definition: host.h:186
isc::dhcp::Option
Definition: option.h:58
isc::dhcp::MySqlHostDataSourceImpl::conn_
MySqlConnection conn_
MySQL connection.
Definition: mysql_host_data_source.cc:2125
isc::db::MySqlConnection::openDatabase
void openDatabase()
Open Database.
Definition: mysql_connection.cc:52
isc::db::MySqlConnection::prepareStatements
void prepareStatements(const TaggedStatement *start_statement, const TaggedStatement *end_statement)
Prepare statements.
Definition: mysql_connection.cc:247
isc::dhcp::OptionDescriptor::formatted_value_
std::string formatted_value_
Option value in textual (CSV) format.
Definition: cfg_option.h:59
LOG_INFO
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
isc::dhcp::dhcpsrv_logger
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
isc::dhcp::IPv6ResrvRange
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
Definition: host.h:188