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>
42 const size_t OPTION_VALUE_MAX_LEN = 4096;
48 const uint8_t MAX_IDENTIFIER_TYPE =
static_cast<uint8_t
>(Host::LAST_IDENTIFIER_TYPE);
51 const 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));
174 getColumnValue(r, row, HOST_ID_COL, host_id);
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;
325 convertFromBytea(r, row, DHCP_IDENTIFIER_COL, identifier_value,
326 sizeof(identifier_value), identifier_len);
330 getColumnValue(r, row, DHCP_IDENTIFIER_TYPE_COL, type);
331 if (type > MAX_IDENTIFIER_TYPE) {
333 <<
static_cast<int>(type));
340 uint32_t subnet_id(SUBNET_ID_UNUSED);
341 if (!isColumnNull(r, row, DHCP4_SUBNET_ID_COL)) {
342 getColumnValue(r, row, DHCP4_SUBNET_ID_COL, subnet_id);
347 subnet_id = SUBNET_ID_UNUSED;
348 if (!isColumnNull(r, row, DHCP6_SUBNET_ID_COL)) {
349 getColumnValue(r, row, DHCP6_SUBNET_ID_COL, subnet_id);
355 if (!isColumnNull(r, row, IPV4_ADDRESS_COL)) {
356 getColumnValue(r, row, IPV4_ADDRESS_COL, addr4);
361 std::string hostname;
362 if (!isColumnNull(r, row, HOSTNAME_COL)) {
363 getColumnValue(r, row, HOSTNAME_COL, hostname);
367 std::string dhcp4_client_classes;
368 if (!isColumnNull(r, row, DHCP4_CLIENT_CLASSES_COL)) {
369 getColumnValue(r, row, DHCP4_CLIENT_CLASSES_COL, dhcp4_client_classes);
373 std::string dhcp6_client_classes;
374 if (!isColumnNull(r, row, DHCP6_CLIENT_CLASSES_COL)) {
375 getColumnValue(r, row, DHCP6_CLIENT_CLASSES_COL, dhcp6_client_classes);
379 std::string user_context;
380 if (!isColumnNull(r, row, USER_CONTEXT_COL)) {
381 getColumnValue(r, row, USER_CONTEXT_COL, user_context);
385 uint32_t dhcp4_next_server_as_uint32(0);
386 if (!isColumnNull(r, row, DHCP4_NEXT_SERVER_COL)) {
387 getColumnValue(r, row, DHCP4_NEXT_SERVER_COL, dhcp4_next_server_as_uint32);
392 std::string dhcp4_server_hostname;
393 if (!isColumnNull(r, row, DHCP4_SERVER_HOSTNAME_COL)) {
394 getColumnValue(r, row, DHCP4_SERVER_HOSTNAME_COL, dhcp4_server_hostname);
398 std::string dhcp4_boot_file_name;
399 if (!isColumnNull(r, row, DHCP4_BOOT_FILE_NAME_COL)) {
400 getColumnValue(r, row, DHCP4_BOOT_FILE_NAME_COL, dhcp4_boot_file_name);
404 std::string auth_key;
405 if (!isColumnNull(r, row, AUTH_KEY_COL)) {
406 getColumnValue(r, row, AUTH_KEY_COL, 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()) {
423 if (!ctx || (ctx->getType() != Element::map)) {
425 <<
"' is not a JSON map");
427 host->setContext(ctx);
430 <<
"' is invalid JSON: " << ex.
what());
434 host->setHostId(host_id);
457 class 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;
542 if (PgSqlExchange::isColumnNull(r, row, option_id_index_)) {
548 PgSqlExchange::getColumnValue(r, row, option_id_index_, option_id);
553 if (most_recent_option_id_ >= option_id) {
559 most_recent_option_id_ = option_id;
563 PgSqlExchange::getColumnValue(r, row, code_index_, code);
566 uint8_t value[OPTION_VALUE_MAX_LEN];
568 if (!isColumnNull(r, row, value_index_)) {
569 PgSqlExchange::convertFromBytea(r, row, value_index_, value,
570 sizeof(value), value_len);
574 std::string formatted_value;
575 if (!isColumnNull(r, row, formatted_value_index_)) {
576 PgSqlExchange::getColumnValue(r, row, formatted_value_index_,
582 if (!isColumnNull(r, row, space_index_)) {
583 PgSqlExchange::getColumnValue(r, row, space_index_, space);
588 space = (universe_ == Option::V4 ?
"dhcp4" :
"dhcp6");
593 PgSqlExchange::getColumnValue(r, row, persistent_index_,
597 std::string user_context;
598 if (!isColumnNull(r, row, user_context_index_)) {
599 PgSqlExchange::getColumnValue(r, row, user_context_index_,
618 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(space);
620 def = LibDHCP::getVendorOptionDef(universe_, vendor_id,
628 def = LibDHCP::getRuntimeOptionDef(space, code);
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()) {
663 if (!ctx || (ctx->getType() != Element::map)) {
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_;
702 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_;
877 class 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);
944 resv_type = IPv6Resrv::TYPE_NA;
948 resv_type = IPv6Resrv::TYPE_PD;
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;
1019 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);
1103 uint16_t type = resv.
getType() == IPv6Resrv::TYPE_NA ? 0 : 2;
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_);
1209 bind_array->addNull(PsqlBindArray::BINARY_FMT);
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;
1424 void checkReadOnly()
const;
1434 std::pair<uint32_t, uint32_t> getVersion()
const;
1468 typedef 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"
1723 PgSqlHostDataSourceImpl::
1724 PgSqlHostDataSourceImpl(
const PgSqlConnection::ParameterMap& parameters)
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) {
1796 PgSqlExchange::getColumnValue(r, 0, 0, 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_));
1945 PgSqlExchange::getColumnValue(r, 0, 0,
version);
1948 PgSqlExchange::getColumnValue(r, 0, 1, minor);
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"));