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>
42const size_t OPTION_VALUE_MAX_LEN = 4096;
51const size_t DHCP_IDENTIFIER_MAX_LEN = 128;
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;
111 PgSqlHostExchange(
const size_t additional_columns_num = 0)
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";
132 BOOST_STATIC_ASSERT(12 < HOST_COLUMNS);
136 virtual ~PgSqlHostExchange() {
144 virtual void clear() {
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));
192 createBindForSend(
const HostPtr& host) {
206 bind_array->add(host->getIdentifier());
209 bind_array->add(host->getIdentifierType());
212 if (host->getIPv4SubnetID() == SUBNET_ID_UNUSED) {
213 bind_array->addNull();
216 bind_array->add(host->getIPv4SubnetID());
220 if (host->getIPv6SubnetID() == SUBNET_ID_UNUSED) {
221 bind_array->addNull();
224 bind_array->add(host->getIPv6SubnetID());
228 bind_array->add((host->getIPv4Reservation()));
231 bind_array->add(host->getHostname());
235 bind_array->addTempString(host->getClientClasses4().toText(
","));
238 bind_array->addTempString(host->getClientClasses6().toText(
","));
243 std::string user_context_ = ctx->str();
244 bind_array->addTempString(user_context_);
246 bind_array->addNull();
250 bind_array->add((host->getNextServer()));
253 bind_array->add(host->getServerHostname());
256 bind_array->add(host->getBootFileName());
259 std::string key = host->getKey().ToText();
261 bind_array->addNull();
263 bind_array->add(key);
266 }
catch (
const std::exception& ex) {
269 "Could not create bind array from Host: "
270 << host->getHostname() <<
", reason: " << ex.
what());
294 HostID row_host_id = getHostId(r, row);
299 if (hosts.empty() || row_host_id != hosts.back()->getHostId()) {
300 HostPtr host = retrieveHost(r, row, row_host_id);
301 hosts.push_back(host);
316 const HostID& peeked_host_id = 0) {
320 HostID host_id = (peeked_host_id ? peeked_host_id : getHostId(r,row));
323 uint8_t identifier_value[DHCP_IDENTIFIER_MAX_LEN];
324 size_t identifier_len;
326 sizeof(identifier_value), identifier_len);
331 if (type > MAX_IDENTIFIER_TYPE) {
333 <<
static_cast<int>(type));
340 uint32_t subnet_id(SUBNET_ID_UNUSED);
347 subnet_id = SUBNET_ID_UNUSED;
361 std::string hostname;
367 std::string dhcp4_client_classes;
369 getColumnValue(r, row, DHCP4_CLIENT_CLASSES_COL, dhcp4_client_classes);
373 std::string dhcp6_client_classes;
375 getColumnValue(r, row, DHCP6_CLIENT_CLASSES_COL, dhcp6_client_classes);
379 std::string user_context;
385 uint32_t dhcp4_next_server_as_uint32(0);
387 getColumnValue(r, row, DHCP4_NEXT_SERVER_COL, dhcp4_next_server_as_uint32);
392 std::string dhcp4_server_hostname;
394 getColumnValue(r, row, DHCP4_SERVER_HOSTNAME_COL, dhcp4_server_hostname);
398 std::string dhcp4_boot_file_name;
400 getColumnValue(r, row, DHCP4_BOOT_FILE_NAME_COL, dhcp4_boot_file_name);
404 std::string auth_key;
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)));
420 if (!user_context.empty()) {
425 <<
"' is not a JSON map");
427 host->setContext(ctx);
430 <<
"' is invalid JSON: " << ex.
what());
434 host->setHostId(host_id);
457class PgSqlHostWithOptionsExchange :
public PgSqlHostExchange {
461 static const size_t OPTION_COLUMNS = 7;
477 class OptionProcessor {
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) {
503 most_recent_option_id_ = 0;
553 if (most_recent_option_id_ >= option_id) {
559 most_recent_option_id_ = option_id;
566 uint8_t value[OPTION_VALUE_MAX_LEN];
568 if (!isColumnNull(r, row, value_index_)) {
570 sizeof(value), value_len);
574 std::string formatted_value;
575 if (!isColumnNull(r, row, formatted_value_index_)) {
582 if (!isColumnNull(r, row, space_index_)) {
588 space = (universe_ ==
Option::V4 ?
"dhcp4" :
"dhcp6");
597 std::string user_context;
598 if (!isColumnNull(r, row, user_context_index_)) {
636 option.reset(
new Option(universe_, code, buf.begin(),
643 if (formatted_value.empty()) {
645 option = def->optionFactory(universe_, code, buf.begin(),
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);
660 if (!user_context.empty()) {
665 <<
"' is no a JSON map");
667 desc.setContext(ctx);
670 <<
"' is invalid JSON: " << ex.
what());
674 cfg->add(desc, space);
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";
696 size_t start_column_;
703 size_t option_id_index_;
712 size_t formatted_value_index_;
718 size_t persistent_index_;
722 size_t user_context_index_;
725 uint64_t most_recent_option_id_;
729 typedef boost::shared_ptr<OptionProcessor> OptionProcessorPtr;
739 enum FetchedOptions {
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_() {
760 if ((fetched_options == DHCP4_ONLY) ||
761 (fetched_options == DHCP4_AND_DHCP6)) {
762 opt_proc4_.reset(
new OptionProcessor(
Option::V4,
764 opt_proc4_->setColumnNames(columns_);
768 if ((fetched_options == DHCP6_ONLY) ||
769 (fetched_options == DHCP4_AND_DHCP6)) {
770 opt_proc6_.reset(
new OptionProcessor(
Option::V6,
772 opt_proc6_->setColumnNames(columns_);
781 virtual void clear() {
782 PgSqlHostExchange::clear();
806 current_host = retrieveHost(r, row);
807 hosts.push_back(current_host);
812 HostID row_host_id = getHostId(r, row);
813 current_host = boost::const_pointer_cast<Host>(hosts.back());
817 if (row_host_id > current_host->getHostId()) {
818 current_host = retrieveHost(r, row, row_host_id);
819 hosts.push_back(current_host);
826 opt_proc4_->retrieveOption(cfg, r, row);
832 opt_proc6_->retrieveOption(cfg, r, row);
849 static size_t getRequiredColumnsNum(
const FetchedOptions& fetched_options) {
850 return (fetched_options == DHCP4_AND_DHCP6 ? 2 * OPTION_COLUMNS :
857 OptionProcessorPtr opt_proc4_;
862 OptionProcessorPtr opt_proc6_;
877class PgSqlHostIPv6Exchange :
public PgSqlHostWithOptionsExchange {
881 static const size_t RESERVATION_COLUMNS = 5;
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) {
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";
905 BOOST_STATIC_ASSERT(4 < RESERVATION_COLUMNS);
914 PgSqlHostWithOptionsExchange::clear();
915 most_recent_reservation_id_ = 0;
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);
938 getColumnValue(r, row, type_index_, tmp);
953 "invalid IPv6 reservation type returned: "
954 << tmp <<
". Only 0 or 2 are allowed.");
962 getColumnValue(r, row, prefix_len_index_, prefix_len);
971 return (reservation);
998 PgSqlHostWithOptionsExchange::processRowData(hosts, r, row);
1001 if (hosts.empty()) {
1003 " IPv6 reservation");
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;
1020 size_t reservation_id_index_;
1023 size_t address_index_;
1026 size_t prefix_len_index_;
1037 uint64_t most_recent_reservation_id_;
1054 static const size_t RESRV_COLUMNS = 6;
1061 PgSqlIPv6ReservationExchange()
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);
1104 bind_array->add(type);
1108 bind_array->addNull();
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());
1118 return (bind_array);
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;
1145 static const size_t OPTION_COLUMNS = 11;
1150 PgSqlOptionExchange()
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";
1165 BOOST_STATIC_ASSERT(10 < OPTION_COLUMNS);
1178 const std::string& opt_space,
1191 bind_array->add(option_->getType());
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_);
1216 bind_array->addNull();
1220 if (!opt_space.empty()) {
1221 bind_array->addTempString(opt_space);
1223 bind_array->addNull();
1232 std::string user_context_ = ctx->str();
1233 bind_array->addTempString(user_context_);
1235 bind_array->addNull();
1242 bind_array->add(host_id);
1244 }
catch (
const std::exception& ex) {
1246 "Could not create bind array for inserting DHCP "
1247 "host option: " << option_->toText() <<
", reason: "
1251 return (bind_array);
1257 std::vector<uint8_t> value_;
1332 const bool return_last_id =
false);
1358 const std::string& opt_space,
1371 const uint64_t host_id);
1391 boost::shared_ptr<PgSqlHostExchange> exchange,
1412 const uint8_t* identifier_begin,
1413 const size_t identifier_len,
1415 boost::shared_ptr<PgSqlHostExchange> exchange)
const;
1434 std::pair<uint32_t, uint32_t>
getVersion()
const;
1468typedef boost::array<PgSqlTaggedStatement, PgSqlHostDataSourceImpl::NUM_STATEMENTS>
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, "
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 "
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"
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 "
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"
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 "
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"
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 "
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"
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 "
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"
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, "
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"
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, "
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"
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) "
1662 "INSERT INTO ipv6_reservations(address, prefix_len, type, "
1663 " dhcp6_iaid, host_id) "
1664 "VALUES ($1, $2, $3, $4, $5)"
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)"
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)"
1696 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 AND ipv4_address = $2"
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"
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"
1725 : host_exchange_(new PgSqlHostWithOptionsExchange(PgSqlHostWithOptionsExchange::DHCP4_ONLY)),
1726 host_ipv6_exchange_(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP6_ONLY)),
1727 host_ipv46_exchange_(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::
1729 host_ipv6_reservation_exchange_(new PgSqlIPv6ReservationExchange()),
1730 host_option_exchange_(new PgSqlOptionExchange()),
1732 is_readonly_(false) {
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);
1774 const bool return_last_id) {
1775 uint64_t last_id = 0;
1778 &bind_array->values_[0],
1779 &bind_array->lengths_[0],
1780 &bind_array->formats_[0], 0));
1782 int s = PQresultStatus(r);
1784 if (s != PGRES_COMMAND_OK) {
1795 if (return_last_id) {
1807 &bind_array->values_[0],
1808 &bind_array->lengths_[0],
1809 &bind_array->formats_[0], 0));
1811 int s = PQresultStatus(r);
1813 if (s != PGRES_COMMAND_OK) {
1821 char* rows_deleted = PQcmdTuples(r);
1822 if (!rows_deleted) {
1824 "Could not retrieve the number of deleted rows.");
1826 return (rows_deleted[0] !=
'0');
1840 const std::string& opt_space,
1852 const uint64_t host_id) {
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());
1862 for (std::list<std::string>::const_iterator space = option_spaces.begin();
1863 space != option_spaces.end(); ++space) {
1865 if (options && !options->empty()) {
1866 for (OptionContainer::const_iterator opt = options->begin();
1867 opt != options->end(); ++opt) {
1878 boost::shared_ptr<PgSqlHostExchange> exchange,
1884 &bind_array->values_[0],
1885 &bind_array->lengths_[0],
1886 &bind_array->formats_[0], 0));
1891 for(
int row = 0; row < rows; ++row) {
1892 exchange->processRowData(result, r, row);
1894 if (single && result.size() > 1) {
1896 "database where only one was expected for query "
1906 const uint8_t* identifier_begin,
1907 const size_t identifier_len,
1909 boost::shared_ptr<PgSqlHostExchange> exchange)
const {
1915 bind_array->add(subnet_id);
1918 bind_array->add(
static_cast<uint8_t
>(identifier_type));
1921 bind_array->add(identifier_begin, identifier_len);
1928 if (!collection.empty())
1929 result = *collection.begin();
1936 DHCPSRV_PGSQL_HOST_DB_GET_VERSION);
1937 const char* version_sql =
"SELECT version, minor FROM schema_version;";
1939 if(PQresultStatus(r) != PGRES_TUPLES_OK) {
1941 << version_sql <<
">, reason: " << PQerrorMessage(
conn_));
1950 return (std::make_pair(
version, minor));
1957 " to operate in read only mode");
1994 cfg_option4, host_id);
2001 cfg_option6, host_id);
2006 if (std::distance(v6resv.first, v6resv.second) > 0) {
2009 impl_->
addResv(resv->second, host_id);
2024 bind_array->add(subnet_id);
2025 bind_array->add(addr);
2035 return del6(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0],
2036 host->getIdentifier().size());
2042 const uint8_t* identifier_begin,
2043 const size_t identifier_len) {
2048 bind_array->add(subnet_id);
2051 bind_array->add(
static_cast<uint8_t
>(identifier_type));
2054 bind_array->add(identifier_begin, identifier_len);
2063 const uint8_t* identifier_begin,
2064 const size_t identifier_len) {
2068 bind_array->add(subnet_id);
2071 bind_array->add(
static_cast<uint8_t
>(identifier_type));
2074 bind_array->add(identifier_begin, identifier_len);
2082 const uint8_t* identifier_begin,
2083 const size_t identifier_len)
const {
2088 bind_array->add(identifier_begin, identifier_len);
2091 bind_array->add(
static_cast<uint8_t
>(identifier_type));
2107 bind_array->add(address);
2119 const uint8_t* identifier_begin,
2120 const size_t identifier_len)
const {
2122 return (impl_->
getHost(subnet_id, identifier_type, identifier_begin,
2131 if (!address.
isV4()) {
2133 " wrong address type, address supplied is an IPv6 address");
2140 bind_array->add(subnet_id);
2143 bind_array->add(address);
2152 if (!collection.empty())
2153 result = *collection.begin();
2161 const uint8_t* identifier_begin,
2162 const size_t identifier_len)
const {
2164 return (impl_->
getHost(subnet_id, identifier_type, identifier_begin,
2171 const uint8_t prefix_len)
const {
2178 bind_array->add(prefix);
2181 bind_array->add(prefix_len);
2190 if (!collection.empty()) {
2191 result = *collection.begin();
2206 bind_array->add(subnet_id);
2209 bind_array->add(address);
2218 if (!collection.empty()) {
2219 result = *collection.begin();
2228 std::string name =
"";
2238 return (std::string(
"Host data source that stores host information"
2239 "in PostgreSQL database"));
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)
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 ...
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.
Multiple lease records found where one expected.
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.
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.
const asiolink::IOAddress & getPrefix() const
Returns prefix for the reservation.
Type getType() const
Returns reservation type.
Type
Type of the reservation.
uint8_t getPrefixLen() const
Returns prefix length.
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.
OptionPtr option_
Option instance.
std::string formatted_value_
Option value in textual (CSV) format.
bool persistent_
Persistence flag.
Universe
defines option universe DHCPv4 or DHCPv6
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.
StatementIndex
Statement Tags.
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.
~PgSqlHostDataSourceImpl()
Destructor.
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 ¶meters)
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 ¶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.
Simple class representing an optional value.
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.
int version()
returns Kea hooks version.
#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
const uint32_t PG_SCHEMA_VERSION_MAJOR
Define PostgreSQL backend version: 5.0.
const uint32_t PG_SCHEMA_VERSION_MINOR
boost::shared_ptr< PsqlBindArray > PsqlBindArrayPtr
Defines a smart pointer to PsqlBindArray.
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
IPv6ResrvCollection::const_iterator IPv6ResrvIterator
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
TaggedStatementArray tagged_statements
Prepared MySQL statements used by the backend to insert and retrieve hosts from the database.
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
boost::array< TaggedStatement, MySqlHostDataSourceImpl::NUM_STATEMENTS > TaggedStatementArray
Array of tagged statements.
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
uint64_t HostID
HostID (used only when storing in MySQL, PostgreSQL or Cassandra)
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
boost::shared_ptr< Option > OptionPtr
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
Defines the logger used by the top-level component of kea-dhcp-ddns.
#define DHCP4_OPTION_SPACE
#define DHCP6_OPTION_SPACE
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
static const int BINARY_FMT
Format value for binary data.