From: Thomas Markwalder Date: Fri, 24 Jun 2016 15:56:07 +0000 (-0400) Subject: [4277] IPv6 Reservations now functional X-Git-Tag: trac4551_base~12^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8f21305bd3e96bafe9b4f84813a12adc4309119f;p=thirdparty%2Fkea.git [4277] IPv6 Reservations now functional src/lib/dhcpsrv/pgsql_exchange.h src/lib/dhcpsrv/pgsql_exchange.cc src/lib/dhcpsrv/pgsql_lease_mgr.cc Moved getIPv6Value() from PgSqlLease6Exchange to PgSqlExchange and made it static PgSqlExchange::dumpRow() gets number of columns from result set, not parameter src/lib/dhcpsrv/pgsql_host_data_source.cc PgSqlIPv6ReservationExchange PgSqlHostIPv6Exchange - now functional src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc TEST_F(PgSqlHostDataSourceTest, get6AddrWithDuid) TEST_F(PgSqlHostDataSourceTest, addDuplicate6WithHWAddr) TEST_F(PgSqlHostDataSourceTest, optionsReservations6) TEST_F(PgSqlHostDataSourceTest, optionsReservations46) TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations6) TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations46) - All included and passing. --- diff --git a/src/lib/dhcpsrv/pgsql_exchange.cc b/src/lib/dhcpsrv/pgsql_exchange.cc index a33878df03..286f35e1a5 100644 --- a/src/lib/dhcpsrv/pgsql_exchange.cc +++ b/src/lib/dhcpsrv/pgsql_exchange.cc @@ -196,6 +196,19 @@ PgSqlExchange::getColumnValue(const PgSqlResult& r, const int row, } } +isc::asiolink::IOAddress +PgSqlExchange::getIPv6Value(const PgSqlResult& r, const int row, + const size_t col) { + const char* data = getRawColumnValue(r, row, col); + try { + return (isc::asiolink::IOAddress(data)); + } catch (const std::exception& ex) { + isc_throw(DbOperationError, "Cannot convert data: " << data + << " for: " << getColumnLabel(r, col) << " row:" << row + << " : " << ex.what()); + } +} + void PgSqlExchange::convertFromBytea(const PgSqlResult& r, const int row, const size_t col, uint8_t* buffer, @@ -254,8 +267,9 @@ PgSqlExchange::getColumnLabel(const PgSqlResult& r, const size_t column) { } std::string -PgSqlExchange::dumpRow(const PgSqlResult& r, int row, size_t columns) { +PgSqlExchange::dumpRow(const PgSqlResult& r, int row) { std::ostringstream stream; + int columns = PQnfields(r); for (int col = 0; col < columns; ++col) { const char* val = getRawColumnValue(r, row, col); std::string name = getColumnLabel(r, col); diff --git a/src/lib/dhcpsrv/pgsql_exchange.h b/src/lib/dhcpsrv/pgsql_exchange.h index 339bee639d..8a7e04f335 100644 --- a/src/lib/dhcpsrv/pgsql_exchange.h +++ b/src/lib/dhcpsrv/pgsql_exchange.h @@ -287,6 +287,10 @@ public: static void getColumnValue(const PgSqlResult& r, const int row, const size_t col, uint8_t &value); + static isc::asiolink::IOAddress getIPv6Value(const PgSqlResult& r, + const int row, + const size_t col); + static bool isColumnNull(const PgSqlResult& r, const int row, const size_t col); @@ -337,7 +341,7 @@ public: size_t &bytes_converted); - static std::string dumpRow(const PgSqlResult& r, int row, size_t columns); + static std::string dumpRow(const PgSqlResult& r, int row); protected: /// @brief Stores text labels for columns, currently only used for diff --git a/src/lib/dhcpsrv/pgsql_host_data_source.cc b/src/lib/dhcpsrv/pgsql_host_data_source.cc index 69191505b9..c89a97e83f 100644 --- a/src/lib/dhcpsrv/pgsql_host_data_source.cc +++ b/src/lib/dhcpsrv/pgsql_host_data_source.cc @@ -363,17 +363,6 @@ private: /// @brief Number of columns holding DHCPv4 or DHCPv6 option information. static const size_t OPTION_COLUMNS = 6; - virtual void clear() { - PgSqlHostExchange::clear(); - if (opt_proc4_) { - opt_proc4_->clear(); - } - - if (opt_proc6_) { - opt_proc6_->clear(); - } - } - /// @brief Receives DHCPv4 or DHCPv6 options information from the /// dhcp4_options or dhcp6_options tables respectively. /// @@ -634,6 +623,22 @@ public: } } + /// @brief Reinitializes state information + /// + /// This function should be called in between statement executions. + /// Deriving classes should be to sure to reinitialize any stateful + /// values that control statement result processing. + virtual void clear() { + PgSqlHostExchange::clear(); + if (opt_proc4_) { + opt_proc4_->clear(); + } + + if (opt_proc6_) { + opt_proc6_->clear(); + } + } + /// @brief Processes the current row. /// /// The processed row includes both host information and DHCP option @@ -644,12 +649,6 @@ public: /// @param [out] hosts Container holding parsed hosts and options. virtual void processRowData(ConstHostCollection& hosts, const PgSqlResult& r, int row) { - -#if 0 - std::cout << "row :" << row << std::endl - << dumpRow(r, row, columns_.size()) << std::endl;; -#endif - HostPtr current_host; if (hosts.empty()) { current_host = retrieveHost(r, row); @@ -709,7 +708,6 @@ private: OptionProcessorPtr opt_proc6_; }; -#if 0 /// @brief This class provides mechanisms for sending and retrieving /// host information, DHCPv4 options, DHCPv6 options and IPv6 reservations. /// @@ -736,9 +734,6 @@ public: /// initializes values representing IPv6 reservation information. PgSqlHostIPv6Exchange(const FetchedOptions& fetched_options) : PgSqlHostWithOptionsExchange(fetched_options, RESERVATION_COLUMNS), - reservation_id_(0), - reserv_type_(0), reserv_type_null_(MLM_FALSE), - ipv6_address_buffer_len_(0), prefix_len_(0), iaid_(0), reservation_id_index_(findAvailColumn()), address_index_(reservation_id_index_ + 1), prefix_len_index_(reservation_id_index_ + 2), @@ -746,24 +741,36 @@ public: iaid_index_(reservation_id_index_ + 4), most_recent_reservation_id_(0) { - memset(ipv6_address_buffer_, 0, sizeof(ipv6_address_buffer_)); - // Provide names of additional columns returned by the queries. columns_[reservation_id_index_] = "reservation_id"; columns_[address_index_] = "address"; columns_[prefix_len_index_] = "prefix_len"; columns_[type_index_] = "type"; columns_[iaid_index_] = "dhcp6_iaid"; + + // BOOST_STATIC_ASSERT(5 < RESERVATION_COLUMNS); } - /// @brief Returns last fetched reservation id. + /// @brief Reinitializes state information + /// + /// This function should be called in between statement executions. + /// Deriving classes should be to sure to reinitialize any stateful + /// values that control statement result processing. + void clear() { + PgSqlHostWithOptionsExchange::clear(); + most_recent_reservation_id_ = 0; + } + + /// @brief Returns reservation id from the row. /// /// @return Reservation id or 0 if no reservation data is fetched. - uint64_t getReservationId() const { - if (reserv_type_null_ == MLM_FALSE) { - return (reservation_id_); + uint64_t getReservationId(const PgSqlResult& r, int row) const { + uint64_t resv_id = 0; + if (!isColumnNull(r, row, reservation_id_index_)) { + getColumnValue(r, row, reservation_id_index_, resv_id); } - return (0); + + return (resv_id); }; /// @brief Creates IPv6 reservation from the data contained in the @@ -772,30 +779,34 @@ public: /// Called after the MYSQL_BIND array created by createBindForReceive(). /// /// @return IPv6Resrv object (containing IPv6 address or prefix reservation) - IPv6Resrv retrieveReservation() { + IPv6Resrv retrieveReservation(const PgSqlResult& r, int row) { // Set the IPv6 Reservation type (0 = IA_NA, 2 = IA_PD) - IPv6Resrv::Type type = IPv6Resrv::TYPE_NA; + IPv6Resrv::Type resv_type; + uint16_t tmp; + getColumnValue(r, row, type_index_, tmp); - switch (reserv_type_) { + switch (tmp) { case 0: - type = IPv6Resrv::TYPE_NA; + resv_type = IPv6Resrv::TYPE_NA; break; case 2: - type = IPv6Resrv::TYPE_PD; + resv_type = IPv6Resrv::TYPE_PD; break; default: isc_throw(BadValue, "invalid IPv6 reservation type returned: " - << static_cast(reserv_type_) - << ". Only 0 or 2 are allowed."); + << tmp << ". Only 0 or 2 are allowed."); } - ipv6_address_buffer_[ipv6_address_buffer_len_] = '\0'; - std::string address = ipv6_address_buffer_; - IPv6Resrv r(type, IOAddress(address), prefix_len_); - return (r); + isc::asiolink::IOAddress address(getIPv6Value(r, row, address_index_)); + + uint16_t prefix_len; + getColumnValue(r, row, prefix_len_index_, prefix_len); + + IPv6Resrv reservation(resv_type, IOAddress(address), prefix_len); + return (reservation); }; /// @brief Processes one row of data fetched from a database. @@ -817,12 +828,13 @@ public: /// /// @param [out] hosts Collection of hosts to which a new host created /// from the processed data should be inserted. - virtual void processRowData(ConstHostCollection& hosts) { - + virtual void processRowData(ConstHostCollection& hosts, + const PgSqlResult& r, int row) { // Call parent class to fetch host information and options. - PgSqlHostWithOptionsExchange::processRowData(hosts); + PgSqlHostWithOptionsExchange::processRowData(hosts, r, row); - if (getReservationId() == 0) { + uint64_t reservation_id = getReservationId(r, row); + if (!reservation_id) { return; } @@ -834,92 +846,16 @@ public: // If we're dealing with a new reservation, let's add it to the // host. - if (getReservationId() > most_recent_reservation_id_) { - most_recent_reservation_id_ = getReservationId(); + if (reservation_id > most_recent_reservation_id_) { + most_recent_reservation_id_ = reservation_id; if (most_recent_reservation_id_ > 0) { - host->addReservation(retrieveReservation()); + host->addReservation(retrieveReservation(r, row)); } } } - /// @brief Create BIND array to receive Host data with IPv6 reservations. - /// - /// Creates a MYSQL_BIND array to receive Host data from the database. - /// After data is successfully received, @ref processedFetchedData is - /// called for each returned row to build collection of @ref Host - /// objects with associated IPv6 reservations. - /// - /// @return Vector of MYSQL_BIND objects representing data to be retrieved. - virtual std::vector createBindForReceive() { - // Reset most recent reservation id value because we're now making - // a new SELECT query. - most_recent_reservation_id_ = 0; - - // Bind values supported by parent classes. - static_cast(PgSqlHostWithOptionsExchange::createBindForReceive()); - - // reservation_id : INT UNSIGNED NOT NULL AUTO_INCREMENT - bind_[reservation_id_index_].buffer_type = MYSQL_TYPE_LONG; - bind_[reservation_id_index_].buffer = reinterpret_cast(&reservation_id_); - bind_[reservation_id_index_].is_unsigned = MLM_TRUE; - - // IPv6 address/prefix VARCHAR(39) - ipv6_address_buffer_len_ = sizeof(ipv6_address_buffer_) - 1; - bind_[address_index_].buffer_type = MYSQL_TYPE_STRING; - bind_[address_index_].buffer = ipv6_address_buffer_; - bind_[address_index_].buffer_length = ipv6_address_buffer_len_; - bind_[address_index_].length = &ipv6_address_buffer_len_; - - // prefix_len : TINYINT - bind_[prefix_len_index_].buffer_type = MYSQL_TYPE_TINY; - bind_[prefix_len_index_].buffer = reinterpret_cast(&prefix_len_); - bind_[prefix_len_index_].is_unsigned = MLM_TRUE; - - // (reservation) type : TINYINT - reserv_type_null_ = MLM_FALSE; - bind_[type_index_].buffer_type = MYSQL_TYPE_TINY; - bind_[type_index_].buffer = reinterpret_cast(&reserv_type_); - bind_[type_index_].is_unsigned = MLM_TRUE; - bind_[type_index_].is_null = &reserv_type_null_; - - // dhcp6_iaid INT UNSIGNED - bind_[iaid_index_].buffer_type = MYSQL_TYPE_LONG; - bind_[iaid_index_].buffer = reinterpret_cast(&iaid_); - bind_[iaid_index_].is_unsigned = MLM_TRUE; - - // Add the error flags - setErrorIndicators(bind_, error_); - - return (bind_); - }; - private: - - /// @brief IPv6 reservation id. - uint64_t reservation_id_; - - /// @brief IPv6 reservation type. - uint8_t reserv_type_; - - /// @brief Boolean flag indicating if reservation type field is null. - /// - /// This flag is used by the class to determine if the returned row - /// contains IPv6 reservation information. - my_bool reserv_type_null_; - - /// @brief Buffer holding IPv6 address/prefix in textual format. - char ipv6_address_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; - - /// @brief Length of the textual address representation. - unsigned long ipv6_address_buffer_len_; - - /// @brief Length of the prefix (128 for addresses) - uint8_t prefix_len_; - - /// @brief IAID. - uint8_t iaid_; - /// @name Indexes of columns holding information about IPv6 reservations. //@{ /// @brief Index of reservation_id column. @@ -943,9 +879,7 @@ private: uint64_t most_recent_reservation_id_; }; -#endif -#if 0 /// @brief This class is used for storing IPv6 reservations in a MySQL database. /// /// This class is only used to insert IPv6 reservations into the @@ -956,7 +890,7 @@ private: /// When a new IPv6 reservation is inserted into the database, an appropriate /// host must be defined in the hosts table. An attempt to insert IPv6 /// reservation for non-existing host will result in failure. -class PgSqlIPv6ReservationExchange { +class PgSqlIPv6ReservationExchange : public PgSqlExchange { private: /// @brief Set number of columns for ipv6_reservation table. @@ -968,12 +902,8 @@ public: /// /// Initialize class members representing a single IPv6 reservation. PgSqlIPv6ReservationExchange() - : host_id_(0), address_("::"), address_len_(0), prefix_len_(0), type_(0), - iaid_(0), resv_(IPv6Resrv::TYPE_NA, asiolink::IOAddress("::"), 128) { - - // Reset error table. - std::fill(&error_[0], &error_[RESRV_COLUMNS], MLM_FALSE); - + : PgSqlExchange(RESRV_COLUMNS), + resv_(IPv6Resrv::TYPE_NA, asiolink::IOAddress("::"), 128) { // Set the column names (for error messages) columns_[0] = "host_id"; columns_[1] = "address"; @@ -983,115 +913,58 @@ public: BOOST_STATIC_ASSERT(4 < RESRV_COLUMNS); } - /// @brief Create MYSQL_BIND objects for IPv6 Reservation. + /// @brief Populate a bind array representing an IPv6 reservation /// - /// Fills in the MYSQL_BIND array for sending data in the IPv6 Reservation - /// object to the database. + /// Constructs a PsqlBindArray for an IPv6 reservation to the database. /// - /// @param resv An object representing IPv6 reservation which will be - /// sent to the database. + /// @param resv The IPv6 reservation to be added to the database. /// None of the fields in the reservation are modified - - /// the reservation data is only read. - /// @param id ID of a host owning this reservation + /// @param host_id ID of the host to which this reservation belongs. /// - /// @return Vector of MySQL BIND objects representing the data to be added. - std::vector createBindForSend(const IPv6Resrv& resv, - const HostID& id) { - + /// @return pointer to newly constructed bind_array containing the + /// bound values extracted the IPv6 reservation + /// + /// @throw DbOperationError if bind_array cannot be populated. + PsqlBindArrayPtr createBindForSend(const IPv6Resrv& resv, + const HostID& host_id) { // Store the values to ensure they remain valid. + // Technically we don't need this, as currently all the values + // are converted to strings and stored by the bind array. resv_ = resv; - host_id_ = id; - // Initialize prior to constructing the array of MYSQL_BIND structures. - // It sets all fields, including is_null, to zero, so we need to set - // is_null only if it should be true. This gives up minor performance - // benefit while being safe approach. For improved readability, the - // code that explicitly sets is_null is there, but is commented out. - memset(bind_, 0, sizeof(bind_)); - - // Set up the structures for the various components of the host structure. + PsqlBindArrayPtr bind_array(new PsqlBindArray()); try { - // address VARCHAR(39) - address_ = resv.getPrefix().toText(); - address_len_ = address_.length(); - bind_[0].buffer_type = MYSQL_TYPE_BLOB; - bind_[0].buffer = reinterpret_cast - (const_cast(address_.c_str())); - bind_[0].buffer_length = address_len_; - bind_[0].length = &address_len_; - - // prefix_len tinyint - prefix_len_ = resv.getPrefixLen(); - bind_[1].buffer_type = MYSQL_TYPE_TINY; - bind_[1].buffer = reinterpret_cast(&prefix_len_); - bind_[1].is_unsigned = MLM_TRUE; - - // type tinyint + // address VARCHAR(39) NOT NULL + bind_array->add(resv.getPrefix()); + + // prefix_len: SMALLINT NOT NULL + bind_array->add(resv.getPrefixLen()); + + // type: SMALLINT NOT NULL // See lease6_types for values (0 = IA_NA, 1 = IA_TA, 2 = IA_PD) - type_ = resv.getType() == IPv6Resrv::TYPE_NA ? 0 : 2; - bind_[2].buffer_type = MYSQL_TYPE_TINY; - bind_[2].buffer = reinterpret_cast(&type_); - bind_[2].is_unsigned = MLM_TRUE; + uint16_t type = resv.getType() == IPv6Resrv::TYPE_NA ? 0 : 2; + bind_array->add(type); - // dhcp6_iaid INT UNSIGNED + // dhcp6_iaid: INT UNSIGNED /// @todo: We don't support iaid in the IPv6Resrv yet. - iaid_ = 0; - bind_[3].buffer_type = MYSQL_TYPE_LONG; - bind_[3].buffer = reinterpret_cast(&iaid_); - bind_[3].is_unsigned = MLM_TRUE; - - // host_id INT UNSIGNED NOT NULL - bind_[4].buffer_type = MYSQL_TYPE_LONG; - bind_[4].buffer = reinterpret_cast(&host_id_); - bind_[4].is_unsigned = MLM_TRUE; + bind_array->addNull(); + // host_id: BIGINT NOT NULL + bind_array->add(host_id); } catch (const std::exception& ex) { isc_throw(DbOperationError, "Could not create bind array from IPv6 Reservation: " << resv_.toText() << ", reason: " << ex.what()); } - // Add the data to the vector. Note the end element is one after the - // end of the array. - // RESRV_COLUMNS -1 as we do not set reservation_id. - return (std::vector(&bind_[0], &bind_[RESRV_COLUMNS-1])); + return (bind_array); } private: - - /// @brief Host unique identifier. - uint64_t host_id_; - - /// @brief Address (or prefix). - std::string address_; - - /// @brief Length of the textual address representation. - unsigned long address_len_; - - /// @brief Length of the prefix (128 for addresses). - uint8_t prefix_len_; - - /// @brief Reservation type. - uint8_t type_; - - /// @brief IAID. - uint8_t iaid_; - /// @brief Object holding reservation being sent to the database. IPv6Resrv resv_; - - /// @brief Array of MySQL bindings. - MYSQL_BIND bind_[RESRV_COLUMNS]; - - /// @brief Array of strings holding columns names. - std::string columns_[RESRV_COLUMNS]; - - /// @brief Array of boolean values indicating if error occurred - /// for respective columns. - my_bool error_[RESRV_COLUMNS]; }; -#endif /// @brief This class is used for inserting options into a database. /// @@ -1242,23 +1115,15 @@ public: /// The contents of the enum are indexes into the list of SQL statements enum StatementIndex { INSERT_HOST, // Insert new host to collection -#if 0 INSERT_V6_RESRV, // Insert v6 reservation -#endif INSERT_V4_OPTION, // Insert DHCPv4 option INSERT_V6_OPTION, // Insert DHCPv6 option -#if 0 GET_HOST_DHCPID, // Gets hosts by host identifier -#endif GET_HOST_ADDR, // Gets hosts by IPv4 address GET_HOST_SUBID4_DHCPID, // Gets host by IPv4 SubnetID, HW address/DUID -#if 0 GET_HOST_SUBID6_DHCPID, // Gets host by IPv6 SubnetID, HW address/DUID -#endif GET_HOST_SUBID_ADDR, // Gets host by IPv4 SubnetID and IPv4 address -#if 0 GET_HOST_PREFIX, // Gets host by IPv6 prefix -#endif GET_VERSION, // Obtain version number NUM_STATEMENTS // Number of statements }; @@ -1292,13 +1157,11 @@ public: PsqlBindArrayPtr& bind, const bool return_last_id = false); -#if 0 /// @brief Inserts IPv6 Reservation into ipv6_reservation table. /// /// @param resv IPv6 Reservation to be added /// @param id ID of a host owning this reservation void addResv(const IPv6Resrv& resv, const HostID& id); -#endif /// @brief Inserts a single DHCP option into the database. /// @@ -1379,17 +1242,10 @@ public: /// has failed. std::pair getVersion() const; -#if 0 - // @todo TKM using plain host exchange for now - boost::shared_ptr host_exchange_; -#else /// @brief Pointer to the object representing an exchange which /// can be used to retrieve hosts and DHCPv4 options. boost::shared_ptr host_exchange_; -#endif - -#if 0 /// @brief Pointer to an object representing an exchange which can /// be used to retrieve hosts, DHCPv6 options and IPv6 reservations. boost::shared_ptr host_ipv6_exchange_; @@ -1402,7 +1258,6 @@ public: /// @brief Pointer to an object representing an exchange which can /// be used to insert new IPv6 reservation. boost::shared_ptr host_ipv6_reservation_exchange_; -#endif /// @brief Pointer to an object representing an exchange which can /// be used to insert DHCPv4 or DHCPv6 option into dhcp4_options @@ -1418,7 +1273,7 @@ public: /// retrieve hosts from the database. PgSqlTaggedStatement tagged_statements[] = { // Inserts a host into the 'hosts' table. Returns the inserted host id. - { 8, // PgSqlHostDataSourceImpl::INSERT_HOST, + {8, // PgSqlHostDataSourceImpl::INSERT_HOST, { OID_BYTEA, OID_INT2, OID_INT4, OID_INT4, OID_INT8, OID_VARCHAR, OID_VARCHAR, OID_VARCHAR }, @@ -1429,13 +1284,14 @@ PgSqlTaggedStatement tagged_statements[] = { "VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING host_id" }, -#if 0 // Inserts a single IPv6 reservation into 'reservations' table. - {PgSqlHostDataSourceImpl::INSERT_V6_RESRV, - "INSERT INTO ipv6_reservations(address, prefix_len, type, " - "dhcp6_iaid, host_id) " - "VALUES (?,?,?,?,?)"}, -#endif + {5, //PgSqlHostDataSourceImpl::INSERT_V6_RESRV, + { OID_VARCHAR, OID_INT2, OID_INT4, OID_INT4, OID_INT4 }, + "insert_v6_resrv", + "INSERT INTO ipv6_reservations(address, prefix_len, type, " + " dhcp6_iaid, host_id) " + "VALUES ($1, $2, $3, $4, $5)" + }, // Inserts a single DHCPv4 option into 'dhcp4_options' table. // Using fixed scope_id = 3, which associates an option with host. @@ -1459,32 +1315,28 @@ PgSqlTaggedStatement tagged_statements[] = { "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 3)" }, -#if 0 - // Retrieves host information, IPv6 reservations and both DHCPv4 and // DHCPv6 options associated with the host. The LEFT JOIN clause is used // to retrieve information from 4 different tables using a single query. // Hence, this query returns multiple rows for a single host. - {PgSqlHostDataSourceImpl::GET_HOST_DHCPID, - "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " - "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, " - "h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, " - "o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, " - "o4.persistent, " - "o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, " - "o6.persistent, " - "r.reservation_id, r.address, r.prefix_len, r.type, " - "r.dhcp6_iaid " - "FROM hosts AS h " - "LEFT JOIN dhcp4_options AS o4 " - "ON h.host_id = o4.host_id " - "LEFT JOIN dhcp6_options AS o6 " - "ON h.host_id = o6.host_id " - "LEFT JOIN ipv6_reservations AS r " - "ON h.host_id = r.host_id " - "WHERE dhcp_identifier = ? AND dhcp_identifier_type = ? " - "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id"}, -#endif + {2, // PgSqlHostDataSourceImpl::GET_HOST_DHCPID, + { OID_BYTEA, OID_INT2 }, + "get_host_dhcpid", + "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " + " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, " + " h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, " + " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, " + " o4.persistent, " + " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, " + " o6.persistent, " + " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid " + "FROM hosts AS h " + "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id " + "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id " + "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " + "WHERE dhcp_identifier = $1 AND dhcp_identifier_type = $2 " + "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id" + }, // Retrieves host information along with the DHCPv4 options associated with // it. Left joining the dhcp4_options table results in multiple rows being @@ -1518,28 +1370,26 @@ PgSqlTaggedStatement tagged_statements[] = { "ORDER BY h.host_id, o.option_id" }, -#if 0 // Retrieves host information, IPv6 reservations and DHCPv6 options // associated with a host. The number of rows returned is a multiplication // of number of IPv6 reservations and DHCPv6 options. - {PgSqlHostDataSourceImpl::GET_HOST_SUBID6_DHCPID, - "SELECT h.host_id, h.dhcp_identifier, " - "h.dhcp_identifier_type, h.dhcp4_subnet_id, " - "h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " - "h.dhcp4_client_classes, h.dhcp6_client_classes, " - "o.option_id, o.code, o.value, o.formatted_value, o.space, " - "o.persistent, " - "r.reservation_id, r.address, r.prefix_len, r.type, " - "r.dhcp6_iaid " - "FROM hosts AS h " - "LEFT JOIN dhcp6_options AS o " - "ON h.host_id = o.host_id " - "LEFT JOIN ipv6_reservations AS r " - "ON h.host_id = r.host_id " - "WHERE h.dhcp6_subnet_id = ? AND h.dhcp_identifier_type = ? " - "AND h.dhcp_identifier = ? " - "ORDER BY h.host_id, o.option_id, r.reservation_id"}, -#endif + {3, //PgSqlHostDataSourceImpl::GET_HOST_SUBID6_DHCPID, + { OID_INT4, OID_INT2, OID_BYTEA }, + "get_host_subid6_dhcpid", + "SELECT h.host_id, h.dhcp_identifier, " + " h.dhcp_identifier_type, h.dhcp4_subnet_id, " + " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " + " h.dhcp4_client_classes, h.dhcp6_client_classes, " + " o.option_id, o.code, o.value, o.formatted_value, o.space, " + " o.persistent, " + " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid " + "FROM hosts AS h " + "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " + "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " + "WHERE h.dhcp6_subnet_id = $1 AND h.dhcp_identifier_type = $2 " + " AND h.dhcp_identifier = $3 " + "ORDER BY h.host_id, o.option_id, r.reservation_id" + }, // Retrieves host information and DHCPv4 options for the host using subnet // identifier and IPv4 reservation. Left joining the dhcp4_options table @@ -1557,7 +1407,6 @@ PgSqlTaggedStatement tagged_statements[] = { "WHERE h.dhcp4_subnet_id = $1 AND h.ipv4_address = $2 " "ORDER BY h.host_id, o.option_id" }, -#if 0 // Retrieves host information, IPv6 reservations and DHCPv6 options // associated with a host using prefix and prefix length. This query @@ -1565,25 +1414,25 @@ PgSqlTaggedStatement tagged_statements[] = { // are returned due to left joining IPv6 reservations and DHCPv6 options. // The number of rows returned is multiplication of number of existing // IPv6 reservations and DHCPv6 options. - {PgSqlHostDataSourceImpl::GET_HOST_PREFIX, - "SELECT h.host_id, h.dhcp_identifier, " - "h.dhcp_identifier_type, h.dhcp4_subnet_id, " - "h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " - "h.dhcp4_client_classes, h.dhcp6_client_classes, " - "o.option_id, o.code, o.value, o.formatted_value, o.space, " - "o.persistent, " - "r.reservation_id, r.address, r.prefix_len, r.type, " - "r.dhcp6_iaid " - "FROM hosts AS h " - "LEFT JOIN dhcp6_options AS o " - "ON h.host_id = o.host_id " - "LEFT JOIN ipv6_reservations AS r " - "ON h.host_id = r.host_id " - "WHERE h.host_id = " - "(SELECT host_id FROM ipv6_reservations " - "WHERE address = ? AND prefix_len = ?) " - "ORDER BY h.host_id, o.option_id, r.reservation_id"}, -#endif + {2, // PgSqlHostDataSourceImpl::GET_HOST_PREFIX, + { OID_VARCHAR, OID_INT2 }, + "get_host_prefix", + "SELECT h.host_id, h.dhcp_identifier, " + " h.dhcp_identifier_type, h.dhcp4_subnet_id, " + " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " + " h.dhcp4_client_classes, h.dhcp6_client_classes, " + " o.option_id, o.code, o.value, o.formatted_value, o.space, " + " o.persistent, " + " r.reservation_id, r.address, r.prefix_len, r.type, " + " r.dhcp6_iaid " + "FROM hosts AS h " + "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " + "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " + "WHERE h.host_id = " + " (SELECT host_id FROM ipv6_reservations " + " WHERE address = $1 AND prefix_len = $2) " + "ORDER BY h.host_id, o.option_id, r.reservation_id" + }, // Retrieves MySQL schema version. { 0, //PgSqlHostDataSourceImpl::GET_VERSION, @@ -1598,17 +1447,11 @@ PgSqlTaggedStatement tagged_statements[] = { PgSqlHostDataSourceImpl:: PgSqlHostDataSourceImpl(const PgSqlConnection::ParameterMap& parameters) -#if 0 - : host_exchange_(new PgSqlHostExchange()), -#else : host_exchange_(new PgSqlHostWithOptionsExchange(PgSqlHostWithOptionsExchange::DHCP4_ONLY)), -#endif -#if 0 host_ipv6_exchange_(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP6_ONLY)), host_ipv46_exchange_(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange:: DHCP4_AND_DHCP6)), host_ipv6_reservation_exchange_(new PgSqlIPv6ReservationExchange()), -#endif host_option_exchange_(new PgSqlOptionExchange()), conn_(parameters) { @@ -1662,16 +1505,13 @@ PgSqlHostDataSourceImpl::addStatement(StatementIndex stindex, } -#if 0 void PgSqlHostDataSourceImpl::addResv(const IPv6Resrv& resv, const HostID& id) { - std::vector bind = - host_ipv6_reservation_exchange_->createBindForSend(resv, id); - - addStatement(INSERT_V6_RESRV, bind); + PsqlBindArrayPtr bind_array; + bind_array = host_ipv6_reservation_exchange_->createBindForSend(resv, id); + addStatement(INSERT_V6_RESRV, bind_array); } -#endif void PgSqlHostDataSourceImpl::addOption(const StatementIndex& stindex, @@ -1835,7 +1675,6 @@ PgSqlHostDataSource::add(const HostPtr& host) { cfg_option6, host_id); } -#if 0 // Insert IPv6 reservations. IPv6ResrvRange v6resv = host->getIPv6Reservations(); if (std::distance(v6resv.first, v6resv.second) > 0) { @@ -1845,8 +1684,6 @@ PgSqlHostDataSource::add(const HostPtr& host) { } } -#endif - // Everything went fine, so explicitly commit the transaction. transaction.commit(); } @@ -1868,15 +1705,6 @@ PgSqlHostDataSource::getAll(const HWAddrPtr& hwaddr, return (ConstHostCollection()); } -#if 1 -ConstHostCollection -PgSqlHostDataSource::getAll(const Host::IdentifierType&, - const uint8_t*, - const size_t) const { - ConstHostCollection result; - return (result); -} -#else ConstHostCollection PgSqlHostDataSource::getAll(const Host::IdentifierType& identifier_type, const uint8_t* identifier_begin, @@ -1884,19 +1712,18 @@ PgSqlHostDataSource::getAll(const Host::IdentifierType& identifier_type, // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); - // Identifier type. - bind_array->add(static_cast(identifier_type)); - // Identifier value. bind_array->add(identifier_begin, identifier_len); + // Identifier type. + bind_array->add(static_cast(identifier_type)); + ConstHostCollection result; impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_DHCPID, bind_array, impl_->host_ipv46_exchange_, result, false); return (result); } -#endif ConstHostCollection PgSqlHostDataSource::getAll4(const asiolink::IOAddress& address) const { @@ -1904,6 +1731,7 @@ PgSqlHostDataSource::getAll4(const asiolink::IOAddress& address) const { // Set up the WHERE clause value PsqlBindArrayPtr bind_array(new PsqlBindArray()); + // v4 Reservation address bind_array->add(address); ConstHostCollection result; @@ -1977,13 +1805,6 @@ PgSqlHostDataSource::get4(const SubnetID& subnet_id, return (result); } -#if 1 -ConstHostPtr -PgSqlHostDataSource::get6(const SubnetID&, const DuidPtr&, - const HWAddrPtr&) const { - return (HostPtr()); -} -#else ConstHostPtr PgSqlHostDataSource::get6(const SubnetID& subnet_id, const DuidPtr& duid, const HWAddrPtr& hwaddr) const { @@ -2009,17 +1830,7 @@ PgSqlHostDataSource::get6(const SubnetID& subnet_id, const DuidPtr& duid, return (ConstHostPtr()); } -#endif -#if 1 -ConstHostPtr -PgSqlHostDataSource::get6(const SubnetID&, - const Host::IdentifierType&, - const uint8_t*, - const size_t) const { - return (ConstHostPtr()); -} -#else ConstHostPtr PgSqlHostDataSource::get6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type, @@ -2030,44 +1841,22 @@ PgSqlHostDataSource::get6(const SubnetID& subnet_id, identifier_len, PgSqlHostDataSourceImpl::GET_HOST_SUBID6_DHCPID, impl_->host_ipv6_exchange_)); } -#endif -#if 1 -ConstHostPtr -PgSqlHostDataSource::get6(const asiolink::IOAddress&, - const uint8_t) const { - - ConstHostPtr result; - return(result); -} -#else ConstHostPtr PgSqlHostDataSource::get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const { - // Set up the WHERE clause value - MYSQL_BIND inbind[2]; - memset(inbind, 0, sizeof(inbind)); - - std::string addr6 = prefix.toText(); - unsigned long addr6_length = addr6.size(); - - inbind[0].buffer_type = MYSQL_TYPE_BLOB; - inbind[0].buffer = reinterpret_cast - (const_cast(addr6.c_str())); - inbind[0].length = &addr6_length; - inbind[0].buffer_length = addr6_length; - + PsqlBindArrayPtr bind_array(new PsqlBindArray()); - uint8_t tmp = prefix_len; - inbind[1].buffer_type = MYSQL_TYPE_TINY; - inbind[1].buffer = reinterpret_cast(&tmp); - inbind[1].is_unsigned = MLM_TRUE; + // Add the prefix + bind_array->add(prefix); + // Add the prefix length + bind_array->add(prefix_len); ConstHostCollection collection; impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_PREFIX, - inbind, impl_->host_ipv6_exchange_, + bind_array, impl_->host_ipv6_exchange_, collection, true); // Return single record if present, else clear the host. @@ -2078,7 +1867,6 @@ PgSqlHostDataSource::get6(const asiolink::IOAddress& prefix, return (result); } -#endif // Miscellaneous database methods. diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index dc4b2b31fd..693fb95db8 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -636,27 +636,6 @@ public: } } - /// @brief Converts a column in a row in a result set into IPv6 address. - /// - /// @param r the result set containing the query results - /// @param row the row number within the result set - /// @param col the column number within the row - /// - /// @return isc::asiolink::IOAddress containing the IPv6 address. - /// @throw DbOperationError if the value cannot be fetched or is - /// invalid. - isc::asiolink::IOAddress getIPv6Value(const PgSqlResult& r, const int row, - const size_t col) const { - const char* data = getRawColumnValue(r, row, col); - try { - return (isc::asiolink::IOAddress(data)); - } catch (const std::exception& ex) { - isc_throw(DbOperationError, "Cannot convert data: " << data - << " for: " << getColumnLabel(r, col) << " row:" << row - << " : " << ex.what()); - } - } - private: /// @brief Lease6 object currently being sent to the database. /// Storing this value ensures that it remains in scope while any bindings diff --git a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc index 882dcccf61..205e2ce6d6 100644 --- a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc @@ -257,7 +257,6 @@ TEST_F(PgSqlHostDataSourceTest, DISABLED_hwaddrOrClientId2) { /// reservation is returned. } -#if 0 // Test verifies that host with IPv6 address and DUID can be added and // later retrieved by IPv6 address. TEST_F(PgSqlHostDataSourceTest, get6AddrWithDuid) { @@ -380,7 +379,6 @@ TEST_F(PgSqlHostDataSourceTest, addDuplicate6WithDUID) { TEST_F(PgSqlHostDataSourceTest, addDuplicate6WithHWAddr) { testAddDuplicate6WithSameHWAddr(); } -#endif // Test if the duplicate IPv4 host instances can't be inserted. The test logic is as // follows: try to add multiple instances of the same host reservation and @@ -394,7 +392,6 @@ TEST_F(PgSqlHostDataSourceTest, addDuplicate4) { TEST_F(PgSqlHostDataSourceTest, optionsReservations4) { testOptionsReservations4(false); } -#if 0 // This test verifies that DHCPv6 options can be inserted in a binary format /// and retrieved from the PostgreSQL host database. @@ -407,7 +404,6 @@ TEST_F(PgSqlHostDataSourceTest, optionsReservations6) { TEST_F(PgSqlHostDataSourceTest, optionsReservations46) { testOptionsReservations46(false); } -#endif // This test verifies that DHCPv4 options can be inserted in a textual format /// and retrieved from the PostgreSQL host database. @@ -415,7 +411,6 @@ TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations4) { testOptionsReservations4(true); } -#if 0 // This test verifies that DHCPv6 options can be inserted in a textual format /// and retrieved from the PostgreSQL host database. TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations6) { @@ -428,6 +423,7 @@ TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations46) { testOptionsReservations46(true); } +#if 0 // This test checks transactional insertion of the host information // into the database. The failure to insert host information at // any stage should cause the whole transaction to be rolled back.