26#include <boost/algorithm/string/split.hpp>
27#include <boost/algorithm/string/classification.hpp>
28#include <boost/array.hpp>
29#include <boost/foreach.hpp>
30#include <boost/pointer_cast.hpp>
31#include <boost/static_assert.hpp>
95 static const size_t HOST_ID_COL = 0;
96 static const size_t DHCP_IDENTIFIER_COL = 1;
97 static const size_t DHCP_IDENTIFIER_TYPE_COL = 2;
98 static const size_t DHCP4_SUBNET_ID_COL = 3;
99 static const size_t DHCP6_SUBNET_ID_COL = 4;
100 static const size_t IPV4_ADDRESS_COL = 5;
101 static const size_t HOSTNAME_COL = 6;
102 static const size_t DHCP4_CLIENT_CLASSES_COL = 7;
103 static const size_t DHCP6_CLIENT_CLASSES_COL = 8;
104 static const size_t USER_CONTEXT_COL = 9;
105 static const size_t DHCP4_NEXT_SERVER_COL = 10;
106 static const size_t DHCP4_SERVER_HOSTNAME_COL = 11;
107 static const size_t DHCP4_BOOT_FILE_NAME_COL = 12;
108 static const size_t AUTH_KEY_COL = 13;
110 static const size_t HOST_COLUMNS = 14;
120 PgSqlHostExchange(
const size_t additional_columns_num = 0)
126 columns_[HOST_ID_COL] =
"host_id";
127 columns_[DHCP_IDENTIFIER_COL] =
"dhcp_identifier";
128 columns_[DHCP_IDENTIFIER_TYPE_COL] =
"dhcp_identifier_type";
129 columns_[DHCP4_SUBNET_ID_COL] =
"dhcp4_subnet_id";
130 columns_[DHCP6_SUBNET_ID_COL] =
"dhcp6_subnet_id";
131 columns_[IPV4_ADDRESS_COL] =
"ipv4_address";
132 columns_[HOSTNAME_COL] =
"hostname";
133 columns_[DHCP4_CLIENT_CLASSES_COL] =
"dhcp4_client_classes";
134 columns_[DHCP6_CLIENT_CLASSES_COL] =
"dhcp6_client_classes";
135 columns_[USER_CONTEXT_COL] =
"user_context";
136 columns_[DHCP4_NEXT_SERVER_COL] =
"dhcp4_next_server";
137 columns_[DHCP4_SERVER_HOSTNAME_COL] =
"dhcp4_server_hostname";
138 columns_[DHCP4_BOOT_FILE_NAME_COL] =
"dhcp4_boot_file_name";
139 columns_[AUTH_KEY_COL] =
"auth_key";
141 BOOST_STATIC_ASSERT(12 < HOST_COLUMNS);
145 virtual ~PgSqlHostExchange() {
153 virtual void clear() {
171 size_t findAvailColumn()
const {
172 std::vector<std::string>::const_iterator empty_column =
173 std::find(columns_.begin(), columns_.end(), std::string());
174 return (std::distance(columns_.begin(), empty_column));
183 getColumnValue(r, row, HOST_ID_COL, host_id);
216 bind_array->add(host->getIdentifier());
219 bind_array->add(host->getIdentifierType());
222 if (host->getIPv4SubnetID() == SUBNET_ID_UNUSED) {
223 bind_array->addNull();
225 bind_array->add(host->getIPv4SubnetID());
229 if (host->getIPv6SubnetID() == SUBNET_ID_UNUSED) {
230 bind_array->addNull();
232 bind_array->add(host->getIPv6SubnetID());
236 bind_array->add((host->getIPv4Reservation()));
239 bind_array->add(host->getHostname());
243 bind_array->addTempString(host->getClientClasses4().toText(
","));
246 bind_array->addTempString(host->getClientClasses6().toText(
","));
251 std::string user_context_ = ctx->str();
252 bind_array->addTempString(user_context_);
254 bind_array->addNull();
258 bind_array->add((host->getNextServer()));
261 bind_array->add(host->getServerHostname());
264 bind_array->add(host->getBootFileName());
267 std::string key = host->getKey().toText();
269 bind_array->addNull();
271 bind_array->addTempString(key);
278 bind_array->add(host->getIPv4Reservation());
279 bind_array->add(host->getIPv4SubnetID());
282 }
catch (
const std::exception& ex) {
285 "Could not create bind array from Host: "
286 << host->getHostname() <<
", reason: " << ex.
what());
310 HostID row_host_id = getHostId(r, row);
315 if (hosts.empty() || row_host_id != hosts.back()->getHostId()) {
316 HostPtr host = retrieveHost(r, row, row_host_id);
317 hosts.push_back(host);
333 const HostID& peeked_host_id = 0) {
337 HostID host_id = (peeked_host_id ? peeked_host_id : getHostId(r,row));
340 uint8_t identifier_value[DHCP_IDENTIFIER_MAX_LEN];
341 size_t identifier_len;
342 convertFromBytea(r, row, DHCP_IDENTIFIER_COL, identifier_value,
343 sizeof(identifier_value), identifier_len);
347 getColumnValue(r, row, DHCP_IDENTIFIER_TYPE_COL, type);
348 if (type > MAX_IDENTIFIER_TYPE) {
350 <<
static_cast<int>(type));
357 uint32_t subnet_id(SUBNET_ID_UNUSED);
358 if (!isColumnNull(r, row, DHCP4_SUBNET_ID_COL)) {
359 getColumnValue(r, row, DHCP4_SUBNET_ID_COL, subnet_id);
364 subnet_id = SUBNET_ID_UNUSED;
365 if (!isColumnNull(r, row, DHCP6_SUBNET_ID_COL)) {
366 getColumnValue(r, row, DHCP6_SUBNET_ID_COL, subnet_id);
372 if (!isColumnNull(r, row, IPV4_ADDRESS_COL)) {
373 getColumnValue(r, row, IPV4_ADDRESS_COL, addr4);
378 std::string hostname;
379 if (!isColumnNull(r, row, HOSTNAME_COL)) {
380 getColumnValue(r, row, HOSTNAME_COL, hostname);
384 std::string dhcp4_client_classes;
385 if (!isColumnNull(r, row, DHCP4_CLIENT_CLASSES_COL)) {
386 getColumnValue(r, row, DHCP4_CLIENT_CLASSES_COL, dhcp4_client_classes);
390 std::string dhcp6_client_classes;
391 if (!isColumnNull(r, row, DHCP6_CLIENT_CLASSES_COL)) {
392 getColumnValue(r, row, DHCP6_CLIENT_CLASSES_COL, dhcp6_client_classes);
396 std::string user_context;
397 if (!isColumnNull(r, row, USER_CONTEXT_COL)) {
398 getColumnValue(r, row, USER_CONTEXT_COL, user_context);
402 uint32_t dhcp4_next_server_as_uint32(0);
403 if (!isColumnNull(r, row, DHCP4_NEXT_SERVER_COL)) {
404 getColumnValue(r, row, DHCP4_NEXT_SERVER_COL, dhcp4_next_server_as_uint32);
409 std::string dhcp4_server_hostname;
410 if (!isColumnNull(r, row, DHCP4_SERVER_HOSTNAME_COL)) {
411 getColumnValue(r, row, DHCP4_SERVER_HOSTNAME_COL, dhcp4_server_hostname);
415 std::string dhcp4_boot_file_name;
416 if (!isColumnNull(r, row, DHCP4_BOOT_FILE_NAME_COL)) {
417 getColumnValue(r, row, DHCP4_BOOT_FILE_NAME_COL, dhcp4_boot_file_name);
421 std::string auth_key;
422 if (!isColumnNull(r, row, AUTH_KEY_COL)) {
423 getColumnValue(r, row, AUTH_KEY_COL, auth_key);
429 host.reset(
new Host(identifier_value, identifier_len,
430 identifier_type, dhcp4_subnet_id,
431 dhcp6_subnet_id, ipv4_reservation, hostname,
432 dhcp4_client_classes, dhcp6_client_classes,
433 dhcp4_next_server, dhcp4_server_hostname,
434 dhcp4_boot_file_name,
AuthKey(auth_key)));
437 if (!user_context.empty()) {
442 <<
"' is not a JSON map");
444 host->setContext(ctx);
447 <<
"' is invalid JSON: " << ex.
what());
451 host->setHostId(host_id);
474class PgSqlHostWithOptionsExchange :
public PgSqlHostExchange {
478 static const size_t OPTION_COLUMNS = 8;
494 class OptionProcessor {
504 const size_t start_column)
505 : universe_(universe), start_column_(start_column),
506 option_id_index_(start_column), code_index_(start_column_ + 1),
507 value_index_(start_column_ + 2),
508 formatted_value_index_(start_column_ + 3),
509 space_index_(start_column_ + 4),
510 persistent_index_(start_column_ + 5),
511 cancelled_index_(start_column_ + 6),
512 user_context_index_(start_column_ + 7),
513 most_recent_option_id_(0) {
521 most_recent_option_id_ = 0;
571 if (most_recent_option_id_ >= option_id) {
577 most_recent_option_id_ = option_id;
586 if (!isColumnNull(r, row, value_index_)) {
588 sizeof(value), value_len);
592 std::string formatted_value;
593 if (!isColumnNull(r, row, formatted_value_index_)) {
600 if (!isColumnNull(r, row, space_index_)) {
621 std::string user_context;
622 if (!isColumnNull(r, row, user_context_index_)) {
665 option.reset(
new Option(universe_, code, buf.begin(),
672 if (formatted_value.empty()) {
674 option = def->optionFactory(universe_, code, buf.begin(),
679 std::vector<std::string> split_vec;
680 boost::split(split_vec, formatted_value,
681 boost::is_any_of(
","));
682 option = def->optionFactory(universe_, code, split_vec);
690 if (!user_context.empty()) {
695 <<
"' is no a JSON map");
697 desc.setContext(ctx);
700 <<
"' is invalid JSON: " << ex.
what());
704 cfg->add(desc, space);
711 void setColumnNames(std::vector<std::string>& columns) {
712 columns[option_id_index_] =
"option_id";
713 columns[code_index_] =
"code";
714 columns[value_index_] =
"value";
715 columns[formatted_value_index_] =
"formatted_value";
716 columns[space_index_] =
"space";
717 columns[persistent_index_] =
"persistent";
718 columns[cancelled_index_] =
"cancelled";
719 columns[user_context_index_] =
"user_context";
727 size_t start_column_;
734 size_t option_id_index_;
743 size_t formatted_value_index_;
749 size_t persistent_index_;
752 size_t cancelled_index_;
756 size_t user_context_index_;
759 uint64_t most_recent_option_id_;
763 typedef boost::shared_ptr<OptionProcessor> OptionProcessorPtr;
773 enum FetchedOptions {
787 PgSqlHostWithOptionsExchange(
const FetchedOptions& fetched_options,
788 const size_t additional_columns_num = 0)
789 : PgSqlHostExchange(getRequiredColumnsNum(fetched_options)
790 + additional_columns_num),
791 opt_proc4_(), opt_proc6_() {
794 if ((fetched_options == DHCP4_ONLY) ||
795 (fetched_options == DHCP4_AND_DHCP6)) {
796 opt_proc4_.reset(
new OptionProcessor(
Option::V4,
798 opt_proc4_->setColumnNames(columns_);
802 if ((fetched_options == DHCP6_ONLY) ||
803 (fetched_options == DHCP4_AND_DHCP6)) {
804 opt_proc6_.reset(
new OptionProcessor(
Option::V6,
806 opt_proc6_->setColumnNames(columns_);
815 virtual void clear() {
816 PgSqlHostExchange::clear();
840 current_host = retrieveHost(r, row);
841 hosts.push_back(current_host);
846 HostID row_host_id = getHostId(r, row);
847 current_host = boost::const_pointer_cast<Host>(hosts.back());
851 if (row_host_id > current_host->getHostId()) {
852 current_host = retrieveHost(r, row, row_host_id);
853 hosts.push_back(current_host);
860 opt_proc4_->retrieveOption(cfg, r, row);
866 opt_proc6_->retrieveOption(cfg, r, row);
883 static size_t getRequiredColumnsNum(
const FetchedOptions& fetched_options) {
884 return (fetched_options == DHCP4_AND_DHCP6 ? 2 * OPTION_COLUMNS :
891 OptionProcessorPtr opt_proc4_;
896 OptionProcessorPtr opt_proc6_;
911class PgSqlHostIPv6Exchange :
public PgSqlHostWithOptionsExchange {
915 static const size_t RESERVATION_COLUMNS = 7;
923 PgSqlHostIPv6Exchange(
const FetchedOptions& fetched_options)
924 : PgSqlHostWithOptionsExchange(fetched_options, RESERVATION_COLUMNS),
925 reservation_id_index_(findAvailColumn()),
926 address_index_(reservation_id_index_ + 1),
927 prefix_len_index_(reservation_id_index_ + 2),
928 type_index_(reservation_id_index_ + 3),
929 iaid_index_(reservation_id_index_ + 4),
930 excluded_prefix_index_(reservation_id_index_ + 5),
931 excluded_prefix_len_index_(reservation_id_index_ + 6),
932 most_recent_reservation_id_(0) {
935 columns_[reservation_id_index_] =
"reservation_id";
936 columns_[address_index_] =
"address";
937 columns_[prefix_len_index_] =
"prefix_len";
938 columns_[type_index_] =
"type";
939 columns_[iaid_index_] =
"dhcp6_iaid";
940 columns_[excluded_prefix_index_] =
"excluded_prefix";
941 columns_[excluded_prefix_len_index_] =
"excluded_prefix_len";
943 BOOST_STATIC_ASSERT(6 < RESERVATION_COLUMNS);
952 PgSqlHostWithOptionsExchange::clear();
953 most_recent_reservation_id_ = 0;
959 uint64_t getReservationId(
const PgSqlResult& r,
int row)
const {
960 uint64_t resv_id = 0;
961 if (!isColumnNull(r, row, reservation_id_index_)) {
962 getColumnValue(r, row, reservation_id_index_, resv_id);
976 getColumnValue(r, row, type_index_, tmp);
991 "invalid IPv6 reservation type returned: "
992 << tmp <<
". Only 0 or 2 are allowed.");
1000 getColumnValue(r, row, prefix_len_index_, prefix_len);
1011 if (!isColumnNull(r, row, excluded_prefix_index_)) {
1013 excluded_prefix_index_));
1014 uint16_t excluded_prefix_len;
1015 getColumnValue(r, row, excluded_prefix_len_index_,
1016 excluded_prefix_len);
1017 reservation.setPDExclude(prefix, excluded_prefix_len);
1019 return (reservation);
1046 PgSqlHostWithOptionsExchange::processRowData(hosts, r, row);
1049 if (hosts.empty()) {
1051 " IPv6 reservation");
1056 uint64_t reservation_id = getReservationId(r, row);
1057 if (reservation_id && (reservation_id > most_recent_reservation_id_)) {
1058 HostPtr host = boost::const_pointer_cast<Host>(hosts.back());
1059 host->addReservation(retrieveReservation(r, row));
1060 most_recent_reservation_id_ = reservation_id;
1068 size_t reservation_id_index_;
1071 size_t address_index_;
1074 size_t prefix_len_index_;
1083 size_t excluded_prefix_index_;
1086 size_t excluded_prefix_len_index_;
1091 uint64_t most_recent_reservation_id_;
1108 static const size_t RESRV_COLUMNS = 8;
1115 PgSqlIPv6ReservationExchange()
1119 columns_[0] =
"host_id";
1120 columns_[1] =
"address";
1121 columns_[2] =
"prefix_len";
1122 columns_[3] =
"type";
1123 columns_[4] =
"dhcp6_iaid";
1124 columns_[5] =
"excluded_prefix";
1125 columns_[6] =
"excluded_prefix_len";
1127 BOOST_STATIC_ASSERT(7 < RESRV_COLUMNS);
1146 const bool unique_ip) {
1156 bind_array->add(resv.getPrefix());
1159 bind_array->add(resv.getPrefixLen());
1164 bind_array->add(type);
1168 bind_array->addNull();
1174 opt->getExcludedPrefix(resv.getPrefix(),
1175 resv.getPrefixLen());
1176 bind_array->add(excluded_prefix);
1178 bind_array->addNull();
1180 uint16_t excluded_prefix_len(opt ? opt->getExcludedPrefixLength() : 0);
1181 bind_array->add(excluded_prefix_len);
1184 bind_array->add(host_id);
1190 bind_array->add(resv.getPrefix());
1191 bind_array->add(resv.getPrefixLen());
1193 }
catch (
const std::exception& ex) {
1195 "Could not create bind array from IPv6 Reservation: "
1196 << resv_.toText() <<
", reason: " << ex.
what());
1199 return (bind_array);
1213 static const size_t OPTION_ID_COL = 0;
1214 static const size_t CODE_COL = 1;
1215 static const size_t VALUE_COL = 2;
1216 static const size_t FORMATTED_VALUE_COL = 3;
1217 static const size_t SPACE_COL = 4;
1218 static const size_t PERSISTENT_COL = 5;
1219 static const size_t CANCELLED_COL = 6;
1220 static const size_t USER_CONTEXT_COL = 7;
1221 static const size_t DHCP_SUBNET_ID_COL = 8;
1222 static const size_t HOST_ID_COL = 9;
1224 static const size_t OPTION_COLUMNS = 10;
1229 PgSqlOptionExchange()
1231 value_len_(0), option_() {
1232 columns_[OPTION_ID_COL] =
"option_id";
1233 columns_[CODE_COL] =
"code";
1234 columns_[VALUE_COL] =
"value";
1235 columns_[FORMATTED_VALUE_COL] =
"formatted_value";
1236 columns_[SPACE_COL] =
"space";
1237 columns_[PERSISTENT_COL] =
"persistent";
1238 columns_[CANCELLED_COL] =
"cancelled";
1239 columns_[USER_CONTEXT_COL] =
"user_context";
1240 columns_[DHCP_SUBNET_ID_COL] =
"dhcp_subnet_id";
1241 columns_[HOST_ID_COL] =
"host_id";
1243 BOOST_STATIC_ASSERT(10 <= OPTION_COLUMNS);
1255 const std::string& opt_space,
1259 option_ = opt_desc.option_;
1268 bind_array->add(option_->getType());
1271 if (opt_desc.formatted_value_.empty() &&
1272 (opt_desc.option_->len() > opt_desc.option_->getHeaderLen())) {
1277 opt_desc.option_->pack(buf);
1278 const uint8_t* buf_ptr = buf.getData();
1279 value_.assign(buf_ptr + opt_desc.option_->getHeaderLen(),
1280 buf_ptr + buf.getLength());
1281 value_len_ = value_.size();
1282 bind_array->add(value_);
1290 if (!opt_desc.formatted_value_.empty()) {
1291 bind_array->addTempString(opt_desc.formatted_value_);
1293 bind_array->addNull();
1297 if (!opt_space.empty()) {
1298 bind_array->addTempString(opt_space);
1300 bind_array->addNull();
1304 bind_array->add(opt_desc.persistent_);
1307 bind_array->add(opt_desc.cancelled_);
1312 std::string user_context_ = ctx->str();
1313 bind_array->addTempString(user_context_);
1315 bind_array->addNull();
1322 bind_array->add(host_id);
1324 }
catch (
const std::exception& ex) {
1326 "Could not create bind array for inserting DHCP "
1327 "host option: " << option_->toText() <<
", reason: "
1331 return (bind_array);
1337 std::vector<uint8_t> value_;
1538 const bool return_last_id =
false);
1572 const std::string& opt_space,
1573 const Optional<SubnetID>& subnet_id,
1587 const uint64_t host_id);
1610 boost::shared_ptr<PgSqlHostExchange> exchange,
1634 const uint8_t* identifier_begin,
1635 const size_t identifier_len,
1637 boost::shared_ptr<PgSqlHostExchange> exchange)
const;
1659 std::pair<uint32_t, uint32_t>
getVersion(
const std::string& timer_name = std::string())
const;
1682typedef boost::array<PgSqlTaggedStatement, PgSqlHostDataSourceImpl::NUM_STATEMENTS>
1683TaggedStatementArray;
1687TaggedStatementArray tagged_statements = { {
1696 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1697 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
1698 " h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
1700 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1701 " h.dhcp4_boot_file_name, h.auth_key, "
1702 " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
1703 " o4.persistent, o4.cancelled, o4.user_context, "
1704 " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
1705 " o6.persistent, o6.cancelled, o6.user_context, "
1706 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1707 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1709 "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id "
1710 "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id "
1711 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1712 "WHERE dhcp_identifier = $1 AND dhcp_identifier_type = $2 "
1713 "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id"
1723 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1724 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1725 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1726 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1727 " h.dhcp4_boot_file_name, h.auth_key, "
1728 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1729 " o.persistent, o.cancelled, o.user_context "
1731 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1732 "WHERE ipv4_address = $1 "
1733 "ORDER BY h.host_id, o.option_id"
1742 "get_host_subid4_dhcpid",
1743 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1744 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1745 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1746 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1747 " h.dhcp4_boot_file_name, h.auth_key, "
1748 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1749 " o.persistent, o.cancelled, o.user_context "
1751 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1752 "WHERE h.dhcp4_subnet_id = $1 AND h.dhcp_identifier_type = $2 "
1753 " AND h.dhcp_identifier = $3 "
1754 "ORDER BY h.host_id, o.option_id"
1763 "get_host_subid6_dhcpid",
1764 "SELECT h.host_id, h.dhcp_identifier, "
1765 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1766 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1767 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1768 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1769 " h.dhcp4_boot_file_name, h.auth_key, "
1770 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1771 " o.persistent, o.cancelled, o.user_context, "
1772 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1773 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1775 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1776 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1777 "WHERE h.dhcp6_subnet_id = $1 AND h.dhcp_identifier_type = $2 "
1778 " AND h.dhcp_identifier = $3 "
1779 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1789 "get_host_subid_addr",
1790 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1791 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1792 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1793 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1794 " h.dhcp4_boot_file_name, h.auth_key, "
1795 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1796 " o.persistent, o.cancelled, o.user_context "
1798 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1799 "WHERE h.dhcp4_subnet_id = $1 AND h.ipv4_address = $2 "
1800 "ORDER BY h.host_id, o.option_id"
1813 "SELECT h.host_id, h.dhcp_identifier, "
1814 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1815 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1816 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1817 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1818 " h.dhcp4_boot_file_name, h.auth_key, "
1819 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1820 " o.persistent, o.cancelled, o.user_context, "
1821 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1822 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1824 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1825 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1826 "WHERE h.host_id = "
1827 " (SELECT host_id FROM ipv6_reservations "
1828 " WHERE address = cast($1 as inet) AND prefix_len = $2) "
1829 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1841 "get_host_subid6_addr",
1842 "SELECT h.host_id, h.dhcp_identifier, "
1843 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1844 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1845 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1846 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1847 " h.dhcp4_boot_file_name, h.auth_key, "
1848 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1849 " o.persistent, o.cancelled, o.user_context, "
1850 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1851 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1853 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1854 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1855 "WHERE h.dhcp6_subnet_id = $1 AND h.host_id IN "
1856 " (SELECT host_id FROM ipv6_reservations "
1857 " WHERE address = cast($2 as inet)) "
1858 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1872 "SELECT h.host_id, h.dhcp_identifier, "
1873 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1874 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1875 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1876 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1877 " h.dhcp4_boot_file_name, h.auth_key, "
1878 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1879 " o.persistent, o.cancelled, o.user_context, "
1880 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1881 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1883 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1884 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1885 "WHERE h.host_id IN "
1886 " (SELECT host_id FROM ipv6_reservations "
1887 " WHERE address = cast($1 as inet)) "
1888 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1900 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1901 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1902 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1903 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1904 " h.dhcp4_boot_file_name, h.auth_key, "
1905 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1906 " o.persistent, o.cancelled, o.user_context "
1908 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1909 "WHERE h.dhcp4_subnet_id = $1 "
1910 "ORDER BY h.host_id, o.option_id"
1926 "SELECT h.host_id, h.dhcp_identifier, "
1927 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
1928 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1929 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1930 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1931 " h.dhcp4_boot_file_name, h.auth_key, "
1932 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1933 " o.persistent, o.cancelled, o.user_context, "
1934 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1935 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1937 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
1938 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1939 "WHERE h.dhcp6_subnet_id = $1 "
1940 "ORDER BY h.host_id, o.option_id, r.reservation_id"
1951 "get_host_hostname",
1952 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1953 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, "
1954 " h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, "
1956 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1957 " h.dhcp4_boot_file_name, h.auth_key, "
1958 " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, "
1959 " o4.persistent, o4.cancelled, o4.user_context, "
1960 " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
1961 " o6.persistent, o6.cancelled, o6.user_context, "
1962 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
1963 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
1965 "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id "
1966 "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id "
1967 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
1968 "WHERE lower(h.hostname) = $1 "
1969 "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id"
1979 "get_host_hostname_subid4",
1980 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
1981 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
1982 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
1983 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
1984 " h.dhcp4_boot_file_name, h.auth_key, "
1985 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
1986 " o.persistent, o.cancelled, o.user_context "
1988 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
1989 "WHERE lower(h.hostname) = $1 AND h.dhcp4_subnet_id = $2 "
1990 "ORDER BY h.host_id, o.option_id"
2002 "get_host_hostname_subid6",
2003 "SELECT h.host_id, h.dhcp_identifier, "
2004 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2005 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2006 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2007 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2008 " h.dhcp4_boot_file_name, h.auth_key, "
2009 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2010 " o.persistent, o.cancelled, o.user_context, "
2011 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
2012 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
2014 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
2015 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
2016 "WHERE lower(h.hostname) = $1 AND h.dhcp6_subnet_id = $2 "
2017 "ORDER BY h.host_id, o.option_id, r.reservation_id"
2027 "get_host_subid4_page",
2028 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2029 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2030 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2031 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2032 " h.dhcp4_boot_file_name, h.auth_key, "
2033 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2034 " o.persistent, o.cancelled, o.user_context "
2035 "FROM ( SELECT * FROM hosts AS h "
2036 " WHERE h.dhcp4_subnet_id = $1 AND h.host_id > $2 "
2037 " ORDER BY h.host_id "
2039 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
2040 "ORDER BY h.host_id, o.option_id"
2052 "get_host_subid6_page",
2053 "SELECT h.host_id, h.dhcp_identifier, "
2054 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2055 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2056 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2057 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2058 " h.dhcp4_boot_file_name, h.auth_key, "
2059 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2060 " o.persistent, o.cancelled, o.user_context, "
2061 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
2062 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
2063 "FROM ( SELECT * FROM hosts AS h "
2064 " WHERE h.dhcp6_subnet_id = $1 AND h.host_id > $2 "
2065 " ORDER BY h.host_id "
2067 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
2068 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
2069 "ORDER BY h.host_id, o.option_id, r.reservation_id"
2080 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
2081 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2082 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2083 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2084 " h.dhcp4_boot_file_name, h.auth_key, "
2085 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2086 " o.persistent, o.cancelled, o.user_context "
2087 "FROM ( SELECT * FROM hosts AS h "
2088 " WHERE h.host_id > $1 "
2089 " ORDER BY h.host_id "
2091 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
2092 "ORDER BY h.host_id, o.option_id"
2105 "SELECT h.host_id, h.dhcp_identifier, "
2106 " h.dhcp_identifier_type, h.dhcp4_subnet_id, "
2107 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
2108 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
2109 " h.dhcp4_next_server, h.dhcp4_server_hostname, "
2110 " h.dhcp4_boot_file_name, h.auth_key, "
2111 " o.option_id, o.code, o.value, o.formatted_value, o.space, "
2112 " o.persistent, o.cancelled, o.user_context, "
2113 " r.reservation_id, host(r.address), r.prefix_len, r.type, "
2114 " r.dhcp6_iaid, host(r.excluded_prefix), r.excluded_prefix_len "
2115 "FROM ( SELECT * FROM hosts AS h "
2116 " WHERE h.host_id > $1 "
2117 " ORDER BY h.host_id "
2119 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
2120 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
2121 "ORDER BY h.host_id, o.option_id, r.reservation_id"
2132 "insert_host_non_unique_ip",
2133 "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
2134 " dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
2135 " dhcp4_client_classes, dhcp6_client_classes, user_context, "
2136 " dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name, auth_key)"
2137 "VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13 ) "
2158 "insert_host_unique_ip",
2159 "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
2160 " dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
2161 " dhcp4_client_classes, dhcp6_client_classes, user_context, "
2162 " dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name, auth_key)"
2163 " SELECT $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13"
2164 " WHERE NOT EXISTS ("
2165 " SELECT 1 FROM hosts WHERE ipv4_address = $14 AND dhcp4_subnet_id = $15"
2176 "insert_v6_resrv_non_unique",
2177 "INSERT INTO ipv6_reservations(address, prefix_len, type, "
2178 " dhcp6_iaid, excluded_prefix, excluded_prefix_len, host_id) "
2179 "VALUES (cast($1 as inet), $2, $3, $4, cast($5 as inet), $6, $7)"
2188 "insert_v6_resrv_unique",
2189 "INSERT INTO ipv6_reservations(address, prefix_len, type, "
2190 " dhcp6_iaid, excluded_prefix, excluded_prefix_len, host_id) "
2191 "SELECT cast($1 as inet), $2, $3, $4, cast($5 as inet), $6, $7 "
2192 " WHERE NOT EXISTS ("
2193 " SELECT 1 FROM ipv6_reservations"
2194 " WHERE address = cast($8 as inet) AND prefix_len = $9"
2205 "insert_v4_host_option",
2206 "INSERT INTO dhcp4_options(code, value, formatted_value, space, "
2207 " persistent, cancelled, user_context, host_id, scope_id) "
2208 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 3)"
2217 "insert_v6_host_option",
2218 "INSERT INTO dhcp6_options(code, value, formatted_value, space, "
2219 " persistent, cancelled, user_context, host_id, scope_id) "
2220 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 3)"
2228 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 AND ipv4_address = $2"
2236 "DELETE FROM hosts USING ipv6_reservations "
2237 " WHERE hosts.host_id = ipv6_reservations.host_id"
2238 " AND dhcp6_subnet_id = $1 AND ipv6_reservations.address = cast($2 as inet)"
2245 "del_host_subid4_id",
2246 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 "
2247 "AND dhcp_identifier_type = $2 "
2248 "AND dhcp_identifier = $3"
2255 "del_host_subid6_id",
2256 "DELETE FROM hosts WHERE dhcp6_subnet_id = $1 "
2257 "AND dhcp_identifier_type = $2 "
2258 "AND dhcp_identifier = $3"
2270 : conn_(parameters, io_service_accessor, db_reconnect_callback),
2271 is_readonly_(true) {
2283 lock_guard<mutex> lock(mgr_.
pool_->mutex_);
2284 if (!mgr_.
pool_->pool_.empty()) {
2286 mgr_.
pool_->pool_.pop_back();
2294 if (mgr_.
pool_->pool_.empty()) {
2304 lock_guard<mutex> lock(mgr_.pool_->mutex_);
2305 mgr_.pool_->pool_.push_back(ctx_);
2306 if (ctx_->conn_.isUnusable()) {
2307 mgr_.unusable_ =
true;
2309 }
else if (ctx_->conn_.isUnusable()) {
2310 mgr_.unusable_ =
true;
2315 : parameters_(parameters), ip_reservations_unique_(true), unusable_(false) {
2319 tls += parameters.count(
"trust-anchor");
2320 tls += parameters.count(
"cert-file");
2321 tls += parameters.count(
"key-file");
2322 tls += parameters.count(
"cipher-list");
2323#ifdef HAVE_PGSQL_SSL
2335 <<
"backend (built with this feature disabled)");
2341 timer_name_ += boost::lexical_cast<std::string>(
reinterpret_cast<uint64_t
>(
this));
2362 ctx->conn_.openDatabase();
2365 ctx->conn_.prepareStatements(tagged_statements.begin(),
2370 ctx->is_readonly_ = ctx->conn_.configuredReadOnly();
2374 if (!ctx->is_readonly_) {
2376 tagged_statements.end());
2381 ctx->host_ipv4_exchange_.reset(
new PgSqlHostWithOptionsExchange(PgSqlHostWithOptionsExchange::DHCP4_ONLY));
2382 ctx->host_ipv6_exchange_.reset(
new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP6_ONLY));
2383 ctx->host_ipv46_exchange_.reset(
new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP4_AND_DHCP6));
2384 ctx->host_ipv6_reservation_exchange_.reset(
new PgSqlIPv6ReservationExchange());
2385 ctx->host_option_exchange_.reset(
new PgSqlOptionExchange());
2405 bool reopened =
false;
2407 const std::string timer_name = db_reconnect_ctl->timerName();
2412 std::list<std::string> host_db_access_list = cfg_db->getHostDbAccessStringList();
2413 for (std::string& hds : host_db_access_list) {
2420 }
catch (
const std::exception& ex) {
2436 if (!db_reconnect_ctl->checkRetries()) {
2439 .arg(db_reconnect_ctl->maxRetries());
2452 .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
2453 .arg(db_reconnect_ctl->maxRetries())
2454 .arg(db_reconnect_ctl->retryInterval());
2460 db_reconnect_ctl->retryInterval(),
2473 const bool return_last_id) {
2474 uint64_t last_id = 0;
2475 PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2476 tagged_statements[stindex].nbparams,
2477 &bind_array->values_[0],
2478 &bind_array->lengths_[0],
2479 &bind_array->formats_[0], 0));
2481 int s = PQresultStatus(r);
2483 if (s != PGRES_COMMAND_OK) {
2491 ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2495 char* rows_affected = PQcmdTuples(r);
2496 if (!rows_affected) {
2498 "Could not retrieve the number of affected rows.");
2506 if (rows_affected[0] ==
'0') {
2510 if (return_last_id) {
2521 PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2522 tagged_statements[stindex].nbparams,
2523 &bind_array->values_[0],
2524 &bind_array->lengths_[0],
2525 &bind_array->formats_[0], 0));
2527 int s = PQresultStatus(r);
2529 if (s != PGRES_COMMAND_OK) {
2532 ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2537 char* rows_deleted = PQcmdTuples(r);
2538 if (!rows_deleted) {
2540 "Could not retrieve the number of deleted rows.");
2542 return (rows_deleted[0] !=
'0');
2561 const std::string& opt_space,
2562 const Optional<SubnetID>&,
2564 PsqlBindArrayPtr bind_array = ctx->host_option_exchange_->createBindForSend(opt_desc, opt_space,
id);
2573 const uint64_t host_id) {
2576 std::list<std::string> option_spaces = options_cfg->getOptionSpaceNames();
2577 std::list<std::string> vendor_spaces = options_cfg->getVendorIdsSpaceNames();
2578 option_spaces.insert(option_spaces.end(), vendor_spaces.begin(),
2579 vendor_spaces.end());
2583 for (
auto const& space : option_spaces) {
2585 if (options && !options->empty()) {
2586 for (
auto const& opt : *options) {
2587 addOption(ctx, stindex, opt, space, Optional<SubnetID>(), host_id);
2597 boost::shared_ptr<PgSqlHostExchange> exchange,
2599 bool single)
const {
2602 PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2603 tagged_statements[stindex].nbparams,
2604 &bind_array->values_[0],
2605 &bind_array->lengths_[0],
2606 &bind_array->formats_[0], 0));
2608 ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2610 int rows = r.getRows();
2611 for (
int row = 0; row < rows; ++row) {
2612 exchange->processRowData(result, r, row);
2614 if (single && result.size() > 1) {
2616 "database where only one was expected for query "
2617 << tagged_statements[stindex].name);
2626 const uint8_t* identifier_begin,
2627 const size_t identifier_len,
2629 boost::shared_ptr<PgSqlHostExchange> exchange)
const {
2635 bind_array->add(subnet_id);
2638 bind_array->add(
static_cast<uint8_t
>(identifier_type));
2641 bind_array->add(identifier_begin, identifier_len);
2648 if (!collection.empty()) {
2649 result = *collection.begin();
2655std::pair<uint32_t, uint32_t>
2667 if (ctx->is_readonly_) {
2669 " to operate in read only mode");
2684 return (impl_->parameters_);
2694 impl_->checkReadOnly(ctx);
2706 bool unique_ip = impl_->ip_reservations_unique_ && !host->getIPv4Reservation().isV4Zero()
2707 && host->getIPv4SubnetID() != SUBNET_ID_UNUSED;
2710 PsqlBindArrayPtr bind_array = ctx->host_ipv4_exchange_->createBindForSend(host, unique_ip);
2713 uint32_t host_id = impl_->addStatement(ctx,
2722 cfg_option4, host_id);
2729 cfg_option6, host_id);
2734 if (std::distance(v6resv.first, v6resv.second) > 0) {
2735 BOOST_FOREACH(
auto const& resv, v6resv) {
2736 impl_->addResv(ctx, resv.second, host_id);
2741 transaction.commit();
2752 impl_->checkReadOnly(ctx);
2755 bind_array->add(subnet_id);
2759 bind_array->add(addr);
2765 bind_array->addTempString(addr.
toText());
2774 const uint8_t* identifier_begin,
2775 const size_t identifier_len) {
2781 impl_->checkReadOnly(ctx);
2786 bind_array->add(subnet_id);
2789 bind_array->add(
static_cast<uint8_t
>(identifier_type));
2792 bind_array->add(identifier_begin, identifier_len);
2801 const uint8_t* identifier_begin,
2802 const size_t identifier_len) {
2808 impl_->checkReadOnly(ctx);
2813 bind_array->add(subnet_id);
2816 bind_array->add(
static_cast<uint8_t
>(identifier_type));
2819 bind_array->add(identifier_begin, identifier_len);
2827 const uint8_t* identifier_begin,
2828 const size_t identifier_len)
const {
2837 bind_array->add(identifier_begin, identifier_len);
2840 bind_array->add(
static_cast<uint8_t
>(identifier_type));
2844 bind_array, ctx->host_ipv46_exchange_, result,
false);
2859 bind_array->add(subnet_id);
2863 bind_array, ctx->host_ipv4_exchange_, result,
false);
2878 bind_array->add(subnet_id);
2882 bind_array, ctx->host_ipv6_exchange_, result,
false);
2897 bind_array->add(hostname);
2901 bind_array, ctx->host_ipv46_exchange_, result,
false);
2917 bind_array->add(hostname);
2920 bind_array->add(subnet_id);
2924 bind_array, ctx->host_ipv4_exchange_, result,
false);
2940 bind_array->add(hostname);
2943 bind_array->add(subnet_id);
2947 bind_array, ctx->host_ipv6_exchange_, result,
false);
2955 uint64_t lower_host_id,
2965 bind_array->add(subnet_id);
2968 bind_array->add(lower_host_id);
2971 string page_size_data =
2972 boost::lexical_cast<std::string>(page_size.page_size_);
2973 bind_array->add(page_size_data);
2977 bind_array, ctx->host_ipv4_exchange_, result,
false);
2985 uint64_t lower_host_id,
2995 bind_array->add(subnet_id);
2998 bind_array->add(lower_host_id);
3001 string page_size_data =
3002 boost::lexical_cast<std::string>(page_size.page_size_);
3003 bind_array->add(page_size_data);
3007 bind_array, ctx->host_ipv6_exchange_, result,
false);
3014 uint64_t lower_host_id,
3024 bind_array->add(lower_host_id);
3027 string page_size_data =
3028 boost::lexical_cast<std::string>(page_size.page_size_);
3029 bind_array->add(page_size_data);
3033 bind_array, ctx->host_ipv4_exchange_, result,
false);
3040 uint64_t lower_host_id,
3050 bind_array->add(lower_host_id);
3053 string page_size_data =
3054 boost::lexical_cast<std::string>(page_size.page_size_);
3055 bind_array->add(page_size_data);
3059 bind_array, ctx->host_ipv6_exchange_, result,
false);
3074 bind_array->add(address);
3078 bind_array, ctx->host_ipv4_exchange_, result,
false);
3086 const uint8_t* identifier_begin,
3087 const size_t identifier_len)
const {
3092 return (impl_->getHost(ctx, subnet_id, identifier_type, identifier_begin, identifier_len,
3094 ctx->host_ipv4_exchange_));
3104 if (!address.isV4()) {
3106 " wrong address type, address supplied is an IPv6 address");
3113 bind_array->add(subnet_id);
3116 bind_array->add(address);
3120 bind_array, ctx->host_ipv4_exchange_, collection,
true);
3124 if (!collection.empty()) {
3125 result = *collection.begin();
3138 if (!address.isV4()) {
3140 " wrong address type, address supplied is an IPv6 address");
3147 bind_array->add(subnet_id);
3150 bind_array->add(address);
3154 bind_array, ctx->host_ipv4_exchange_, collection,
false);
3155 return (collection);
3161 const uint8_t* identifier_begin,
3162 const size_t identifier_len)
const {
3167 return (impl_->getHost(ctx, subnet_id, identifier_type, identifier_begin, identifier_len,
3169 ctx->host_ipv6_exchange_));
3174 const uint8_t prefix_len)
const {
3175 if (!prefix.isV6()) {
3177 "wrong address type, address supplied is an IPv4 address");
3188 bind_array->add(prefix);
3191 bind_array->add(prefix_len);
3195 bind_array, ctx->host_ipv6_exchange_, collection,
true);
3199 if (!collection.empty()) {
3200 result = *collection.begin();
3209 if (!address.isV6()) {
3211 "wrong address type, address supplied is an IPv4 address");
3222 bind_array->add(subnet_id);
3225 bind_array->add(address);
3229 bind_array, ctx->host_ipv6_exchange_, collection,
true);
3233 if (!collection.empty()) {
3234 result = *collection.begin();
3243 if (!address.isV6()) {
3245 "wrong address type, address supplied is an IPv4 address");
3256 bind_array->add(subnet_id);
3259 bind_array->add(address);
3263 bind_array, ctx->host_ipv6_exchange_, collection,
false);
3264 return (collection);
3269 if (!address.isV6()) {
3271 "wrong address type, address supplied is an IPv4 address");
3282 bind_array->add(address);
3286 bind_array, ctx->host_ipv6_exchange_, collection,
false);
3287 return (collection);
3297 impl_->checkReadOnly(ctx);
3313 transaction.commit();
3320 std::string name =
"";
3326 name = ctx->conn_.getParameter(
"name");
3335 return (std::string(
"Host data source that stores host information"
3336 "in PostgreSQL database"));
3339std::pair<uint32_t, uint32_t>
3341 return(impl_->getVersion(timer_name));
3351 impl_->checkReadOnly(ctx);
3352 ctx->conn_.commit();
3362 impl_->checkReadOnly(ctx);
3363 ctx->conn_.rollback();
3368 impl_->ip_reservations_unique_ = unique;
3374 return (impl_->unusable_);
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.
The IOAddress class represents an IP addresses (version agnostic)
std::string toText() const
Convert the address to a string.
bool isV4() const
Convenience function to check for an IPv4 address.
static ElementPtr fromJSON(const std::string &in, bool preproc=false)
These functions will parse the given string (JSON) representation of a compound element.
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
static bool invokeDbLostCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's lost connectivity callback.
static std::string redactedAccessString(const ParameterMap ¶meters)
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 ¶meters, 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 ¶meters, const IOServiceAccessorPtr &ac=IOServiceAccessorPtr(), const DbCallback &cb=DbCallback(), const std::string &timer_name=std::string())
Get the schema version.
Base class for marshalling data to and from PostgreSQL.
static void convertFromBytea(const PgSqlResult &r, const int row, const size_t col, uint8_t *buffer, const size_t buffer_size, size_t &bytes_converted)
Converts a column in a row in a result set to a binary bytes.
static bool isColumnNull(const PgSqlResult &r, const int row, const size_t col)
Returns true if a column within a row is null.
static void getColumnValue(const PgSqlResult &r, const int row, const size_t col, std::string &value)
Fetches text column value as a string.
RAII wrapper for PostgreSQL Result sets.
RAII object representing a PostgreSQL transaction.
Attempt to modify data in read-only database.
virtual void update(HostPtr const &host)
Attempts to update an existing host entry.
static CfgMgr & instance()
returns a single instance of Configuration Manager
static constexpr size_t MAX_CLIENT_ID_LEN
Maximum size of a client ID.
static bool delBackend(const std::string &db_type)
Delete an alternate host backend (aka host data source).
static void addBackend(const std::string &access)
Add an alternate host backend (aka host data source).
Wraps value holding size of the page with host reservations.
Represents a device with IPv4 and/or IPv6 reservations.
IdentifierType
Type of the host identifier.
static const IdentifierType LAST_IDENTIFIER_TYPE
Constant pointing to the last identifier of the IdentifierType enumeration.
IPv6 reservation for a host.
Type
Type of the reservation.
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
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.
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.
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
Universe
defines option universe DHCPv4 or DHCPv6
PostgreSQL Host Context Pool.
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 ¶meters, 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.
StatementIndex
Statement Tags.
@ GET_HOST_HOSTNAME_SUBID6
@ INSERT_HOST_NON_UNIQUE_IP
@ INSERT_V6_RESRV_NON_UNIQUE
@ GET_HOST_HOSTNAME_SUBID4
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.
~PgSqlHostDataSourceImpl()
Destructor.
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 ¶meters)
Constructor.
bool unusable_
Indicates if there is at least one connection that can no longer be used for normal operations.
PgSqlHostContextPtr ctx_
The context.
~PgSqlHostContextAlloc()
Destructor.
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 ¶meters)
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.
RAII class creating a critical section.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
#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.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
A wrapper interface for the ASIO library.
boost::shared_ptr< const Element > ConstElementPtr
boost::shared_ptr< IOServiceAccessor > IOServiceAccessorPtr
Pointer to an instance of IOServiceAccessor.
boost::shared_ptr< PsqlBindArray > PsqlBindArrayPtr
Defines a smart pointer to PsqlBindArray.
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.
boost::shared_ptr< PgSqlHostContext > PgSqlHostContextPtr
Type of pointers to contexts.
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
boost::shared_ptr< Option6PDExclude > Option6PDExcludePtr
Pointer to the Option6PDExclude object.
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
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
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
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.
uint64_t HostID
HostID (used only when storing in MySQL or PostgreSQL backends)
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB_RECONNECT_ATTEMPT_SCHEDULE
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB_RECONNECT_FAILED
const size_t OPTION_VALUE_MAX_LEN
Maximum length of option value.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
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
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
Defines the logger used by the top-level component of kea-lfc.
#define DHCP4_OPTION_SPACE
global std option spaces
#define DHCP6_OPTION_SPACE
static const int BINARY_FMT
Format value for binary data.