Kea 1.5.0
pgsql_host_data_source.cc
Go to the documentation of this file.
1// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10#include <dhcp/libdhcp++.h>
11#include <dhcp/option.h>
13#include <dhcp/option_space.h>
14#include <dhcpsrv/cfg_option.h>
15#include <dhcpsrv/dhcpsrv_log.h>
17#include <util/buffer.h>
18#include <util/optional_value.h>
19
20#include <boost/algorithm/string/split.hpp>
21#include <boost/algorithm/string/classification.hpp>
22#include <boost/array.hpp>
23#include <boost/pointer_cast.hpp>
24#include <boost/static_assert.hpp>
25
26#include <stdint.h>
27#include <string>
28
29using namespace isc;
30using namespace isc::asiolink;
31using namespace isc::db;
32using namespace isc::dhcp;
33using namespace isc::util;
34using namespace isc::data;
35using namespace std;
36
37namespace {
38
42const size_t OPTION_VALUE_MAX_LEN = 4096;
43
48const uint8_t MAX_IDENTIFIER_TYPE = static_cast<uint8_t>(Host::LAST_IDENTIFIER_TYPE);
49
51const size_t DHCP_IDENTIFIER_MAX_LEN = 128;
52
79class PgSqlHostExchange : public PgSqlExchange {
80private:
81
86 static const int HOST_ID_COL = 0;
87 static const int DHCP_IDENTIFIER_COL = 1;
88 static const int DHCP_IDENTIFIER_TYPE_COL = 2;
89 static const int DHCP4_SUBNET_ID_COL = 3;
90 static const int DHCP6_SUBNET_ID_COL = 4;
91 static const int IPV4_ADDRESS_COL = 5;
92 static const int HOSTNAME_COL = 6;
93 static const int DHCP4_CLIENT_CLASSES_COL = 7;
94 static const int DHCP6_CLIENT_CLASSES_COL = 8;
95 static const int USER_CONTEXT_COL = 9;
96 static const int DHCP4_NEXT_SERVER_COL = 10;
97 static const int DHCP4_SERVER_HOSTNAME_COL = 11;
98 static const int DHCP4_BOOT_FILE_NAME_COL = 12;
99 static const int AUTH_KEY_COL = 13;
101 static const size_t HOST_COLUMNS = 14;
102
103public:
104
111 PgSqlHostExchange(const size_t additional_columns_num = 0)
112 : PgSqlExchange(HOST_COLUMNS + additional_columns_num) {
113 // Set the column names for use by this class. This only comprises
114 // names used by the PgSqlHostExchange class. Derived classes will
115 // need to set names for the columns they use. Currently these are
116 // only used for logging purposes.
117 columns_[HOST_ID_COL] = "host_id";
118 columns_[DHCP_IDENTIFIER_COL] = "dhcp_identifier";
119 columns_[DHCP_IDENTIFIER_TYPE_COL] = "dhcp_identifier_type";
120 columns_[DHCP4_SUBNET_ID_COL] = "dhcp4_subnet_id";
121 columns_[DHCP6_SUBNET_ID_COL] = "dhcp6_subnet_id";
122 columns_[IPV4_ADDRESS_COL] = "ipv4_address";
123 columns_[HOSTNAME_COL] = "hostname";
124 columns_[DHCP4_CLIENT_CLASSES_COL] = "dhcp4_client_classes";
125 columns_[DHCP6_CLIENT_CLASSES_COL] = "dhcp6_client_classes";
126 columns_[USER_CONTEXT_COL] = "user_context";
127 columns_[DHCP4_NEXT_SERVER_COL] = "dhcp4_next_server";
128 columns_[DHCP4_SERVER_HOSTNAME_COL] = "dhcp4_server_hostname";
129 columns_[DHCP4_BOOT_FILE_NAME_COL] = "dhcp4_boot_file_name";
130 columns_[AUTH_KEY_COL] = "auth_key";
131
132 BOOST_STATIC_ASSERT(12 < HOST_COLUMNS);
133 };
134
136 virtual ~PgSqlHostExchange() {
137 }
138
144 virtual void clear() {
145 host_.reset();
146 };
147
162 size_t findAvailColumn() const {
163 std::vector<std::string>::const_iterator empty_column =
164 std::find(columns_.begin(), columns_.end(), std::string());
165 return (std::distance(columns_.begin(), empty_column));
166 }
167
172 HostID getHostId(const PgSqlResult& r, int row) {
173 HostID host_id;
174 getColumnValue(r, row, HOST_ID_COL, host_id);
175 return (host_id);
176 }
177
192 createBindForSend(const HostPtr& host) {
193 if (!host) {
194 isc_throw(BadValue, "createBindForSend:: host object is NULL");
195 }
196
197 // Store the host to ensure bound values remain in scope
198 host_ = host;
199
200 // Bind the host data to the array
201 PsqlBindArrayPtr bind_array(new PsqlBindArray());
202 try {
203 // host_id : is auto_incremented skip it
204
205 // dhcp_identifier : BYTEA NOT NULL
206 bind_array->add(host->getIdentifier());
207
208 // dhcp_identifier_type : SMALLINT NOT NULL
209 bind_array->add(host->getIdentifierType());
210
211 // dhcp4_subnet_id : INT NULL
212 if (host->getIPv4SubnetID() == SUBNET_ID_UNUSED) {
213 bind_array->addNull();
214 }
215 else {
216 bind_array->add(host->getIPv4SubnetID());
217 }
218
219 // dhcp6_subnet_id : INT NULL
220 if (host->getIPv6SubnetID() == SUBNET_ID_UNUSED) {
221 bind_array->addNull();
222 }
223 else {
224 bind_array->add(host->getIPv6SubnetID());
225 }
226
227 // ipv4_address : BIGINT NULL
228 bind_array->add((host->getIPv4Reservation()));
229
230 // hostname : VARCHAR(255) NULL
231 bind_array->add(host->getHostname());
232
233 // dhcp4_client_classes : VARCHAR(255) NULL
234 // Override default separator to not include space after comma.
235 bind_array->addTempString(host->getClientClasses4().toText(","));
236
237 // dhcp6_client_classes : VARCHAR(255) NULL
238 bind_array->addTempString(host->getClientClasses6().toText(","));
239
240 // user_context: TEXT NULL
241 ConstElementPtr ctx = host->getContext();
242 if (ctx) {
243 std::string user_context_ = ctx->str();
244 bind_array->addTempString(user_context_);
245 } else {
246 bind_array->addNull();
247 }
248
249 // dhcp4_next_server : BIGINT NULL
250 bind_array->add((host->getNextServer()));
251
252 // dhcp4_server_hostname : VARCHAR(64)
253 bind_array->add(host->getServerHostname());
254
255 // dhcp4_boot_file_name : VARCHAR(128)
256 bind_array->add(host->getBootFileName());
257
258 // add auth keys
259 std::string key = host->getKey().ToText();
260 if (key.empty()) {
261 bind_array->addNull();
262 } else {
263 bind_array->add(key);
264 }
265
266 } catch (const std::exception& ex) {
267 host_.reset();
269 "Could not create bind array from Host: "
270 << host->getHostname() << ", reason: " << ex.what());
271 }
272
273 return (bind_array);
274 };
275
289 virtual void processRowData(ConstHostCollection& hosts,
290 const PgSqlResult& r, int row) {
291 // Peek at the host id , so we can skip it if we already have it
292 // This lets us avoid constructing a copy of host for each
293 // of its sub-rows (options, etc...)
294 HostID row_host_id = getHostId(r, row);
295
296 // Add new host only if there are no hosts or the host id of the
297 // most recently added host is different than the host id of the
298 // currently processed host.
299 if (hosts.empty() || row_host_id != hosts.back()->getHostId()) {
300 HostPtr host = retrieveHost(r, row, row_host_id);
301 hosts.push_back(host);
302 }
303 }
304
315 HostPtr retrieveHost(const PgSqlResult& r, int row,
316 const HostID& peeked_host_id = 0) {
317
318 // If the caller peeked ahead at the host_id use that, otherwise
319 // read it from the row.
320 HostID host_id = (peeked_host_id ? peeked_host_id : getHostId(r,row));
321
322 // dhcp_identifier : BYTEA NOT NULL
323 uint8_t identifier_value[DHCP_IDENTIFIER_MAX_LEN];
324 size_t identifier_len;
325 convertFromBytea(r, row, DHCP_IDENTIFIER_COL, identifier_value,
326 sizeof(identifier_value), identifier_len);
327
328 // dhcp_identifier_type : SMALLINT NOT NULL
329 uint8_t type;
330 getColumnValue(r, row, DHCP_IDENTIFIER_TYPE_COL, type);
331 if (type > MAX_IDENTIFIER_TYPE) {
332 isc_throw(BadValue, "invalid dhcp identifier type returned: "
333 << static_cast<int>(type));
334 }
335
336 Host::IdentifierType identifier_type =
337 static_cast<Host::IdentifierType>(type);
338
339 // dhcp4_subnet_id : INT NULL
340 uint32_t subnet_id(SUBNET_ID_UNUSED);
341 if (!isColumnNull(r, row, DHCP4_SUBNET_ID_COL)) {
342 getColumnValue(r, row, DHCP4_SUBNET_ID_COL, subnet_id);
343 }
344 SubnetID dhcp4_subnet_id = static_cast<SubnetID>(subnet_id);
345
346 // dhcp6_subnet_id : INT NULL
347 subnet_id = SUBNET_ID_UNUSED;
348 if (!isColumnNull(r, row, DHCP6_SUBNET_ID_COL)) {
349 getColumnValue(r, row, DHCP6_SUBNET_ID_COL, subnet_id);
350 }
351 SubnetID dhcp6_subnet_id = static_cast<SubnetID>(subnet_id);
352
353 // ipv4_address : BIGINT NULL
354 uint32_t addr4(0);
355 if (!isColumnNull(r, row, IPV4_ADDRESS_COL)) {
356 getColumnValue(r, row, IPV4_ADDRESS_COL, addr4);
357 }
358 isc::asiolink::IOAddress ipv4_reservation(addr4);
359
360 // hostname : VARCHAR(255) NULL
361 std::string hostname;
362 if (!isColumnNull(r, row, HOSTNAME_COL)) {
363 getColumnValue(r, row, HOSTNAME_COL, hostname);
364 }
365
366 // dhcp4_client_classes : VARCHAR(255) NULL
367 std::string dhcp4_client_classes;
368 if (!isColumnNull(r, row, DHCP4_CLIENT_CLASSES_COL)) {
369 getColumnValue(r, row, DHCP4_CLIENT_CLASSES_COL, dhcp4_client_classes);
370 }
371
372 // dhcp6_client_classes : VARCHAR(255) NULL
373 std::string dhcp6_client_classes;
374 if (!isColumnNull(r, row, DHCP6_CLIENT_CLASSES_COL)) {
375 getColumnValue(r, row, DHCP6_CLIENT_CLASSES_COL, dhcp6_client_classes);
376 }
377
378 // user_context: TEXT
379 std::string user_context;
380 if (!isColumnNull(r, row, USER_CONTEXT_COL)) {
381 getColumnValue(r, row, USER_CONTEXT_COL, user_context);
382 }
383
384 // dhcp4_next_server : BIGINT NULL
385 uint32_t dhcp4_next_server_as_uint32(0);
386 if (!isColumnNull(r, row, DHCP4_NEXT_SERVER_COL)) {
387 getColumnValue(r, row, DHCP4_NEXT_SERVER_COL, dhcp4_next_server_as_uint32);
388 }
389 isc::asiolink::IOAddress dhcp4_next_server(dhcp4_next_server_as_uint32);
390
391 // dhcp4_server_hostname : VARCHAR(64)
392 std::string dhcp4_server_hostname;
393 if (!isColumnNull(r, row, DHCP4_SERVER_HOSTNAME_COL)) {
394 getColumnValue(r, row, DHCP4_SERVER_HOSTNAME_COL, dhcp4_server_hostname);
395 }
396
397 // dhcp4_boot_file_name : VARCHAR(128)
398 std::string dhcp4_boot_file_name;
399 if (!isColumnNull(r, row, DHCP4_BOOT_FILE_NAME_COL)) {
400 getColumnValue(r, row, DHCP4_BOOT_FILE_NAME_COL, dhcp4_boot_file_name);
401 }
402
403 // auth_key : VARCHAR(16)
404 std::string auth_key;
405 if (!isColumnNull(r, row, AUTH_KEY_COL)) {
406 getColumnValue(r, row, AUTH_KEY_COL, auth_key);
407 }
408
409 // Finally, attempt to create the new host.
410 HostPtr host;
411 try {
412 host.reset(new Host(identifier_value, identifier_len,
413 identifier_type, dhcp4_subnet_id,
414 dhcp6_subnet_id, ipv4_reservation, hostname,
415 dhcp4_client_classes, dhcp6_client_classes,
416 dhcp4_next_server, dhcp4_server_hostname,
417 dhcp4_boot_file_name, AuthKey(auth_key)));
418
419 // Set the user context if there is one.
420 if (!user_context.empty()) {
421 try {
422 ConstElementPtr ctx = Element::fromJSON(user_context);
423 if (!ctx || (ctx->getType() != Element::map)) {
424 isc_throw(BadValue, "user context '" << user_context
425 << "' is not a JSON map");
426 }
427 host->setContext(ctx);
428 } catch (const isc::data::JSONError& ex) {
429 isc_throw(BadValue, "user context '" << user_context
430 << "' is invalid JSON: " << ex.what());
431 }
432 }
433
434 host->setHostId(host_id);
435 } catch (const isc::Exception& ex) {
436 isc_throw(DbOperationError, "Could not create host: " << ex.what());
437 }
438
439 return(host);
440 };
441
442protected:
445 HostPtr host_;
446};
447
457class PgSqlHostWithOptionsExchange : public PgSqlHostExchange {
458private:
459
461 static const size_t OPTION_COLUMNS = 7;
462
477 class OptionProcessor {
478 public:
479
486 OptionProcessor(const Option::Universe& universe,
487 const size_t start_column)
488 : universe_(universe), start_column_(start_column),
489 option_id_index_(start_column), code_index_(start_column_ + 1),
490 value_index_(start_column_ + 2),
491 formatted_value_index_(start_column_ + 3),
492 space_index_(start_column_ + 4),
493 persistent_index_(start_column_ + 5),
494 user_context_index_(start_column_ + 6),
495 most_recent_option_id_(0) {
496 }
497
502 void clear() {
503 most_recent_option_id_ = 0;
504 }
505
538 void retrieveOption(const CfgOptionPtr& cfg, const PgSqlResult& r,
539 int row) {
540 // If the option id on this row is NULL, then there's no
541 // option of this type (4/6) on this row to fetch, so bail.
542 if (PgSqlExchange::isColumnNull(r, row, option_id_index_)) {
543 return;
544 }
545
546 // option_id: INT
547 uint64_t option_id;
548 PgSqlExchange::getColumnValue(r, row, option_id_index_, option_id);
549
550 // The row option id must be greater than id if the most recent
551 // option because they are ordered by option id. Otherwise
552 // we assume that we have already processed this option.
553 if (most_recent_option_id_ >= option_id) {
554 return;
555 }
556
557 // Remember current option id as the most recent processed one. We
558 // will be comparing it with option ids in subsequent rows.
559 most_recent_option_id_ = option_id;
560
561 // code: SMALLINT NOT NULL
562 uint16_t code;
563 PgSqlExchange::getColumnValue(r, row, code_index_, code);
564
565 // value: BYTEA
566 uint8_t value[OPTION_VALUE_MAX_LEN];
567 size_t value_len(0);
568 if (!isColumnNull(r, row, value_index_)) {
569 PgSqlExchange::convertFromBytea(r, row, value_index_, value,
570 sizeof(value), value_len);
571 }
572
573 // formatted_value: TEXT
574 std::string formatted_value;
575 if (!isColumnNull(r, row, formatted_value_index_)) {
576 PgSqlExchange::getColumnValue(r, row, formatted_value_index_,
577 formatted_value);
578 }
579
580 // space: VARCHAR(128)
581 std::string space;
582 if (!isColumnNull(r, row, space_index_)) {
583 PgSqlExchange::getColumnValue(r, row, space_index_, space);
584 }
585
586 // If empty or null space provided, use a default top level space.
587 if (space.empty()) {
588 space = (universe_ == Option::V4 ? "dhcp4" : "dhcp6");
589 }
590
591 // persistent: BOOL default false
592 bool persistent;
593 PgSqlExchange::getColumnValue(r, row, persistent_index_,
594 persistent);
595
596 // user_context: TEXT
597 std::string user_context;
598 if (!isColumnNull(r, row, user_context_index_)) {
599 PgSqlExchange::getColumnValue(r, row, user_context_index_,
600 user_context);
601 }
602
603 // Options are held in a binary or textual format in the database.
604 // This is similar to having an option specified in a server
605 // configuration file. Such option is converted to appropriate C++
606 // class, using option definition. Thus, we need to find the
607 // option definition for this option code and option space.
608
609 // If the option space is a standard DHCPv4 or DHCPv6 option space,
610 // this is most likely a standard option, for which we have a
611 // definition created within libdhcp++.
613
614 // Otherwise, we may check if this an option encapsulated within the
615 // vendor space.
616 if (!def && (space != DHCP4_OPTION_SPACE) &&
617 (space != DHCP6_OPTION_SPACE)) {
618 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(space);
619 if (vendor_id > 0) {
620 def = LibDHCP::getVendorOptionDef(universe_, vendor_id,
621 code);
622 }
623 }
624
625 // In all other cases, we use runtime option definitions, which
626 // should be also registered within the libdhcp++.
627 if (!def) {
628 def = LibDHCP::getRuntimeOptionDef(space, code);
629 }
630
631 OptionPtr option;
632
633 if (!def) {
634 // If no definition found, we use generic option type.
635 OptionBuffer buf(value, value + value_len);
636 option.reset(new Option(universe_, code, buf.begin(),
637 buf.end()));
638 } else {
639 // The option value may be specified in textual or binary format
640 // in the database. If formatted_value is empty, the binary
641 // format is used. Depending on the format we use a different
642 // variant of the optionFactory function.
643 if (formatted_value.empty()) {
644 OptionBuffer buf(value, value + value_len);
645 option = def->optionFactory(universe_, code, buf.begin(),
646 buf.end());
647 } else {
648 // Spit the value specified in comma separated values
649 // format.
650 std::vector<std::string> split_vec;
651 boost::split(split_vec, formatted_value,
652 boost::is_any_of(","));
653 option = def->optionFactory(universe_, code, split_vec);
654 }
655 }
656
657 OptionDescriptor desc(option, persistent, formatted_value);
658
659 // Set the user context if there is one into the option descriptor.
660 if (!user_context.empty()) {
661 try {
662 ConstElementPtr ctx = Element::fromJSON(user_context);
663 if (!ctx || (ctx->getType() != Element::map)) {
664 isc_throw(BadValue, "user context '" << user_context
665 << "' is no a JSON map");
666 }
667 desc.setContext(ctx);
668 } catch (const isc::data::JSONError& ex) {
669 isc_throw(BadValue, "user context '" << user_context
670 << "' is invalid JSON: " << ex.what());
671 }
672 }
673
674 cfg->add(desc, space);
675 }
676
681 void setColumnNames(std::vector<std::string>& columns) {
682 columns[option_id_index_] = "option_id";
683 columns[code_index_] = "code";
684 columns[value_index_] = "value";
685 columns[formatted_value_index_] = "formatted_value";
686 columns[space_index_] = "space";
687 columns[persistent_index_] = "persistent";
688 columns[user_context_index_] = "user_context";
689 }
690
691 private:
693 Option::Universe universe_;
694
696 size_t start_column_;
697
699
701
702
703 size_t option_id_index_;
704
706 size_t code_index_;
707
709 size_t value_index_;
710
712 size_t formatted_value_index_;
713
715 size_t space_index_;
716
718 size_t persistent_index_;
720
722 size_t user_context_index_;
723
725 uint64_t most_recent_option_id_;
726 };
727
729 typedef boost::shared_ptr<OptionProcessor> OptionProcessorPtr;
730
731public:
732
739 enum FetchedOptions {
740 DHCP4_ONLY,
741 DHCP6_ONLY,
742 DHCP4_AND_DHCP6
743 };
744
753 PgSqlHostWithOptionsExchange(const FetchedOptions& fetched_options,
754 const size_t additional_columns_num = 0)
755 : PgSqlHostExchange(getRequiredColumnsNum(fetched_options)
756 + additional_columns_num),
757 opt_proc4_(), opt_proc6_() {
758
759 // Create option processor for DHCPv4 options, if required.
760 if ((fetched_options == DHCP4_ONLY) ||
761 (fetched_options == DHCP4_AND_DHCP6)) {
762 opt_proc4_.reset(new OptionProcessor(Option::V4,
763 findAvailColumn()));
764 opt_proc4_->setColumnNames(columns_);
765 }
766
767 // Create option processor for DHCPv6 options, if required.
768 if ((fetched_options == DHCP6_ONLY) ||
769 (fetched_options == DHCP4_AND_DHCP6)) {
770 opt_proc6_.reset(new OptionProcessor(Option::V6,
771 findAvailColumn()));
772 opt_proc6_->setColumnNames(columns_);
773 }
774 }
775
781 virtual void clear() {
782 PgSqlHostExchange::clear();
783 if (opt_proc4_) {
784 opt_proc4_->clear();
785 }
786
787 if (opt_proc6_) {
788 opt_proc6_->clear();
789 }
790 }
791
801 virtual void processRowData(ConstHostCollection& hosts,
802 const PgSqlResult& r, int row) {
803 HostPtr current_host;
804 if (hosts.empty()) {
805 // Must be the first one, fetch it.
806 current_host = retrieveHost(r, row);
807 hosts.push_back(current_host);
808 } else {
809 // Peek at the host id so we can skip it if we already have
810 // this host. This lets us avoid retrieving the host needlessly
811 // for each of its sub-rows (options, etc...).
812 HostID row_host_id = getHostId(r, row);
813 current_host = boost::const_pointer_cast<Host>(hosts.back());
814
815 // if the row's host id is greater than the one we've been
816 // working on we're starting a new host, so fetch it.
817 if (row_host_id > current_host->getHostId()) {
818 current_host = retrieveHost(r, row, row_host_id);
819 hosts.push_back(current_host);
820 }
821 }
822
823 // Parse DHCPv4 options if required to do so.
824 if (opt_proc4_) {
825 CfgOptionPtr cfg = current_host->getCfgOption4();
826 opt_proc4_->retrieveOption(cfg, r, row);
827 }
828
829 // Parse DHCPv6 options if required to do so.
830 if (opt_proc6_) {
831 CfgOptionPtr cfg = current_host->getCfgOption6();
832 opt_proc6_->retrieveOption(cfg, r, row);
833 }
834 }
835
836private:
837
849 static size_t getRequiredColumnsNum(const FetchedOptions& fetched_options) {
850 return (fetched_options == DHCP4_AND_DHCP6 ? 2 * OPTION_COLUMNS :
851 OPTION_COLUMNS);
852 }
853
857 OptionProcessorPtr opt_proc4_;
858
862 OptionProcessorPtr opt_proc6_;
863};
864
877class PgSqlHostIPv6Exchange : public PgSqlHostWithOptionsExchange {
878private:
879
881 static const size_t RESERVATION_COLUMNS = 5;
882
883public:
884
889 PgSqlHostIPv6Exchange(const FetchedOptions& fetched_options)
890 : PgSqlHostWithOptionsExchange(fetched_options, RESERVATION_COLUMNS),
891 reservation_id_index_(findAvailColumn()),
892 address_index_(reservation_id_index_ + 1),
893 prefix_len_index_(reservation_id_index_ + 2),
894 type_index_(reservation_id_index_ + 3),
895 iaid_index_(reservation_id_index_ + 4),
896 most_recent_reservation_id_(0) {
897
898 // Provide names of additional columns returned by the queries.
899 columns_[reservation_id_index_] = "reservation_id";
900 columns_[address_index_] = "address";
901 columns_[prefix_len_index_] = "prefix_len";
902 columns_[type_index_] = "type";
903 columns_[iaid_index_] = "dhcp6_iaid";
904
905 BOOST_STATIC_ASSERT(4 < RESERVATION_COLUMNS);
906 }
907
913 void clear() {
914 PgSqlHostWithOptionsExchange::clear();
915 most_recent_reservation_id_ = 0;
916 }
917
921 uint64_t getReservationId(const PgSqlResult& r, int row) const {
922 uint64_t resv_id = 0;
923 if (!isColumnNull(r, row, reservation_id_index_)) {
924 getColumnValue(r, row, reservation_id_index_, resv_id);
925 }
926
927 return (resv_id);
928 };
929
934 IPv6Resrv retrieveReservation(const PgSqlResult& r, int row) {
935
936 // type: SMALLINT NOT NULL
937 uint16_t tmp;
938 getColumnValue(r, row, type_index_, tmp);
939
940 // Convert it to IPv6 Reservation type (0 = IA_NA, 2 = IA_PD)
941 IPv6Resrv::Type resv_type;
942 switch (tmp) {
943 case 0:
944 resv_type = IPv6Resrv::TYPE_NA;
945 break;
946
947 case 2:
948 resv_type = IPv6Resrv::TYPE_PD;
949 break;
950
951 default:
953 "invalid IPv6 reservation type returned: "
954 << tmp << ". Only 0 or 2 are allowed.");
955 }
956
957 // address VARCHAR(39) NOT NULL
958 isc::asiolink::IOAddress address(getIPv6Value(r, row, address_index_));
959
960 // prefix_len: SMALLINT NOT NULL
961 uint16_t prefix_len;
962 getColumnValue(r, row, prefix_len_index_, prefix_len);
963
964 // @todo once we support populating iaid
965 // iaid: INT
966 // int iaid;
967 // getColumnValue(r, row, iaid_index_, iaid);
968
969 // Create the reservation.
970 IPv6Resrv reservation(resv_type, IOAddress(address), prefix_len);
971 return (reservation);
972 };
973
995 virtual void processRowData(ConstHostCollection& hosts,
996 const PgSqlResult& r, int row) {
997 // Call parent class to fetch host information and options.
998 PgSqlHostWithOptionsExchange::processRowData(hosts, r, row);
999
1000 // Shouldn't happen but just in case
1001 if (hosts.empty()) {
1002 isc_throw(Unexpected, "no host information while retrieving"
1003 " IPv6 reservation");
1004 }
1005
1006 // If we have reservation id we havent' seen yet, retrieve the
1007 // the reservation, adding it to the current host
1008 uint64_t reservation_id = getReservationId(r, row);
1009 if (reservation_id && (reservation_id > most_recent_reservation_id_)) {
1010 HostPtr host = boost::const_pointer_cast<Host>(hosts.back());
1011 host->addReservation(retrieveReservation(r, row));
1012 most_recent_reservation_id_ = reservation_id;
1013 }
1014 }
1015
1016private:
1018
1019
1020 size_t reservation_id_index_;
1021
1023 size_t address_index_;
1024
1026 size_t prefix_len_index_;
1027
1029 size_t type_index_;
1030
1032 size_t iaid_index_;
1033
1035
1037 uint64_t most_recent_reservation_id_;
1038};
1039
1050class PgSqlIPv6ReservationExchange : public PgSqlExchange {
1051private:
1052
1054 static const size_t RESRV_COLUMNS = 6;
1055
1056public:
1057
1061 PgSqlIPv6ReservationExchange()
1062 : PgSqlExchange(RESRV_COLUMNS),
1063 resv_(IPv6Resrv::TYPE_NA, asiolink::IOAddress("::"), 128) {
1064 // Set the column names (for error messages)
1065 columns_[0] = "host_id";
1066 columns_[1] = "address";
1067 columns_[2] = "prefix_len";
1068 columns_[3] = "type";
1069 columns_[4] = "dhcp6_iaid";
1070 BOOST_STATIC_ASSERT(5 < RESRV_COLUMNS);
1071 }
1072
1085 PsqlBindArrayPtr createBindForSend(const IPv6Resrv& resv,
1086 const HostID& host_id) {
1087 // Store the values to ensure they remain valid.
1088 // Technically we don't need this, as currently all the values
1089 // are converted to strings and stored by the bind array.
1090 resv_ = resv;
1091
1092 PsqlBindArrayPtr bind_array(new PsqlBindArray());
1093
1094 try {
1095 // address VARCHAR(39) NOT NULL
1096 bind_array->add(resv.getPrefix());
1097
1098 // prefix_len: SMALLINT NOT NULL
1099 bind_array->add(resv.getPrefixLen());
1100
1101 // type: SMALLINT NOT NULL
1102 // See lease6_types table for values (0 = IA_NA, 2 = IA_PD)
1103 uint16_t type = resv.getType() == IPv6Resrv::TYPE_NA ? 0 : 2;
1104 bind_array->add(type);
1105
1106 // dhcp6_iaid: INT UNSIGNED
1108 bind_array->addNull();
1109
1110 // host_id: BIGINT NOT NULL
1111 bind_array->add(host_id);
1112 } catch (const std::exception& ex) {
1114 "Could not create bind array from IPv6 Reservation: "
1115 << resv_.toText() << ", reason: " << ex.what());
1116 }
1117
1118 return (bind_array);
1119 }
1120
1121private:
1123 IPv6Resrv resv_;
1124};
1125
1129class PgSqlOptionExchange : public PgSqlExchange {
1130private:
1131
1132 static const int OPTION_ID_COL = 0;
1133 static const int CODE_COL = 1;
1134 static const int VALUE_COL = 2;
1135 static const int FORMATTED_VALUE_COL = 3;
1136 static const int SPACE_COL = 4;
1137 static const int PERSISTENT_COL = 5;
1138 static const int USER_CONTEXT_COL = 6;
1139 static const int DHCP_CLIENT_CLASS_COL = 7;
1140 static const int DHCP_SUBNET_ID_COL = 8;
1141 static const int HOST_ID_COL = 9;
1142 static const int SCOPE_ID_COL = 10;
1143
1145 static const size_t OPTION_COLUMNS = 11;
1146
1147public:
1148
1150 PgSqlOptionExchange()
1151 : PgSqlExchange(OPTION_COLUMNS), value_(),
1152 value_len_(0), option_() {
1153 columns_[OPTION_ID_COL] = "option_id";
1154 columns_[CODE_COL] = "code";
1155 columns_[VALUE_COL] = "value";
1156 columns_[FORMATTED_VALUE_COL] = "formatted_value";
1157 columns_[SPACE_COL] = "space";
1158 columns_[PERSISTENT_COL] = "persistent";
1159 columns_[USER_CONTEXT_COL] = "user_context";
1160 columns_[DHCP_CLIENT_CLASS_COL] = "dhcp_client_class";
1161 columns_[DHCP_SUBNET_ID_COL] = "dhcp_subnet_id";
1162 columns_[HOST_ID_COL] = "host_id";
1163 columns_[SCOPE_ID_COL] = "scope_id";
1164
1165 BOOST_STATIC_ASSERT(10 < OPTION_COLUMNS);
1166 }
1167
1177 createBindForSend(const OptionDescriptor& opt_desc,
1178 const std::string& opt_space,
1179 const HostID& host_id) {
1180 // Hold pointer to the option to make sure it remains valid until
1181 // we complete a query.
1182 option_ = opt_desc.option_;
1183
1184 // Create the bind-array
1185 PsqlBindArrayPtr bind_array(new PsqlBindArray());
1186
1187 try {
1188 // option_id: is auto_incremented so skip it
1189
1190 // code: SMALLINT UNSIGNED NOT NULL
1191 bind_array->add(option_->getType());
1192
1193 // value: BYTEA NULL
1194 if (opt_desc.formatted_value_.empty() &&
1195 (opt_desc.option_->len() > opt_desc.option_->getHeaderLen())) {
1196 // The formatted_value is empty and the option value is
1197 // non-empty so we need to prepare on-wire format for the
1198 // option and store it in the database as a BYTEA.
1199 OutputBuffer buf(opt_desc.option_->len());
1200 opt_desc.option_->pack(buf);
1201 const char* buf_ptr = static_cast<const char*>(buf.getData());
1202 value_.assign(buf_ptr + opt_desc.option_->getHeaderLen(),
1203 buf_ptr + buf.getLength());
1204 value_len_ = value_.size();
1205 bind_array->add(value_);
1206 } else {
1207 // No value or formatted_value specified. In this case, the
1208 // value BYTEA should be NULL.
1209 bind_array->addNull(PsqlBindArray::BINARY_FMT);
1210 }
1211
1212 // formatted_value: TEXT NULL,
1213 if (!opt_desc.formatted_value_.empty()) {
1214 bind_array->addTempString(opt_desc.formatted_value_);
1215 } else {
1216 bind_array->addNull();
1217 }
1218
1219 // space: VARCHAR(128) NULL
1220 if (!opt_space.empty()) {
1221 bind_array->addTempString(opt_space);
1222 } else {
1223 bind_array->addNull();
1224 }
1225
1226 // persistent: BOOLEAN DEFAULT false
1227 bind_array->add(opt_desc.persistent_);
1228
1229 // user_context: TEXT NULL,
1230 ConstElementPtr ctx = opt_desc.getContext();
1231 if (ctx) {
1232 std::string user_context_ = ctx->str();
1233 bind_array->addTempString(user_context_);
1234 } else {
1235 bind_array->addNull();
1236 }
1237
1238 // host_id: INT NULL
1239 if (!host_id) {
1240 isc_throw(BadValue, "host_id cannot be null");
1241 }
1242 bind_array->add(host_id);
1243
1244 } catch (const std::exception& ex) {
1246 "Could not create bind array for inserting DHCP "
1247 "host option: " << option_->toText() << ", reason: "
1248 << ex.what());
1249 }
1250
1251 return (bind_array);
1252 }
1253
1254private:
1255
1257 std::vector<uint8_t> value_;
1258
1260 size_t value_len_;
1261
1263 OptionPtr option_;
1264};
1265
1266} // end of anonymous namespace
1267
1268namespace isc {
1269namespace dhcp {
1270
1273public:
1274
1282 GET_HOST_DHCPID, // Gets hosts by host identifier
1283 GET_HOST_ADDR, // Gets hosts by IPv4 address
1284 GET_HOST_SUBID4_DHCPID, // Gets host by IPv4 SubnetID, HW address/DUID
1285 GET_HOST_SUBID6_DHCPID, // Gets host by IPv6 SubnetID, HW address/DUID
1286 GET_HOST_SUBID_ADDR, // Gets host by IPv4 SubnetID and IPv4 address
1287 GET_HOST_PREFIX, // Gets host by IPv6 prefix
1288 GET_HOST_SUBID6_ADDR, // Gets host by IPv6 SubnetID and IPv6 prefix
1289 INSERT_HOST, // Insert new host to collection
1290 INSERT_V6_RESRV, // Insert v6 reservation
1291 INSERT_V4_HOST_OPTION, // Insert DHCPv4 option
1292 INSERT_V6_HOST_OPTION, // Insert DHCPv6 option
1293 DEL_HOST_ADDR4, // Delete v4 host (subnet-id, addr4)
1294 DEL_HOST_SUBID4_ID, // Delete v4 host (subnet-id, ident.type, identifier)
1295 DEL_HOST_SUBID6_ID, // Delete v6 host (subnet-id, ident.type, identifier)
1296 NUM_STATEMENTS // Number of statements
1298
1305
1311
1314
1331 PsqlBindArrayPtr& bind,
1332 const bool return_last_id = false);
1333
1340 PsqlBindArrayPtr& bind);
1341
1346 void addResv(const IPv6Resrv& resv, const HostID& id);
1347
1357 const OptionDescriptor& opt_desc,
1358 const std::string& opt_space,
1359 const OptionalValue<SubnetID>& subnet_id,
1360 const HostID& host_id);
1361
1369 void addOptions(const StatementIndex& stindex,
1370 const ConstCfgOptionPtr& options_cfg,
1371 const uint64_t host_id);
1372
1391 boost::shared_ptr<PgSqlHostExchange> exchange,
1392 ConstHostCollection& result, bool single) const;
1393
1410 ConstHostPtr getHost(const SubnetID& subnet_id,
1411 const Host::IdentifierType& identifier_type,
1412 const uint8_t* identifier_begin,
1413 const size_t identifier_len,
1414 StatementIndex stindex,
1415 boost::shared_ptr<PgSqlHostExchange> exchange) const;
1416
1424 void checkReadOnly() const;
1425
1434 std::pair<uint32_t, uint32_t> getVersion() const;
1435
1438 boost::shared_ptr<PgSqlHostWithOptionsExchange> host_exchange_;
1439
1442 boost::shared_ptr<PgSqlHostIPv6Exchange> host_ipv6_exchange_;
1443
1447 boost::shared_ptr<PgSqlHostIPv6Exchange> host_ipv46_exchange_;
1448
1451 boost::shared_ptr<PgSqlIPv6ReservationExchange> host_ipv6_reservation_exchange_;
1452
1456 boost::shared_ptr<PgSqlOptionExchange> host_option_exchange_;
1457
1460
1463};
1464
1465namespace {
1466
1468typedef boost::array<PgSqlTaggedStatement, PgSqlHostDataSourceImpl::NUM_STATEMENTS>
1470
1474 // PgSqlHostDataSourceImpl::GET_HOST_DHCPID
1475 // Retrieves host information, IPv6 reservations and both DHCPv4 and
1476 // DHCPv6 options associated with the host. The LEFT JOIN clause is used
1477 // to retrieve information from 4 different tables using a single query.
1478 // Hence, this query returns multiple rows for a single host.
1479 {2,
1480 { OID_BYTEA, OID_INT2 },
1481 "get_host_dhcpid",
1482 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1483 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
1484 " h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
1485 " h.user_context, "
1486 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1487 " h.dhcp4_boot_file_name, h.auth_key, "
1488 " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
1489 " o4.persistent, o4.user_context, "
1490 " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
1491 " o6.persistent, o6.user_context, "
1492 " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
1493 "FROM hosts AS h "
1494 "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id "
1495 "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id "
1496 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1497 "WHERE dhcp_identifier = $1 AND dhcp_identifier_type = $2 "
1498 "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id"
1499 },
1500
1501 // PgSqlHostDataSourceImpl::GET_HOST_ADDR
1502 // Retrieves host information along with the DHCPv4 options associated with
1503 // it. Left joining the dhcp4_options table results in multiple rows being
1504 // returned for the same host. The host is retrieved by IPv4 address.
1505 {1,
1506 { OID_INT8 }, "get_host_addr",
1507 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1508 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1509 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1510 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1511 " h.dhcp4_boot_file_name, h.auth_key, "
1512 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1513 " o.persistent, o.user_context "
1514 "FROM hosts AS h "
1515 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1516 "WHERE ipv4_address = $1 "
1517 "ORDER BY h.host_id, o.option_id"
1518 },
1519
1520 //PgSqlHostDataSourceImpl::GET_HOST_SUBID4_DHCPID
1521 // Retrieves host information and DHCPv4 options using subnet identifier
1522 // and client's identifier. Left joining the dhcp4_options table results in
1523 // multiple rows being returned for the same host.
1524 {3,
1526 "get_host_subid4_dhcpid",
1527 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1528 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1529 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1530 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1531 " h.dhcp4_boot_file_name, h.auth_key, "
1532 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1533 " o.persistent, o.user_context "
1534 "FROM hosts AS h "
1535 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1536 "WHERE h.dhcp4_subnet_id = $1 AND h.dhcp_identifier_type = $2 "
1537 " AND h.dhcp_identifier = $3 "
1538 "ORDER BY h.host_id, o.option_id"
1539 },
1540
1541 // PgSqlHostDataSourceImpl::GET_HOST_SUBID6_DHCPID
1542 // Retrieves host information, IPv6 reservations and DHCPv6 options
1543 // associated with a host. The number of rows returned is a multiplication
1544 // of number of IPv6 reservations and DHCPv6 options.
1545 {3,
1547 "get_host_subid6_dhcpid",
1548 "SELECT h.host_id, h.dhcp_identifier, "
1549 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1550 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1551 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1552 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1553 " h.dhcp4_boot_file_name, h.auth_key, "
1554 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1555 " o.persistent, o.user_context, "
1556 " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
1557 "FROM hosts AS h "
1558 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1559 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1560 "WHERE h.dhcp6_subnet_id = $1 AND h.dhcp_identifier_type = $2 "
1561 " AND h.dhcp_identifier = $3 "
1562 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1563 },
1564
1565 //PgSqlHostDataSourceImpl::GET_HOST_SUBID_ADDR
1566 // Retrieves host information and DHCPv4 options for the host using subnet
1567 // identifier and IPv4 reservation. Left joining the dhcp4_options table
1568 // results in multiple rows being returned for the host. The number of
1569 // rows depends on the number of options defined for the host.
1570 {2,
1571 { OID_INT8, OID_INT8 },
1572 "get_host_subid_addr",
1573 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1574 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1575 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1576 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1577 " h.dhcp4_boot_file_name, h.auth_key, "
1578 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1579 " o.persistent, o.user_context "
1580 "FROM hosts AS h "
1581 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1582 "WHERE h.dhcp4_subnet_id = $1 AND h.ipv4_address = $2 "
1583 "ORDER BY h.host_id, o.option_id"
1584 },
1585
1586 // PgSqlHostDataSourceImpl::GET_HOST_PREFIX
1587 // Retrieves host information, IPv6 reservations and DHCPv6 options
1588 // associated with a host using prefix and prefix length. This query
1589 // returns host information for a single host. However, multiple rows
1590 // are returned due to left joining IPv6 reservations and DHCPv6 options.
1591 // The number of rows returned is multiplication of number of existing
1592 // IPv6 reservations and DHCPv6 options.
1593 {2,
1594 { OID_VARCHAR, OID_INT2 },
1595 "get_host_prefix",
1596 "SELECT h.host_id, h.dhcp_identifier, "
1597 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1598 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1599 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1600 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1601 " h.dhcp4_boot_file_name, h.auth_key, "
1602 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1603 " o.persistent, o.user_context, "
1604 " r.reservation_id, r.address, r.prefix_len, r.type, "
1605 " r.dhcp6_iaid "
1606 "FROM hosts AS h "
1607 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1608 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1609 "WHERE h.host_id = "
1610 " (SELECT host_id FROM ipv6_reservations "
1611 " WHERE address = $1 AND prefix_len = $2) "
1612 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1613 },
1614
1615 // PgSqlHostDataSourceImpl::GET_HOST_SUBID6_ADDR
1616 // Retrieves host information, IPv6 reservations and DHCPv6 options
1617 // associated with a host using IPv6 subnet id and prefix. This query
1618 // returns host information for a single host. However, multiple rows
1619 // are returned due to left joining IPv6 reservations and DHCPv6 options.
1620 // The number of rows returned is multiplication of number of existing
1621 // IPv6 reservations and DHCPv6 options.
1622 {2,
1623 { OID_INT8, OID_VARCHAR },
1624 "get_host_subid6_addr",
1625 "SELECT h.host_id, h.dhcp_identifier, "
1626 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1627 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1628 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1629 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1630 " h.dhcp4_boot_file_name, h.auth_key, "
1631 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1632 " o.persistent, o.user_context, "
1633 " r.reservation_id, r.address, r.prefix_len, r.type, "
1634 " r.dhcp6_iaid "
1635 "FROM hosts AS h "
1636 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1637 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1638 "WHERE h.dhcp6_subnet_id = $1 AND r.address = $2 "
1639 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1640 },
1641
1642 // PgSqlHostDataSourceImpl::INSERT_HOST
1643 // Inserts a host into the 'hosts' table. Returns the inserted host id.
1644 {13,
1648 "insert_host",
1649 "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
1650 " dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
1651 " dhcp4_client_classes, dhcp6_client_classes, user_context, "
1652 " dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name, auth_key) "
1653 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) "
1654 "RETURNING host_id"
1655 },
1656
1657 //PgSqlHostDataSourceImpl::INSERT_V6_RESRV
1658 // Inserts a single IPv6 reservation into 'reservations' table.
1659 {5,
1661 "insert_v6_resrv",
1662 "INSERT INTO ipv6_reservations(address, prefix_len, type, "
1663 " dhcp6_iaid, host_id) "
1664 "VALUES ($1, $2, $3, $4, $5)"
1665 },
1666
1667 // PgSqlHostDataSourceImpl::INSERT_V4_HOST_OPTION
1668 // Inserts a single DHCPv4 option into 'dhcp4_options' table.
1669 // Using fixed scope_id = 3, which associates an option with host.
1670 {7,
1673 "insert_v4_host_option",
1674 "INSERT INTO dhcp4_options(code, value, formatted_value, space, "
1675 " persistent, user_context, host_id, scope_id) "
1676 "VALUES ($1, $2, $3, $4, $5, $6, $7, 3)"
1677 },
1678
1679 // PgSqlHostDataSourceImpl::INSERT_V6_HOST_OPTION
1680 // Inserts a single DHCPv6 option into 'dhcp6_options' table.
1681 // Using fixed scope_id = 3, which associates an option with host.
1682 {7,
1685 "insert_v6_host_option",
1686 "INSERT INTO dhcp6_options(code, value, formatted_value, space, "
1687 " persistent, user_context, host_id, scope_id) "
1688 "VALUES ($1, $2, $3, $4, $5, $6, $7, 3)"
1689 },
1690
1691 // PgSqlHostDataSourceImpl::DEL_HOST_ADDR4
1692 // Deletes a v4 host that matches (subnet-id, addr4)
1693 {2,
1694 { OID_INT8, OID_INT8 },
1695 "del_host_addr4",
1696 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 AND ipv4_address = $2"
1697 },
1698
1699 // PgSqlHostDataSourceImpl::DEL_HOST_SUBID4_ID
1700 // Deletes a v4 host that matches (subnet4-id, identifier-type, identifier)
1701 {3,
1703 "del_host_subid4_id",
1704 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 "
1705 "AND dhcp_identifier_type = $2 "
1706 "AND dhcp_identifier = $3"
1707 },
1708
1709 // PgSqlHostDataSourceImpl::DEL_HOST_SUBID6_ID
1710 // Deletes a v6 host that matches (subnet6-id, identifier-type, identifier)
1711 {3,
1713 "del_host_subid6_id",
1714 "DELETE FROM hosts WHERE dhcp6_subnet_id = $1 "
1715 "AND dhcp_identifier_type = $2 "
1716 "AND dhcp_identifier = $3"
1717 }
1718}
1719};
1720
1721}; // end anonymous namespace
1722
1725 : host_exchange_(new PgSqlHostWithOptionsExchange(PgSqlHostWithOptionsExchange::DHCP4_ONLY)),
1726 host_ipv6_exchange_(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP6_ONLY)),
1727 host_ipv46_exchange_(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::
1728 DHCP4_AND_DHCP6)),
1729 host_ipv6_reservation_exchange_(new PgSqlIPv6ReservationExchange()),
1730 host_option_exchange_(new PgSqlOptionExchange()),
1731 conn_(parameters),
1732 is_readonly_(false) {
1733
1734 // Open the database.
1736
1737 // Validate the schema version first.
1738 std::pair<uint32_t, uint32_t> code_version(PG_SCHEMA_VERSION_MAJOR,
1740 std::pair<uint32_t, uint32_t> db_version = getVersion();
1741 if (code_version != db_version) {
1743 "PostgreSQL schema version mismatch: need version: "
1744 << code_version.first << "." << code_version.second
1745 << " found version: " << db_version.first << "."
1746 << db_version.second);
1747 }
1748
1749 // Now prepare the SQL statements.
1752
1753 // Check if the backend is explicitly configured to operate with
1754 // read only access to the database.
1756
1757 // If we are using read-write mode for the database we also prepare
1758 // statements for INSERTS etc.
1759 if (!is_readonly_) {
1761 tagged_statements.end());
1762
1763 } else {
1764 LOG_INFO(dhcpsrv_logger, DHCPSRV_PGSQL_HOST_DB_READONLY);
1765 }
1766}
1767
1769}
1770
1771uint64_t
1773 PsqlBindArrayPtr& bind_array,
1774 const bool return_last_id) {
1775 uint64_t last_id = 0;
1776 PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name,
1777 tagged_statements[stindex].nbparams,
1778 &bind_array->values_[0],
1779 &bind_array->lengths_[0],
1780 &bind_array->formats_[0], 0));
1781
1782 int s = PQresultStatus(r);
1783
1784 if (s != PGRES_COMMAND_OK) {
1785 // Failure: check for the special case of duplicate entry.
1787 isc_throw(DuplicateEntry, "Database duplicate entry error");
1788 }
1789
1790 // Connection determines if the error is fatal or not, and
1791 // throws the appropriate exception
1793 }
1794
1795 if (return_last_id) {
1796 PgSqlExchange::getColumnValue(r, 0, 0, last_id);
1797 }
1798
1799 return (last_id);
1800}
1801
1802bool
1804 PsqlBindArrayPtr& bind_array) {
1805 PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name,
1806 tagged_statements[stindex].nbparams,
1807 &bind_array->values_[0],
1808 &bind_array->lengths_[0],
1809 &bind_array->formats_[0], 0));
1810
1811 int s = PQresultStatus(r);
1812
1813 if (s != PGRES_COMMAND_OK) {
1814 // Connection determines if the error is fatal or not, and
1815 // throws the appropriate exception
1817 }
1818
1819 // Now check how many rows (hosts) were deleted. This should be either
1820 // "0" or "1".
1821 char* rows_deleted = PQcmdTuples(r);
1822 if (!rows_deleted) {
1824 "Could not retrieve the number of deleted rows.");
1825 }
1826 return (rows_deleted[0] != '0');
1827}
1828
1829void
1831 const HostID& id) {
1832 PsqlBindArrayPtr bind_array;
1833 bind_array = host_ipv6_reservation_exchange_->createBindForSend(resv, id);
1834 addStatement(INSERT_V6_RESRV, bind_array);
1835}
1836
1837void
1839 const OptionDescriptor& opt_desc,
1840 const std::string& opt_space,
1842 const HostID& id) {
1843 PsqlBindArrayPtr bind_array;
1844 bind_array = host_option_exchange_->createBindForSend(opt_desc, opt_space,
1845 id);
1846 addStatement(stindex, bind_array);
1847}
1848
1849void
1851 const ConstCfgOptionPtr& options_cfg,
1852 const uint64_t host_id) {
1853 // Get option space names and vendor space names and combine them within a
1854 // single list.
1855 std::list<std::string> option_spaces = options_cfg->getOptionSpaceNames();
1856 std::list<std::string> vendor_spaces = options_cfg->getVendorIdsSpaceNames();
1857 option_spaces.insert(option_spaces.end(), vendor_spaces.begin(),
1858 vendor_spaces.end());
1859
1860 // For each option space retrieve all options and insert them into the
1861 // database.
1862 for (std::list<std::string>::const_iterator space = option_spaces.begin();
1863 space != option_spaces.end(); ++space) {
1864 OptionContainerPtr options = options_cfg->getAll(*space);
1865 if (options && !options->empty()) {
1866 for (OptionContainer::const_iterator opt = options->begin();
1867 opt != options->end(); ++opt) {
1868 addOption(stindex, *opt, *space, OptionalValue<SubnetID>(),
1869 host_id);
1870 }
1871 }
1872 }
1873}
1874
1875void
1878 boost::shared_ptr<PgSqlHostExchange> exchange,
1879 ConstHostCollection& result, bool single) const {
1880
1881 exchange->clear();
1882 PgSqlResult r(PQexecPrepared(conn_, tagged_statements[stindex].name,
1883 tagged_statements[stindex].nbparams,
1884 &bind_array->values_[0],
1885 &bind_array->lengths_[0],
1886 &bind_array->formats_[0], 0));
1887
1889
1890 int rows = r.getRows();
1891 for(int row = 0; row < rows; ++row) {
1892 exchange->processRowData(result, r, row);
1893
1894 if (single && result.size() > 1) {
1895 isc_throw(MultipleRecords, "multiple records were found in the "
1896 "database where only one was expected for query "
1897 << tagged_statements[stindex].name);
1898 }
1899 }
1900}
1901
1904getHost(const SubnetID& subnet_id,
1905 const Host::IdentifierType& identifier_type,
1906 const uint8_t* identifier_begin,
1907 const size_t identifier_len,
1908 StatementIndex stindex,
1909 boost::shared_ptr<PgSqlHostExchange> exchange) const {
1910
1911 // Set up the WHERE clause value
1912 PsqlBindArrayPtr bind_array(new PsqlBindArray());
1913
1914 // Add the subnet id.
1915 bind_array->add(subnet_id);
1916
1917 // Add the Identifier type.
1918 bind_array->add(static_cast<uint8_t>(identifier_type));
1919
1920 // Add the identifier value.
1921 bind_array->add(identifier_begin, identifier_len);
1922
1923 ConstHostCollection collection;
1924 getHostCollection(stindex, bind_array, exchange, collection, true);
1925
1926 // Return single record if present, else clear the host.
1927 ConstHostPtr result;
1928 if (!collection.empty())
1929 result = *collection.begin();
1930
1931 return (result);
1932}
1933
1934std::pair<uint32_t, uint32_t> PgSqlHostDataSourceImpl::getVersion() const {
1936 DHCPSRV_PGSQL_HOST_DB_GET_VERSION);
1937 const char* version_sql = "SELECT version, minor FROM schema_version;";
1938 PgSqlResult r(PQexec(conn_, version_sql));
1939 if(PQresultStatus(r) != PGRES_TUPLES_OK) {
1940 isc_throw(DbOperationError, "unable to execute PostgreSQL statement <"
1941 << version_sql << ">, reason: " << PQerrorMessage(conn_));
1942 }
1943
1944 uint32_t version;
1946
1947 uint32_t minor;
1948 PgSqlExchange::getColumnValue(r, 0, 1, minor);
1949
1950 return (std::make_pair(version, minor));
1951}
1952
1953void
1955 if (is_readonly_) {
1956 isc_throw(ReadOnlyDb, "PostgreSQL host database backend is configured"
1957 " to operate in read only mode");
1958 }
1959}
1960
1961/*********** PgSqlHostDataSource *********************/
1962
1965 : impl_(new PgSqlHostDataSourceImpl(parameters)) {
1966}
1967
1969 delete impl_;
1970}
1971
1972void
1974 // If operating in read-only mode, throw exception.
1975 impl_->checkReadOnly();
1976
1977 // Initiate PostgreSQL transaction as we will have to make multiple queries
1978 // to insert host information into multiple tables. If that fails on
1979 // any stage, the transaction will be rolled back by the destructor of
1980 // the PgSqlTransaction class.
1981 PgSqlTransaction transaction(impl_->conn_);
1982
1983 // Create the PgSQL Bind array for the host
1984 PsqlBindArrayPtr bind_array = impl_->host_exchange_->createBindForSend(host);
1985
1986 // ... and insert the host.
1987 uint32_t host_id = impl_->addStatement(PgSqlHostDataSourceImpl::INSERT_HOST,
1988 bind_array, true);
1989
1990 // Insert DHCPv4 options.
1991 ConstCfgOptionPtr cfg_option4 = host->getCfgOption4();
1992 if (cfg_option4) {
1994 cfg_option4, host_id);
1995 }
1996
1997 // Insert DHCPv6 options.
1998 ConstCfgOptionPtr cfg_option6 = host->getCfgOption6();
1999 if (cfg_option6) {
2001 cfg_option6, host_id);
2002 }
2003
2004 // Insert IPv6 reservations.
2005 IPv6ResrvRange v6resv = host->getIPv6Reservations();
2006 if (std::distance(v6resv.first, v6resv.second) > 0) {
2007 for (IPv6ResrvIterator resv = v6resv.first; resv != v6resv.second;
2008 ++resv) {
2009 impl_->addResv(resv->second, host_id);
2010 }
2011 }
2012
2013 // Everything went fine, so explicitly commit the transaction.
2014 transaction.commit();
2015}
2016
2017bool
2019 // If operating in read-only mode, throw exception.
2020 impl_->checkReadOnly();
2021
2022 if (addr.isV4()) {
2023 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2024 bind_array->add(subnet_id);
2025 bind_array->add(addr);
2027 bind_array));
2028 }
2029
2030 ConstHostPtr host = get6(subnet_id, addr);
2031 if (!host) {
2032 return (false);
2033 }
2034
2035 return del6(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0],
2036 host->getIdentifier().size());
2037}
2038
2039bool
2041 const Host::IdentifierType& identifier_type,
2042 const uint8_t* identifier_begin,
2043 const size_t identifier_len) {
2044
2045 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2046
2047 // Subnet-id
2048 bind_array->add(subnet_id);
2049
2050 // identifier-type
2051 bind_array->add(static_cast<uint8_t>(identifier_type));
2052
2053 // identifier
2054 bind_array->add(identifier_begin, identifier_len);
2055
2057 bind_array));
2058}
2059
2060bool
2062 const Host::IdentifierType& identifier_type,
2063 const uint8_t* identifier_begin,
2064 const size_t identifier_len) {
2065 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2066
2067 // Subnet-id
2068 bind_array->add(subnet_id);
2069
2070 // identifier-type
2071 bind_array->add(static_cast<uint8_t>(identifier_type));
2072
2073 // identifier
2074 bind_array->add(identifier_begin, identifier_len);
2075
2077 bind_array));
2078}
2079
2082 const uint8_t* identifier_begin,
2083 const size_t identifier_len) const {
2084 // Set up the WHERE clause value
2085 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2086
2087 // Identifier value.
2088 bind_array->add(identifier_begin, identifier_len);
2089
2090 // Identifier type.
2091 bind_array->add(static_cast<uint8_t>(identifier_type));
2092
2093 ConstHostCollection result;
2095 bind_array, impl_->host_ipv46_exchange_,
2096 result, false);
2097 return (result);
2098}
2099
2102
2103 // Set up the WHERE clause value
2104 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2105
2106 // v4 Reservation address
2107 bind_array->add(address);
2108
2109 ConstHostCollection result;
2111 impl_->host_exchange_, result, false);
2112
2113 return (result);
2114}
2115
2118 const Host::IdentifierType& identifier_type,
2119 const uint8_t* identifier_begin,
2120 const size_t identifier_len) const {
2121
2122 return (impl_->getHost(subnet_id, identifier_type, identifier_begin,
2123 identifier_len,
2125 impl_->host_exchange_));
2126}
2127
2130 const asiolink::IOAddress& address) const {
2131 if (!address.isV4()) {
2132 isc_throw(BadValue, "PgSqlHostDataSource::get4(id, address) - "
2133 " wrong address type, address supplied is an IPv6 address");
2134 }
2135
2136 // Set up the WHERE clause value
2137 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2138
2139 // Add the subnet id
2140 bind_array->add(subnet_id);
2141
2142 // Add the address
2143 bind_array->add(address);
2144
2145 ConstHostCollection collection;
2147 bind_array, impl_->host_exchange_, collection,
2148 true);
2149
2150 // Return single record if present, else clear the host.
2151 ConstHostPtr result;
2152 if (!collection.empty())
2153 result = *collection.begin();
2154
2155 return (result);
2156}
2157
2160 const Host::IdentifierType& identifier_type,
2161 const uint8_t* identifier_begin,
2162 const size_t identifier_len) const {
2163
2164 return (impl_->getHost(subnet_id, identifier_type, identifier_begin,
2166 impl_->host_ipv6_exchange_));
2167}
2168
2171 const uint8_t prefix_len) const {
2173
2174 // Set up the WHERE clause value
2175 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2176
2177 // Add the prefix
2178 bind_array->add(prefix);
2179
2180 // Add the prefix length
2181 bind_array->add(prefix_len);
2182
2183 ConstHostCollection collection;
2185 bind_array, impl_->host_ipv6_exchange_,
2186 collection, true);
2187
2188 // Return single record if present, else clear the host.
2189 ConstHostPtr result;
2190 if (!collection.empty()) {
2191 result = *collection.begin();
2192 }
2193
2194 return (result);
2195}
2196
2199 const asiolink::IOAddress& address) const {
2201
2202 // Set up the WHERE clause value
2203 PsqlBindArrayPtr bind_array(new PsqlBindArray());
2204
2205 // Add the subnet id
2206 bind_array->add(subnet_id);
2207
2208 // Add the prefix
2209 bind_array->add(address);
2210
2211 ConstHostCollection collection;
2213 bind_array, impl_->host_ipv6_exchange_,
2214 collection, true);
2215
2216 // Return single record if present, else clear the host.
2217 ConstHostPtr result;
2218 if (!collection.empty()) {
2219 result = *collection.begin();
2220 }
2221
2222 return (result);
2223}
2224
2225// Miscellaneous database methods.
2226
2227std::string PgSqlHostDataSource::getName() const {
2228 std::string name = "";
2229 try {
2230 name = impl_->conn_.getParameter("name");
2231 } catch (...) {
2232 // Return an empty name
2233 }
2234 return (name);
2235}
2236
2238 return (std::string("Host data source that stores host information"
2239 "in PostgreSQL database"));
2240}
2241
2242std::pair<uint32_t, uint32_t> PgSqlHostDataSource::getVersion() const {
2243 return(impl_->getVersion());
2244}
2245
2246void
2248 // If operating in read-only mode, throw exception.
2249 impl_->checkReadOnly();
2250 impl_->conn_.commit();
2251}
2252
2253void
2255 // If operating in read-only mode, throw exception.
2256 impl_->checkReadOnly();
2257 impl_->conn_.rollback();
2258}
2259
2260}; // end of isc::dhcp namespace
2261}; // end of isc namespace
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when an unexpected error condition occurs.
static ElementPtr fromJSON(const std::string &in, bool preproc=false)
These functions will parse the given string (JSON) representation of a compound element.
Definition: data.cc:750
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
Definition: data.h:43
bool configuredReadOnly() const
Convenience method checking if database should be opened with read only access.
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
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.
Definition: db_exceptions.h:42
Multiple lease records found where one expected.
Definition: db_exceptions.h:28
Common PgSql Connector Pool.
void rollback()
Rollback Transactions.
bool compareError(const PgSqlResult &r, const char *error_state)
Checks a result set's SQL state against an error state.
static const char DUPLICATE_KEY[]
Define the PgSql error state for a duplicate key error.
void commit()
Commit Transactions.
void prepareStatements(const PgSqlTaggedStatement *start_statement, const PgSqlTaggedStatement *end_statement)
Prepare statements.
void openDatabase()
Open Database.
void checkStatementError(const PgSqlResult &r, PgSqlTaggedStatement &statement) const
Checks result of the r object.
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.
Definition: db_exceptions.h:49
Authentication keys.
Definition: host.h:34
Represents a device with IPv4 and/or IPv6 reservations.
Definition: host.h:242
IdentifierType
Type of the host identifier.
Definition: host.h:252
static const IdentifierType LAST_IDENTIFIER_TYPE
Constant pointing to the last identifier of the IdentifierType enumeration.
Definition: host.h:262
IPv6 reservation for a host.
Definition: host.h:106
const asiolink::IOAddress & getPrefix() const
Returns prefix for the reservation.
Definition: host.h:135
Type getType() const
Returns reservation type.
Definition: host.h:149
Type
Type of the reservation.
Definition: host.h:112
uint8_t getPrefixLen() const
Returns prefix length.
Definition: host.h:140
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition: libdhcp++.cc:144
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:184
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
Definition: libdhcp++.cc:916
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:205
Option descriptor.
Definition: cfg_option.h:35
OptionPtr option_
Option instance.
Definition: cfg_option.h:38
std::string formatted_value_
Option value in textual (CSV) format.
Definition: cfg_option.h:59
bool persistent_
Persistence flag.
Definition: cfg_option.h:44
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:67
Implementation of the PgSqlHostDataSource.
uint64_t addStatement(PgSqlHostDataSourceImpl::StatementIndex stindex, PsqlBindArrayPtr &bind, const bool return_last_id=false)
Executes statements which insert a row into one of the tables.
boost::shared_ptr< PgSqlHostIPv6Exchange > host_ipv46_exchange_
Pointer to an object representing an exchange which can be used to retrieve hosts,...
void addResv(const IPv6Resrv &resv, const HostID &id)
Inserts IPv6 Reservation into ipv6_reservation table.
void addOption(const PgSqlHostDataSourceImpl::StatementIndex &stindex, const OptionDescriptor &opt_desc, const std::string &opt_space, const OptionalValue< SubnetID > &subnet_id, const HostID &host_id)
Inserts a single DHCP option into the database.
boost::shared_ptr< PgSqlIPv6ReservationExchange > host_ipv6_reservation_exchange_
Pointer to an object representing an exchange which can be used to insert new IPv6 reservation.
void addOptions(const StatementIndex &stindex, const ConstCfgOptionPtr &options_cfg, const uint64_t host_id)
Inserts multiple options into the database.
bool delStatement(PgSqlHostDataSourceImpl::StatementIndex stindex, PsqlBindArrayPtr &bind)
Executes statements that delete records.
bool is_readonly_
Indicates if the database is opened in read only mode.
boost::shared_ptr< PgSqlHostWithOptionsExchange > host_exchange_
Pointer to the object representing an exchange which can be used to retrieve hosts and DHCPv4 options...
PgSqlConnection conn_
PgSQL connection.
std::pair< uint32_t, uint32_t > getVersion() const
Returns PostgreSQL schema version of the open database.
void checkReadOnly() const
Throws exception if database is read only.
ConstHostPtr getHost(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len, StatementIndex stindex, boost::shared_ptr< PgSqlHostExchange > exchange) const
Retrieves a host by subnet and client's unique identifier.
void getHostCollection(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 ...
static const StatementIndex WRITE_STMTS_BEGIN
Index of first statement performing write to the database.
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...
PgSqlHostDataSourceImpl(const PgSqlConnection::ParameterMap &parameters)
Constructor.
boost::shared_ptr< PgSqlHostIPv6Exchange > host_ipv6_exchange_
Pointer to an object representing an exchange which can be used to retrieve hosts,...
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 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 getAll4(const asiolink::IOAddress &address) const
Returns a collection of hosts using the specified IPv4 address.
virtual bool del(const SubnetID &subnet_id, const asiolink::IOAddress &addr)
Attempts to delete a host by (subnet-id, address)
virtual void rollback()
Rollback Transactions.
virtual std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
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 void commit()
Commit Transactions.
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.
Simple class representing an optional value.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
int version()
returns Kea hooks version.
#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:23
const size_t OID_INT4
const size_t OID_INT2
const uint32_t PG_SCHEMA_VERSION_MAJOR
Define PostgreSQL backend version: 5.0.
const uint32_t PG_SCHEMA_VERSION_MINOR
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
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
IPv6ResrvCollection::const_iterator IPv6ResrvIterator
Definition: host.h:186
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Definition: cfg_option.h:497
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
Definition: host.h:725
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
Definition: host.h:731
TaggedStatementArray tagged_statements
Prepared MySQL statements used by the backend to insert and retrieve hosts from the database.
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
Definition: host.h:188
boost::array< TaggedStatement, MySqlHostDataSourceImpl::NUM_STATEMENTS > TaggedStatementArray
Array of tagged statements.
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
uint64_t HostID
HostID (used only when storing in MySQL, PostgreSQL or Cassandra)
Definition: host.h:28
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
Definition: cfg_option.h:206
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Definition: host.h:728
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:25
boost::shared_ptr< Option > OptionPtr
Definition: option.h:38
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
Definition: cfg_option.h:500
Definition: edns.h:19
Defines the logger used by the top-level component of kea-dhcp-ddns.
#define DHCP4_OPTION_SPACE
Definition: option_space.h:16
#define DHCP6_OPTION_SPACE
Definition: option_space.h:17
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
Definition: user_context.h:24
static const int BINARY_FMT
Format value for binary data.