Kea 2.7.3
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 = 7;
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 excluded_prefix_index_(reservation_id_index_ + 5),
931 excluded_prefix_len_index_(reservation_id_index_ + 6),
932 most_recent_reservation_id_(0) {
933
934 // Provide names of additional columns returned by the queries.
935 columns_[reservation_id_index_] = "reservation_id";
936 columns_[address_index_] = "address";
937 columns_[prefix_len_index_] = "prefix_len";
938 columns_[type_index_] = "type";
939 columns_[iaid_index_] = "dhcp6_iaid";
940 columns_[excluded_prefix_index_] = "excluded_prefix";
941 columns_[excluded_prefix_len_index_] = "excluded_prefix_len";
942
943 BOOST_STATIC_ASSERT(6 < RESERVATION_COLUMNS);
944 }
945
951 void clear() {
952 PgSqlHostWithOptionsExchange::clear();
953 most_recent_reservation_id_ = 0;
954 }
955
959 uint64_t getReservationId(const PgSqlResult& r, int row) const {
960 uint64_t resv_id = 0;
961 if (!isColumnNull(r, row, reservation_id_index_)) {
962 getColumnValue(r, row, reservation_id_index_, resv_id);
963 }
964
965 return (resv_id);
966 };
967
972 IPv6Resrv retrieveReservation(const PgSqlResult& r, int row) {
973
974 // type: SMALLINT NOT NULL
975 uint16_t tmp;
976 getColumnValue(r, row, type_index_, tmp);
977
978 // Convert it to IPv6 Reservation type (0 = IA_NA, 2 = IA_PD)
979 IPv6Resrv::Type resv_type;
980 switch (tmp) {
981 case 0:
982 resv_type = IPv6Resrv::TYPE_NA;
983 break;
984
985 case 2:
986 resv_type = IPv6Resrv::TYPE_PD;
987 break;
988
989 default:
991 "invalid IPv6 reservation type returned: "
992 << tmp << ". Only 0 or 2 are allowed.");
993 }
994
995 // address VARCHAR(39) NOT NULL
996 isc::asiolink::IOAddress address(getIPv6Value(r, row, address_index_));
997
998 // prefix_len: SMALLINT NOT NULL
999 uint16_t prefix_len;
1000 getColumnValue(r, row, prefix_len_index_, prefix_len);
1001
1002 // @todo once we support populating iaid
1003 // iaid: INT
1004 // int iaid;
1005 // getColumnValue(r, row, iaid_index_, iaid);
1006
1007 // Create the reservation.
1008 IPv6Resrv reservation(resv_type, IOAddress(address), prefix_len);
1009
1010 // excluded_prefix and excluded_prefix_len
1011 if (!isColumnNull(r, row, excluded_prefix_index_)) {
1012 isc::asiolink::IOAddress prefix(getIPv6Value(r, row,
1013 excluded_prefix_index_));
1014 uint16_t excluded_prefix_len;
1015 getColumnValue(r, row, excluded_prefix_len_index_,
1016 excluded_prefix_len);
1017 reservation.setPDExclude(prefix, excluded_prefix_len);
1018 }
1019 return (reservation);
1020 };
1021
1043 virtual void processRowData(ConstHostCollection& hosts,
1044 const PgSqlResult& r, int row) {
1045 // Call parent class to fetch host information and options.
1046 PgSqlHostWithOptionsExchange::processRowData(hosts, r, row);
1047
1048 // Shouldn't happen but just in case
1049 if (hosts.empty()) {
1050 isc_throw(Unexpected, "no host information while retrieving"
1051 " IPv6 reservation");
1052 }
1053
1054 // If we have reservation id we haven't seen yet, retrieve the
1055 // the reservation, adding it to the current host
1056 uint64_t reservation_id = getReservationId(r, row);
1057 if (reservation_id && (reservation_id > most_recent_reservation_id_)) {
1058 HostPtr host = boost::const_pointer_cast<Host>(hosts.back());
1059 host->addReservation(retrieveReservation(r, row));
1060 most_recent_reservation_id_ = reservation_id;
1061 }
1062 }
1063
1064private:
1066
1067
1068 size_t reservation_id_index_;
1069
1071 size_t address_index_;
1072
1074 size_t prefix_len_index_;
1075
1077 size_t type_index_;
1078
1080 size_t iaid_index_;
1081
1083 size_t excluded_prefix_index_;
1084
1086 size_t excluded_prefix_len_index_;
1087
1089
1091 uint64_t most_recent_reservation_id_;
1092};
1093
1104class PgSqlIPv6ReservationExchange : public PgSqlExchange {
1105private:
1106
1108 static const size_t RESRV_COLUMNS = 8;
1109
1110public:
1111
1115 PgSqlIPv6ReservationExchange()
1116 : PgSqlExchange(RESRV_COLUMNS),
1117 resv_(IPv6Resrv::TYPE_NA, asiolink::IOAddress("::"), 128) {
1118 // Set the column names (for error messages)
1119 columns_[0] = "host_id";
1120 columns_[1] = "address";
1121 columns_[2] = "prefix_len";
1122 columns_[3] = "type";
1123 columns_[4] = "dhcp6_iaid";
1124 columns_[5] = "excluded_prefix";
1125 columns_[6] = "excluded_prefix_len";
1126
1127 BOOST_STATIC_ASSERT(7 < RESRV_COLUMNS);
1128 }
1129
1144 PsqlBindArrayPtr createBindForSend(const IPv6Resrv& resv,
1145 const HostID& host_id,
1146 const bool unique_ip) {
1147 // Store the values to ensure they remain valid.
1148 // Technically we don't need this, as currently all the values
1149 // are converted to strings and stored by the bind array.
1150 resv_ = resv;
1151
1152 PsqlBindArrayPtr bind_array(new PsqlBindArray());
1153
1154 try {
1155 // address VARCHAR(39) NOT NULL
1156 bind_array->add(resv.getPrefix());
1157
1158 // prefix_len: SMALLINT NOT NULL
1159 bind_array->add(resv.getPrefixLen());
1160
1161 // type: SMALLINT NOT NULL
1162 // See lease6_types table for values (0 = IA_NA, 2 = IA_PD)
1163 uint16_t type = resv.getType() == IPv6Resrv::TYPE_NA ? 0 : 2;
1164 bind_array->add(type);
1165
1166 // dhcp6_iaid: INT UNSIGNED
1168 bind_array->addNull();
1169
1170 // excluded_prefix INET NOT NULL.
1171 Option6PDExcludePtr opt = resv.getPDExclude();
1172 if (opt) {
1173 IOAddress excluded_prefix =
1174 opt->getExcludedPrefix(resv.getPrefix(),
1175 resv.getPrefixLen());
1176 bind_array->add(excluded_prefix);
1177 } else {
1178 bind_array->addNull();
1179 }
1180 uint16_t excluded_prefix_len(opt ? opt->getExcludedPrefixLength() : 0);
1181 bind_array->add(excluded_prefix_len);
1182
1183 // host_id: BIGINT NOT NULL
1184 bind_array->add(host_id);
1185
1186 // When checking whether the IP is unique we need to bind the IPv6 address
1187 // and prefix length at the end of the query as it has additional binding
1188 // for the IPv6 address and prefix length.
1189 if (unique_ip) {
1190 bind_array->add(resv.getPrefix()); // address
1191 bind_array->add(resv.getPrefixLen()); // prefix_len
1192 }
1193 } catch (const std::exception& ex) {
1195 "Could not create bind array from IPv6 Reservation: "
1196 << resv_.toText() << ", reason: " << ex.what());
1197 }
1198
1199 return (bind_array);
1200 }
1201
1202private:
1204 IPv6Resrv resv_;
1205};
1206
1210class PgSqlOptionExchange : public PgSqlExchange {
1211private:
1212
1213 static const size_t OPTION_ID_COL = 0;
1214 static const size_t CODE_COL = 1;
1215 static const size_t VALUE_COL = 2;
1216 static const size_t FORMATTED_VALUE_COL = 3;
1217 static const size_t SPACE_COL = 4;
1218 static const size_t PERSISTENT_COL = 5;
1219 static const size_t CANCELLED_COL = 6;
1220 static const size_t USER_CONTEXT_COL = 7;
1221 static const size_t DHCP_SUBNET_ID_COL = 8;
1222 static const size_t HOST_ID_COL = 9;
1224 static const size_t OPTION_COLUMNS = 10;
1225
1226public:
1227
1229 PgSqlOptionExchange()
1230 : PgSqlExchange(OPTION_COLUMNS), value_(),
1231 value_len_(0), option_() {
1232 columns_[OPTION_ID_COL] = "option_id";
1233 columns_[CODE_COL] = "code";
1234 columns_[VALUE_COL] = "value";
1235 columns_[FORMATTED_VALUE_COL] = "formatted_value";
1236 columns_[SPACE_COL] = "space";
1237 columns_[PERSISTENT_COL] = "persistent";
1238 columns_[CANCELLED_COL] = "cancelled";
1239 columns_[USER_CONTEXT_COL] = "user_context";
1240 columns_[DHCP_SUBNET_ID_COL] = "dhcp_subnet_id";
1241 columns_[HOST_ID_COL] = "host_id";
1242
1243 BOOST_STATIC_ASSERT(10 <= OPTION_COLUMNS);
1244 }
1245
1254 PsqlBindArrayPtr createBindForSend(const OptionDescriptor& opt_desc,
1255 const std::string& opt_space,
1256 const HostID& host_id) {
1257 // Hold pointer to the option to make sure it remains valid until
1258 // we complete a query.
1259 option_ = opt_desc.option_;
1260
1261 // Create the bind-array
1262 PsqlBindArrayPtr bind_array(new PsqlBindArray());
1263
1264 try {
1265 // option_id: is auto_incremented so skip it
1266
1267 // code: SMALLINT UNSIGNED NOT NULL
1268 bind_array->add(option_->getType());
1269
1270 // value: BYTEA NULL
1271 if (opt_desc.formatted_value_.empty() &&
1272 (opt_desc.option_->len() > opt_desc.option_->getHeaderLen())) {
1273 // The formatted_value is empty and the option value is
1274 // non-empty so we need to prepare on-wire format for the
1275 // option and store it in the database as a BYTEA.
1276 OutputBuffer buf(opt_desc.option_->len());
1277 opt_desc.option_->pack(buf);
1278 const uint8_t* buf_ptr = buf.getData();
1279 value_.assign(buf_ptr + opt_desc.option_->getHeaderLen(),
1280 buf_ptr + buf.getLength());
1281 value_len_ = value_.size();
1282 bind_array->add(value_);
1283 } else {
1284 // No value or formatted_value specified. In this case, the
1285 // value BYTEA should be NULL.
1286 bind_array->addNull(PsqlBindArray::BINARY_FMT);
1287 }
1288
1289 // formatted_value: TEXT NULL,
1290 if (!opt_desc.formatted_value_.empty()) {
1291 bind_array->addTempString(opt_desc.formatted_value_);
1292 } else {
1293 bind_array->addNull();
1294 }
1295
1296 // space: VARCHAR(128) NULL
1297 if (!opt_space.empty()) {
1298 bind_array->addTempString(opt_space);
1299 } else {
1300 bind_array->addNull();
1301 }
1302
1303 // persistent: BOOLEAN DEFAULT false
1304 bind_array->add(opt_desc.persistent_);
1305
1306 // cancelled: BOOLEAN DEFAULT false
1307 bind_array->add(opt_desc.cancelled_);
1308
1309 // user_context: TEXT NULL,
1310 ConstElementPtr ctx = opt_desc.getContext();
1311 if (ctx) {
1312 std::string user_context_ = ctx->str();
1313 bind_array->addTempString(user_context_);
1314 } else {
1315 bind_array->addNull();
1316 }
1317
1318 // host_id: INT NULL
1319 if (!host_id) {
1320 isc_throw(BadValue, "host_id cannot be null");
1321 }
1322 bind_array->add(host_id);
1323
1324 } catch (const std::exception& ex) {
1326 "Could not create bind array for inserting DHCP "
1327 "host option: " << option_->toText() << ", reason: "
1328 << ex.what());
1329 }
1330
1331 return (bind_array);
1332 }
1333
1334private:
1335
1337 std::vector<uint8_t> value_;
1338
1340 size_t value_len_;
1341
1343 OptionPtr option_;
1344};
1345
1346} // namespace
1347
1348namespace isc {
1349namespace dhcp {
1350
1361public:
1362
1369 IOServiceAccessorPtr io_service_accessor,
1370 db::DbCallback db_reconnect_callback);
1371
1376
1379 boost::shared_ptr<PgSqlHostWithOptionsExchange> host_ipv4_exchange_;
1380
1383 boost::shared_ptr<PgSqlHostIPv6Exchange> host_ipv6_exchange_;
1384
1388 boost::shared_ptr<PgSqlHostIPv6Exchange> host_ipv46_exchange_;
1389
1392 boost::shared_ptr<PgSqlIPv6ReservationExchange> host_ipv6_reservation_exchange_;
1393
1397 boost::shared_ptr<PgSqlOptionExchange> host_option_exchange_;
1398
1401
1404};
1405
1413public:
1414
1416 std::vector<PgSqlHostContextPtr> pool_;
1417
1419 std::mutex mutex_;
1420};
1421
1423typedef boost::shared_ptr<PgSqlHostContextPool> PgSqlHostContextPoolPtr;
1424
1427public:
1428
1438 GET_HOST_DHCPID, // Gets hosts by host identifier
1439 GET_HOST_ADDR, // Gets hosts by IPv4 address
1440 GET_HOST_SUBID4_DHCPID, // Gets host by IPv4 SubnetID, HW address/DUID
1441 GET_HOST_SUBID6_DHCPID, // Gets host by IPv6 SubnetID, HW address/DUID
1442 GET_HOST_SUBID_ADDR, // Gets host by IPv4 SubnetID and IPv4 address
1443 GET_HOST_PREFIX, // Gets host by IPv6 prefix
1444 GET_HOST_SUBID6_ADDR, // Gets host by IPv6 SubnetID and IPv6 prefix
1445 GET_HOST_ADDR6, // Gets hosts by IPv6 address/prefix
1446 GET_HOST_SUBID4, // Gets hosts by IPv4 SubnetID
1447 GET_HOST_SUBID6, // Gets hosts by IPv6 SubnetID
1448 GET_HOST_HOSTNAME, // Gets hosts by hostname
1449 GET_HOST_HOSTNAME_SUBID4, // Gets hosts by hostname and IPv4 SubnetID
1450 GET_HOST_HOSTNAME_SUBID6, // Gets hosts by hostname and IPv6 SubnetID
1451 GET_HOST_SUBID4_PAGE, // Gets hosts by IPv4 SubnetID beginning by HID
1452 GET_HOST_SUBID6_PAGE, // Gets hosts by IPv6 SubnetID beginning by HID
1453 GET_HOST_PAGE4, // Gets v4 hosts beginning by HID
1454 GET_HOST_PAGE6, // Gets v6 hosts beginning by HID
1455 INSERT_HOST_NON_UNIQUE_IP, // Insert new host to collection with allowing IP duplicates
1456 INSERT_HOST_UNIQUE_IP, // Insert new host to collection with checking for IP duplicates
1457 INSERT_V6_RESRV_NON_UNIQUE,// Insert v6 reservation without checking that it is unique
1458 INSERT_V6_RESRV_UNIQUE, // Insert v6 reservation with checking that it is unique
1459 INSERT_V4_HOST_OPTION, // Insert DHCPv4 option
1460 INSERT_V6_HOST_OPTION, // Insert DHCPv6 option
1461 DEL_HOST_ADDR4, // Delete v4 host (subnet-id, addr4)
1462 DEL_HOST_ADDR6, // Delete v6 host (subnet-id, addr6)
1463 DEL_HOST_SUBID4_ID, // Delete v4 host (subnet-id, ident.type, identifier)
1464 DEL_HOST_SUBID6_ID, // Delete v6 host (subnet-id, ident.type, identifier)
1465 NUM_STATEMENTS // Number of statements
1467
1474
1480
1483
1506 static bool dbReconnect(ReconnectCtlPtr db_reconnect_ctl);
1507
1518
1535 uint64_t addStatement(PgSqlHostContextPtr& ctx,
1537 PsqlBindArrayPtr& bind,
1538 const bool return_last_id = false);
1539
1549 PsqlBindArrayPtr& bind);
1550
1556 void addResv(PgSqlHostContextPtr& ctx,
1557 const IPv6Resrv& resv,
1558 const HostID& id);
1559
1571 const OptionDescriptor& opt_desc,
1572 const std::string& opt_space,
1573 const Optional<SubnetID>& subnet_id,
1574 const HostID& host_id);
1575
1585 const StatementIndex& stindex,
1586 const ConstCfgOptionPtr& options_cfg,
1587 const uint64_t host_id);
1588
1608 StatementIndex stindex,
1609 PsqlBindArrayPtr bind,
1610 boost::shared_ptr<PgSqlHostExchange> exchange,
1611 ConstHostCollection& result,
1612 bool single) const;
1613
1632 const SubnetID& subnet_id,
1633 const Host::IdentifierType& identifier_type,
1634 const uint8_t* identifier_begin,
1635 const size_t identifier_len,
1636 StatementIndex stindex,
1637 boost::shared_ptr<PgSqlHostExchange> exchange) const;
1638
1648 void checkReadOnly(PgSqlHostContextPtr& ctx) const;
1649
1659 std::pair<uint32_t, uint32_t> getVersion(const std::string& timer_name = std::string()) const;
1660
1663
1667
1670
1674
1676 std::string timer_name_;
1677};
1678
1679namespace {
1680
1682typedef boost::array<PgSqlTaggedStatement, PgSqlHostDataSourceImpl::NUM_STATEMENTS>
1683TaggedStatementArray;
1684
1687TaggedStatementArray tagged_statements = { {
1688 // PgSqlHostDataSourceImpl::GET_HOST_DHCPID
1689 // Retrieves host information, IPv6 reservations and both DHCPv4 and
1690 // DHCPv6 options associated with the host. The LEFT JOIN clause is used
1691 // to retrieve information from 4 different tables using a single query.
1692 // Hence, this query returns multiple rows for a single host.
1693 {2,
1694 { OID_BYTEA, OID_INT2 },
1695 "get_host_dhcpid",
1696 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1697 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
1698 " h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
1699 " h.user_context, "
1700 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1701 " h.dhcp4_boot_file_name, h.auth_key, "
1702 " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
1703 " o4.persistent, o4.cancelled, o4.user_context, "
1704 " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
1705 " o6.persistent, o6.cancelled, o6.user_context, "
1706 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1707 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1708 "FROM hosts AS h "
1709 "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id "
1710 "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id "
1711 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1712 "WHERE dhcp_identifier = $1 AND dhcp_identifier_type = $2 "
1713 "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id"
1714 },
1715
1716 // PgSqlHostDataSourceImpl::GET_HOST_ADDR
1717 // Retrieves host information along with the DHCPv4 options associated with
1718 // it. Left joining the dhcp4_options table results in multiple rows being
1719 // returned for the same host. The host is retrieved by IPv4 address.
1720 {1,
1721 { OID_INT8 },
1722 "get_host_addr",
1723 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1724 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1725 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1726 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1727 " h.dhcp4_boot_file_name, h.auth_key, "
1728 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1729 " o.persistent, o.cancelled, o.user_context "
1730 "FROM hosts AS h "
1731 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1732 "WHERE ipv4_address = $1 "
1733 "ORDER BY h.host_id, o.option_id"
1734 },
1735
1736 // PgSqlHostDataSourceImpl::GET_HOST_SUBID4_DHCPID
1737 // Retrieves host information and DHCPv4 options using subnet identifier
1738 // and client's identifier. Left joining the dhcp4_options table results in
1739 // multiple rows being returned for the same host.
1740 {3,
1742 "get_host_subid4_dhcpid",
1743 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1744 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1745 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1746 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1747 " h.dhcp4_boot_file_name, h.auth_key, "
1748 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1749 " o.persistent, o.cancelled, o.user_context "
1750 "FROM hosts AS h "
1751 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1752 "WHERE h.dhcp4_subnet_id = $1 AND h.dhcp_identifier_type = $2 "
1753 " AND h.dhcp_identifier = $3 "
1754 "ORDER BY h.host_id, o.option_id"
1755 },
1756
1757 // PgSqlHostDataSourceImpl::GET_HOST_SUBID6_DHCPID
1758 // Retrieves host information, IPv6 reservations and DHCPv6 options
1759 // associated with a host. The number of rows returned is a multiplication
1760 // of number of IPv6 reservations and DHCPv6 options.
1761 {3,
1763 "get_host_subid6_dhcpid",
1764 "SELECT h.host_id, h.dhcp_identifier, "
1765 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1766 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1767 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1768 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1769 " h.dhcp4_boot_file_name, h.auth_key, "
1770 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1771 " o.persistent, o.cancelled, o.user_context, "
1772 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1773 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1774 "FROM hosts AS h "
1775 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1776 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1777 "WHERE h.dhcp6_subnet_id = $1 AND h.dhcp_identifier_type = $2 "
1778 " AND h.dhcp_identifier = $3 "
1779 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1780 },
1781
1782 // PgSqlHostDataSourceImpl::GET_HOST_SUBID_ADDR
1783 // Retrieves host information and DHCPv4 options for the host using subnet
1784 // identifier and IPv4 reservation. Left joining the dhcp4_options table
1785 // results in multiple rows being returned for the host. The number of
1786 // rows depends on the number of options defined for the host.
1787 {2,
1788 { OID_INT8, OID_INT8 },
1789 "get_host_subid_addr",
1790 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1791 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1792 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1793 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1794 " h.dhcp4_boot_file_name, h.auth_key, "
1795 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1796 " o.persistent, o.cancelled, o.user_context "
1797 "FROM hosts AS h "
1798 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1799 "WHERE h.dhcp4_subnet_id = $1 AND h.ipv4_address = $2 "
1800 "ORDER BY h.host_id, o.option_id"
1801 },
1802
1803 // PgSqlHostDataSourceImpl::GET_HOST_PREFIX
1804 // Retrieves host information, IPv6 reservations and DHCPv6 options
1805 // associated with a host using prefix and prefix length. This query
1806 // returns host information for a single host. However, multiple rows
1807 // are returned due to left joining IPv6 reservations and DHCPv6 options.
1808 // The number of rows returned is multiplication of number of existing
1809 // IPv6 reservations and DHCPv6 options.
1810 {2,
1811 { OID_VARCHAR, OID_INT2 },
1812 "get_host_prefix",
1813 "SELECT h.host_id, h.dhcp_identifier, "
1814 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1815 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1816 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1817 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1818 " h.dhcp4_boot_file_name, h.auth_key, "
1819 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1820 " o.persistent, o.cancelled, o.user_context, "
1821 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1822 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1823 "FROM hosts AS h "
1824 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1825 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1826 "WHERE h.host_id = "
1827 " (SELECT host_id FROM ipv6_reservations "
1828 " WHERE address = cast($1 as inet) AND prefix_len = $2) "
1829 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1830 },
1831
1832 // PgSqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR
1833 // Retrieves host information, IPv6 reservations and DHCPv6 options
1834 // associated with a host using IPv6 subnet id and prefix. This query
1835 // returns host information for a single host. However, multiple rows
1836 // are returned due to left joining IPv6 reservations and DHCPv6 options.
1837 // The number of rows returned is multiplication of number of existing
1838 // IPv6 reservations and DHCPv6 options.
1839 {2,
1840 { OID_INT8, OID_VARCHAR },
1841 "get_host_subid6_addr",
1842 "SELECT h.host_id, h.dhcp_identifier, "
1843 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1844 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1845 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1846 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1847 " h.dhcp4_boot_file_name, h.auth_key, "
1848 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1849 " o.persistent, o.cancelled, o.user_context, "
1850 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1851 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1852 "FROM hosts AS h "
1853 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1854 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1855 "WHERE h.dhcp6_subnet_id = $1 AND h.host_id IN "
1856 " (SELECT host_id FROM ipv6_reservations "
1857 " WHERE address = cast($2 as inet)) "
1858 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1859 },
1860
1861 // PgSqlHostDataSourceImpl::GET_HOST_ADDR6
1862 // Retrieves host information, IPv6 reservations and DHCPv6 options
1863 // associated with a host using IPv6 address/prefix. This query
1864 // may return host information for one or more host reservations. Even
1865 // if only one host is found, multiple rows
1866 // are returned due to left joining IPv6 reservations and DHCPv6 options.
1867 // The number of rows returned is multiplication of number of existing
1868 // IPv6 reservations and DHCPv6 options.
1869 {1,
1870 { OID_VARCHAR },
1871 "get_host_addr6",
1872 "SELECT h.host_id, h.dhcp_identifier, "
1873 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1874 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1875 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1876 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1877 " h.dhcp4_boot_file_name, h.auth_key, "
1878 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1879 " o.persistent, o.cancelled, o.user_context, "
1880 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1881 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1882 "FROM hosts AS h "
1883 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1884 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1885 "WHERE h.host_id IN "
1886 " (SELECT host_id FROM ipv6_reservations "
1887 " WHERE address = cast($1 as inet)) "
1888 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1889 },
1890
1891 // PgSqlHostDataSourceImpl::GET_HOST_SUBID4
1892 //
1893 // Retrieves host information for all hosts in a subnet, along with the
1894 // DHCPv4 options associated with it. Left joining the dhcp4_options table
1895 // results in multiple rows being returned for the same host. The hosts are
1896 // retrieved by subnet id.
1897 {1,
1898 { OID_INT8 },
1899 "get_host_subid4",
1900 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1901 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1902 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1903 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1904 " h.dhcp4_boot_file_name, h.auth_key, "
1905 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1906 " o.persistent, o.cancelled, o.user_context "
1907 "FROM hosts AS h "
1908 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1909 "WHERE h.dhcp4_subnet_id = $1 "
1910 "ORDER BY h.host_id, o.option_id"
1911 },
1912
1913 // PgSqlHostDataSourceImpl::GET_HOST_SUBID6
1914 //
1915 // Retrieves host information, IPv6 reservations and DHCPv6 options
1916 // associated with all hosts using the IPv6 subnet id. This query returns
1917 // host information for many hosts. However, multiple rows are
1918 // returned due to left joining IPv6 reservations and DHCPv6 options.
1919 // The number of rows returned is multiplication of number of existing
1920 // IPv6 reservations and DHCPv6 options for each host in a subnet. There
1921 // are usually many hosts in a subnet. The amount of returned data may
1922 // be huge.
1923 {1,
1924 { OID_INT8 },
1925 "get_host_subid6",
1926 "SELECT h.host_id, h.dhcp_identifier, "
1927 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1928 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1929 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1930 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1931 " h.dhcp4_boot_file_name, h.auth_key, "
1932 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1933 " o.persistent, o.cancelled, o.user_context, "
1934 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1935 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1936 "FROM hosts AS h "
1937 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1938 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1939 "WHERE h.dhcp6_subnet_id = $1 "
1940 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1941 },
1942
1943 // PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME
1944 // Retrieves host information, IPv6 reservations and both DHCPv4 and
1945 // DHCPv6 options associated with all hosts using the hostname.
1946 // The LEFT JOIN clause is used to retrieve information from 4 different
1947 // tables using a single query. Hence, this query returns multiple rows
1948 // for a single host.
1949 {1,
1950 { OID_VARCHAR },
1951 "get_host_hostname",
1952 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1953 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
1954 " h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
1955 " h.user_context, "
1956 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1957 " h.dhcp4_boot_file_name, h.auth_key, "
1958 " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
1959 " o4.persistent, o4.cancelled, o4.user_context, "
1960 " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
1961 " o6.persistent, o6.cancelled, o6.user_context, "
1962 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1963 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1964 "FROM hosts AS h "
1965 "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id "
1966 "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id "
1967 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1968 "WHERE lower(h.hostname) = $1 "
1969 "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id"
1970 },
1971
1972 // PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID4
1973 // Retrieves host information for all hosts with a hostname in a subnet,
1974 // along with the DHCPv4 options associated with it. Left joining
1975 // the dhcp4_options table results in multiple rows being returned for
1976 // the same host.
1977 {2,
1978 { OID_VARCHAR, OID_INT8 },
1979 "get_host_hostname_subid4",
1980 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1981 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1982 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1983 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1984 " h.dhcp4_boot_file_name, h.auth_key, "
1985 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1986 " o.persistent, o.cancelled, o.user_context "
1987 "FROM hosts AS h "
1988 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1989 "WHERE lower(h.hostname) = $1 AND h.dhcp4_subnet_id = $2 "
1990 "ORDER BY h.host_id, o.option_id"
1991 },
1992
1993 // PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID6
1994 // Retrieves host information, IPv6 reservations and DHCPv6 options
1995 // associated with all hosts using the hostname and the IPv6 subnet id.
1996 // This query returns host information for many hosts. However, multiple
1997 // rows are returned due to left joining IPv6 reservations and DHCPv6
1998 // options. The number of rows returned is multiplication of number of
1999 // existing IPv6 reservations and DHCPv6 options for each host in a subnet.
2000 {2,
2001 { OID_VARCHAR, OID_INT8 },
2002 "get_host_hostname_subid6",
2003 "SELECT h.host_id, h.dhcp_identifier, "
2004 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2005 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2006 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2007 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2008 " h.dhcp4_boot_file_name, h.auth_key, "
2009 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2010 " o.persistent, o.cancelled, o.user_context, "
2011 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
2012 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
2013 "FROM hosts AS h "
2014 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
2015 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
2016 "WHERE lower(h.hostname) = $1 AND h.dhcp6_subnet_id = $2 "
2017 "ORDER BY h.host_id, o.option_id, r.reservation_id"
2018 },
2019
2020 // PgSqlHostDataSourceImpl::GET_HOST_SUBID4_PAGE
2021 // Retrieves host information along with the DHCPv4 options associated with
2022 // it. Left joining the dhcp4_options table results in multiple rows being
2023 // returned for the same host. The hosts are retrieved by subnet id,
2024 // starting from specified host id. Specified number of hosts is returned.
2025 {3,
2027 "get_host_subid4_page",
2028 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2029 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2030 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2031 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2032 " h.dhcp4_boot_file_name, h.auth_key, "
2033 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2034 " o.persistent, o.cancelled, o.user_context "
2035 "FROM ( SELECT * FROM hosts AS h "
2036 " WHERE h.dhcp4_subnet_id = $1 AND h.host_id > $2 "
2037 " ORDER BY h.host_id "
2038 " LIMIT $3 ) AS h "
2039 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
2040 "ORDER BY h.host_id, o.option_id"
2041 },
2042
2043 // PgSqlHostDataSourceImpl::GET_HOST_SUBID6_PAGE
2044 // Retrieves host information, IPv6 reservations and DHCPv6 options
2045 // associated with a host using IPv6 subnet id. This query returns
2046 // host information for a single host. However, multiple rows are
2047 // returned due to left joining IPv6 reservations and DHCPv6 options.
2048 // The number of rows returned is multiplication of number of existing
2049 // IPv6 reservations and DHCPv6 options.
2050 {3,
2052 "get_host_subid6_page",
2053 "SELECT h.host_id, h.dhcp_identifier, "
2054 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2055 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2056 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2057 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2058 " h.dhcp4_boot_file_name, h.auth_key, "
2059 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2060 " o.persistent, o.cancelled, o.user_context, "
2061 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
2062 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
2063 "FROM ( SELECT * FROM hosts AS h "
2064 " WHERE h.dhcp6_subnet_id = $1 AND h.host_id > $2 "
2065 " ORDER BY h.host_id "
2066 " LIMIT $3 ) AS h "
2067 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
2068 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
2069 "ORDER BY h.host_id, o.option_id, r.reservation_id"
2070 },
2071
2072 // PgSqlHostDataSourceImpl::GET_HOST_PAGE4
2073 // Retrieves host information along with the DHCPv4 options associated with
2074 // it. Left joining the dhcp4_options table results in multiple rows being
2075 // returned for the same host. The hosts are retrieved starting from
2076 // specified host id. Specified number of hosts is returned.
2077 {2,
2078 { OID_INT8, OID_INT8 },
2079 "get_host_page4",
2080 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2081 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2082 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2083 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2084 " h.dhcp4_boot_file_name, h.auth_key, "
2085 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2086 " o.persistent, o.cancelled, o.user_context "
2087 "FROM ( SELECT * FROM hosts AS h "
2088 " WHERE h.host_id > $1 "
2089 " ORDER BY h.host_id "
2090 " LIMIT $2 ) AS h "
2091 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
2092 "ORDER BY h.host_id, o.option_id"
2093 },
2094
2095 // PgSqlHostDataSourceImpl::GET_HOST_PAGE6
2096 // Retrieves host information, IPv6 reservations and DHCPv6 options
2097 // associated with a host using IPv6 subnet id. This query returns
2098 // host information for a single host. However, multiple rows are
2099 // returned due to left joining IPv6 reservations and DHCPv6 options.
2100 // The number of rows returned is multiplication of number of existing
2101 // IPv6 reservations and DHCPv6 options.
2102 {2,
2103 { OID_INT8, OID_INT8 },
2104 "get_host_page6",
2105 "SELECT h.host_id, h.dhcp_identifier, "
2106 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2107 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2108 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2109 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2110 " h.dhcp4_boot_file_name, h.auth_key, "
2111 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2112 " o.persistent, o.cancelled, o.user_context, "
2113 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
2114 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
2115 "FROM ( SELECT * FROM hosts AS h "
2116 " WHERE h.host_id > $1 "
2117 " ORDER BY h.host_id "
2118 " LIMIT $2 ) AS h "
2119 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
2120 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
2121 "ORDER BY h.host_id, o.option_id, r.reservation_id"
2122 },
2123
2124 // PgSqlHostDataSourceImpl::INSERT_HOST_NON_UNIQUE_IP
2125 // Inserts a host into the 'hosts' table without checking that there is
2126 // a reservation for the IP address.
2127 {13,
2132 "insert_host_non_unique_ip",
2133 "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
2134 " dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
2135 " dhcp4_client_classes, dhcp6_client_classes, user_context, "
2136 " dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name, auth_key)"
2137 "VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13 ) "
2138 "RETURNING host_id"
2139 },
2140
2141 // PgSqlHostDataSourceImpl::INSERT_HOST_UNIQUE_IP
2142 // Inserts a host into the 'hosts' table with checking that reserved IP
2143 // address is unique. The innermost query checks if there is at least
2144 // one host for the given IP/subnet combination. For checking whether
2145 // hosts exists or not it doesn't matter if we select actual columns,
2146 // thus SELECT 1 was used as an optimization to avoid selecting data
2147 // that will be ignored anyway. If it does not exist the new host is
2148 // inserted. If the host with the given IP address already exists the
2149 // new host won't be inserted. The caller can check the number of
2150 // affected rows to detect that there was a duplicate host in the
2151 // database. Returns the inserted host id.
2152 {15,
2158 "insert_host_unique_ip",
2159 "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
2160 " dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
2161 " dhcp4_client_classes, dhcp6_client_classes, user_context, "
2162 " dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name, auth_key)"
2163 " SELECT $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13"
2164 " WHERE NOT EXISTS ("
2165 " SELECT 1 FROM hosts WHERE ipv4_address = $14 AND dhcp4_subnet_id = $15"
2166 " LIMIT 1"
2167 " ) "
2168 "RETURNING host_id"
2169 },
2170
2171 // PgSqlHostDataSourceImpl::INSERT_V6_RESRV_NON_UNIQUE
2172 // Inserts a single IPv6 reservation into 'reservations' table without
2173 // checking that the inserted reservation is unique.
2174 {7,
2176 "insert_v6_resrv_non_unique",
2177 "INSERT INTO ipv6_reservations(address, prefix_len, type, "
2178 " dhcp6_iaid, excluded_prefix, excluded_prefix_len, host_id) "
2179 "VALUES (cast($1 as inet), $2, $3, $4, cast($5 as inet), $6, $7)"
2180 },
2181
2182 // PgSqlHostDataSourceImpl::INSERT_V6_RESRV_UNIQUE
2183 // Inserts a single IPv6 reservation into 'reservations' table with
2184 // checking that the inserted reservation is unique.
2185 {9,
2188 "insert_v6_resrv_unique",
2189 "INSERT INTO ipv6_reservations(address, prefix_len, type, "
2190 " dhcp6_iaid, excluded_prefix, excluded_prefix_len, host_id) "
2191 "SELECT cast($1 as inet), $2, $3, $4, cast($5 as inet), $6, $7 "
2192 " WHERE NOT EXISTS ("
2193 " SELECT 1 FROM ipv6_reservations"
2194 " WHERE address = cast($8 as inet) AND prefix_len = $9"
2195 " LIMIT 1"
2196 " )"
2197 },
2198
2199 // PgSqlHostDataSourceImpl::INSERT_V4_HOST_OPTION
2200 // Inserts a single DHCPv4 option into 'dhcp4_options' table.
2201 // Using fixed scope_id = 3, which associates an option with host.
2202 {8,
2205 "insert_v4_host_option",
2206 "INSERT INTO dhcp4_options(code, value, formatted_value, space, "
2207 " persistent, cancelled, user_context, host_id, scope_id) "
2208 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 3)"
2209 },
2210
2211 // PgSqlHostDataSourceImpl::INSERT_V6_HOST_OPTION
2212 // Inserts a single DHCPv6 option into 'dhcp6_options' table.
2213 // Using fixed scope_id = 3, which associates an option with host.
2214 {8,
2217 "insert_v6_host_option",
2218 "INSERT INTO dhcp6_options(code, value, formatted_value, space, "
2219 " persistent, cancelled, user_context, host_id, scope_id) "
2220 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 3)"
2221 },
2222
2223 // PgSqlHostDataSourceImpl::DEL_HOST_ADDR4
2224 // Deletes a v4 host that matches (subnet-id, addr4)
2225 {2,
2226 { OID_INT8, OID_INT8 },
2227 "del_host_addr4",
2228 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 AND ipv4_address = $2"
2229 },
2230
2231 // PgSqlHostDataSourceImpl::DEL_HOST_ADDR6
2232 // Deletes a v6 host that matches (subnet-id, addr6)
2233 {2,
2234 { OID_INT8, OID_VARCHAR },
2235 "del_host_addr6",
2236 "DELETE FROM hosts USING ipv6_reservations "
2237 " WHERE hosts.host_id = ipv6_reservations.host_id"
2238 " AND dhcp6_subnet_id = $1 AND ipv6_reservations.address = cast($2 as inet)"
2239 },
2240
2241 // PgSqlHostDataSourceImpl::DEL_HOST_SUBID4_ID
2242 // Deletes a v4 host that matches (subnet4-id, identifier-type, identifier)
2243 {3,
2245 "del_host_subid4_id",
2246 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 "
2247 "AND dhcp_identifier_type = $2 "
2248 "AND dhcp_identifier = $3"
2249 },
2250
2251 // PgSqlHostDataSourceImpl::DEL_HOST_SUBID6_ID
2252 // Deletes a v6 host that matches (subnet6-id, identifier-type, identifier)
2253 {3,
2255 "del_host_subid6_id",
2256 "DELETE FROM hosts WHERE dhcp6_subnet_id = $1 "
2257 "AND dhcp_identifier_type = $2 "
2258 "AND dhcp_identifier = $3"
2259 }
2260}
2261};
2262
2263} // namespace
2264
2265// PgSqlHostContext Constructor
2266
2268 IOServiceAccessorPtr io_service_accessor,
2269 db::DbCallback db_reconnect_callback)
2270 : conn_(parameters, io_service_accessor, db_reconnect_callback),
2271 is_readonly_(true) {
2272}
2273
2274// PgSqlHostContextAlloc Constructor and Destructor
2275
2277 PgSqlHostDataSourceImpl& mgr) : ctx_(), mgr_(mgr) {
2278
2279 if (MultiThreadingMgr::instance().getMode()) {
2280 // multi-threaded
2281 {
2282 // we need to protect the whole pool_ operation, hence extra scope {}
2283 lock_guard<mutex> lock(mgr_.pool_->mutex_);
2284 if (!mgr_.pool_->pool_.empty()) {
2285 ctx_ = mgr_.pool_->pool_.back();
2286 mgr_.pool_->pool_.pop_back();
2287 }
2288 }
2289 if (!ctx_) {
2290 ctx_ = mgr_.createContext();
2291 }
2292 } else {
2293 // single-threaded
2294 if (mgr_.pool_->pool_.empty()) {
2295 isc_throw(Unexpected, "No available PostgreSQL host context?!");
2296 }
2297 ctx_ = mgr_.pool_->pool_.back();
2298 }
2299}
2300
2302 if (MultiThreadingMgr::instance().getMode()) {
2303 // multi-threaded
2304 lock_guard<mutex> lock(mgr_.pool_->mutex_);
2305 mgr_.pool_->pool_.push_back(ctx_);
2306 if (ctx_->conn_.isUnusable()) {
2307 mgr_.unusable_ = true;
2308 }
2309 } else if (ctx_->conn_.isUnusable()) {
2310 mgr_.unusable_ = true;
2311 }
2312}
2313
2315 : parameters_(parameters), ip_reservations_unique_(true), unusable_(false) {
2316
2317 // Check TLS support.
2318 size_t tls(0);
2319 tls += parameters.count("trust-anchor");
2320 tls += parameters.count("cert-file");
2321 tls += parameters.count("key-file");
2322 tls += parameters.count("cipher-list");
2323#ifdef HAVE_PGSQL_SSL
2324 if ((tls > 0) && !PgSqlConnection::warned_about_tls) {
2328 PQinitSSL(1);
2329 }
2330#else
2331 if (tls > 0) {
2334 isc_throw(DbOpenError, "Attempt to configure TLS for PostgreSQL "
2335 << "backend (built with this feature disabled)");
2336 }
2337#endif
2338
2339 // Create unique timer name per instance.
2340 timer_name_ = "PgSqlHostMgr[";
2341 timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
2342 timer_name_ += "]DbReconnectTimer";
2343
2346 timer_name_);
2347
2348 // Create an initial context.
2349 pool_.reset(new PgSqlHostContextPool());
2350 pool_->pool_.push_back(createContext());
2351}
2352
2353// Create context.
2354
2360
2361 // Open the database.
2362 ctx->conn_.openDatabase();
2363
2364 // Now prepare the SQL statements.
2365 ctx->conn_.prepareStatements(tagged_statements.begin(),
2366 tagged_statements.begin() + WRITE_STMTS_BEGIN);
2367
2368 // Check if the backend is explicitly configured to operate with
2369 // read only access to the database.
2370 ctx->is_readonly_ = ctx->conn_.configuredReadOnly();
2371
2372 // If we are using read-write mode for the database we also prepare
2373 // statements for INSERTS etc.
2374 if (!ctx->is_readonly_) {
2375 ctx->conn_.prepareStatements(tagged_statements.begin() + WRITE_STMTS_BEGIN,
2376 tagged_statements.end());
2377 } else {
2379 }
2380
2381 ctx->host_ipv4_exchange_.reset(new PgSqlHostWithOptionsExchange(PgSqlHostWithOptionsExchange::DHCP4_ONLY));
2382 ctx->host_ipv6_exchange_.reset(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP6_ONLY));
2383 ctx->host_ipv46_exchange_.reset(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP4_AND_DHCP6));
2384 ctx->host_ipv6_reservation_exchange_.reset(new PgSqlIPv6ReservationExchange());
2385 ctx->host_option_exchange_.reset(new PgSqlOptionExchange());
2386
2387 // Create ReconnectCtl for this connection.
2388 ctx->conn_.makeReconnectCtl(timer_name_);
2389
2390 return (ctx);
2391}
2392
2395
2396bool
2399
2400 // Invoke application layer connection lost callback.
2401 if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) {
2402 return (false);
2403 }
2404
2405 bool reopened = false;
2406
2407 const std::string timer_name = db_reconnect_ctl->timerName();
2408
2409 // At least one connection was lost.
2410 try {
2411 CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
2412 std::list<std::string> host_db_access_list = cfg_db->getHostDbAccessStringList();
2413 for (std::string& hds : host_db_access_list) {
2414 auto parameters = DatabaseConnection::parse(hds);
2415 if (HostMgr::delBackend("postgresql", hds, true)) {
2417 }
2418 }
2419 reopened = true;
2420 } catch (const std::exception& ex) {
2422 .arg(ex.what());
2423 }
2424
2425 if (reopened) {
2426 // Cancel the timer.
2427 if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
2428 TimerMgr::instance()->unregisterTimer(timer_name);
2429 }
2430
2431 // Invoke application layer connection recovered callback.
2432 if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) {
2433 return (false);
2434 }
2435 } else {
2436 if (!db_reconnect_ctl->checkRetries()) {
2437 // We're out of retries, log it and initiate shutdown.
2439 .arg(db_reconnect_ctl->maxRetries());
2440
2441 // Cancel the timer.
2442 if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
2443 TimerMgr::instance()->unregisterTimer(timer_name);
2444 }
2445
2446 // Invoke application layer connection failed callback.
2448 return (false);
2449 }
2450
2452 .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
2453 .arg(db_reconnect_ctl->maxRetries())
2454 .arg(db_reconnect_ctl->retryInterval());
2455
2456 // Start the timer.
2457 if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
2458 TimerMgr::instance()->registerTimer(timer_name,
2459 std::bind(&PgSqlHostDataSourceImpl::dbReconnect, db_reconnect_ctl),
2460 db_reconnect_ctl->retryInterval(),
2462 }
2463 TimerMgr::instance()->setup(timer_name);
2464 }
2465
2466 return (true);
2467}
2468
2469uint64_t
2471 StatementIndex stindex,
2472 PsqlBindArrayPtr& bind_array,
2473 const bool return_last_id) {
2474 uint64_t last_id = 0;
2475 PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2476 tagged_statements[stindex].nbparams,
2477 &bind_array->values_[0],
2478 &bind_array->lengths_[0],
2479 &bind_array->formats_[0], 0));
2480
2481 int s = PQresultStatus(r);
2482
2483 if (s != PGRES_COMMAND_OK) {
2484 // Failure: check for the special case of duplicate entry.
2485 if (ctx->conn_.compareError(r, PgSqlConnection::DUPLICATE_KEY)) {
2486 isc_throw(DuplicateEntry, "Database duplicate entry error");
2487 }
2488
2489 // Connection determines if the error is fatal or not, and
2490 // throws the appropriate exception
2491 ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2492 }
2493
2494 // Get the number of affected rows.
2495 char* rows_affected = PQcmdTuples(r);
2496 if (!rows_affected) {
2498 "Could not retrieve the number of affected rows.");
2499 }
2500
2501 // If the number of rows inserted is 0 it means that the query detected
2502 // an attempt to insert duplicated data for which there is no unique
2503 // index in the database. Unique indexes are not created in the database
2504 // when it may be sometimes allowed to insert duplicated records per
2505 // server's configuration.
2506 if (rows_affected[0] == '0') {
2507 isc_throw(DuplicateEntry, "Database duplicate entry error");
2508 }
2509
2510 if (return_last_id) {
2511 PgSqlExchange::getColumnValue(r, 0, 0, last_id);
2512 }
2513
2514 return (last_id);
2515}
2516
2517bool
2519 StatementIndex stindex,
2520 PsqlBindArrayPtr& bind_array) {
2521 PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2522 tagged_statements[stindex].nbparams,
2523 &bind_array->values_[0],
2524 &bind_array->lengths_[0],
2525 &bind_array->formats_[0], 0));
2526
2527 int s = PQresultStatus(r);
2528
2529 if (s != PGRES_COMMAND_OK) {
2530 // Connection determines if the error is fatal or not, and
2531 // throws the appropriate exception
2532 ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2533 }
2534
2535 // Now check how many rows (hosts) were deleted. This should be either
2536 // "0" or "1".
2537 char* rows_deleted = PQcmdTuples(r);
2538 if (!rows_deleted) {
2540 "Could not retrieve the number of deleted rows.");
2541 }
2542 return (rows_deleted[0] != '0');
2543}
2544
2545void
2547 const IPv6Resrv& resv,
2548 const HostID& id) {
2549 PsqlBindArrayPtr bind_array = ctx->host_ipv6_reservation_exchange_->
2550 createBindForSend(resv, id, ip_reservations_unique_);
2551
2552 addStatement(ctx,
2554 bind_array);
2555}
2556
2557void
2559 const StatementIndex& stindex,
2560 const OptionDescriptor& opt_desc,
2561 const std::string& opt_space,
2562 const Optional<SubnetID>&,
2563 const HostID& id) {
2564 PsqlBindArrayPtr bind_array = ctx->host_option_exchange_->createBindForSend(opt_desc, opt_space, id);
2565
2566 addStatement(ctx, stindex, bind_array);
2567}
2568
2569void
2571 const StatementIndex& stindex,
2572 const ConstCfgOptionPtr& options_cfg,
2573 const uint64_t host_id) {
2574 // Get option space names and vendor space names and combine them within a
2575 // single list.
2576 std::list<std::string> option_spaces = options_cfg->getOptionSpaceNames();
2577 std::list<std::string> vendor_spaces = options_cfg->getVendorIdsSpaceNames();
2578 option_spaces.insert(option_spaces.end(), vendor_spaces.begin(),
2579 vendor_spaces.end());
2580
2581 // For each option space retrieve all options and insert them into the
2582 // database.
2583 for (auto const& space : option_spaces) {
2584 OptionContainerPtr options = options_cfg->getAllCombined(space);
2585 if (options && !options->empty()) {
2586 for (auto const& opt : *options) {
2587 addOption(ctx, stindex, opt, space, Optional<SubnetID>(), host_id);
2588 }
2589 }
2590 }
2591}
2592
2593void
2595 StatementIndex stindex,
2596 PsqlBindArrayPtr bind_array,
2597 boost::shared_ptr<PgSqlHostExchange> exchange,
2598 ConstHostCollection& result,
2599 bool single) const {
2600
2601 exchange->clear();
2602 PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2603 tagged_statements[stindex].nbparams,
2604 &bind_array->values_[0],
2605 &bind_array->lengths_[0],
2606 &bind_array->formats_[0], 0));
2607
2608 ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2609
2610 int rows = r.getRows();
2611 for (int row = 0; row < rows; ++row) {
2612 exchange->processRowData(result, r, row);
2613
2614 if (single && result.size() > 1) {
2615 isc_throw(MultipleRecords, "multiple records were found in the "
2616 "database where only one was expected for query "
2617 << tagged_statements[stindex].name);
2618 }
2619 }
2620}
2621
2624 const SubnetID& subnet_id,
2625 const Host::IdentifierType& identifier_type,
2626 const uint8_t* identifier_begin,
2627 const size_t identifier_len,
2628 StatementIndex stindex,
2629 boost::shared_ptr<PgSqlHostExchange> exchange) const {
2630
2631 // Set up the WHERE clause value
2632 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2633
2634 // Add the subnet id.
2635 bind_array->add(subnet_id);
2636
2637 // Add the Identifier type.
2638 bind_array->add(static_cast<uint8_t>(identifier_type));
2639
2640 // Add the identifier value.
2641 bind_array->add(identifier_begin, identifier_len);
2642
2643 ConstHostCollection collection;
2644 getHostCollection(ctx, stindex, bind_array, exchange, collection, true);
2645
2646 // Return single record if present, else clear the host.
2647 ConstHostPtr result;
2648 if (!collection.empty()) {
2649 result = *collection.begin();
2650 }
2651
2652 return (result);
2653}
2654
2655std::pair<uint32_t, uint32_t>
2664
2665void
2667 if (ctx->is_readonly_) {
2668 isc_throw(ReadOnlyDb, "PostgreSQL host database backend is configured"
2669 " to operate in read only mode");
2670 }
2671}
2672
2673/*********** PgSqlHostDataSource *********************/
2674
2678
2681
2684 return (impl_->parameters_);
2685}
2686
2687void
2689 // Get a context
2690 PgSqlHostContextAlloc get_context(*impl_);
2691 PgSqlHostContextPtr ctx = get_context.ctx_;
2692
2693 // If operating in read-only mode, throw exception.
2694 impl_->checkReadOnly(ctx);
2695
2696 // Initiate PostgreSQL transaction as we will have to make multiple queries
2697 // to insert host information into multiple tables. If that fails on
2698 // any stage, the transaction will be rolled back by the destructor of
2699 // the PgSqlTransaction class.
2700 PgSqlTransaction transaction(ctx->conn_);
2701
2702 // If we're configured to check that an IP reservation within a given subnet
2703 // is unique, the IP reservation exists and the subnet is actually set
2704 // we will be using a special query that checks for uniqueness. Otherwise,
2705 // we will use a regular insert statement.
2706 bool unique_ip = impl_->ip_reservations_unique_ && !host->getIPv4Reservation().isV4Zero()
2707 && host->getIPv4SubnetID() != SUBNET_ID_UNUSED;
2708
2709 // Create the PgSQL Bind array for the host
2710 PsqlBindArrayPtr bind_array = ctx->host_ipv4_exchange_->createBindForSend(host, unique_ip);
2711
2712 // ... and insert the host.
2713 uint32_t host_id = impl_->addStatement(ctx,
2716 bind_array, true);
2717
2718 // Insert DHCPv4 options.
2719 ConstCfgOptionPtr cfg_option4 = host->getCfgOption4();
2720 if (cfg_option4) {
2722 cfg_option4, host_id);
2723 }
2724
2725 // Insert DHCPv6 options.
2726 ConstCfgOptionPtr cfg_option6 = host->getCfgOption6();
2727 if (cfg_option6) {
2729 cfg_option6, host_id);
2730 }
2731
2732 // Insert IPv6 reservations.
2733 IPv6ResrvRange v6resv = host->getIPv6Reservations();
2734 if (std::distance(v6resv.first, v6resv.second) > 0) {
2735 BOOST_FOREACH(auto const& resv, v6resv) {
2736 impl_->addResv(ctx, resv.second, host_id);
2737 }
2738 }
2739
2740 // Everything went fine, so explicitly commit the transaction.
2741 transaction.commit();
2742}
2743
2744bool
2746 const asiolink::IOAddress& addr) {
2747 // Get a context
2748 PgSqlHostContextAlloc get_context(*impl_);
2749 PgSqlHostContextPtr ctx = get_context.ctx_;
2750
2751 // If operating in read-only mode, throw exception.
2752 impl_->checkReadOnly(ctx);
2753
2754 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2755 bind_array->add(subnet_id);
2756
2757 // v4
2758 if (addr.isV4()) {
2759 bind_array->add(addr);
2760 return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_ADDR4,
2761 bind_array));
2762 }
2763
2764 // v6
2765 bind_array->addTempString(addr.toText());
2766
2767 return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_ADDR6,
2768 bind_array));
2769}
2770
2771bool
2773 const Host::IdentifierType& identifier_type,
2774 const uint8_t* identifier_begin,
2775 const size_t identifier_len) {
2776 // Get a context
2777 PgSqlHostContextAlloc get_context(*impl_);
2778 PgSqlHostContextPtr ctx = get_context.ctx_;
2779
2780 // If operating in read-only mode, throw exception.
2781 impl_->checkReadOnly(ctx);
2782
2783 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2784
2785 // Subnet-id
2786 bind_array->add(subnet_id);
2787
2788 // identifier-type
2789 bind_array->add(static_cast<uint8_t>(identifier_type));
2790
2791 // identifier
2792 bind_array->add(identifier_begin, identifier_len);
2793
2794 return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_SUBID4_ID,
2795 bind_array));
2796}
2797
2798bool
2800 const Host::IdentifierType& identifier_type,
2801 const uint8_t* identifier_begin,
2802 const size_t identifier_len) {
2803 // Get a context
2804 PgSqlHostContextAlloc get_context(*impl_);
2805 PgSqlHostContextPtr ctx = get_context.ctx_;
2806
2807 // If operating in read-only mode, throw exception.
2808 impl_->checkReadOnly(ctx);
2809
2810 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2811
2812 // Subnet-id
2813 bind_array->add(subnet_id);
2814
2815 // identifier-type
2816 bind_array->add(static_cast<uint8_t>(identifier_type));
2817
2818 // identifier
2819 bind_array->add(identifier_begin, identifier_len);
2820
2821 return (impl_->delStatement(ctx, PgSqlHostDataSourceImpl::DEL_HOST_SUBID6_ID,
2822 bind_array));
2823}
2824
2827 const uint8_t* identifier_begin,
2828 const size_t identifier_len) const {
2829 // Get a context
2830 PgSqlHostContextAlloc get_context(*impl_);
2831 PgSqlHostContextPtr ctx = get_context.ctx_;
2832
2833 // Set up the WHERE clause value
2834 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2835
2836 // Identifier value.
2837 bind_array->add(identifier_begin, identifier_len);
2838
2839 // Identifier type.
2840 bind_array->add(static_cast<uint8_t>(identifier_type));
2841
2842 ConstHostCollection result;
2843 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_DHCPID,
2844 bind_array, ctx->host_ipv46_exchange_, result, false);
2845
2846 return (result);
2847}
2848
2851 // Get a context
2852 PgSqlHostContextAlloc get_context(*impl_);
2853 PgSqlHostContextPtr ctx = get_context.ctx_;
2854
2855 // Set up the WHERE clause value
2856 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2857
2858 // Add the subnet id.
2859 bind_array->add(subnet_id);
2860
2861 ConstHostCollection result;
2862 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID4,
2863 bind_array, ctx->host_ipv4_exchange_, result, false);
2864
2865 return (result);
2866}
2867
2870 // Get a context
2871 PgSqlHostContextAlloc get_context(*impl_);
2872 PgSqlHostContextPtr ctx = get_context.ctx_;
2873
2874 // Set up the WHERE clause value
2875 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2876
2877 // Add the subnet id.
2878 bind_array->add(subnet_id);
2879
2880 ConstHostCollection result;
2881 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID6,
2882 bind_array, ctx->host_ipv6_exchange_, result, false);
2883
2884 return (result);
2885}
2886
2888PgSqlHostDataSource::getAllbyHostname(const std::string& hostname) 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 ConstHostCollection result;
2900 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME,
2901 bind_array, ctx->host_ipv46_exchange_, result, false);
2902
2903 return (result);
2904}
2905
2907PgSqlHostDataSource::getAllbyHostname4(const std::string& hostname,
2908 const SubnetID& subnet_id) const {
2909 // Get a context
2910 PgSqlHostContextAlloc get_context(*impl_);
2911 PgSqlHostContextPtr ctx = get_context.ctx_;
2912
2913 // Set up the WHERE clause value
2914 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2915
2916 // Add the hostname.
2917 bind_array->add(hostname);
2918
2919 // Add the subnet id.
2920 bind_array->add(subnet_id);
2921
2922 ConstHostCollection result;
2923 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID4,
2924 bind_array, ctx->host_ipv4_exchange_, result, false);
2925
2926 return (result);
2927}
2928
2930PgSqlHostDataSource::getAllbyHostname6(const std::string& hostname,
2931 const SubnetID& subnet_id) const {
2932 // Get a context
2933 PgSqlHostContextAlloc get_context(*impl_);
2934 PgSqlHostContextPtr ctx = get_context.ctx_;
2935
2936 // Set up the WHERE clause value
2937 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2938
2939 // Add the hostname.
2940 bind_array->add(hostname);
2941
2942 // Add the subnet id.
2943 bind_array->add(subnet_id);
2944
2945 ConstHostCollection result;
2946 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID6,
2947 bind_array, ctx->host_ipv6_exchange_, result, false);
2948
2949 return (result);
2950}
2951
2954 size_t& /*source_index*/,
2955 uint64_t lower_host_id,
2956 const HostPageSize& page_size) const {
2957 // Get a context
2958 PgSqlHostContextAlloc get_context(*impl_);
2959 PgSqlHostContextPtr ctx = get_context.ctx_;
2960
2961 // Set up the WHERE clause value
2962 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2963
2964 // Add the subnet id.
2965 bind_array->add(subnet_id);
2966
2967 // Add the lower bound host id.
2968 bind_array->add(lower_host_id);
2969
2970 // Add the page size value.
2971 string page_size_data =
2972 boost::lexical_cast<std::string>(page_size.page_size_);
2973 bind_array->add(page_size_data);
2974
2975 ConstHostCollection result;
2976 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID4_PAGE,
2977 bind_array, ctx->host_ipv4_exchange_, result, false);
2978
2979 return (result);
2980}
2981
2984 size_t& /*source_index*/,
2985 uint64_t lower_host_id,
2986 const HostPageSize& page_size) const {
2987 // Get a context
2988 PgSqlHostContextAlloc get_context(*impl_);
2989 PgSqlHostContextPtr ctx = get_context.ctx_;
2990
2991 // Set up the WHERE clause value
2992 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2993
2994 // Add the subnet id.
2995 bind_array->add(subnet_id);
2996
2997 // Add the lower bound host id.
2998 bind_array->add(lower_host_id);
2999
3000 // Add the page size value.
3001 string page_size_data =
3002 boost::lexical_cast<std::string>(page_size.page_size_);
3003 bind_array->add(page_size_data);
3004
3005 ConstHostCollection result;
3006 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID6_PAGE,
3007 bind_array, ctx->host_ipv6_exchange_, result, false);
3008
3009 return (result);
3010}
3011
3013PgSqlHostDataSource::getPage4(size_t& /*source_index*/,
3014 uint64_t lower_host_id,
3015 const HostPageSize& page_size) const {
3016 // Get a context
3017 PgSqlHostContextAlloc get_context(*impl_);
3018 PgSqlHostContextPtr ctx = get_context.ctx_;
3019
3020 // Set up the WHERE clause value
3021 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3022
3023 // Add the lower bound host id.
3024 bind_array->add(lower_host_id);
3025
3026 // Add the page size value.
3027 string page_size_data =
3028 boost::lexical_cast<std::string>(page_size.page_size_);
3029 bind_array->add(page_size_data);
3030
3031 ConstHostCollection result;
3032 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_PAGE4,
3033 bind_array, ctx->host_ipv4_exchange_, result, false);
3034
3035 return (result);
3036}
3037
3039PgSqlHostDataSource::getPage6(size_t& /*source_index*/,
3040 uint64_t lower_host_id,
3041 const HostPageSize& page_size) const {
3042 // Get a context
3043 PgSqlHostContextAlloc get_context(*impl_);
3044 PgSqlHostContextPtr ctx = get_context.ctx_;
3045
3046 // Set up the WHERE clause value
3047 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3048
3049 // Add the lower bound host id.
3050 bind_array->add(lower_host_id);
3051
3052 // Add the page size value.
3053 string page_size_data =
3054 boost::lexical_cast<std::string>(page_size.page_size_);
3055 bind_array->add(page_size_data);
3056
3057 ConstHostCollection result;
3058 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_PAGE6,
3059 bind_array, ctx->host_ipv6_exchange_, result, false);
3060
3061 return (result);
3062}
3063
3066 // Get a context
3067 PgSqlHostContextAlloc get_context(*impl_);
3068 PgSqlHostContextPtr ctx = get_context.ctx_;
3069
3070 // Set up the WHERE clause value
3071 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3072
3073 // v4 Reservation address
3074 bind_array->add(address);
3075
3076 ConstHostCollection result;
3077 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_ADDR,
3078 bind_array, ctx->host_ipv4_exchange_, result, false);
3079
3080 return (result);
3081}
3082
3085 const Host::IdentifierType& identifier_type,
3086 const uint8_t* identifier_begin,
3087 const size_t identifier_len) const {
3088 // Get a context
3089 PgSqlHostContextAlloc get_context(*impl_);
3090 PgSqlHostContextPtr ctx = get_context.ctx_;
3091
3092 return (impl_->getHost(ctx, subnet_id, identifier_type, identifier_begin, identifier_len,
3094 ctx->host_ipv4_exchange_));
3095}
3096
3099 const asiolink::IOAddress& address) const {
3100 // Get a context
3101 PgSqlHostContextAlloc get_context(*impl_);
3102 PgSqlHostContextPtr ctx = get_context.ctx_;
3103
3104 if (!address.isV4()) {
3105 isc_throw(BadValue, "PgSqlHostDataSource::get4(id, address) - "
3106 " wrong address type, address supplied is an IPv6 address");
3107 }
3108
3109 // Set up the WHERE clause value
3110 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3111
3112 // Add the subnet id
3113 bind_array->add(subnet_id);
3114
3115 // Add the address
3116 bind_array->add(address);
3117
3118 ConstHostCollection collection;
3119 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID_ADDR,
3120 bind_array, ctx->host_ipv4_exchange_, collection, true);
3121
3122 // Return single record if present, else clear the host.
3123 ConstHostPtr result;
3124 if (!collection.empty()) {
3125 result = *collection.begin();
3126 }
3127
3128 return (result);
3129}
3130
3133 const asiolink::IOAddress& address) const {
3134 // Get a context
3135 PgSqlHostContextAlloc get_context(*impl_);
3136 PgSqlHostContextPtr ctx = get_context.ctx_;
3137
3138 if (!address.isV4()) {
3139 isc_throw(BadValue, "PgSqlHostDataSource::get4(id, address) - "
3140 " wrong address type, address supplied is an IPv6 address");
3141 }
3142
3143 // Set up the WHERE clause value
3144 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3145
3146 // Add the subnet id
3147 bind_array->add(subnet_id);
3148
3149 // Add the address
3150 bind_array->add(address);
3151
3152 ConstHostCollection collection;
3153 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID_ADDR,
3154 bind_array, ctx->host_ipv4_exchange_, collection, false);
3155 return (collection);
3156}
3157
3160 const Host::IdentifierType& identifier_type,
3161 const uint8_t* identifier_begin,
3162 const size_t identifier_len) const {
3163 // Get a context
3164 PgSqlHostContextAlloc get_context(*impl_);
3165 PgSqlHostContextPtr ctx = get_context.ctx_;
3166
3167 return (impl_->getHost(ctx, subnet_id, identifier_type, identifier_begin, identifier_len,
3169 ctx->host_ipv6_exchange_));
3170}
3171
3174 const uint8_t prefix_len) const {
3175 if (!prefix.isV6()) {
3176 isc_throw(BadValue, "PgSqlHostDataSource::get6(prefix, prefix_len): "
3177 "wrong address type, address supplied is an IPv4 address");
3178 }
3179
3180 // Get a context
3181 PgSqlHostContextAlloc get_context(*impl_);
3182 PgSqlHostContextPtr ctx = get_context.ctx_;
3183
3184 // Set up the WHERE clause value
3185 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3186
3187 // Add the prefix
3188 bind_array->add(prefix);
3189
3190 // Add the prefix length
3191 bind_array->add(prefix_len);
3192
3193 ConstHostCollection collection;
3194 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_PREFIX,
3195 bind_array, ctx->host_ipv6_exchange_, collection, true);
3196
3197 // Return single record if present, else clear the host.
3198 ConstHostPtr result;
3199 if (!collection.empty()) {
3200 result = *collection.begin();
3201 }
3202
3203 return (result);
3204}
3205
3208 const asiolink::IOAddress& address) const {
3209 if (!address.isV6()) {
3210 isc_throw(BadValue, "PgSqlHostDataSource::get6(id, address): "
3211 "wrong address type, address supplied is an IPv4 address");
3212 }
3213
3214 // Get a context
3215 PgSqlHostContextAlloc get_context(*impl_);
3216 PgSqlHostContextPtr ctx = get_context.ctx_;
3217
3218 // Set up the WHERE clause value
3219 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3220
3221 // Add the subnet id
3222 bind_array->add(subnet_id);
3223
3224 // Add the prefix
3225 bind_array->add(address);
3226
3227 ConstHostCollection collection;
3228 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR,
3229 bind_array, ctx->host_ipv6_exchange_, collection, true);
3230
3231 // Return single record if present, else clear the host.
3232 ConstHostPtr result;
3233 if (!collection.empty()) {
3234 result = *collection.begin();
3235 }
3236
3237 return (result);
3238}
3239
3242 const asiolink::IOAddress& address) const {
3243 if (!address.isV6()) {
3244 isc_throw(BadValue, "PgSqlHostDataSource::get6(id, address): "
3245 "wrong address type, address supplied is an IPv4 address");
3246 }
3247
3248 // Get a context
3249 PgSqlHostContextAlloc get_context(*impl_);
3250 PgSqlHostContextPtr ctx = get_context.ctx_;
3251
3252 // Set up the WHERE clause value
3253 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3254
3255 // Add the subnet id
3256 bind_array->add(subnet_id);
3257
3258 // Add the prefix
3259 bind_array->add(address);
3260
3261 ConstHostCollection collection;
3262 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR,
3263 bind_array, ctx->host_ipv6_exchange_, collection, false);
3264 return (collection);
3265}
3266
3269 if (!address.isV6()) {
3270 isc_throw(BadValue, "PgSqlHostDataSource::get6(address): "
3271 "wrong address type, address supplied is an IPv4 address");
3272 }
3273
3274 // Get a context
3275 PgSqlHostContextAlloc get_context(*impl_);
3276 PgSqlHostContextPtr ctx = get_context.ctx_;
3277
3278 // Set up the WHERE clause value
3279 PsqlBindArrayPtr bind_array(new PsqlBindArray());
3280
3281 // Add the prefix
3282 bind_array->add(address);
3283
3284 ConstHostCollection collection;
3285 impl_->getHostCollection(ctx, PgSqlHostDataSourceImpl::GET_HOST_ADDR6,
3286 bind_array, ctx->host_ipv6_exchange_, collection, false);
3287 return (collection);
3288}
3289
3290void
3292 // Get a context.
3293 PgSqlHostContextAlloc const context(*impl_);
3294 PgSqlHostContextPtr ctx(context.ctx_);
3295
3296 // If operating in read-only mode, throw exception.
3297 impl_->checkReadOnly(ctx);
3298
3299 // Initiate PostgreSQL transaction as we will have to make multiple queries
3300 // to update host information into multiple tables. If that fails on
3301 // any stage, the transaction will be rolled back by the destructor of
3302 // the PgSqlTransaction class.
3303 PgSqlTransaction transaction(ctx->conn_);
3304
3305 // As much as having dedicated prepared statements for updating tables would be consistent with
3306 // the implementation of other commands, it's difficult if not impossible to cover all cases for
3307 // updating the host to exactly as is described in the command, which may involve inserts and
3308 // deletes alongside updates. So let's delete and add. The delete cascades into all tables. The
3309 // add explicitly adds into all tables.
3311
3312 // Everything went fine, so explicitly commit the transaction.
3313 transaction.commit();
3314}
3315
3316// Miscellaneous database methods.
3317
3318std::string
3320 std::string name = "";
3321 // Get a context
3322 PgSqlHostContextAlloc get_context(*impl_);
3323 PgSqlHostContextPtr ctx = get_context.ctx_;
3324
3325 try {
3326 name = ctx->conn_.getParameter("name");
3327 } catch (...) {
3328 // Return an empty name
3329 }
3330 return (name);
3331}
3332
3333std::string
3335 return (std::string("Host data source that stores host information"
3336 "in PostgreSQL database"));
3337}
3338
3339std::pair<uint32_t, uint32_t>
3340PgSqlHostDataSource::getVersion(const std::string& timer_name) const {
3341 return(impl_->getVersion(timer_name));
3342}
3343
3344void
3346 // Get a context
3347 PgSqlHostContextAlloc get_context(*impl_);
3348 PgSqlHostContextPtr ctx = get_context.ctx_;
3349
3350 // If operating in read-only mode, throw exception.
3351 impl_->checkReadOnly(ctx);
3352 ctx->conn_.commit();
3353}
3354
3355void
3357 // Get a context
3358 PgSqlHostContextAlloc get_context(*impl_);
3359 PgSqlHostContextPtr ctx = get_context.ctx_;
3360
3361 // If operating in read-only mode, throw exception.
3362 impl_->checkReadOnly(ctx);
3363 ctx->conn_.rollback();
3364}
3365
3366bool
3368 impl_->ip_reservations_unique_ = unique;
3369 return (true);
3370}
3371
3372bool
3374 return (impl_->unusable_);
3375}
3376
3377} // namespace dhcp
3378} // 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:76
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:327
IdentifierType
Type of the host identifier.
Definition host.h:337
static const IdentifierType LAST_IDENTIFIER_TYPE
Constant pointing to the last identifier of the IdentifierType enumeration.
Definition host.h:347
IPv6 reservation for a host.
Definition host.h:163
Type
Type of the reservation.
Definition host.h:169
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition libdhcp++.cc:128
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:170
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:191
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
Definition libdhcp++.cc:249
Option descriptor.
Definition cfg_option.h:47
Universe
defines option universe DHCPv4 or DHCPv6
Definition option.h:90
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< Option6PDExclude > Option6PDExcludePtr
Pointer to the Option6PDExclude object.
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
Definition host.h:837
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
Definition host.h:843
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:273
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:70
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:840
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:46
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.