Kea 2.7.0
pgsql_host_data_source.cc
Go to the documentation of this file.
1// Copyright (C) 2016-2024 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
11#include <dhcp/libdhcp++.h>
12#include <dhcp/option.h>
14#include <dhcp/option_space.h>
16#include <dhcpsrv/cfg_option.h>
17#include <dhcpsrv/cfgmgr.h>
18#include <dhcpsrv/dhcpsrv_log.h>
19#include <dhcpsrv/host_mgr.h>
21#include <dhcpsrv/timer_mgr.h>
22#include <util/buffer.h>
24#include <util/optional.h>
25
26#include <boost/algorithm/string/split.hpp>
27#include <boost/algorithm/string/classification.hpp>
28#include <boost/array.hpp>
29#include <boost/foreach.hpp>
30#include <boost/pointer_cast.hpp>
31#include <boost/static_assert.hpp>
32
33#include <stdint.h>
34
35#include <mutex>
36#include <string>
37
38using namespace isc;
39using namespace isc::asiolink;
40using namespace isc::db;
41using namespace isc::dhcp;
42using namespace isc::util;
43using namespace isc::data;
44using namespace std;
45
46namespace {
47
51const size_t OPTION_VALUE_MAX_LEN = 4096;
52
57const uint8_t MAX_IDENTIFIER_TYPE = static_cast<uint8_t>(Host::LAST_IDENTIFIER_TYPE);
58
60const size_t DHCP_IDENTIFIER_MAX_LEN = ClientId::MAX_CLIENT_ID_LEN;
61
88class PgSqlHostExchange : public PgSqlExchange {
89private:
90
95 static const size_t HOST_ID_COL = 0;
96 static const size_t DHCP_IDENTIFIER_COL = 1;
97 static const size_t DHCP_IDENTIFIER_TYPE_COL = 2;
98 static const size_t DHCP4_SUBNET_ID_COL = 3;
99 static const size_t DHCP6_SUBNET_ID_COL = 4;
100 static const size_t IPV4_ADDRESS_COL = 5;
101 static const size_t HOSTNAME_COL = 6;
102 static const size_t DHCP4_CLIENT_CLASSES_COL = 7;
103 static const size_t DHCP6_CLIENT_CLASSES_COL = 8;
104 static const size_t USER_CONTEXT_COL = 9;
105 static const size_t DHCP4_NEXT_SERVER_COL = 10;
106 static const size_t DHCP4_SERVER_HOSTNAME_COL = 11;
107 static const size_t DHCP4_BOOT_FILE_NAME_COL = 12;
108 static const size_t AUTH_KEY_COL = 13;
110 static const size_t HOST_COLUMNS = 14;
111
112public:
113
120 PgSqlHostExchange(const size_t additional_columns_num = 0)
121 : PgSqlExchange(HOST_COLUMNS + additional_columns_num) {
122 // Set the column names for use by this class. This only comprises
123 // names used by the PgSqlHostExchange class. Derived classes will
124 // need to set names for the columns they use. Currently these are
125 // only used for logging purposes.
126 columns_[HOST_ID_COL] = "host_id";
127 columns_[DHCP_IDENTIFIER_COL] = "dhcp_identifier";
128 columns_[DHCP_IDENTIFIER_TYPE_COL] = "dhcp_identifier_type";
129 columns_[DHCP4_SUBNET_ID_COL] = "dhcp4_subnet_id";
130 columns_[DHCP6_SUBNET_ID_COL] = "dhcp6_subnet_id";
131 columns_[IPV4_ADDRESS_COL] = "ipv4_address";
132 columns_[HOSTNAME_COL] = "hostname";
133 columns_[DHCP4_CLIENT_CLASSES_COL] = "dhcp4_client_classes";
134 columns_[DHCP6_CLIENT_CLASSES_COL] = "dhcp6_client_classes";
135 columns_[USER_CONTEXT_COL] = "user_context";
136 columns_[DHCP4_NEXT_SERVER_COL] = "dhcp4_next_server";
137 columns_[DHCP4_SERVER_HOSTNAME_COL] = "dhcp4_server_hostname";
138 columns_[DHCP4_BOOT_FILE_NAME_COL] = "dhcp4_boot_file_name";
139 columns_[AUTH_KEY_COL] = "auth_key";
140
141 BOOST_STATIC_ASSERT(12 < HOST_COLUMNS);
142 };
143
145 virtual ~PgSqlHostExchange() {
146 }
147
153 virtual void clear() {
154 host_.reset();
155 };
156
171 size_t findAvailColumn() const {
172 std::vector<std::string>::const_iterator empty_column =
173 std::find(columns_.begin(), columns_.end(), std::string());
174 return (std::distance(columns_.begin(), empty_column));
175 }
176
181 HostID getHostId(const PgSqlResult& r, int row) {
182 HostID host_id;
183 getColumnValue(r, row, HOST_ID_COL, host_id);
184 return (host_id);
185 }
186
202 PsqlBindArrayPtr createBindForSend(const HostPtr& host, const bool unique_ip) {
203 if (!host) {
204 isc_throw(BadValue, "createBindForSend:: host object is NULL");
205 }
206
207 // Store the host to ensure bound values remain in scope
208 host_ = host;
209
210 // Bind the host data to the array
211 PsqlBindArrayPtr bind_array(new PsqlBindArray());
212 try {
213 // host_id : is auto_incremented skip it
214
215 // dhcp_identifier : BYTEA NOT NULL
216 bind_array->add(host->getIdentifier());
217
218 // dhcp_identifier_type : SMALLINT NOT NULL
219 bind_array->add(host->getIdentifierType());
220
221 // dhcp4_subnet_id : INT NULL
222 if (host->getIPv4SubnetID() == SUBNET_ID_UNUSED) {
223 bind_array->addNull();
224 } else {
225 bind_array->add(host->getIPv4SubnetID());
226 }
227
228 // dhcp6_subnet_id : INT NULL
229 if (host->getIPv6SubnetID() == SUBNET_ID_UNUSED) {
230 bind_array->addNull();
231 } else {
232 bind_array->add(host->getIPv6SubnetID());
233 }
234
235 // ipv4_address : BIGINT NULL
236 bind_array->add((host->getIPv4Reservation()));
237
238 // hostname : VARCHAR(255) NULL
239 bind_array->add(host->getHostname());
240
241 // dhcp4_client_classes : VARCHAR(255) NULL
242 // Override default separator to not include space after comma.
243 bind_array->addTempString(host->getClientClasses4().toText(","));
244
245 // dhcp6_client_classes : VARCHAR(255) NULL
246 bind_array->addTempString(host->getClientClasses6().toText(","));
247
248 // user_context: TEXT NULL
249 ConstElementPtr ctx = host->getContext();
250 if (ctx) {
251 std::string user_context_ = ctx->str();
252 bind_array->addTempString(user_context_);
253 } else {
254 bind_array->addNull();
255 }
256
257 // dhcp4_next_server : BIGINT NULL
258 bind_array->add((host->getNextServer()));
259
260 // dhcp4_server_hostname : VARCHAR(64)
261 bind_array->add(host->getServerHostname());
262
263 // dhcp4_boot_file_name : VARCHAR(128)
264 bind_array->add(host->getBootFileName());
265
266 // add auth keys
267 std::string key = host->getKey().toText();
268 if (key.empty()) {
269 bind_array->addNull();
270 } else {
271 bind_array->addTempString(key);
272 }
273
274 // When checking whether the IP is unique we need to bind the IPv4 address
275 // at the end of the query as it has additional binding for the IPv4
276 // address.
277 if (unique_ip) {
278 bind_array->add(host->getIPv4Reservation()); // ipv4_address
279 bind_array->add(host->getIPv4SubnetID()); // subnet_id
280 }
281
282 } catch (const std::exception& ex) {
283 host_.reset();
285 "Could not create bind array from Host: "
286 << host->getHostname() << ", reason: " << ex.what());
287 }
288
289 return (bind_array);
290 };
291
305 virtual void processRowData(ConstHostCollection& hosts,
306 const PgSqlResult& r, int row) {
307 // Peek at the host id , so we can skip it if we already have it
308 // This lets us avoid constructing a copy of host for each
309 // of its sub-rows (options, etc...)
310 HostID row_host_id = getHostId(r, row);
311
312 // Add new host only if there are no hosts or the host id of the
313 // most recently added host is different than the host id of the
314 // currently processed host.
315 if (hosts.empty() || row_host_id != hosts.back()->getHostId()) {
316 HostPtr host = retrieveHost(r, row, row_host_id);
317 hosts.push_back(host);
318 }
319 }
320
332 HostPtr retrieveHost(const PgSqlResult& r, int row,
333 const HostID& peeked_host_id = 0) {
334
335 // If the caller peeked ahead at the host_id use that, otherwise
336 // read it from the row.
337 HostID host_id = (peeked_host_id ? peeked_host_id : getHostId(r,row));
338
339 // dhcp_identifier : BYTEA NOT NULL
340 uint8_t identifier_value[DHCP_IDENTIFIER_MAX_LEN];
341 size_t identifier_len;
342 convertFromBytea(r, row, DHCP_IDENTIFIER_COL, identifier_value,
343 sizeof(identifier_value), identifier_len);
344
345 // dhcp_identifier_type : SMALLINT NOT NULL
346 uint8_t type;
347 getColumnValue(r, row, DHCP_IDENTIFIER_TYPE_COL, type);
348 if (type > MAX_IDENTIFIER_TYPE) {
349 isc_throw(BadValue, "invalid dhcp identifier type returned: "
350 << static_cast<int>(type));
351 }
352
353 Host::IdentifierType identifier_type =
354 static_cast<Host::IdentifierType>(type);
355
356 // dhcp4_subnet_id : INT NULL
357 uint32_t subnet_id(SUBNET_ID_UNUSED);
358 if (!isColumnNull(r, row, DHCP4_SUBNET_ID_COL)) {
359 getColumnValue(r, row, DHCP4_SUBNET_ID_COL, subnet_id);
360 }
361 SubnetID dhcp4_subnet_id = static_cast<SubnetID>(subnet_id);
362
363 // dhcp6_subnet_id : INT NULL
364 subnet_id = SUBNET_ID_UNUSED;
365 if (!isColumnNull(r, row, DHCP6_SUBNET_ID_COL)) {
366 getColumnValue(r, row, DHCP6_SUBNET_ID_COL, subnet_id);
367 }
368 SubnetID dhcp6_subnet_id = static_cast<SubnetID>(subnet_id);
369
370 // ipv4_address : BIGINT NULL
371 uint32_t addr4(0);
372 if (!isColumnNull(r, row, IPV4_ADDRESS_COL)) {
373 getColumnValue(r, row, IPV4_ADDRESS_COL, addr4);
374 }
375 isc::asiolink::IOAddress ipv4_reservation(addr4);
376
377 // hostname : VARCHAR(255) NULL
378 std::string hostname;
379 if (!isColumnNull(r, row, HOSTNAME_COL)) {
380 getColumnValue(r, row, HOSTNAME_COL, hostname);
381 }
382
383 // dhcp4_client_classes : VARCHAR(255) NULL
384 std::string dhcp4_client_classes;
385 if (!isColumnNull(r, row, DHCP4_CLIENT_CLASSES_COL)) {
386 getColumnValue(r, row, DHCP4_CLIENT_CLASSES_COL, dhcp4_client_classes);
387 }
388
389 // dhcp6_client_classes : VARCHAR(255) NULL
390 std::string dhcp6_client_classes;
391 if (!isColumnNull(r, row, DHCP6_CLIENT_CLASSES_COL)) {
392 getColumnValue(r, row, DHCP6_CLIENT_CLASSES_COL, dhcp6_client_classes);
393 }
394
395 // user_context: TEXT
396 std::string user_context;
397 if (!isColumnNull(r, row, USER_CONTEXT_COL)) {
398 getColumnValue(r, row, USER_CONTEXT_COL, user_context);
399 }
400
401 // dhcp4_next_server : BIGINT NULL
402 uint32_t dhcp4_next_server_as_uint32(0);
403 if (!isColumnNull(r, row, DHCP4_NEXT_SERVER_COL)) {
404 getColumnValue(r, row, DHCP4_NEXT_SERVER_COL, dhcp4_next_server_as_uint32);
405 }
406 isc::asiolink::IOAddress dhcp4_next_server(dhcp4_next_server_as_uint32);
407
408 // dhcp4_server_hostname : VARCHAR(64)
409 std::string dhcp4_server_hostname;
410 if (!isColumnNull(r, row, DHCP4_SERVER_HOSTNAME_COL)) {
411 getColumnValue(r, row, DHCP4_SERVER_HOSTNAME_COL, dhcp4_server_hostname);
412 }
413
414 // dhcp4_boot_file_name : VARCHAR(128)
415 std::string dhcp4_boot_file_name;
416 if (!isColumnNull(r, row, DHCP4_BOOT_FILE_NAME_COL)) {
417 getColumnValue(r, row, DHCP4_BOOT_FILE_NAME_COL, dhcp4_boot_file_name);
418 }
419
420 // auth_key : VARCHAR(16)
421 std::string auth_key;
422 if (!isColumnNull(r, row, AUTH_KEY_COL)) {
423 getColumnValue(r, row, AUTH_KEY_COL, auth_key);
424 }
425
426 // Finally, attempt to create the new host.
427 HostPtr host;
428 try {
429 host.reset(new Host(identifier_value, identifier_len,
430 identifier_type, dhcp4_subnet_id,
431 dhcp6_subnet_id, ipv4_reservation, hostname,
432 dhcp4_client_classes, dhcp6_client_classes,
433 dhcp4_next_server, dhcp4_server_hostname,
434 dhcp4_boot_file_name, AuthKey(auth_key)));
435
436 // Set the user context if there is one.
437 if (!user_context.empty()) {
438 try {
439 ConstElementPtr ctx = Element::fromJSON(user_context);
440 if (!ctx || (ctx->getType() != Element::map)) {
441 isc_throw(BadValue, "user context '" << user_context
442 << "' is not a JSON map");
443 }
444 host->setContext(ctx);
445 } catch (const isc::data::JSONError& ex) {
446 isc_throw(BadValue, "user context '" << user_context
447 << "' is invalid JSON: " << ex.what());
448 }
449 }
450
451 host->setHostId(host_id);
452 } catch (const isc::Exception& ex) {
453 isc_throw(DbOperationError, "Could not create host: " << ex.what());
454 }
455
456 return(host);
457 };
458
459protected:
462 HostPtr host_;
463};
464
474class PgSqlHostWithOptionsExchange : public PgSqlHostExchange {
475private:
476
478 static const size_t OPTION_COLUMNS = 8;
479
494 class OptionProcessor {
495 public:
496
503 OptionProcessor(const Option::Universe& universe,
504 const size_t start_column)
505 : universe_(universe), start_column_(start_column),
506 option_id_index_(start_column), code_index_(start_column_ + 1),
507 value_index_(start_column_ + 2),
508 formatted_value_index_(start_column_ + 3),
509 space_index_(start_column_ + 4),
510 persistent_index_(start_column_ + 5),
511 cancelled_index_(start_column_ + 6),
512 user_context_index_(start_column_ + 7),
513 most_recent_option_id_(0) {
514 }
515
520 void clear() {
521 most_recent_option_id_ = 0;
522 }
523
556 void retrieveOption(const CfgOptionPtr& cfg, const PgSqlResult& r,
557 int row) {
558 // If the option id on this row is NULL, then there's no
559 // option of this type (4/6) on this row to fetch, so bail.
560 if (PgSqlExchange::isColumnNull(r, row, option_id_index_)) {
561 return;
562 }
563
564 // option_id: INT
565 uint64_t option_id;
566 PgSqlExchange::getColumnValue(r, row, option_id_index_, option_id);
567
568 // The row option id must be greater than id if the most recent
569 // option because they are ordered by option id. Otherwise
570 // we assume that we have already processed this option.
571 if (most_recent_option_id_ >= option_id) {
572 return;
573 }
574
575 // Remember current option id as the most recent processed one. We
576 // will be comparing it with option ids in subsequent rows.
577 most_recent_option_id_ = option_id;
578
579 // code: SMALLINT NOT NULL
580 uint16_t code;
581 PgSqlExchange::getColumnValue(r, row, code_index_, code);
582
583 // value: BYTEA
584 uint8_t value[OPTION_VALUE_MAX_LEN];
585 size_t value_len(0);
586 if (!isColumnNull(r, row, value_index_)) {
587 PgSqlExchange::convertFromBytea(r, row, value_index_, value,
588 sizeof(value), value_len);
589 }
590
591 // formatted_value: TEXT
592 std::string formatted_value;
593 if (!isColumnNull(r, row, formatted_value_index_)) {
594 PgSqlExchange::getColumnValue(r, row, formatted_value_index_,
595 formatted_value);
596 }
597
598 // space: VARCHAR(128)
599 std::string space;
600 if (!isColumnNull(r, row, space_index_)) {
601 PgSqlExchange::getColumnValue(r, row, space_index_, space);
602 }
603
604 // If empty or null space provided, use a default top level space.
605 if (space.empty()) {
606 space = (universe_ == Option::V4 ?
608 }
609
610 // persistent: BOOL default false
611 bool persistent;
612 PgSqlExchange::getColumnValue(r, row, persistent_index_,
613 persistent);
614
615 // cancelled: BOOL default false
616 bool cancelled;
617 PgSqlExchange::getColumnValue(r, row, cancelled_index_,
618 cancelled);
619
620 // user_context: TEXT
621 std::string user_context;
622 if (!isColumnNull(r, row, user_context_index_)) {
623 PgSqlExchange::getColumnValue(r, row, user_context_index_,
624 user_context);
625 }
626
627 // Options are held in a binary or textual format in the database.
628 // This is similar to having an option specified in a server
629 // configuration file. Such option is converted to appropriate C++
630 // class, using option definition. Thus, we need to find the
631 // option definition for this option code and option space.
632
633 // If the option space is a standard DHCPv4 or DHCPv6 option space,
634 // this is most likely a standard option, for which we have a
635 // definition created within libdhcp++.
637
638 // Otherwise, we may check if this an option encapsulated within the
639 // vendor space.
640 if (!def && (space != DHCP4_OPTION_SPACE) &&
641 (space != DHCP6_OPTION_SPACE)) {
642 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(space);
643 if (vendor_id > 0) {
644 def = LibDHCP::getVendorOptionDef(universe_, vendor_id,
645 code);
646 }
647 }
648
649 // In all other cases, we use runtime option definitions, which
650 // should be also registered within the libdhcp++.
651 if (!def) {
652 def = LibDHCP::getRuntimeOptionDef(space, code);
653 }
654
655 // Finish with a last resort option definition.
656 if (!def) {
657 def = LibDHCP::getLastResortOptionDef(space, code);
658 }
659
660 OptionPtr option;
661
662 if (!def) {
663 // If no definition found, we use generic option type.
664 OptionBuffer buf(value, value + value_len);
665 option.reset(new Option(universe_, code, buf.begin(),
666 buf.end()));
667 } else {
668 // The option value may be specified in textual or binary format
669 // in the database. If formatted_value is empty, the binary
670 // format is used. Depending on the format we use a different
671 // variant of the optionFactory function.
672 if (formatted_value.empty()) {
673 OptionBuffer buf(value, value + value_len);
674 option = def->optionFactory(universe_, code, buf.begin(),
675 buf.end());
676 } else {
677 // Spit the value specified in comma separated values
678 // format.
679 std::vector<std::string> split_vec;
680 boost::split(split_vec, formatted_value,
681 boost::is_any_of(","));
682 option = def->optionFactory(universe_, code, split_vec);
683 }
684 }
685
686 OptionDescriptor desc(option, persistent, cancelled,
687 formatted_value);
688
689 // Set the user context if there is one into the option descriptor.
690 if (!user_context.empty()) {
691 try {
692 ConstElementPtr ctx = Element::fromJSON(user_context);
693 if (!ctx || (ctx->getType() != Element::map)) {
694 isc_throw(BadValue, "user context '" << user_context
695 << "' is no a JSON map");
696 }
697 desc.setContext(ctx);
698 } catch (const isc::data::JSONError& ex) {
699 isc_throw(BadValue, "user context '" << user_context
700 << "' is invalid JSON: " << ex.what());
701 }
702 }
703
704 cfg->add(desc, space);
705 }
706
711 void setColumnNames(std::vector<std::string>& columns) {
712 columns[option_id_index_] = "option_id";
713 columns[code_index_] = "code";
714 columns[value_index_] = "value";
715 columns[formatted_value_index_] = "formatted_value";
716 columns[space_index_] = "space";
717 columns[persistent_index_] = "persistent";
718 columns[cancelled_index_] = "cancelled";
719 columns[user_context_index_] = "user_context";
720 }
721
722 private:
724 Option::Universe universe_;
725
727 size_t start_column_;
728
730
732
733
734 size_t option_id_index_;
735
737 size_t code_index_;
738
740 size_t value_index_;
741
743 size_t formatted_value_index_;
744
746 size_t space_index_;
747
749 size_t persistent_index_;
750
752 size_t cancelled_index_;
754
756 size_t user_context_index_;
757
759 uint64_t most_recent_option_id_;
760 };
761
763 typedef boost::shared_ptr<OptionProcessor> OptionProcessorPtr;
764
765public:
766
773 enum FetchedOptions {
774 DHCP4_ONLY,
775 DHCP6_ONLY,
776 DHCP4_AND_DHCP6
777 };
778
787 PgSqlHostWithOptionsExchange(const FetchedOptions& fetched_options,
788 const size_t additional_columns_num = 0)
789 : PgSqlHostExchange(getRequiredColumnsNum(fetched_options)
790 + additional_columns_num),
791 opt_proc4_(), opt_proc6_() {
792
793 // Create option processor for DHCPv4 options, if required.
794 if ((fetched_options == DHCP4_ONLY) ||
795 (fetched_options == DHCP4_AND_DHCP6)) {
796 opt_proc4_.reset(new OptionProcessor(Option::V4,
797 findAvailColumn()));
798 opt_proc4_->setColumnNames(columns_);
799 }
800
801 // Create option processor for DHCPv6 options, if required.
802 if ((fetched_options == DHCP6_ONLY) ||
803 (fetched_options == DHCP4_AND_DHCP6)) {
804 opt_proc6_.reset(new OptionProcessor(Option::V6,
805 findAvailColumn()));
806 opt_proc6_->setColumnNames(columns_);
807 }
808 }
809
815 virtual void clear() {
816 PgSqlHostExchange::clear();
817 if (opt_proc4_) {
818 opt_proc4_->clear();
819 }
820
821 if (opt_proc6_) {
822 opt_proc6_->clear();
823 }
824 }
825
835 virtual void processRowData(ConstHostCollection& hosts,
836 const PgSqlResult& r, int row) {
837 HostPtr current_host;
838 if (hosts.empty()) {
839 // Must be the first one, fetch it.
840 current_host = retrieveHost(r, row);
841 hosts.push_back(current_host);
842 } else {
843 // Peek at the host id so we can skip it if we already have
844 // this host. This lets us avoid retrieving the host needlessly
845 // for each of its sub-rows (options, etc...).
846 HostID row_host_id = getHostId(r, row);
847 current_host = boost::const_pointer_cast<Host>(hosts.back());
848
849 // if the row's host id is greater than the one we've been
850 // working on we're starting a new host, so fetch it.
851 if (row_host_id > current_host->getHostId()) {
852 current_host = retrieveHost(r, row, row_host_id);
853 hosts.push_back(current_host);
854 }
855 }
856
857 // Parse DHCPv4 options if required to do so.
858 if (opt_proc4_) {
859 CfgOptionPtr cfg = current_host->getCfgOption4();
860 opt_proc4_->retrieveOption(cfg, r, row);
861 }
862
863 // Parse DHCPv6 options if required to do so.
864 if (opt_proc6_) {
865 CfgOptionPtr cfg = current_host->getCfgOption6();
866 opt_proc6_->retrieveOption(cfg, r, row);
867 }
868 }
869
870private:
871
883 static size_t getRequiredColumnsNum(const FetchedOptions& fetched_options) {
884 return (fetched_options == DHCP4_AND_DHCP6 ? 2 * OPTION_COLUMNS :
885 OPTION_COLUMNS);
886 }
887
891 OptionProcessorPtr opt_proc4_;
892
896 OptionProcessorPtr opt_proc6_;
897};
898
911class PgSqlHostIPv6Exchange : public PgSqlHostWithOptionsExchange {
912private:
913
915 static const size_t RESERVATION_COLUMNS = 5;
916
917public:
918
923 PgSqlHostIPv6Exchange(const FetchedOptions& fetched_options)
924 : PgSqlHostWithOptionsExchange(fetched_options, RESERVATION_COLUMNS),
925 reservation_id_index_(findAvailColumn()),
926 address_index_(reservation_id_index_ + 1),
927 prefix_len_index_(reservation_id_index_ + 2),
928 type_index_(reservation_id_index_ + 3),
929 iaid_index_(reservation_id_index_ + 4),
930 most_recent_reservation_id_(0) {
931
932 // Provide names of additional columns returned by the queries.
933 columns_[reservation_id_index_] = "reservation_id";
934 columns_[address_index_] = "address";
935 columns_[prefix_len_index_] = "prefix_len";
936 columns_[type_index_] = "type";
937 columns_[iaid_index_] = "dhcp6_iaid";
938
939 BOOST_STATIC_ASSERT(4 < RESERVATION_COLUMNS);
940 }
941
947 void clear() {
948 PgSqlHostWithOptionsExchange::clear();
949 most_recent_reservation_id_ = 0;
950 }
951
955 uint64_t getReservationId(const PgSqlResult& r, int row) const {
956 uint64_t resv_id = 0;
957 if (!isColumnNull(r, row, reservation_id_index_)) {
958 getColumnValue(r, row, reservation_id_index_, resv_id);
959 }
960
961 return (resv_id);
962 };
963
968 IPv6Resrv retrieveReservation(const PgSqlResult& r, int row) {
969
970 // type: SMALLINT NOT NULL
971 uint16_t tmp;
972 getColumnValue(r, row, type_index_, tmp);
973
974 // Convert it to IPv6 Reservation type (0 = IA_NA, 2 = IA_PD)
975 IPv6Resrv::Type resv_type;
976 switch (tmp) {
977 case 0:
978 resv_type = IPv6Resrv::TYPE_NA;
979 break;
980
981 case 2:
982 resv_type = IPv6Resrv::TYPE_PD;
983 break;
984
985 default:
987 "invalid IPv6 reservation type returned: "
988 << tmp << ". Only 0 or 2 are allowed.");
989 }
990
991 // address VARCHAR(39) NOT NULL
992 isc::asiolink::IOAddress address(getIPv6Value(r, row, address_index_));
993
994 // prefix_len: SMALLINT NOT NULL
995 uint16_t prefix_len;
996 getColumnValue(r, row, prefix_len_index_, prefix_len);
997
998 // @todo once we support populating iaid
999 // iaid: INT
1000 // int iaid;
1001 // getColumnValue(r, row, iaid_index_, iaid);
1002
1003 // Create the reservation.
1004 IPv6Resrv reservation(resv_type, IOAddress(address), prefix_len);
1005 return (reservation);
1006 };
1007
1029 virtual void processRowData(ConstHostCollection& hosts,
1030 const PgSqlResult& r, int row) {
1031 // Call parent class to fetch host information and options.
1032 PgSqlHostWithOptionsExchange::processRowData(hosts, r, row);
1033
1034 // Shouldn't happen but just in case
1035 if (hosts.empty()) {
1036 isc_throw(Unexpected, "no host information while retrieving"
1037 " IPv6 reservation");
1038 }
1039
1040 // If we have reservation id we haven't seen yet, retrieve the
1041 // the reservation, adding it to the current host
1042 uint64_t reservation_id = getReservationId(r, row);
1043 if (reservation_id && (reservation_id > most_recent_reservation_id_)) {
1044 HostPtr host = boost::const_pointer_cast<Host>(hosts.back());
1045 host->addReservation(retrieveReservation(r, row));
1046 most_recent_reservation_id_ = reservation_id;
1047 }
1048 }
1049
1050private:
1052
1053
1054 size_t reservation_id_index_;
1055
1057 size_t address_index_;
1058
1060 size_t prefix_len_index_;
1061
1063 size_t type_index_;
1064
1066 size_t iaid_index_;
1067
1069
1071 uint64_t most_recent_reservation_id_;
1072};
1073
1084class PgSqlIPv6ReservationExchange : public PgSqlExchange {
1085private:
1086
1088 static const size_t RESRV_COLUMNS = 6;
1089
1090public:
1091
1095 PgSqlIPv6ReservationExchange()
1096 : PgSqlExchange(RESRV_COLUMNS),
1097 resv_(IPv6Resrv::TYPE_NA, asiolink::IOAddress("::"), 128) {
1098 // Set the column names (for error messages)
1099 columns_[0] = "host_id";
1100 columns_[1] = "address";
1101 columns_[2] = "prefix_len";
1102 columns_[3] = "type";
1103 columns_[4] = "dhcp6_iaid";
1104
1105 BOOST_STATIC_ASSERT(5 < RESRV_COLUMNS);
1106 }
1107
1122 PsqlBindArrayPtr createBindForSend(const IPv6Resrv& resv,
1123 const HostID& host_id,
1124 const bool unique_ip) {
1125 // Store the values to ensure they remain valid.
1126 // Technically we don't need this, as currently all the values
1127 // are converted to strings and stored by the bind array.
1128 resv_ = resv;
1129
1130 PsqlBindArrayPtr bind_array(new PsqlBindArray());
1131
1132 try {
1133 // address VARCHAR(39) NOT NULL
1134 bind_array->add(resv.getPrefix());
1135
1136 // prefix_len: SMALLINT NOT NULL
1137 bind_array->add(resv.getPrefixLen());
1138
1139 // type: SMALLINT NOT NULL
1140 // See lease6_types table for values (0 = IA_NA, 2 = IA_PD)
1141 uint16_t type = resv.getType() == IPv6Resrv::TYPE_NA ? 0 : 2;
1142 bind_array->add(type);
1143
1144 // dhcp6_iaid: INT UNSIGNED
1146 bind_array->addNull();
1147
1148 // host_id: BIGINT NOT NULL
1149 bind_array->add(host_id);
1150
1151 // When checking whether the IP is unique we need to bind the IPv6 address
1152 // and prefix length at the end of the query as it has additional binding
1153 // for the IPv6 address and prefix length.
1154 if (unique_ip) {
1155 bind_array->add(resv.getPrefix()); // address
1156 bind_array->add(resv.getPrefixLen()); // prefix_len
1157 }
1158 } catch (const std::exception& ex) {
1160 "Could not create bind array from IPv6 Reservation: "
1161 << resv_.toText() << ", reason: " << ex.what());
1162 }
1163
1164 return (bind_array);
1165 }
1166
1167private:
1169 IPv6Resrv resv_;
1170};
1171
1175class PgSqlOptionExchange : public PgSqlExchange {
1176private:
1177
1178 static const size_t OPTION_ID_COL = 0;
1179 static const size_t CODE_COL = 1;
1180 static const size_t VALUE_COL = 2;
1181 static const size_t FORMATTED_VALUE_COL = 3;
1182 static const size_t SPACE_COL = 4;
1183 static const size_t PERSISTENT_COL = 5;
1184 static const size_t CANCELLED_COL = 6;
1185 static const size_t USER_CONTEXT_COL = 7;
1186 static const size_t DHCP_SUBNET_ID_COL = 8;
1187 static const size_t HOST_ID_COL = 9;
1189 static const size_t OPTION_COLUMNS = 10;
1190
1191public:
1192
1194 PgSqlOptionExchange()
1195 : PgSqlExchange(OPTION_COLUMNS), value_(),
1196 value_len_(0), option_() {
1197 columns_[OPTION_ID_COL] = "option_id";
1198 columns_[CODE_COL] = "code";
1199 columns_[VALUE_COL] = "value";
1200 columns_[FORMATTED_VALUE_COL] = "formatted_value";
1201 columns_[SPACE_COL] = "space";
1202 columns_[PERSISTENT_COL] = "persistent";
1203 columns_[CANCELLED_COL] = "cancelled";
1204 columns_[USER_CONTEXT_COL] = "user_context";
1205 columns_[DHCP_SUBNET_ID_COL] = "dhcp_subnet_id";
1206 columns_[HOST_ID_COL] = "host_id";
1207
1208 BOOST_STATIC_ASSERT(10 <= OPTION_COLUMNS);
1209 }
1210
1219 PsqlBindArrayPtr createBindForSend(const OptionDescriptor& opt_desc,
1220 const std::string& opt_space,
1221 const HostID& host_id) {
1222 // Hold pointer to the option to make sure it remains valid until
1223 // we complete a query.
1224 option_ = opt_desc.option_;
1225
1226 // Create the bind-array
1227 PsqlBindArrayPtr bind_array(new PsqlBindArray());
1228
1229 try {
1230 // option_id: is auto_incremented so skip it
1231
1232 // code: SMALLINT UNSIGNED NOT NULL
1233 bind_array->add(option_->getType());
1234
1235 // value: BYTEA NULL
1236 if (opt_desc.formatted_value_.empty() &&
1237 (opt_desc.option_->len() > opt_desc.option_->getHeaderLen())) {
1238 // The formatted_value is empty and the option value is
1239 // non-empty so we need to prepare on-wire format for the
1240 // option and store it in the database as a BYTEA.
1241 OutputBuffer buf(opt_desc.option_->len());
1242 opt_desc.option_->pack(buf);
1243 const uint8_t* buf_ptr = buf.getData();
1244 value_.assign(buf_ptr + opt_desc.option_->getHeaderLen(),
1245 buf_ptr + buf.getLength());
1246 value_len_ = value_.size();
1247 bind_array->add(value_);
1248 } else {
1249 // No value or formatted_value specified. In this case, the
1250 // value BYTEA should be NULL.
1251 bind_array->addNull(PsqlBindArray::BINARY_FMT);
1252 }
1253
1254 // formatted_value: TEXT NULL,
1255 if (!opt_desc.formatted_value_.empty()) {
1256 bind_array->addTempString(opt_desc.formatted_value_);
1257 } else {
1258 bind_array->addNull();
1259 }
1260
1261 // space: VARCHAR(128) NULL
1262 if (!opt_space.empty()) {
1263 bind_array->addTempString(opt_space);
1264 } else {
1265 bind_array->addNull();
1266 }
1267
1268 // persistent: BOOLEAN DEFAULT false
1269 bind_array->add(opt_desc.persistent_);
1270
1271 // cancelled: BOOLEAN DEFAULT false
1272 bind_array->add(opt_desc.cancelled_);
1273
1274 // user_context: TEXT NULL,
1275 ConstElementPtr ctx = opt_desc.getContext();
1276 if (ctx) {
1277 std::string user_context_ = ctx->str();
1278 bind_array->addTempString(user_context_);
1279 } else {
1280 bind_array->addNull();
1281 }
1282
1283 // host_id: INT NULL
1284 if (!host_id) {
1285 isc_throw(BadValue, "host_id cannot be null");
1286 }
1287 bind_array->add(host_id);
1288
1289 } catch (const std::exception& ex) {
1291 "Could not create bind array for inserting DHCP "
1292 "host option: " << option_->toText() << ", reason: "
1293 << ex.what());
1294 }
1295
1296 return (bind_array);
1297 }
1298
1299private:
1300
1302 std::vector<uint8_t> value_;
1303
1305 size_t value_len_;
1306
1308 OptionPtr option_;
1309};
1310
1311} // namespace
1312
1313namespace isc {
1314namespace dhcp {
1315
1326public:
1327
1334 IOServiceAccessorPtr io_service_accessor,
1335 db::DbCallback db_reconnect_callback);
1336
1341
1344 boost::shared_ptr<PgSqlHostWithOptionsExchange> host_ipv4_exchange_;
1345
1348 boost::shared_ptr<PgSqlHostIPv6Exchange> host_ipv6_exchange_;
1349
1353 boost::shared_ptr<PgSqlHostIPv6Exchange> host_ipv46_exchange_;
1354
1357 boost::shared_ptr<PgSqlIPv6ReservationExchange> host_ipv6_reservation_exchange_;
1358
1362 boost::shared_ptr<PgSqlOptionExchange> host_option_exchange_;
1363
1366
1369};
1370
1378public:
1379
1381 std::vector<PgSqlHostContextPtr> pool_;
1382
1384 std::mutex mutex_;
1385};
1386
1388typedef boost::shared_ptr<PgSqlHostContextPool> PgSqlHostContextPoolPtr;
1389
1392public:
1393
1403 GET_HOST_DHCPID, // Gets hosts by host identifier
1404 GET_HOST_ADDR, // Gets hosts by IPv4 address
1405 GET_HOST_SUBID4_DHCPID, // Gets host by IPv4 SubnetID, HW address/DUID
1406 GET_HOST_SUBID6_DHCPID, // Gets host by IPv6 SubnetID, HW address/DUID
1407 GET_HOST_SUBID_ADDR, // Gets host by IPv4 SubnetID and IPv4 address
1408 GET_HOST_PREFIX, // Gets host by IPv6 prefix
1409 GET_HOST_SUBID6_ADDR, // Gets host by IPv6 SubnetID and IPv6 prefix
1410 GET_HOST_ADDR6, // Gets hosts by IPv6 address/prefix
1411 GET_HOST_SUBID4, // Gets hosts by IPv4 SubnetID
1412 GET_HOST_SUBID6, // Gets hosts by IPv6 SubnetID
1413 GET_HOST_HOSTNAME, // Gets hosts by hostname
1414 GET_HOST_HOSTNAME_SUBID4, // Gets hosts by hostname and IPv4 SubnetID
1415 GET_HOST_HOSTNAME_SUBID6, // Gets hosts by hostname and IPv6 SubnetID
1416 GET_HOST_SUBID4_PAGE, // Gets hosts by IPv4 SubnetID beginning by HID
1417 GET_HOST_SUBID6_PAGE, // Gets hosts by IPv6 SubnetID beginning by HID
1418 GET_HOST_PAGE4, // Gets v4 hosts beginning by HID
1419 GET_HOST_PAGE6, // Gets v6 hosts beginning by HID
1420 INSERT_HOST_NON_UNIQUE_IP, // Insert new host to collection with allowing IP duplicates
1421 INSERT_HOST_UNIQUE_IP, // Insert new host to collection with checking for IP duplicates
1422 INSERT_V6_RESRV_NON_UNIQUE,// Insert v6 reservation without checking that it is unique
1423 INSERT_V6_RESRV_UNIQUE, // Insert v6 reservation with checking that it is unique
1424 INSERT_V4_HOST_OPTION, // Insert DHCPv4 option
1425 INSERT_V6_HOST_OPTION, // Insert DHCPv6 option
1426 DEL_HOST_ADDR4, // Delete v4 host (subnet-id, addr4)
1427 DEL_HOST_ADDR6, // Delete v6 host (subnet-id, addr6)
1428 DEL_HOST_SUBID4_ID, // Delete v4 host (subnet-id, ident.type, identifier)
1429 DEL_HOST_SUBID6_ID, // Delete v6 host (subnet-id, ident.type, identifier)
1430 NUM_STATEMENTS // Number of statements
1432
1439
1445
1448
1471 static bool dbReconnect(ReconnectCtlPtr db_reconnect_ctl);
1472
1483
1500 uint64_t addStatement(PgSqlHostContextPtr& ctx,
1502 PsqlBindArrayPtr& bind,
1503 const bool return_last_id = false);
1504
1514 PsqlBindArrayPtr& bind);
1515
1521 void addResv(PgSqlHostContextPtr& ctx,
1522 const IPv6Resrv& resv,
1523 const HostID& id);
1524
1536 const OptionDescriptor& opt_desc,
1537 const std::string& opt_space,
1538 const Optional<SubnetID>& subnet_id,
1539 const HostID& host_id);
1540
1550 const StatementIndex& stindex,
1551 const ConstCfgOptionPtr& options_cfg,
1552 const uint64_t host_id);
1553
1573 StatementIndex stindex,
1574 PsqlBindArrayPtr bind,
1575 boost::shared_ptr<PgSqlHostExchange> exchange,
1576 ConstHostCollection& result,
1577 bool single) const;
1578
1597 const SubnetID& subnet_id,
1598 const Host::IdentifierType& identifier_type,
1599 const uint8_t* identifier_begin,
1600 const size_t identifier_len,
1601 StatementIndex stindex,
1602 boost::shared_ptr<PgSqlHostExchange> exchange) const;
1603
1613 void checkReadOnly(PgSqlHostContextPtr& ctx) const;
1614
1624 std::pair<uint32_t, uint32_t> getVersion(const std::string& timer_name = std::string()) const;
1625
1628
1632
1635
1639
1641 std::string timer_name_;
1642};
1643
1644namespace {
1645
1647typedef boost::array<PgSqlTaggedStatement, PgSqlHostDataSourceImpl::NUM_STATEMENTS>
1648TaggedStatementArray;
1649
1652TaggedStatementArray tagged_statements = { {
1653 // PgSqlHostDataSourceImpl::GET_HOST_DHCPID
1654 // Retrieves host information, IPv6 reservations and both DHCPv4 and
1655 // DHCPv6 options associated with the host. The LEFT JOIN clause is used
1656 // to retrieve information from 4 different tables using a single query.
1657 // Hence, this query returns multiple rows for a single host.
1658 {2,
1659 { OID_BYTEA, OID_INT2 },
1660 "get_host_dhcpid",
1661 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1662 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
1663 " h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
1664 " h.user_context, "
1665 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1666 " h.dhcp4_boot_file_name, h.auth_key, "
1667 " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
1668 " o4.persistent, o4.cancelled, o4.user_context, "
1669 " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
1670 " o6.persistent, o6.cancelled, o6.user_context, "
1671 " r.reservation_id, host(r.address), r.prefix_len, r.type, r.dhcp6_iaid "
1672 "FROM hosts AS h "
1673 "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id "
1674 "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id "
1675 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1676 "WHERE dhcp_identifier = $1 AND dhcp_identifier_type = $2 "
1677 "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id"
1678 },
1679
1680 // PgSqlHostDataSourceImpl::GET_HOST_ADDR
1681 // Retrieves host information along with the DHCPv4 options associated with
1682 // it. Left joining the dhcp4_options table results in multiple rows being
1683 // returned for the same host. The host is retrieved by IPv4 address.
1684 {1,
1685 { OID_INT8 },
1686 "get_host_addr",
1687 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1688 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1689 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1690 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1691 " h.dhcp4_boot_file_name, h.auth_key, "
1692 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1693 " o.persistent, o.cancelled, o.user_context "
1694 "FROM hosts AS h "
1695 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1696 "WHERE ipv4_address = $1 "
1697 "ORDER BY h.host_id, o.option_id"
1698 },
1699
1700 // PgSqlHostDataSourceImpl::GET_HOST_SUBID4_DHCPID
1701 // Retrieves host information and DHCPv4 options using subnet identifier
1702 // and client's identifier. Left joining the dhcp4_options table results in
1703 // multiple rows being returned for the same host.
1704 {3,
1706 "get_host_subid4_dhcpid",
1707 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1708 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1709 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1710 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1711 " h.dhcp4_boot_file_name, h.auth_key, "
1712 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1713 " o.persistent, o.cancelled, o.user_context "
1714 "FROM hosts AS h "
1715 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1716 "WHERE h.dhcp4_subnet_id = $1 AND h.dhcp_identifier_type = $2 "
1717 " AND h.dhcp_identifier = $3 "
1718 "ORDER BY h.host_id, o.option_id"
1719 },
1720
1721 // PgSqlHostDataSourceImpl::GET_HOST_SUBID6_DHCPID
1722 // Retrieves host information, IPv6 reservations and DHCPv6 options
1723 // associated with a host. The number of rows returned is a multiplication
1724 // of number of IPv6 reservations and DHCPv6 options.
1725 {3,
1727 "get_host_subid6_dhcpid",
1728 "SELECT h.host_id, h.dhcp_identifier, "
1729 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1730 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1731 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1732 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1733 " h.dhcp4_boot_file_name, h.auth_key, "
1734 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1735 " o.persistent, o.cancelled, o.user_context, "
1736 " r.reservation_id, host(r.address), r.prefix_len, r.type, r.dhcp6_iaid "
1737 "FROM hosts AS h "
1738 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1739 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1740 "WHERE h.dhcp6_subnet_id = $1 AND h.dhcp_identifier_type = $2 "
1741 " AND h.dhcp_identifier = $3 "
1742 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1743 },
1744
1745 // PgSqlHostDataSourceImpl::GET_HOST_SUBID_ADDR
1746 // Retrieves host information and DHCPv4 options for the host using subnet
1747 // identifier and IPv4 reservation. Left joining the dhcp4_options table
1748 // results in multiple rows being returned for the host. The number of
1749 // rows depends on the number of options defined for the host.
1750 {2,
1751 { OID_INT8, OID_INT8 },
1752 "get_host_subid_addr",
1753 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1754 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1755 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1756 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1757 " h.dhcp4_boot_file_name, h.auth_key, "
1758 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1759 " o.persistent, o.cancelled, o.user_context "
1760 "FROM hosts AS h "
1761 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1762 "WHERE h.dhcp4_subnet_id = $1 AND h.ipv4_address = $2 "
1763 "ORDER BY h.host_id, o.option_id"
1764 },
1765
1766 // PgSqlHostDataSourceImpl::GET_HOST_PREFIX
1767 // Retrieves host information, IPv6 reservations and DHCPv6 options
1768 // associated with a host using prefix and prefix length. This query
1769 // returns host information for a single host. However, multiple rows
1770 // are returned due to left joining IPv6 reservations and DHCPv6 options.
1771 // The number of rows returned is multiplication of number of existing
1772 // IPv6 reservations and DHCPv6 options.
1773 {2,
1774 { OID_VARCHAR, OID_INT2 },
1775 "get_host_prefix",
1776 "SELECT h.host_id, h.dhcp_identifier, "
1777 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1778 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1779 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1780 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1781 " h.dhcp4_boot_file_name, h.auth_key, "
1782 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1783 " o.persistent, o.cancelled, o.user_context, "
1784 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1785 " r.dhcp6_iaid "
1786 "FROM hosts AS h "
1787 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1788 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1789 "WHERE h.host_id = "
1790 " (SELECT host_id FROM ipv6_reservations "
1791 " WHERE address = cast($1 as inet) AND prefix_len = $2) "
1792 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1793 },
1794
1795 // PgSqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR
1796 // Retrieves host information, IPv6 reservations and DHCPv6 options
1797 // associated with a host using IPv6 subnet id and prefix. This query
1798 // returns host information for a single host. However, multiple rows
1799 // are returned due to left joining IPv6 reservations and DHCPv6 options.
1800 // The number of rows returned is multiplication of number of existing
1801 // IPv6 reservations and DHCPv6 options.
1802 {2,
1803 { OID_INT8, OID_VARCHAR },
1804 "get_host_subid6_addr",
1805 "SELECT h.host_id, h.dhcp_identifier, "
1806 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1807 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1808 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1809 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1810 " h.dhcp4_boot_file_name, h.auth_key, "
1811 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1812 " o.persistent, o.cancelled, o.user_context, "
1813 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1814 " r.dhcp6_iaid "
1815 "FROM hosts AS h "
1816 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1817 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1818 "WHERE h.dhcp6_subnet_id = $1 AND h.host_id IN "
1819 " (SELECT host_id FROM ipv6_reservations "
1820 " WHERE address = cast($2 as inet)) "
1821 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1822 },
1823
1824 // PgSqlHostDataSourceImpl::GET_HOST_ADDR6
1825 // Retrieves host information, IPv6 reservations and DHCPv6 options
1826 // associated with a host using IPv6 address/prefix. This query
1827 // may return host information for one or more host reservations. Even
1828 // if only one host is found, multiple rows
1829 // are returned due to left joining IPv6 reservations and DHCPv6 options.
1830 // The number of rows returned is multiplication of number of existing
1831 // IPv6 reservations and DHCPv6 options.
1832 {1,
1833 { OID_VARCHAR },
1834 "get_host_addr6",
1835 "SELECT h.host_id, h.dhcp_identifier, "
1836 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1837 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1838 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1839 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1840 " h.dhcp4_boot_file_name, h.auth_key, "
1841 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1842 " o.persistent, o.cancelled, o.user_context, "
1843 " r.reservation_id, r.address, r.prefix_len, r.type, "
1844 " r.dhcp6_iaid "
1845 "FROM hosts AS h "
1846 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1847 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1848 "WHERE h.host_id IN "
1849 " (SELECT host_id FROM ipv6_reservations "
1850 " WHERE address = cast($1 as inet)) "
1851 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1852 },
1853
1854 // PgSqlHostDataSourceImpl::GET_HOST_SUBID4
1855 //
1856 // Retrieves host information for all hosts in a subnet, along with the
1857 // DHCPv4 options associated with it. Left joining the dhcp4_options table
1858 // results in multiple rows being returned for the same host. The hosts are
1859 // retrieved by subnet id.
1860 {1,
1861 { OID_INT8 },
1862 "get_host_subid4",
1863 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1864 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1865 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1866 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1867 " h.dhcp4_boot_file_name, h.auth_key, "
1868 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1869 " o.persistent, o.cancelled, o.user_context "
1870 "FROM hosts AS h "
1871 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1872 "WHERE h.dhcp4_subnet_id = $1 "
1873 "ORDER BY h.host_id, o.option_id"
1874 },
1875
1876 // PgSqlHostDataSourceImpl::GET_HOST_SUBID6
1877 //
1878 // Retrieves host information, IPv6 reservations and DHCPv6 options
1879 // associated with all hosts using the IPv6 subnet id. This query returns
1880 // host information for many hosts. However, multiple rows are
1881 // returned due to left joining IPv6 reservations and DHCPv6 options.
1882 // The number of rows returned is multiplication of number of existing
1883 // IPv6 reservations and DHCPv6 options for each host in a subnet. There
1884 // are usually many hosts in a subnet. The amount of returned data may
1885 // be huge.
1886 {1,
1887 { OID_INT8 },
1888 "get_host_subid6",
1889 "SELECT h.host_id, h.dhcp_identifier, "
1890 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1891 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1892 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1893 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1894 " h.dhcp4_boot_file_name, h.auth_key, "
1895 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1896 " o.persistent, o.cancelled, o.user_context, "
1897 " r.reservation_id, host(r.address), r.prefix_len, r.type, r.dhcp6_iaid "
1898 "FROM hosts AS h "
1899 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1900 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1901 "WHERE h.dhcp6_subnet_id = $1 "
1902 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1903 },
1904
1905 // PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME
1906 // Retrieves host information, IPv6 reservations and both DHCPv4 and
1907 // DHCPv6 options associated with all hosts using the hostname.
1908 // The LEFT JOIN clause is used to retrieve information from 4 different
1909 // tables using a single query. Hence, this query returns multiple rows
1910 // for a single host.
1911 {1,
1912 { OID_VARCHAR },
1913 "get_host_hostname",
1914 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1915 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
1916 " h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
1917 " h.user_context, "
1918 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1919 " h.dhcp4_boot_file_name, h.auth_key, "
1920 " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
1921 " o4.persistent, o4.cancelled, o4.user_context, "
1922 " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
1923 " o6.persistent, o6.cancelled, o6.user_context, "
1924 " r.reservation_id, host(r.address), r.prefix_len, r.type, r.dhcp6_iaid "
1925 "FROM hosts AS h "
1926 "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id "
1927 "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id "
1928 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1929 "WHERE lower(h.hostname) = $1 "
1930 "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id"
1931 },
1932
1933 // PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID4
1934 // Retrieves host information for all hosts with a hostname in a subnet,
1935 // along with the DHCPv4 options associated with it. Left joining
1936 // the dhcp4_options table results in multiple rows being returned for
1937 // the same host.
1938 {2,
1939 { OID_VARCHAR, OID_INT8 },
1940 "get_host_hostname_subid4",
1941 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1942 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1943 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1944 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1945 " h.dhcp4_boot_file_name, h.auth_key, "
1946 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1947 " o.persistent, o.cancelled, o.user_context "
1948 "FROM hosts AS h "
1949 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1950 "WHERE lower(h.hostname) = $1 AND h.dhcp4_subnet_id = $2 "
1951 "ORDER BY h.host_id, o.option_id"
1952 },
1953
1954 // PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID6
1955 // Retrieves host information, IPv6 reservations and DHCPv6 options
1956 // associated with all hosts using the hostname and the IPv6 subnet id.
1957 // This query returns host information for many hosts. However, multiple
1958 // rows are returned due to left joining IPv6 reservations and DHCPv6
1959 // options. The number of rows returned is multiplication of number of
1960 // existing IPv6 reservations and DHCPv6 options for each host in a subnet.
1961 {2,
1962 { OID_VARCHAR, OID_INT8 },
1963 "get_host_hostname_subid6",
1964 "SELECT h.host_id, h.dhcp_identifier, "
1965 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1966 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1967 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1968 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1969 " h.dhcp4_boot_file_name, h.auth_key, "
1970 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1971 " o.persistent, o.cancelled, o.user_context, "
1972 " r.reservation_id, host(r.address), r.prefix_len, r.type, r.dhcp6_iaid "
1973 "FROM hosts AS h "
1974 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1975 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1976 "WHERE lower(h.hostname) = $1 AND h.dhcp6_subnet_id = $2 "
1977 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1978 },
1979
1980 // PgSqlHostDataSourceImpl::GET_HOST_SUBID4_PAGE
1981 // Retrieves host information along with the DHCPv4 options associated with
1982 // it. Left joining the dhcp4_options table results in multiple rows being
1983 // returned for the same host. The hosts are retrieved by subnet id,
1984 // starting from specified host id. Specified number of hosts is returned.
1985 {3,
1987 "get_host_subid4_page",
1988 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1989 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1990 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1991 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1992 " h.dhcp4_boot_file_name, h.auth_key, "
1993 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1994 " o.persistent, o.cancelled, o.user_context "
1995 "FROM ( SELECT * FROM hosts AS h "
1996 " WHERE h.dhcp4_subnet_id = $1 AND h.host_id > $2 "
1997 " ORDER BY h.host_id "
1998 " LIMIT $3 ) AS h "
1999 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
2000 "ORDER BY h.host_id, o.option_id"
2001 },
2002
2003 // PgSqlHostDataSourceImpl::GET_HOST_SUBID6_PAGE
2004 // Retrieves host information, IPv6 reservations and DHCPv6 options
2005 // associated with a host using IPv6 subnet id. This query returns
2006 // host information for a single host. However, multiple rows are
2007 // returned due to left joining IPv6 reservations and DHCPv6 options.
2008 // The number of rows returned is multiplication of number of existing
2009 // IPv6 reservations and DHCPv6 options.
2010 {3,
2012 "get_host_subid6_page",
2013 "SELECT h.host_id, h.dhcp_identifier, "
2014 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2015 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2016 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2017 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2018 " h.dhcp4_boot_file_name, h.auth_key, "
2019 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2020 " o.persistent, o.cancelled, o.user_context, "
2021 " r.reservation_id, host(r.address), r.prefix_len, r.type, r.dhcp6_iaid "
2022 "FROM ( SELECT * FROM hosts AS h "
2023 " WHERE h.dhcp6_subnet_id = $1 AND h.host_id > $2 "
2024 " ORDER BY h.host_id "
2025 " LIMIT $3 ) AS h "
2026 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
2027 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
2028 "ORDER BY h.host_id, o.option_id, r.reservation_id"
2029 },
2030
2031 // PgSqlHostDataSourceImpl::GET_HOST_PAGE4
2032 // Retrieves host information along with the DHCPv4 options associated with
2033 // it. Left joining the dhcp4_options table results in multiple rows being
2034 // returned for the same host. The hosts are retrieved starting from
2035 // specified host id. Specified number of hosts is returned.
2036 {2,
2037 { OID_INT8, OID_INT8 },
2038 "get_host_page4",
2039 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2040 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2041 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2042 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2043 " h.dhcp4_boot_file_name, h.auth_key, "
2044 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2045 " o.persistent, o.cancelled, o.user_context "
2046 "FROM ( SELECT * FROM hosts AS h "
2047 " WHERE h.host_id > $1 "
2048 " ORDER BY h.host_id "
2049 " LIMIT $2 ) AS h "
2050 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
2051 "ORDER BY h.host_id, o.option_id"
2052 },
2053
2054 // PgSqlHostDataSourceImpl::GET_HOST_PAGE6
2055 // Retrieves host information, IPv6 reservations and DHCPv6 options
2056 // associated with a host using IPv6 subnet id. This query returns
2057 // host information for a single host. However, multiple rows are
2058 // returned due to left joining IPv6 reservations and DHCPv6 options.
2059 // The number of rows returned is multiplication of number of existing
2060 // IPv6 reservations and DHCPv6 options.
2061 {2,
2062 { OID_INT8, OID_INT8 },
2063 "get_host_page6",
2064 "SELECT h.host_id, h.dhcp_identifier, "
2065 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2066 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2067 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2068 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2069 " h.dhcp4_boot_file_name, h.auth_key, "
2070 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2071 " o.persistent, o.cancelled, o.user_context, "
2072 " r.reservation_id, host(r.address), r.prefix_len, r.type, r.dhcp6_iaid "
2073 "FROM ( SELECT * FROM hosts AS h "
2074 " WHERE h.host_id > $1 "
2075 " ORDER BY h.host_id "
2076 " LIMIT $2 ) AS h "
2077 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
2078 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
2079 "ORDER BY h.host_id, o.option_id, r.reservation_id"
2080 },
2081
2082 // PgSqlHostDataSourceImpl::INSERT_HOST_NON_UNIQUE_IP
2083 // Inserts a host into the 'hosts' table without checking that there is
2084 // a reservation for the IP address.
2085 {13,
2090 "insert_host_non_unique_ip",
2091 "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
2092 " dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
2093 " dhcp4_client_classes, dhcp6_client_classes, user_context, "
2094 " dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name, auth_key)"
2095 "VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13 ) "
2096 "RETURNING host_id"
2097 },
2098
2099 // PgSqlHostDataSourceImpl::INSERT_HOST_UNIQUE_IP
2100 // Inserts a host into the 'hosts' table with checking that reserved IP
2101 // address is unique. The innermost query checks if there is at least
2102 // one host for the given IP/subnet combination. For checking whether
2103 // hosts exists or not it doesn't matter if we select actual columns,
2104 // thus SELECT 1 was used as an optimization to avoid selecting data
2105 // that will be ignored anyway. If it does not exist the new host is
2106 // inserted. If the host with the given IP address already exists the
2107 // new host won't be inserted. The caller can check the number of
2108 // affected rows to detect that there was a duplicate host in the
2109 // database. Returns the inserted host id.
2110 {15,
2116 "insert_host_unique_ip",
2117 "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
2118 " dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
2119 " dhcp4_client_classes, dhcp6_client_classes, user_context, "
2120 " dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name, auth_key)"
2121 " SELECT $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13"
2122 " WHERE NOT EXISTS ("
2123 " SELECT 1 FROM hosts WHERE ipv4_address = $14 AND dhcp4_subnet_id = $15"
2124 " LIMIT 1"
2125 " ) "
2126 "RETURNING host_id"
2127 },
2128
2129 // PgSqlHostDataSourceImpl::INSERT_V6_RESRV_NON_UNIQUE
2130 // Inserts a single IPv6 reservation into 'reservations' table without
2131 // checking that the inserted reservation is unique.
2132 {5,
2134 "insert_v6_resrv_non_unique",
2135 "INSERT INTO ipv6_reservations(address, prefix_len, type, "
2136 " dhcp6_iaid, host_id) "
2137 "VALUES (cast($1 as inet), $2, $3, $4, $5)"
2138 },
2139
2140 // PgSqlHostDataSourceImpl::INSERT_V6_RESRV_UNIQUE
2141 // Inserts a single IPv6 reservation into 'reservations' table with
2142 // checking that the inserted reservation is unique.
2143 {7,
2145 "insert_v6_resrv_unique",
2146 "INSERT INTO ipv6_reservations(address, prefix_len, type, "
2147 " dhcp6_iaid, host_id) "
2148 "SELECT cast($1 as inet), $2, $3, $4, $5 "
2149 " WHERE NOT EXISTS ("
2150 " SELECT 1 FROM ipv6_reservations"
2151 " WHERE address = cast($6 as inet) AND prefix_len = $7"
2152 " LIMIT 1"
2153 " )"
2154 },
2155
2156 // PgSqlHostDataSourceImpl::INSERT_V4_HOST_OPTION
2157 // Inserts a single DHCPv4 option into 'dhcp4_options' table.
2158 // Using fixed scope_id = 3, which associates an option with host.
2159 {8,
2162 "insert_v4_host_option",
2163 "INSERT INTO dhcp4_options(code, value, formatted_value, space, "
2164 " persistent, cancelled, user_context, host_id, scope_id) "
2165 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 3)"
2166 },
2167
2168 // PgSqlHostDataSourceImpl::INSERT_V6_HOST_OPTION
2169 // Inserts a single DHCPv6 option into 'dhcp6_options' table.
2170 // Using fixed scope_id = 3, which associates an option with host.
2171 {8,
2174 "insert_v6_host_option",
2175 "INSERT INTO dhcp6_options(code, value, formatted_value, space, "
2176 " persistent, cancelled, user_context, host_id, scope_id) "
2177 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 3)"
2178 },
2179
2180 // PgSqlHostDataSourceImpl::DEL_HOST_ADDR4
2181 // Deletes a v4 host that matches (subnet-id, addr4)
2182 {2,
2183 { OID_INT8, OID_INT8 },
2184 "del_host_addr4",
2185 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 AND ipv4_address = $2"
2186 },
2187
2188 // PgSqlHostDataSourceImpl::DEL_HOST_ADDR6
2189 // Deletes a v6 host that matches (subnet-id, addr6)
2190 {2,
2191 { OID_INT8, OID_VARCHAR },
2192 "del_host_addr6",
2193 "DELETE FROM hosts USING ipv6_reservations "
2194 " WHERE hosts.host_id = ipv6_reservations.host_id"
2195 " AND dhcp6_subnet_id = $1 AND ipv6_reservations.address = cast($2 as inet)"
2196 },
2197
2198 // PgSqlHostDataSourceImpl::DEL_HOST_SUBID4_ID
2199 // Deletes a v4 host that matches (subnet4-id, identifier-type, identifier)
2200 {3,
2202 "del_host_subid4_id",
2203 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 "
2204 "AND dhcp_identifier_type = $2 "
2205 "AND dhcp_identifier = $3"
2206 },
2207
2208 // PgSqlHostDataSourceImpl::DEL_HOST_SUBID6_ID
2209 // Deletes a v6 host that matches (subnet6-id, identifier-type, identifier)
2210 {3,
2212 "del_host_subid6_id",
2213 "DELETE FROM hosts WHERE dhcp6_subnet_id = $1 "
2214 "AND dhcp_identifier_type = $2 "
2215 "AND dhcp_identifier = $3"
2216 }
2217}
2218};
2219
2220} // namespace
2221
2222// PgSqlHostContext Constructor
2223
2225 IOServiceAccessorPtr io_service_accessor,
2226 db::DbCallback db_reconnect_callback)
2227 : conn_(parameters, io_service_accessor, db_reconnect_callback),
2228 is_readonly_(true) {
2229}
2230
2231// PgSqlHostContextAlloc Constructor and Destructor
2232
2234 PgSqlHostDataSourceImpl& mgr) : ctx_(), mgr_(mgr) {
2235
2236 if (MultiThreadingMgr::instance().getMode()) {
2237 // multi-threaded
2238 {
2239 // we need to protect the whole pool_ operation, hence extra scope {}
2240 lock_guard<mutex> lock(mgr_.pool_->mutex_);
2241 if (!mgr_.pool_->pool_.empty()) {
2242 ctx_ = mgr_.pool_->pool_.back();
2243 mgr_.pool_->pool_.pop_back();
2244 }
2245 }
2246 if (!ctx_) {
2247 ctx_ = mgr_.createContext();
2248 }
2249 } else {
2250 // single-threaded
2251 if (mgr_.pool_->pool_.empty()) {
2252 isc_throw(Unexpected, "No available PostgreSQL host context?!");
2253 }
2254 ctx_ = mgr_.pool_->pool_.back();
2255 }
2256}
2257
2259 if (MultiThreadingMgr::instance().getMode()) {
2260 // multi-threaded
2261 lock_guard<mutex> lock(mgr_.pool_->mutex_);
2262 mgr_.pool_->pool_.push_back(ctx_);
2263 if (ctx_->conn_.isUnusable()) {
2264 mgr_.unusable_ = true;
2265 }
2266 } else if (ctx_->conn_.isUnusable()) {
2267 mgr_.unusable_ = true;
2268 }
2269}
2270
2272 : parameters_(parameters), ip_reservations_unique_(true), unusable_(false) {
2273
2274 // Check TLS support.
2275 size_t tls(0);
2276 tls += parameters.count("trust-anchor");
2277 tls += parameters.count("cert-file");
2278 tls += parameters.count("key-file");
2279 tls += parameters.count("cipher-list");
2280#ifdef HAVE_PGSQL_SSL
2281 if ((tls > 0) && !PgSqlConnection::warned_about_tls) {
2285 PQinitSSL(1);
2286 }
2287#else
2288 if (tls > 0) {
2291 isc_throw(DbOpenError, "Attempt to configure TLS for PostgreSQL "
2292 << "backend (built with this feature disabled)");
2293 }
2294#endif
2295
2296 // Create unique timer name per instance.
2297 timer_name_ = "PgSqlHostMgr[";
2298 timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
2299 timer_name_ += "]DbReconnectTimer";
2300
2303 timer_name_);
2304
2305 // Create an initial context.
2306 pool_.reset(new PgSqlHostContextPool());
2307 pool_->pool_.push_back(createContext());
2308}
2309
2310// Create context.
2311
2317
2318 // Open the database.
2319 ctx->conn_.openDatabase();
2320
2321 // Now prepare the SQL statements.
2322 ctx->conn_.prepareStatements(tagged_statements.begin(),
2323 tagged_statements.begin() + WRITE_STMTS_BEGIN);
2324
2325 // Check if the backend is explicitly configured to operate with
2326 // read only access to the database.
2327 ctx->is_readonly_ = ctx->conn_.configuredReadOnly();
2328
2329 // If we are using read-write mode for the database we also prepare
2330 // statements for INSERTS etc.
2331 if (!ctx->is_readonly_) {
2332 ctx->conn_.prepareStatements(tagged_statements.begin() + WRITE_STMTS_BEGIN,
2333 tagged_statements.end());
2334 } else {
2336 }
2337
2338 ctx->host_ipv4_exchange_.reset(new PgSqlHostWithOptionsExchange(PgSqlHostWithOptionsExchange::DHCP4_ONLY));
2339 ctx->host_ipv6_exchange_.reset(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP6_ONLY));
2340 ctx->host_ipv46_exchange_.reset(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP4_AND_DHCP6));
2341 ctx->host_ipv6_reservation_exchange_.reset(new PgSqlIPv6ReservationExchange());
2342 ctx->host_option_exchange_.reset(new PgSqlOptionExchange());
2343
2344 // Create ReconnectCtl for this connection.
2345 ctx->conn_.makeReconnectCtl(timer_name_);
2346
2347 return (ctx);
2348}
2349
2352
2353bool
2356
2357 // Invoke application layer connection lost callback.
2358 if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) {
2359 return (false);
2360 }
2361
2362 bool reopened = false;
2363
2364 const std::string timer_name = db_reconnect_ctl->timerName();
2365
2366 // At least one connection was lost.
2367 try {
2368 CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
2369 std::list<std::string> host_db_access_list = cfg_db->getHostDbAccessStringList();
2370 for (std::string& hds : host_db_access_list) {
2371 auto parameters = DatabaseConnection::parse(hds);
2372 if (HostMgr::delBackend("postgresql", hds, true)) {
2374 }
2375 }
2376 reopened = true;
2377 } catch (const std::exception& ex) {
2379 .arg(ex.what());
2380 }
2381
2382 if (reopened) {
2383 // Cancel the timer.
2384 if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
2385 TimerMgr::instance()->unregisterTimer(timer_name);
2386 }
2387
2388 // Invoke application layer connection recovered callback.
2389 if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) {
2390 return (false);
2391 }
2392 } else {
2393 if (!db_reconnect_ctl->checkRetries()) {
2394 // We're out of retries, log it and initiate shutdown.
2396 .arg(db_reconnect_ctl->maxRetries());
2397
2398 // Cancel the timer.
2399 if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
2400 TimerMgr::instance()->unregisterTimer(timer_name);
2401 }
2402
2403 // Invoke application layer connection failed callback.
2405 return (false);
2406 }
2407
2409 .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
2410 .arg(db_reconnect_ctl->maxRetries())
2411 .arg(db_reconnect_ctl->retryInterval());
2412
2413 // Start the timer.
2414 if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
2415 TimerMgr::instance()->registerTimer(timer_name,
2416 std::bind(&PgSqlHostDataSourceImpl::dbReconnect, db_reconnect_ctl),
2417 db_reconnect_ctl->retryInterval(),
2419 }
2420 TimerMgr::instance()->setup(timer_name);
2421 }
2422
2423 return (true);
2424}
2425
2426uint64_t
2428 StatementIndex stindex,
2429 PsqlBindArrayPtr& bind_array,
2430 const bool return_last_id) {
2431 uint64_t last_id = 0;
2432 PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2433 tagged_statements[stindex].nbparams,
2434 &bind_array->values_[0],
2435 &bind_array->lengths_[0],
2436 &bind_array->formats_[0], 0));
2437
2438 int s = PQresultStatus(r);
2439
2440 if (s != PGRES_COMMAND_OK) {
2441 // Failure: check for the special case of duplicate entry.
2442 if (ctx->conn_.compareError(r, PgSqlConnection::DUPLICATE_KEY)) {
2443 isc_throw(DuplicateEntry, "Database duplicate entry error");
2444 }
2445
2446 // Connection determines if the error is fatal or not, and
2447 // throws the appropriate exception
2448 ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2449 }
2450
2451 // Get the number of affected rows.
2452 char* rows_affected = PQcmdTuples(r);
2453 if (!rows_affected) {
2455 "Could not retrieve the number of affected rows.");
2456 }
2457
2458 // If the number of rows inserted is 0 it means that the query detected
2459 // an attempt to insert duplicated data for which there is no unique
2460 // index in the database. Unique indexes are not created in the database
2461 // when it may be sometimes allowed to insert duplicated records per
2462 // server's configuration.
2463 if (rows_affected[0] == '0') {
2464 isc_throw(DuplicateEntry, "Database duplicate entry error");
2465 }
2466
2467 if (return_last_id) {
2468 PgSqlExchange::getColumnValue(r, 0, 0, last_id);
2469 }
2470
2471 return (last_id);
2472}
2473
2474bool
2476 StatementIndex stindex,
2477 PsqlBindArrayPtr& bind_array) {
2478 PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2479 tagged_statements[stindex].nbparams,
2480 &bind_array->values_[0],
2481 &bind_array->lengths_[0],
2482 &bind_array->formats_[0], 0));
2483
2484 int s = PQresultStatus(r);
2485
2486 if (s != PGRES_COMMAND_OK) {
2487 // Connection determines if the error is fatal or not, and
2488 // throws the appropriate exception
2489 ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2490 }
2491
2492 // Now check how many rows (hosts) were deleted. This should be either
2493 // "0" or "1".
2494 char* rows_deleted = PQcmdTuples(r);
2495 if (!rows_deleted) {
2497 "Could not retrieve the number of deleted rows.");
2498 }
2499 return (rows_deleted[0] != '0');
2500}
2501
2502void
2504 const IPv6Resrv& resv,
2505 const HostID& id) {
2506 PsqlBindArrayPtr bind_array = ctx->host_ipv6_reservation_exchange_->
2507 createBindForSend(resv, id, ip_reservations_unique_);
2508
2509 addStatement(ctx,
2511 bind_array);
2512}
2513
2514void
2516 const StatementIndex& stindex,
2517 const OptionDescriptor& opt_desc,
2518 const std::string& opt_space,
2519 const Optional<SubnetID>&,
2520 const HostID& id) {
2521 PsqlBindArrayPtr bind_array = ctx->host_option_exchange_->createBindForSend(opt_desc, opt_space, id);
2522
2523 addStatement(ctx, stindex, bind_array);
2524}
2525
2526void
2528 const StatementIndex& stindex,
2529 const ConstCfgOptionPtr& options_cfg,
2530 const uint64_t host_id) {
2531 // Get option space names and vendor space names and combine them within a
2532 // single list.
2533 std::list<std::string> option_spaces = options_cfg->getOptionSpaceNames();
2534 std::list<std::string> vendor_spaces = options_cfg->getVendorIdsSpaceNames();
2535 option_spaces.insert(option_spaces.end(), vendor_spaces.begin(),
2536 vendor_spaces.end());
2537
2538 // For each option space retrieve all options and insert them into the
2539 // database.
2540 for (auto const& space : option_spaces) {
2541 OptionContainerPtr options = options_cfg->getAllCombined(space);
2542 if (options && !options->empty()) {
2543 for (auto const& opt : *options) {
2544 addOption(ctx, stindex, opt, space, Optional<SubnetID>(), host_id);
2545 }
2546 }
2547 }
2548}
2549
2550void
2552 StatementIndex stindex,
2553 PsqlBindArrayPtr bind_array,
2554 boost::shared_ptr<PgSqlHostExchange> exchange,
2555 ConstHostCollection& result,
2556 bool single) const {
2557
2558 exchange->clear();
2559 PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2560 tagged_statements[stindex].nbparams,
2561 &bind_array->values_[0],
2562 &bind_array->lengths_[0],
2563 &bind_array->formats_[0], 0));
2564
2565 ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2566
2567 int rows = r.getRows();
2568 for (int row = 0; row < rows; ++row) {
2569 exchange->processRowData(result, r, row);
2570
2571 if (single && result.size() > 1) {
2572 isc_throw(MultipleRecords, "multiple records were found in the "
2573 "database where only one was expected for query "
2574 << tagged_statements[stindex].name);
2575 }
2576 }
2577}
2578
2581 const SubnetID& subnet_id,
2582 const Host::IdentifierType& identifier_type,
2583 const uint8_t* identifier_begin,
2584 const size_t identifier_len,
2585 StatementIndex stindex,
2586 boost::shared_ptr<PgSqlHostExchange> exchange) const {
2587
2588 // Set up the WHERE clause value
2589 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2590
2591 // Add the subnet id.
2592 bind_array->add(subnet_id);
2593
2594 // Add the Identifier type.
2595 bind_array->add(static_cast<uint8_t>(identifier_type));
2596
2597 // Add the identifier value.
2598 bind_array->add(identifier_begin, identifier_len);
2599
2600 ConstHostCollection collection;
2601 getHostCollection(ctx, stindex, bind_array, exchange, collection, true);
2602
2603 // Return single record if present, else clear the host.
2604 ConstHostPtr result;
2605 if (!collection.empty()) {
2606 result = *collection.begin();
2607 }
2608
2609 return (result);
2610}
2611
2612std::pair<uint32_t, uint32_t>
2621
2622void
2624 if (ctx->is_readonly_) {
2625 isc_throw(ReadOnlyDb, "PostgreSQL host database backend is configured"
2626 " to operate in read only mode");
2627 }
2628}
2629
2630/*********** PgSqlHostDataSource *********************/
2631
2635
2638
2641 return (impl_->parameters_);
2642}
2643
2644void
2646 // Get a context
2647 PgSqlHostContextAlloc get_context(*impl_);
2648 PgSqlHostContextPtr ctx = get_context.ctx_;
2649
2650 // If operating in read-only mode, throw exception.
2651 impl_->checkReadOnly(ctx);
2652
2653 // Initiate PostgreSQL transaction as we will have to make multiple queries
2654 // to insert host information into multiple tables. If that fails on
2655 // any stage, the transaction will be rolled back by the destructor of
2656 // the PgSqlTransaction class.
2657 PgSqlTransaction transaction(ctx->conn_);
2658
2659 // If we're configured to check that an IP reservation within a given subnet
2660 // is unique, the IP reservation exists and the subnet is actually set
2661 // we will be using a special query that checks for uniqueness. Otherwise,
2662 // we will use a regular insert statement.
2663 bool unique_ip = impl_->ip_reservations_unique_ && !host->getIPv4Reservation().isV4Zero()
2664 && host->getIPv4SubnetID() != SUBNET_ID_UNUSED;
2665
2666 // Create the PgSQL Bind array for the host
2667 PsqlBindArrayPtr bind_array = ctx->host_ipv4_exchange_->createBindForSend(host, unique_ip);
2668
2669 // ... and insert the host.
2670 uint32_t host_id = impl_->addStatement(ctx,
2673 bind_array, true);
2674
2675 // Insert DHCPv4 options.
2676 ConstCfgOptionPtr cfg_option4 = host->getCfgOption4();
2677 if (cfg_option4) {
2679 cfg_option4, host_id);
2680 }
2681
2682 // Insert DHCPv6 options.
2683 ConstCfgOptionPtr cfg_option6 = host->getCfgOption6();
2684 if (cfg_option6) {
2686 cfg_option6, host_id);
2687 }
2688
2689 // Insert IPv6 reservations.
2690 IPv6ResrvRange v6resv = host->getIPv6Reservations();
2691 if (std::distance(v6resv.first, v6resv.second) > 0) {
2692 BOOST_FOREACH(auto const& resv, v6resv) {
2693 impl_->addResv(ctx, resv.second, host_id);
2694 }
2695 }
2696
2697 // Everything went fine, so explicitly commit the transaction.
2698 transaction.commit();
2699}
2700
2701bool
2703 const asiolink::IOAddress& addr) {
2704 // Get a context
2705 PgSqlHostContextAlloc get_context(*impl_);
2706 PgSqlHostContextPtr ctx = get_context.ctx_;
2707
2708 // If operating in read-only mode, throw exception.
2709 impl_->checkReadOnly(ctx);
2710
2711 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2712 bind_array->add(subnet_id);
2713
2714 // v4
2715 if (addr.isV4()) {
2716 bind_array->add(addr);
2717 return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_ADDR4,
2718 bind_array));
2719 }
2720
2721 // v6
2722 bind_array->addTempString(addr.toText());
2723
2724 return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_ADDR6,
2725 bind_array));
2726}
2727
2728bool
2730 const Host::IdentifierType& identifier_type,
2731 const uint8_t* identifier_begin,
2732 const size_t identifier_len) {
2733 // Get a context
2734 PgSqlHostContextAlloc get_context(*impl_);
2735 PgSqlHostContextPtr ctx = get_context.ctx_;
2736
2737 // If operating in read-only mode, throw exception.
2738 impl_->checkReadOnly(ctx);
2739
2740 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2741
2742 // Subnet-id
2743 bind_array->add(subnet_id);
2744
2745 // identifier-type
2746 bind_array->add(static_cast<uint8_t>(identifier_type));
2747
2748 // identifier
2749 bind_array->add(identifier_begin, identifier_len);
2750
2751 return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_SUBID4_ID,
2752 bind_array));
2753}
2754
2755bool
2757 const Host::IdentifierType& identifier_type,
2758 const uint8_t* identifier_begin,
2759 const size_t identifier_len) {
2760 // Get a context
2761 PgSqlHostContextAlloc get_context(*impl_);
2762 PgSqlHostContextPtr ctx = get_context.ctx_;
2763
2764 // If operating in read-only mode, throw exception.
2765 impl_->checkReadOnly(ctx);
2766
2767 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2768
2769 // Subnet-id
2770 bind_array->add(subnet_id);
2771
2772 // identifier-type
2773 bind_array->add(static_cast<uint8_t>(identifier_type));
2774
2775 // identifier
2776 bind_array->add(identifier_begin, identifier_len);
2777
2778 return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_SUBID6_ID,
2779 bind_array));
2780}
2781
2784 const uint8_t* identifier_begin,
2785 const size_t identifier_len) const {
2786 // Get a context
2787 PgSqlHostContextAlloc get_context(*impl_);
2788 PgSqlHostContextPtr ctx = get_context.ctx_;
2789
2790 // Set up the WHERE clause value
2791 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2792
2793 // Identifier value.
2794 bind_array->add(identifier_begin, identifier_len);
2795
2796 // Identifier type.
2797 bind_array->add(static_cast<uint8_t>(identifier_type));
2798
2799 ConstHostCollection result;
2800 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_DHCPID,
2801 bind_array, ctx->host_ipv46_exchange_, result, false);
2802
2803 return (result);
2804}
2805
2808 // Get a context
2809 PgSqlHostContextAlloc get_context(*impl_);
2810 PgSqlHostContextPtr ctx = get_context.ctx_;
2811
2812 // Set up the WHERE clause value
2813 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2814
2815 // Add the subnet id.
2816 bind_array->add(subnet_id);
2817
2818 ConstHostCollection result;
2819 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID4,
2820 bind_array, ctx->host_ipv4_exchange_, result, false);
2821
2822 return (result);
2823}
2824
2827 // Get a context
2828 PgSqlHostContextAlloc get_context(*impl_);
2829 PgSqlHostContextPtr ctx = get_context.ctx_;
2830
2831 // Set up the WHERE clause value
2832 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2833
2834 // Add the subnet id.
2835 bind_array->add(subnet_id);
2836
2837 ConstHostCollection result;
2838 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID6,
2839 bind_array, ctx->host_ipv6_exchange_, result, false);
2840
2841 return (result);
2842}
2843
2845PgSqlHostDataSource::getAllbyHostname(const std::string& hostname) const {
2846 // Get a context
2847 PgSqlHostContextAlloc get_context(*impl_);
2848 PgSqlHostContextPtr ctx = get_context.ctx_;
2849
2850 // Set up the WHERE clause value
2851 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2852
2853 // Add the hostname.
2854 bind_array->add(hostname);
2855
2856 ConstHostCollection result;
2857 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME,
2858 bind_array, ctx->host_ipv46_exchange_, result, false);
2859
2860 return (result);
2861}
2862
2864PgSqlHostDataSource::getAllbyHostname4(const std::string& hostname,
2865 const SubnetID& subnet_id) const {
2866 // Get a context
2867 PgSqlHostContextAlloc get_context(*impl_);
2868 PgSqlHostContextPtr ctx = get_context.ctx_;
2869
2870 // Set up the WHERE clause value
2871 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2872
2873 // Add the hostname.
2874 bind_array->add(hostname);
2875
2876 // Add the subnet id.
2877 bind_array->add(subnet_id);
2878
2879 ConstHostCollection result;
2880 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID4,
2881 bind_array, ctx->host_ipv4_exchange_, result, false);
2882
2883 return (result);
2884}
2885
2887PgSqlHostDataSource::getAllbyHostname6(const std::string& hostname,
2888 const SubnetID& subnet_id) const {
2889 // Get a context
2890 PgSqlHostContextAlloc get_context(*impl_);
2891 PgSqlHostContextPtr ctx = get_context.ctx_;
2892
2893 // Set up the WHERE clause value
2894 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2895
2896 // Add the hostname.
2897 bind_array->add(hostname);
2898
2899 // Add the subnet id.
2900 bind_array->add(subnet_id);
2901
2902 ConstHostCollection result;
2903 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID6,
2904 bind_array, ctx->host_ipv6_exchange_, result, false);
2905
2906 return (result);
2907}
2908
2911 size_t& /*source_index*/,
2912 uint64_t lower_host_id,
2913 const HostPageSize& page_size) const {
2914 // Get a context
2915 PgSqlHostContextAlloc get_context(*impl_);
2916 PgSqlHostContextPtr ctx = get_context.ctx_;
2917
2918 // Set up the WHERE clause value
2919 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2920
2921 // Add the subnet id.
2922 bind_array->add(subnet_id);
2923
2924 // Add the lower bound host id.
2925 bind_array->add(lower_host_id);
2926
2927 // Add the page size value.
2928 string page_size_data =
2929 boost::lexical_cast<std::string>(page_size.page_size_);
2930 bind_array->add(page_size_data);
2931
2932 ConstHostCollection result;
2933 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID4_PAGE,
2934 bind_array, ctx->host_ipv4_exchange_, result, false);
2935
2936 return (result);
2937}
2938
2941 size_t& /*source_index*/,
2942 uint64_t lower_host_id,
2943 const HostPageSize& page_size) const {
2944 // Get a context
2945 PgSqlHostContextAlloc get_context(*impl_);
2946 PgSqlHostContextPtr ctx = get_context.ctx_;
2947
2948 // Set up the WHERE clause value
2949 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2950
2951 // Add the subnet id.
2952 bind_array->add(subnet_id);
2953
2954 // Add the lower bound host id.
2955 bind_array->add(lower_host_id);
2956
2957 // Add the page size value.
2958 string page_size_data =
2959 boost::lexical_cast<std::string>(page_size.page_size_);
2960 bind_array->add(page_size_data);
2961
2962 ConstHostCollection result;
2963 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID6_PAGE,
2964 bind_array, ctx->host_ipv6_exchange_, result, false);
2965
2966 return (result);
2967}
2968
2970PgSqlHostDataSource::getPage4(size_t& /*source_index*/,
2971 uint64_t lower_host_id,
2972 const HostPageSize& page_size) const {
2973 // Get a context
2974 PgSqlHostContextAlloc get_context(*impl_);
2975 PgSqlHostContextPtr ctx = get_context.ctx_;
2976
2977 // Set up the WHERE clause value
2978 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2979
2980 // Add the lower bound host id.
2981 bind_array->add(lower_host_id);
2982
2983 // Add the page size value.
2984 string page_size_data =
2985 boost::lexical_cast<std::string>(page_size.page_size_);
2986 bind_array->add(page_size_data);
2987
2988 ConstHostCollection result;
2989 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_PAGE4,
2990 bind_array, ctx->host_ipv4_exchange_, result, false);
2991
2992 return (result);
2993}
2994
2996PgSqlHostDataSource::getPage6(size_t& /*source_index*/,
2997 uint64_t lower_host_id,
2998 const HostPageSize& page_size) const {
2999 // Get a context
3000 PgSqlHostContextAlloc get_context(*impl_);
3001 PgSqlHostContextPtr ctx = get_context.ctx_;
3002
3003 // Set up the WHERE clause value
3004 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3005
3006 // Add the lower bound host id.
3007 bind_array->add(lower_host_id);
3008
3009 // Add the page size value.
3010 string page_size_data =
3011 boost::lexical_cast<std::string>(page_size.page_size_);
3012 bind_array->add(page_size_data);
3013
3014 ConstHostCollection result;
3015 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_PAGE6,
3016 bind_array, ctx->host_ipv6_exchange_, result, false);
3017
3018 return (result);
3019}
3020
3023 // Get a context
3024 PgSqlHostContextAlloc get_context(*impl_);
3025 PgSqlHostContextPtr ctx = get_context.ctx_;
3026
3027 // Set up the WHERE clause value
3028 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3029
3030 // v4 Reservation address
3031 bind_array->add(address);
3032
3033 ConstHostCollection result;
3034 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_ADDR,
3035 bind_array, ctx->host_ipv4_exchange_, result, false);
3036
3037 return (result);
3038}
3039
3042 const Host::IdentifierType& identifier_type,
3043 const uint8_t* identifier_begin,
3044 const size_t identifier_len) const {
3045 // Get a context
3046 PgSqlHostContextAlloc get_context(*impl_);
3047 PgSqlHostContextPtr ctx = get_context.ctx_;
3048
3049 return (impl_->getHost(ctx, subnet_id, identifier_type, identifier_begin, identifier_len,
3051 ctx->host_ipv4_exchange_));
3052}
3053
3056 const asiolink::IOAddress& address) const {
3057 // Get a context
3058 PgSqlHostContextAlloc get_context(*impl_);
3059 PgSqlHostContextPtr ctx = get_context.ctx_;
3060
3061 if (!address.isV4()) {
3062 isc_throw(BadValue, "PgSqlHostDataSource::get4(id, address) - "
3063 " wrong address type, address supplied is an IPv6 address");
3064 }
3065
3066 // Set up the WHERE clause value
3067 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3068
3069 // Add the subnet id
3070 bind_array->add(subnet_id);
3071
3072 // Add the address
3073 bind_array->add(address);
3074
3075 ConstHostCollection collection;
3076 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID_ADDR,
3077 bind_array, ctx->host_ipv4_exchange_, collection, true);
3078
3079 // Return single record if present, else clear the host.
3080 ConstHostPtr result;
3081 if (!collection.empty()) {
3082 result = *collection.begin();
3083 }
3084
3085 return (result);
3086}
3087
3090 const asiolink::IOAddress& address) const {
3091 // Get a context
3092 PgSqlHostContextAlloc get_context(*impl_);
3093 PgSqlHostContextPtr ctx = get_context.ctx_;
3094
3095 if (!address.isV4()) {
3096 isc_throw(BadValue, "PgSqlHostDataSource::get4(id, address) - "
3097 " wrong address type, address supplied is an IPv6 address");
3098 }
3099
3100 // Set up the WHERE clause value
3101 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3102
3103 // Add the subnet id
3104 bind_array->add(subnet_id);
3105
3106 // Add the address
3107 bind_array->add(address);
3108
3109 ConstHostCollection collection;
3110 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID_ADDR,
3111 bind_array, ctx->host_ipv4_exchange_, collection, false);
3112 return (collection);
3113}
3114
3117 const Host::IdentifierType& identifier_type,
3118 const uint8_t* identifier_begin,
3119 const size_t identifier_len) const {
3120 // Get a context
3121 PgSqlHostContextAlloc get_context(*impl_);
3122 PgSqlHostContextPtr ctx = get_context.ctx_;
3123
3124 return (impl_->getHost(ctx, subnet_id, identifier_type, identifier_begin, identifier_len,
3126 ctx->host_ipv6_exchange_));
3127}
3128
3131 const uint8_t prefix_len) const {
3132 if (!prefix.isV6()) {
3133 isc_throw(BadValue, "PgSqlHostDataSource::get6(prefix, prefix_len): "
3134 "wrong address type, address supplied is an IPv4 address");
3135 }
3136
3137 // Get a context
3138 PgSqlHostContextAlloc get_context(*impl_);
3139 PgSqlHostContextPtr ctx = get_context.ctx_;
3140
3141 // Set up the WHERE clause value
3142 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3143
3144 // Add the prefix
3145 bind_array->add(prefix);
3146
3147 // Add the prefix length
3148 bind_array->add(prefix_len);
3149
3150 ConstHostCollection collection;
3151 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_PREFIX,
3152 bind_array, ctx->host_ipv6_exchange_, collection, true);
3153
3154 // Return single record if present, else clear the host.
3155 ConstHostPtr result;
3156 if (!collection.empty()) {
3157 result = *collection.begin();
3158 }
3159
3160 return (result);
3161}
3162
3165 const asiolink::IOAddress& address) const {
3166 if (!address.isV6()) {
3167 isc_throw(BadValue, "PgSqlHostDataSource::get6(id, address): "
3168 "wrong address type, address supplied is an IPv4 address");
3169 }
3170
3171 // Get a context
3172 PgSqlHostContextAlloc get_context(*impl_);
3173 PgSqlHostContextPtr ctx = get_context.ctx_;
3174
3175 // Set up the WHERE clause value
3176 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3177
3178 // Add the subnet id
3179 bind_array->add(subnet_id);
3180
3181 // Add the prefix
3182 bind_array->add(address);
3183
3184 ConstHostCollection collection;
3185 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR,
3186 bind_array, ctx->host_ipv6_exchange_, collection, true);
3187
3188 // Return single record if present, else clear the host.
3189 ConstHostPtr result;
3190 if (!collection.empty()) {
3191 result = *collection.begin();
3192 }
3193
3194 return (result);
3195}
3196
3199 const asiolink::IOAddress& address) const {
3200 if (!address.isV6()) {
3201 isc_throw(BadValue, "PgSqlHostDataSource::get6(id, address): "
3202 "wrong address type, address supplied is an IPv4 address");
3203 }
3204
3205 // Get a context
3206 PgSqlHostContextAlloc get_context(*impl_);
3207 PgSqlHostContextPtr ctx = get_context.ctx_;
3208
3209 // Set up the WHERE clause value
3210 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3211
3212 // Add the subnet id
3213 bind_array->add(subnet_id);
3214
3215 // Add the prefix
3216 bind_array->add(address);
3217
3218 ConstHostCollection collection;
3219 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR,
3220 bind_array, ctx->host_ipv6_exchange_, collection, false);
3221 return (collection);
3222}
3223
3226 if (!address.isV6()) {
3227 isc_throw(BadValue, "PgSqlHostDataSource::get6(address): "
3228 "wrong address type, address supplied is an IPv4 address");
3229 }
3230
3231 // Get a context
3232 PgSqlHostContextAlloc get_context(*impl_);
3233 PgSqlHostContextPtr ctx = get_context.ctx_;
3234
3235 // Set up the WHERE clause value
3236 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3237
3238 // Add the prefix
3239 bind_array->add(address);
3240
3241 ConstHostCollection collection;
3242 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_ADDR6,
3243 bind_array, ctx->host_ipv6_exchange_, collection, false);
3244 return (collection);
3245}
3246
3247void
3249 // Get a context.
3250 PgSqlHostContextAlloc const context(*impl_);
3251 PgSqlHostContextPtr ctx(context.ctx_);
3252
3253 // If operating in read-only mode, throw exception.
3254 impl_->checkReadOnly(ctx);
3255
3256 // Initiate PostgreSQL transaction as we will have to make multiple queries
3257 // to update host information into multiple tables. If that fails on
3258 // any stage, the transaction will be rolled back by the destructor of
3259 // the PgSqlTransaction class.
3260 PgSqlTransaction transaction(ctx->conn_);
3261
3262 // As much as having dedicated prepared statements for updating tables would be consistent with
3263 // the implementation of other commands, it's difficult if not impossible to cover all cases for
3264 // updating the host to exactly as is described in the command, which may involve inserts and
3265 // deletes alongside updates. So let's delete and add. The delete cascades into all tables. The
3266 // add explicitly adds into all tables.
3268
3269 // Everything went fine, so explicitly commit the transaction.
3270 transaction.commit();
3271}
3272
3273// Miscellaneous database methods.
3274
3275std::string
3277 std::string name = "";
3278 // Get a context
3279 PgSqlHostContextAlloc get_context(*impl_);
3280 PgSqlHostContextPtr ctx = get_context.ctx_;
3281
3282 try {
3283 name = ctx->conn_.getParameter("name");
3284 } catch (...) {
3285 // Return an empty name
3286 }
3287 return (name);
3288}
3289
3290std::string
3292 return (std::string("Host data source that stores host information"
3293 "in PostgreSQL database"));
3294}
3295
3296std::pair<uint32_t, uint32_t>
3297PgSqlHostDataSource::getVersion(const std::string& timer_name) const {
3298 return(impl_->getVersion(timer_name));
3299}
3300
3301void
3303 // Get a context
3304 PgSqlHostContextAlloc get_context(*impl_);
3305 PgSqlHostContextPtr ctx = get_context.ctx_;
3306
3307 // If operating in read-only mode, throw exception.
3308 impl_->checkReadOnly(ctx);
3309 ctx->conn_.commit();
3310}
3311
3312void
3314 // Get a context
3315 PgSqlHostContextAlloc get_context(*impl_);
3316 PgSqlHostContextPtr ctx = get_context.ctx_;
3317
3318 // If operating in read-only mode, throw exception.
3319 impl_->checkReadOnly(ctx);
3320 ctx->conn_.rollback();
3321}
3322
3323bool
3325 impl_->ip_reservations_unique_ = unique;
3326 return (true);
3327}
3328
3329bool
3331 return (impl_->unusable_);
3332}
3333
3334} // namespace dhcp
3335} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when an unexpected error condition occurs.
static ElementPtr fromJSON(const std::string &in, bool preproc=false)
These functions will parse the given string (JSON) representation of a compound element.
Definition data.cc:798
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
Definition data.h:49
static bool invokeDbLostCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's lost connectivity callback.
static std::string redactedAccessString(const ParameterMap &parameters)
Redact database access string.
static bool invokeDbFailedCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restore failed connectivity callback.
static ParameterMap parse(const std::string &dbaccess)
Parse database access string.
static bool invokeDbRecoveredCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restored connectivity callback.
static isc::asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Exception thrown on failure to open database.
Exception thrown on failure to execute a database function.
Database duplicate entry error.
Multiple lease records found where one expected.
Common PgSql Connector Pool.
static bool warned_about_tls
Emit the TLS support warning only once.
static const char DUPLICATE_KEY[]
Define the PgSql error state for a duplicate key error.
static void ensureSchemaVersion(const ParameterMap &parameters, const DbCallback &cb=DbCallback(), const std::string &timer_name=std::string())
Retrieve schema version, validate it against the hardcoded version, and attempt to initialize the sch...
static std::pair< uint32_t, uint32_t > getVersion(const ParameterMap &parameters, const IOServiceAccessorPtr &ac=IOServiceAccessorPtr(), const DbCallback &cb=DbCallback(), const std::string &timer_name=std::string())
Get the schema version.
Base class for marshalling data to and from PostgreSQL.
static void convertFromBytea(const PgSqlResult &r, const int row, const size_t col, uint8_t *buffer, const size_t buffer_size, size_t &bytes_converted)
Converts a column in a row in a result set to a binary bytes.
static bool isColumnNull(const PgSqlResult &r, const int row, const size_t col)
Returns true if a column within a row is null.
static void getColumnValue(const PgSqlResult &r, const int row, const size_t col, std::string &value)
Fetches text column value as a string.
RAII wrapper for PostgreSQL Result sets.
RAII object representing a PostgreSQL transaction.
Attempt to modify data in read-only database.
Authentication keys.
Definition host.h:75
virtual void update(HostPtr const &host)
Attempts to update an existing host entry.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:25
static constexpr size_t MAX_CLIENT_ID_LEN
Maximum size of a client ID.
Definition duid.h:235
static bool delBackend(const std::string &db_type)
Delete an alternate host backend (aka host data source).
Definition host_mgr.cc:62
static void addBackend(const std::string &access)
Add an alternate host backend (aka host data source).
Definition host_mgr.cc:57
Wraps value holding size of the page with host reservations.
Represents a device with IPv4 and/or IPv6 reservations.
Definition host.h:297
IdentifierType
Type of the host identifier.
Definition host.h:307
static const IdentifierType LAST_IDENTIFIER_TYPE
Constant pointing to the last identifier of the IdentifierType enumeration.
Definition host.h:317
IPv6 reservation for a host.
Definition host.h:161
Type
Type of the reservation.
Definition host.h:167
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition libdhcp++.cc:126
static OptionDefinitionPtr getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id, const uint16_t code)
Returns vendor option definition for a given vendor-id and code.
Definition libdhcp++.cc:168
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
static OptionDefinitionPtr getRuntimeOptionDef(const std::string &space, const uint16_t code)
Returns runtime (non-standard) option definition by space and option code.
Definition libdhcp++.cc:189
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
Definition libdhcp++.cc:247
Option descriptor.
Definition cfg_option.h:47
Universe
defines option universe DHCPv4 or DHCPv6
Definition option.h:83
std::mutex mutex_
The mutex to protect pool access.
std::vector< PgSqlHostContextPtr > pool_
The vector of available contexts.
boost::shared_ptr< PgSqlHostIPv6Exchange > host_ipv46_exchange_
Pointer to an object representing an exchange which can be used to retrieve hosts,...
boost::shared_ptr< PgSqlIPv6ReservationExchange > host_ipv6_reservation_exchange_
Pointer to an object representing an exchange which can be used to insert new IPv6 reservation.
PgSqlHostContext(const DatabaseConnection::ParameterMap &parameters, IOServiceAccessorPtr io_service_accessor, db::DbCallback db_reconnect_callback)
Constructor.
PgSqlConnection conn_
PostgreSQL connection.
boost::shared_ptr< PgSqlHostWithOptionsExchange > host_ipv4_exchange_
The exchange objects are used for transfer of data to/from the database.
bool is_readonly_
Indicates if the database is opened in read only mode.
boost::shared_ptr< PgSqlHostIPv6Exchange > host_ipv6_exchange_
Pointer to an object representing an exchange which can be used to retrieve hosts,...
boost::shared_ptr< PgSqlOptionExchange > host_option_exchange_
Pointer to an object representing an exchange which can be used to insert DHCPv4 or DHCPv6 option int...
Implementation of the PgSqlHostDataSource.
bool ip_reservations_unique_
Holds the setting whether the IP reservations must be unique or may be non-unique.
uint64_t addStatement(PgSqlHostContextPtr &ctx, PgSqlHostDataSourceImpl::StatementIndex stindex, PsqlBindArrayPtr &bind, const bool return_last_id=false)
Executes statements which insert a row into one of the tables.
static bool dbReconnect(ReconnectCtlPtr db_reconnect_ctl)
Attempts to reconnect the server to the host DB backend manager.
std::pair< uint32_t, uint32_t > getVersion(const std::string &timer_name=std::string()) const
Returns PostgreSQL schema version of the open database.
void checkReadOnly(PgSqlHostContextPtr &ctx) const
Throws exception if database is read only.
DatabaseConnection::ParameterMap parameters_
The parameters.
PgSqlHostContextPoolPtr pool_
The pool of contexts.
void addOption(PgSqlHostContextPtr &ctx, const PgSqlHostDataSourceImpl::StatementIndex &stindex, const OptionDescriptor &opt_desc, const std::string &opt_space, const Optional< SubnetID > &subnet_id, const HostID &host_id)
Inserts a single DHCP option into the database.
void addOptions(PgSqlHostContextPtr &ctx, const StatementIndex &stindex, const ConstCfgOptionPtr &options_cfg, const uint64_t host_id)
Inserts multiple options into the database.
bool delStatement(PgSqlHostContextPtr &ctx, PgSqlHostDataSourceImpl::StatementIndex stindex, PsqlBindArrayPtr &bind)
Executes statements that delete records.
static const StatementIndex WRITE_STMTS_BEGIN
Index of first statement performing write to the database.
void addResv(PgSqlHostContextPtr &ctx, const IPv6Resrv &resv, const HostID &id)
Inserts IPv6 Reservation into ipv6_reservation table.
std::string timer_name_
Timer name used to register database reconnect timer.
ConstHostPtr getHost(PgSqlHostContextPtr &ctx, const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len, StatementIndex stindex, boost::shared_ptr< PgSqlHostExchange > exchange) const
Retrieves a host by subnet and client's unique identifier.
PgSqlHostContextPtr createContext() const
Create a new context.
void getHostCollection(PgSqlHostContextPtr &ctx, StatementIndex stindex, PsqlBindArrayPtr bind, boost::shared_ptr< PgSqlHostExchange > exchange, ConstHostCollection &result, bool single) const
Creates collection of Host objects with associated information such as IPv6 reservations and/or DHCP ...
PgSqlHostDataSourceImpl(const DatabaseConnection::ParameterMap &parameters)
Constructor.
bool unusable_
Indicates if there is at least one connection that can no longer be used for normal operations.
PgSqlHostContextAlloc(PgSqlHostDataSourceImpl &mgr)
Constructor.
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)
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.
virtual bool isUnusable()
Flag which indicates if the host manager has at least one unusable connection.
virtual std::string getName() const
Returns the name of the open database.
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...
virtual std::string getDescription() const
Returns description of the backend.
virtual ConstHostCollection getAllbyHostname4(const std::string &hostname, const SubnetID &subnet_id) const
Return all hosts with a hostname in a DHCPv4 subnet.
virtual ConstHostCollection getPage6(const SubnetID &subnet_id, size_t &source_index, uint64_t lower_host_id, const HostPageSize &page_size) const
Returns range of hosts in a DHCPv6 subnet.
virtual bool del(const SubnetID &subnet_id, const asiolink::IOAddress &addr)
Attempts to delete hosts by (subnet-id, address)
virtual ConstHostCollection getPage4(const SubnetID &subnet_id, size_t &source_index, uint64_t lower_host_id, const HostPageSize &page_size) const
Returns range of hosts in a DHCPv4 subnet.
virtual void rollback()
Rollback Transactions.
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)
virtual ConstHostCollection getAll6(const SubnetID &subnet_id) const
Return all hosts in a DHCPv6 subnet.
virtual ConstHostCollection getAllbyHostname6(const std::string &hostname, const SubnetID &subnet_id) const
Return all hosts with a hostname in a DHCPv6 subnet.
virtual void commit()
Commit Transactions.
virtual bool setIPReservationsUnique(const bool unique)
Controls whether IP reservations are unique or non-unique.
virtual ConstHostCollection getAll4(const SubnetID &subnet_id) const
Return all hosts in a DHCPv4 subnet.
void update(HostPtr const &host)
Implements BaseHostDataSource::update() for PostgreSQL.
virtual isc::db::DatabaseConnection::ParameterMap getParameters() const
Return backend parameters.
PgSqlHostDataSource(const db::DatabaseConnection::ParameterMap &parameters)
Constructor.
virtual void add(const HostPtr &host)
Adds a new host to the collection.
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.
virtual ~PgSqlHostDataSource()
Virtual destructor.
virtual ConstHostCollection getAllbyHostname(const std::string &hostname) const
Return all hosts with a hostname.
virtual std::pair< uint32_t, uint32_t > getVersion(const std::string &timer_name=std::string()) const
Returns backend version.
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition timer_mgr.cc:446
RAII class creating a critical section.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition buffer.h:343
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
const size_t OID_INT4
const size_t OID_INT2
boost::shared_ptr< IOServiceAccessor > IOServiceAccessorPtr
Pointer to an instance of IOServiceAccessor.
const size_t OID_VARCHAR
boost::shared_ptr< PsqlBindArray > PsqlBindArrayPtr
Defines a smart pointer to PsqlBindArray.
const size_t OID_TEXT
const size_t OID_BOOL
const size_t OID_INT8
const size_t OID_BYTEA
std::function< bool(util::ReconnectCtlPtr db_reconnect_ctl)> DbCallback
Defines a callback prototype for propagating events upward.
std::function< isc::asiolink::IOServicePtr()> IOServiceAccessor
Function which returns the IOService that can be used to recover the connection.
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition dhcpsrv_log.h:56
boost::shared_ptr< PgSqlHostContext > PgSqlHostContextPtr
Type of pointers to contexts.
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Definition cfg_option.h:803
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
Definition host.h:807
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
Definition host.h:813
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB_GET_VERSION
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
Definition host.h:243
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition dhcpsrv_log.h:38
const isc::log::MessageID DHCPSRV_PGSQL_NO_TLS_SUPPORT
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB_RECONNECT_ATTEMPT_FAILED
const isc::log::MessageID DHCPSRV_PGSQL_TLS_SUPPORT
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition subnet_id.h:25
uint64_t HostID
HostID (used only when storing in MySQL or PostgreSQL backends)
Definition host.h:69
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
Definition cfg_option.h:303
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB_RECONNECT_ATTEMPT_SCHEDULE
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Definition host.h:810
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB_RECONNECT_FAILED
const size_t OPTION_VALUE_MAX_LEN
Maximum length of option value.
Definition host.h:45
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition option.h:24
boost::shared_ptr< PgSqlHostContextPool > PgSqlHostContextPoolPtr
Type of pointers to context pools.
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB_READONLY
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
Definition cfg_option.h:806
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
Defines the logger used by the top-level component of kea-lfc.
#define DHCP4_OPTION_SPACE
global std option spaces
#define DHCP6_OPTION_SPACE
static const int BINARY_FMT
Format value for binary data.