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